mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
refactor(database): ♻️ Move Token to its own ORM abstraction, optimize familiar_followers route
This commit is contained in:
parent
962c159ddd
commit
845041e4db
|
|
@ -27,7 +27,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -40,7 +40,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -56,7 +56,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -46,7 +46,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -64,7 +64,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -33,7 +33,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", users[1].id),
|
meta.route.replace(":id", users[1].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -54,7 +54,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -65,7 +65,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", users[1].id),
|
meta.route.replace(":id", users[1].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -33,7 +33,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", users[0].id),
|
meta.route.replace(":id", users[0].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -54,7 +54,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -65,7 +65,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", users[0].id),
|
meta.route.replace(":id", users[0].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/statuses/${status.id}/favourite`, {
|
await fakeRequest(`/api/v1/statuses/${status.id}/favourite`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -46,7 +46,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -64,7 +64,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -33,7 +33,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -53,7 +53,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -72,7 +72,7 @@ describe(meta.route, () => {
|
||||||
const replyResponse = await fakeRequest("/api/v1/statuses", {
|
const replyResponse = await fakeRequest("/api/v1/statuses", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Reply",
|
status: "Reply",
|
||||||
|
|
@ -88,7 +88,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -108,7 +108,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -126,7 +126,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -138,7 +138,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/accounts/${users[0].id}/mute`, {
|
await fakeRequest(`/api/v1/accounts/${users[0].id}/mute`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -36,7 +36,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -49,7 +49,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -65,7 +65,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
156
api/api/v1/accounts/familiar_followers/index.test.ts
Normal file
156
api/api/v1/accounts/familiar_followers/index.test.ts
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||||
|
import { fakeRequest, getTestUsers } from "~/tests/utils.ts";
|
||||||
|
import { meta } from "./index.ts";
|
||||||
|
|
||||||
|
const { users, tokens, deleteUsers } = await getTestUsers(5);
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
// Create followers relationships
|
||||||
|
const result1 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[1].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result1.status).toBe(200);
|
||||||
|
|
||||||
|
const result2 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[2].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result2.status).toBe(200);
|
||||||
|
|
||||||
|
const result3 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[3].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result3.status).toBe(200);
|
||||||
|
|
||||||
|
const result4 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[2].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result4.status).toBe(200);
|
||||||
|
|
||||||
|
const result5 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[3].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result5.status).toBe(200);
|
||||||
|
|
||||||
|
const result6 = await fakeRequest(
|
||||||
|
`/api/v1/accounts/${users[3].id}/follow`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[2].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result6.status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await deleteUsers();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(meta.route, () => {
|
||||||
|
test("should return 0 familiar followers", async () => {
|
||||||
|
const response = await fakeRequest(`${meta.route}?id=${users[4].id}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
expect(data.length).toBe(1);
|
||||||
|
expect(data[0].id).toBe(users[4].id);
|
||||||
|
expect(data[0].accounts).toBeArrayOfSize(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return 1 familiar follower", async () => {
|
||||||
|
const response = await fakeRequest(`${meta.route}?id=${users[2].id}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
expect(data.length).toBe(1);
|
||||||
|
expect(data[0].id).toBe(users[2].id);
|
||||||
|
expect(data[0].accounts[0].id).toBe(users[1].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return 2 familiar followers", async () => {
|
||||||
|
const response = await fakeRequest(`${meta.route}?id=${users[3].id}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
expect(data.length).toBe(1);
|
||||||
|
expect(data[0].id).toBe(users[3].id);
|
||||||
|
expect(data[0].accounts).toBeArrayOfSize(2);
|
||||||
|
expect(data[0].accounts[0].id).toBe(users[2].id);
|
||||||
|
expect(data[0].accounts[1].id).toBe(users[1].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should work with multiple ids", async () => {
|
||||||
|
const response = await fakeRequest(
|
||||||
|
`${meta.route}?id[]=${users[2].id}&id[]=${users[3].id}&id[]=${users[4].id}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
expect(data.length).toBe(3);
|
||||||
|
expect(data[0].id).toBe(users[2].id);
|
||||||
|
expect(data[0].accounts[0].id).toBe(users[1].id);
|
||||||
|
expect(data[1].id).toBe(users[3].id);
|
||||||
|
expect(data[1].accounts[0].id).toBe(users[2].id);
|
||||||
|
expect(data[1].accounts[1].id).toBe(users[1].id);
|
||||||
|
expect(data[2].id).toBe(users[4].id);
|
||||||
|
expect(data[2].accounts).toBeArrayOfSize(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { apiRoute, applyConfig, auth, qsQuery } from "@/api";
|
import { apiRoute, applyConfig, auth, qsQuery } from "@/api";
|
||||||
import { createRoute } from "@hono/zod-openapi";
|
import { createRoute } from "@hono/zod-openapi";
|
||||||
import { User, db } from "@versia/kit/db";
|
import { User, db } from "@versia/kit/db";
|
||||||
import { RolePermissions, Users } from "@versia/kit/tables";
|
import { RolePermissions, type Users } from "@versia/kit/tables";
|
||||||
import { type SQL, inArray } from "drizzle-orm";
|
import { type InferSelectModel, sql } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { ErrorSchema } from "~/types/api";
|
import { ErrorSchema } from "~/types/api";
|
||||||
|
|
||||||
|
|
@ -23,7 +23,12 @@ export const meta = applyConfig({
|
||||||
|
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
query: z.object({
|
query: z.object({
|
||||||
id: z.array(z.string().uuid()).min(1).max(10).or(z.string().uuid()),
|
id: z
|
||||||
|
.array(z.string().uuid())
|
||||||
|
.min(1)
|
||||||
|
.max(10)
|
||||||
|
.or(z.string().uuid())
|
||||||
|
.transform((v) => (Array.isArray(v) ? v : [v])),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -42,7 +47,12 @@ const route = createRoute({
|
||||||
description: "Familiar followers",
|
description: "Familiar followers",
|
||||||
content: {
|
content: {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
schema: z.array(User.schema),
|
schema: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
accounts: z.array(User.schema),
|
||||||
|
}),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -66,53 +76,35 @@ export default apiRoute((app) =>
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idFollowerRelationships = await db.query.Relationships.findMany({
|
// Find followers of the accounts in "ids", that you also follow
|
||||||
columns: {
|
const finalUsers = await Promise.all(
|
||||||
ownerId: true,
|
ids.map(async (id) => ({
|
||||||
},
|
id,
|
||||||
where: (relationship, { inArray, and, eq }): SQL | undefined =>
|
accounts: await User.fromIds(
|
||||||
and(
|
(
|
||||||
inArray(
|
await db.execute(sql<InferSelectModel<typeof Users>>`
|
||||||
relationship.subjectId,
|
SELECT "Users"."id" FROM "Users"
|
||||||
Array.isArray(ids) ? ids : [ids],
|
INNER JOIN "Relationships" AS "SelfFollowing"
|
||||||
),
|
ON "SelfFollowing"."subjectId" = "Users"."id"
|
||||||
eq(relationship.following, true),
|
WHERE "SelfFollowing"."ownerId" = ${self.id}
|
||||||
),
|
AND "SelfFollowing"."following" = true
|
||||||
});
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM "Relationships" AS "IdsFollowers"
|
||||||
if (idFollowerRelationships.length === 0) {
|
WHERE "IdsFollowers"."subjectId" = ${id}
|
||||||
return context.json([], 200);
|
AND "IdsFollowers"."ownerId" = "Users"."id"
|
||||||
}
|
AND "IdsFollowers"."following" = true
|
||||||
|
)
|
||||||
// Find users that you follow in idFollowerRelationships
|
`)
|
||||||
const relevantRelationships = await db.query.Relationships.findMany({
|
).rows.map((u) => u.id as string),
|
||||||
columns: {
|
|
||||||
subjectId: true,
|
|
||||||
},
|
|
||||||
where: (relationship, { inArray, and, eq }): SQL | undefined =>
|
|
||||||
and(
|
|
||||||
eq(relationship.ownerId, self.id),
|
|
||||||
inArray(
|
|
||||||
relationship.subjectId,
|
|
||||||
idFollowerRelationships.map((f) => f.ownerId),
|
|
||||||
),
|
|
||||||
eq(relationship.following, true),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (relevantRelationships.length === 0) {
|
|
||||||
return context.json([], 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalUsers = await User.manyFromSql(
|
|
||||||
inArray(
|
|
||||||
Users.id,
|
|
||||||
relevantRelationships.map((r) => r.subjectId),
|
|
||||||
),
|
),
|
||||||
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
return context.json(
|
return context.json(
|
||||||
finalUsers.map((o) => o.toApi()),
|
finalUsers.map((u) => ({
|
||||||
|
...u,
|
||||||
|
accounts: u.accounts.map((a) => a.toApi()),
|
||||||
|
})),
|
||||||
200,
|
200,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?acct=${users[0].data.username}`,
|
`${meta.route}?acct=${users[0].data.username}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ beforeAll(async () => {
|
||||||
const res1 = await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
const res1 = await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -30,7 +30,7 @@ beforeAll(async () => {
|
||||||
const res2 = await fakeRequest(`/api/v1/accounts/${users[2].id}/follow`, {
|
const res2 = await fakeRequest(`/api/v1/accounts/${users[2].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -56,7 +56,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?id[]=${users[2].id}`,
|
`${meta.route}?id[]=${users[2].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -86,7 +86,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?id[]=${users[1].id}`,
|
`${meta.route}?id[]=${users[1].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?q=${users[0].data.username}`,
|
`${meta.route}?q=${users[0].data.username}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@ export default apiRoute((app) =>
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const application = await Application.getFromToken(token);
|
const application = await Application.getFromToken(
|
||||||
|
token.data.accessToken,
|
||||||
|
);
|
||||||
|
|
||||||
if (!application) {
|
if (!application) {
|
||||||
return context.json({ error: "Unauthorized" }, 401);
|
return context.json({ error: "Unauthorized" }, 401);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ beforeAll(async () => {
|
||||||
// Upload one emoji as admin, then one as each user
|
// Upload one emoji as admin, then one as each user
|
||||||
const response = await fakeRequest("/api/v1/emojis", {
|
const response = await fakeRequest("/api/v1/emojis", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -29,7 +29,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
await fakeRequest("/api/v1/emojis", {
|
await fakeRequest("/api/v1/emojis", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -41,7 +41,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
await fakeRequest("/api/v1/emojis", {
|
await fakeRequest("/api/v1/emojis", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -64,7 +64,7 @@ describe(meta.route, () => {
|
||||||
test("should return all global emojis", async () => {
|
test("should return all global emojis", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ describe(meta.route, () => {
|
||||||
test("should return all user emojis", async () => {
|
test("should return all user emojis", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ beforeAll(async () => {
|
||||||
// Create an emoji
|
// Create an emoji
|
||||||
const response = await fakeRequest("/api/v1/emojis", {
|
const response = await fakeRequest("/api/v1/emojis", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -55,7 +55,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
|
|
@ -67,7 +67,7 @@ describe(meta.route, () => {
|
||||||
test("should not work if the user is trying to update an emoji they don't own", async () => {
|
test("should not work if the user is trying to update an emoji they don't own", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
|
|
@ -82,7 +82,7 @@ describe(meta.route, () => {
|
||||||
test("should return the emoji", async () => {
|
test("should return the emoji", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
|
|
@ -95,7 +95,7 @@ describe(meta.route, () => {
|
||||||
test("should update the emoji", async () => {
|
test("should update the emoji", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
|
|
@ -112,7 +112,7 @@ describe(meta.route, () => {
|
||||||
test("should update the emoji with another url, but keep the shortcode", async () => {
|
test("should update the emoji with another url, but keep the shortcode", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
|
|
@ -129,7 +129,7 @@ describe(meta.route, () => {
|
||||||
test("should update the emoji to be non-global", async () => {
|
test("should update the emoji to be non-global", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
|
|
@ -143,7 +143,7 @@ describe(meta.route, () => {
|
||||||
// Check if the other user can see it
|
// Check if the other user can see it
|
||||||
const response2 = await fakeRequest("/api/v1/custom_emojis", {
|
const response2 = await fakeRequest("/api/v1/custom_emojis", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
|
|
@ -156,7 +156,7 @@ describe(meta.route, () => {
|
||||||
test("should delete the emoji", async () => {
|
test("should delete the emoji", async () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", id), {
|
const response = await fakeRequest(meta.route.replace(":id", id), {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -83,7 +83,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -95,7 +95,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
@ -118,7 +118,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -136,7 +136,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -155,7 +155,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -171,7 +171,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[2].accessToken}`,
|
Authorization: `Bearer ${tokens[2].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -45,7 +45,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -69,7 +69,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -41,7 +41,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
|
@ -62,7 +62,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -73,7 +73,7 @@ describe(meta.route, () => {
|
||||||
const response2 = await fakeRequest(meta.route, {
|
const response2 = await fakeRequest(meta.route, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(response2.status).toBe(200);
|
expect(response2.status).toBe(200);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -19,7 +19,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
notifications = await fakeRequest("/api/v1/notifications", {
|
notifications = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -60,7 +60,7 @@ describe(meta.route, () => {
|
||||||
test("should not display dismissed notification", async () => {
|
test("should not display dismissed notification", async () => {
|
||||||
const response = await fakeRequest("/api/v1/notifications", {
|
const response = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -19,7 +19,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
notifications = await fakeRequest("/api/v1/notifications", {
|
notifications = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", "invalid"),
|
meta.route.replace(":id", "invalid"),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -57,7 +57,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", "00000000-0000-0000-0000-000000000000"),
|
meta.route.replace(":id", "00000000-0000-0000-0000-000000000000"),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -70,7 +70,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", notifications[0].id),
|
meta.route.replace(":id", notifications[0].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -19,7 +19,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
notifications = await fakeRequest("/api/v1/notifications", {
|
notifications = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
const newNotifications = await fakeRequest("/api/v1/notifications", {
|
const newNotifications = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -22,7 +22,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/statuses/${statuses[i].id}/favourite`, {
|
await fakeRequest(`/api/v1/statuses/${statuses[i].id}/favourite`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -31,7 +31,7 @@ beforeAll(async () => {
|
||||||
|
|
||||||
notifications = await fakeRequest("/api/v1/notifications", {
|
notifications = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -76,7 +76,7 @@ describe(meta.route, () => {
|
||||||
test("should not display dismissed notification", async () => {
|
test("should not display dismissed notification", async () => {
|
||||||
const response = await fakeRequest("/api/v1/notifications", {
|
const response = await fakeRequest("/api/v1/notifications", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ beforeAll(async () => {
|
||||||
const res1 = await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
const res1 = await fakeRequest(`/api/v1/accounts/${users[0].id}/follow`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -31,7 +31,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -45,7 +45,7 @@ beforeAll(async () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: getFormData({}),
|
body: getFormData({}),
|
||||||
},
|
},
|
||||||
|
|
@ -56,7 +56,7 @@ beforeAll(async () => {
|
||||||
const res4 = await fakeRequest("/api/v1/statuses", {
|
const res4 = await fakeRequest("/api/v1/statuses", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: `@${users[0].data.username} test mention`,
|
status: `@${users[0].data.username} test mention`,
|
||||||
|
|
@ -83,7 +83,7 @@ describe(meta.route, () => {
|
||||||
test("should return 200 with notifications", async () => {
|
test("should return 200 with notifications", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ describe(meta.route, () => {
|
||||||
const filterResponse = await fakeRequest("/api/v2/filters", {
|
const filterResponse = await fakeRequest("/api/v2/filters", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
@ -132,7 +132,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -89,7 +89,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", role.id), {
|
const response = await fakeRequest(meta.route.replace(":id", role.id), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -133,7 +133,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -144,7 +144,7 @@ describe(meta.route, () => {
|
||||||
const response2 = await fakeRequest("/api/v1/roles", {
|
const response2 = await fakeRequest("/api/v1/roles", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route.replace(":id", role.id), {
|
const response = await fakeRequest(meta.route.replace(":id", role.id), {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ describe(meta.route, () => {
|
||||||
const response2 = await fakeRequest("/api/v1/roles", {
|
const response2 = await fakeRequest("/api/v1/roles", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -210,7 +210,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -47,7 +47,7 @@ describe(meta.route, () => {
|
||||||
`/api/v1/statuses/${timeline[0].id}`,
|
`/api/v1/statuses/${timeline[0].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/statuses/${status.id}/favourite`, {
|
await fakeRequest(`/api/v1/statuses/${status.id}/favourite`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", timeline[0].id),
|
meta.route.replace(":id", timeline[0].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ beforeAll(async () => {
|
||||||
await fakeRequest(`/api/v1/statuses/${status.id}/reblog`, {
|
await fakeRequest(`/api/v1/statuses/${status.id}/reblog`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", timeline[0].id),
|
meta.route.replace(":id", timeline[0].id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -42,7 +42,7 @@ describe(meta.route, () => {
|
||||||
await fakeRequest(`/api/v1/statuses/${timeline[1].id}/favourite`, {
|
await fakeRequest(`/api/v1/statuses/${timeline[1].id}/favourite`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -52,7 +52,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -70,7 +70,7 @@ describe(meta.route, () => {
|
||||||
`/api/v1/statuses/${timeline[1].id}`,
|
`/api/v1/statuses/${timeline[1].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[1].accessToken}`,
|
Authorization: `Bearer ${tokens[1].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams(),
|
body: new URLSearchParams(),
|
||||||
});
|
});
|
||||||
|
|
@ -51,7 +51,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "a".repeat(config.validation.max_note_size + 1),
|
status: "a".repeat(config.validation.max_note_size + 1),
|
||||||
|
|
@ -66,7 +66,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -82,7 +82,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -98,7 +98,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -114,7 +114,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -130,7 +130,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -146,7 +146,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -169,7 +169,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
@ -194,7 +194,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -207,7 +207,7 @@ describe(meta.route, () => {
|
||||||
const response2 = await fakeRequest(meta.route, {
|
const response2 = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world again!",
|
status: "Hello, world again!",
|
||||||
|
|
@ -231,7 +231,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -244,7 +244,7 @@ describe(meta.route, () => {
|
||||||
const response2 = await fakeRequest(meta.route, {
|
const response2 = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world again!",
|
status: "Hello, world again!",
|
||||||
|
|
@ -268,7 +268,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, :test:!",
|
status: "Hello, :test:!",
|
||||||
|
|
@ -295,7 +295,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: `Hello, @${users[1].data.username}!`,
|
status: `Hello, @${users[1].data.username}!`,
|
||||||
|
|
@ -322,7 +322,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: `Hello, @${users[1].data.username}@${
|
status: `Hello, @${users[1].data.username}@${
|
||||||
|
|
@ -353,7 +353,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hi! <script>alert('Hello, world!');</script>",
|
status: "Hi! <script>alert('Hello, world!');</script>",
|
||||||
|
|
@ -377,7 +377,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -403,7 +403,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "<img src='https://example.com/image.jpg'> <video src='https://example.com/video.mp4'> Test!",
|
status: "<img src='https://example.com/image.jpg'> <video src='https://example.com/video.mp4'> Test!",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ describe(meta.route, () => {
|
||||||
test("should correctly parse limit", async () => {
|
test("should correctly parse limit", async () => {
|
||||||
const response = await fakeRequest(`${meta.route}?limit=5`, {
|
const response = await fakeRequest(`${meta.route}?limit=5`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ describe(meta.route, () => {
|
||||||
test("should return 200 with statuses", async () => {
|
test("should return 200 with statuses", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ describe(meta.route, () => {
|
||||||
test("should send correct Link header", async () => {
|
test("should send correct Link header", async () => {
|
||||||
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -104,7 +104,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -119,7 +119,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&min_id=${timeline[20].id}`,
|
`${meta.route}?limit=20&min_id=${timeline[20].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -145,7 +145,7 @@ describe(meta.route, () => {
|
||||||
const filterResponse = await fakeRequest("/api/v2/filters", {
|
const filterResponse = await fakeRequest("/api/v2/filters", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
@ -162,7 +162,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe(meta.route, () => {
|
||||||
test("should correctly parse limit", async () => {
|
test("should correctly parse limit", async () => {
|
||||||
const response = await fakeRequest(`${meta.route}?limit=5`, {
|
const response = await fakeRequest(`${meta.route}?limit=5`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ describe(meta.route, () => {
|
||||||
test("should return 200 with statuses", async () => {
|
test("should return 200 with statuses", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&local=true`,
|
`${meta.route}?limit=20&local=true`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -85,7 +85,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?remote=true&allow_local_only=false&only_media=false`,
|
`${meta.route}?remote=true&allow_local_only=false&only_media=false`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -104,7 +104,7 @@ describe(meta.route, () => {
|
||||||
test("should send correct Link header", async () => {
|
test("should send correct Link header", async () => {
|
||||||
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -145,7 +145,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
`${meta.route}?limit=20&max_id=${timeline[19].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -160,7 +160,7 @@ describe(meta.route, () => {
|
||||||
`${meta.route}?limit=20&min_id=${timeline[20].id}`,
|
`${meta.route}?limit=20&min_id=${timeline[20].id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -187,7 +187,7 @@ describe(meta.route, () => {
|
||||||
const filterResponse = await fakeRequest("/api/v2/filters", {
|
const filterResponse = await fakeRequest("/api/v2/filters", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
@ -206,7 +206,7 @@ describe(meta.route, () => {
|
||||||
|
|
||||||
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
const response = await fakeRequest(`${meta.route}?limit=20`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -229,7 +229,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const { tokens, deleteUsers } = await getTestUsers(2);
|
||||||
const response = await fakeRequest("/api/v2/filters", {
|
const response = await fakeRequest("/api/v2/filters", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
@ -49,7 +49,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", filter.id),
|
meta.route.replace(":id", filter.id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -75,7 +75,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
@ -111,7 +111,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
"keywords_attributes[0][id]": filter.keywords[0].id,
|
"keywords_attributes[0][id]": filter.keywords[0].id,
|
||||||
|
|
@ -131,7 +131,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", filter.id),
|
meta.route.replace(":id", filter.id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -148,7 +148,7 @@ describe(meta.route, () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
},
|
},
|
||||||
|
|
@ -161,7 +161,7 @@ describe(meta.route, () => {
|
||||||
meta.route.replace(":id", filter.id),
|
meta.route.replace(":id", filter.id),
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ describe(meta.route, () => {
|
||||||
test("should return user filters (none)", async () => {
|
test("should return user filters (none)", async () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ describe(meta.route, () => {
|
||||||
const response = await fakeRequest(meta.route, {
|
const response = await fakeRequest(meta.route, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Application as APIApplication } from "@versia/client/types";
|
import type { Application as APIApplication } from "@versia/client/types";
|
||||||
import { db } from "@versia/kit/db";
|
import { Token, db } from "@versia/kit/db";
|
||||||
import { Applications } from "@versia/kit/tables";
|
import { Applications } from "@versia/kit/tables";
|
||||||
import {
|
import {
|
||||||
type InferInsertModel,
|
type InferInsertModel,
|
||||||
|
|
@ -81,15 +81,11 @@ export class Application extends BaseInterface<typeof Applications> {
|
||||||
public static async getFromToken(
|
public static async getFromToken(
|
||||||
token: string,
|
token: string,
|
||||||
): Promise<Application | null> {
|
): Promise<Application | null> {
|
||||||
const result = await db.query.Tokens.findFirst({
|
const result = await Token.fromAccessToken(token);
|
||||||
where: (tokens, { eq }): SQL | undefined =>
|
|
||||||
eq(tokens.accessToken, token),
|
|
||||||
with: {
|
|
||||||
application: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return result?.application ? new Application(result.application) : null;
|
return result?.data.application
|
||||||
|
? new Application(result.data.application)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromClientId(clientId: string): Promise<Application | null> {
|
public static fromClientId(clientId: string): Promise<Application | null> {
|
||||||
|
|
|
||||||
171
classes/database/token.ts
Normal file
171
classes/database/token.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
import type { Token as ApiToken } from "@versia/client/types";
|
||||||
|
import { User, db } from "@versia/kit/db";
|
||||||
|
import { type Applications, Tokens } from "@versia/kit/tables";
|
||||||
|
import {
|
||||||
|
type InferInsertModel,
|
||||||
|
type InferSelectModel,
|
||||||
|
type SQL,
|
||||||
|
desc,
|
||||||
|
eq,
|
||||||
|
inArray,
|
||||||
|
} from "drizzle-orm";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { BaseInterface } from "./base.ts";
|
||||||
|
|
||||||
|
export type TokenType = InferSelectModel<typeof Tokens> & {
|
||||||
|
application: InferSelectModel<typeof Applications> | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Token extends BaseInterface<typeof Tokens, TokenType> {
|
||||||
|
public static schema: z.ZodType<ApiToken> = z.object({
|
||||||
|
access_token: z.string(),
|
||||||
|
token_type: z.enum(["bearer"]),
|
||||||
|
scope: z.string(),
|
||||||
|
created_at: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
public async reload(): Promise<void> {
|
||||||
|
const reloaded = await Token.fromId(this.data.id);
|
||||||
|
|
||||||
|
if (!reloaded) {
|
||||||
|
throw new Error("Failed to reload token");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data = reloaded.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async fromId(id: string | null): Promise<Token | null> {
|
||||||
|
if (!id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Token.fromSql(eq(Tokens.id, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async fromIds(ids: string[]): Promise<Token[]> {
|
||||||
|
return await Token.manyFromSql(inArray(Tokens.id, ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async fromSql(
|
||||||
|
sql: SQL<unknown> | undefined,
|
||||||
|
orderBy: SQL<unknown> | undefined = desc(Tokens.id),
|
||||||
|
): Promise<Token | null> {
|
||||||
|
const found = await db.query.Tokens.findFirst({
|
||||||
|
where: sql,
|
||||||
|
orderBy,
|
||||||
|
with: {
|
||||||
|
application: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Token(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async manyFromSql(
|
||||||
|
sql: SQL<unknown> | undefined,
|
||||||
|
orderBy: SQL<unknown> | undefined = desc(Tokens.id),
|
||||||
|
limit?: number,
|
||||||
|
offset?: number,
|
||||||
|
extra?: Parameters<typeof db.query.Tokens.findMany>[0],
|
||||||
|
): Promise<Token[]> {
|
||||||
|
const found = await db.query.Tokens.findMany({
|
||||||
|
where: sql,
|
||||||
|
orderBy,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
with: {
|
||||||
|
application: true,
|
||||||
|
...extra?.with,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return found.map((s) => new Token(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(newAttachment: Partial<TokenType>): Promise<TokenType> {
|
||||||
|
await db
|
||||||
|
.update(Tokens)
|
||||||
|
.set(newAttachment)
|
||||||
|
.where(eq(Tokens.id, this.id));
|
||||||
|
|
||||||
|
const updated = await Token.fromId(this.data.id);
|
||||||
|
|
||||||
|
if (!updated) {
|
||||||
|
throw new Error("Failed to update token");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data = updated.data;
|
||||||
|
return updated.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public save(): Promise<TokenType> {
|
||||||
|
return this.update(this.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async delete(ids?: string[]): Promise<void> {
|
||||||
|
if (Array.isArray(ids)) {
|
||||||
|
await db.delete(Tokens).where(inArray(Tokens.id, ids));
|
||||||
|
} else {
|
||||||
|
await db.delete(Tokens).where(eq(Tokens.id, this.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async insert(
|
||||||
|
data: InferInsertModel<typeof Tokens>,
|
||||||
|
): Promise<Token> {
|
||||||
|
const inserted = (await db.insert(Tokens).values(data).returning())[0];
|
||||||
|
|
||||||
|
const token = await Token.fromId(inserted.id);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
throw new Error("Failed to insert token");
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async insertMany(
|
||||||
|
data: InferInsertModel<typeof Tokens>[],
|
||||||
|
): Promise<Token[]> {
|
||||||
|
const inserted = await db.insert(Tokens).values(data).returning();
|
||||||
|
|
||||||
|
return await Token.fromIds(inserted.map((i) => i.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string {
|
||||||
|
return this.data.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async fromAccessToken(
|
||||||
|
accessToken: string,
|
||||||
|
): Promise<Token | null> {
|
||||||
|
return await Token.fromSql(eq(Tokens.accessToken, accessToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the associated user from this token
|
||||||
|
*
|
||||||
|
* @returns The user associated with this token
|
||||||
|
*/
|
||||||
|
public async getUser(): Promise<User | null> {
|
||||||
|
if (!this.data.userId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await User.fromId(this.data.userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toApi(): ApiToken {
|
||||||
|
return {
|
||||||
|
access_token: this.data.accessToken,
|
||||||
|
token_type: "Bearer",
|
||||||
|
scope: this.data.scope,
|
||||||
|
created_at: Math.floor(
|
||||||
|
new Date(this.data.createdAt).getTime() / 1000,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import type { Tokens } from "@versia/kit/tables";
|
|
||||||
import type { InferSelectModel } from "drizzle-orm";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of token.
|
|
||||||
*/
|
|
||||||
export enum TokenType {
|
|
||||||
Bearer = "Bearer",
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Token = InferSelectModel<typeof Tokens>;
|
|
||||||
|
|
@ -3,18 +3,10 @@ import type {
|
||||||
FollowAccept,
|
FollowAccept,
|
||||||
FollowReject,
|
FollowReject,
|
||||||
} from "@versia/federation/types";
|
} from "@versia/federation/types";
|
||||||
import { User, db } from "@versia/kit/db";
|
import { type Application, type Token, type User, db } from "@versia/kit/db";
|
||||||
import {
|
import type { Instances, Roles, Users } from "@versia/kit/tables";
|
||||||
Applications,
|
import { type InferSelectModel, type SQL, sql } from "drizzle-orm";
|
||||||
type Instances,
|
|
||||||
type Roles,
|
|
||||||
Tokens,
|
|
||||||
type Users,
|
|
||||||
} from "@versia/kit/tables";
|
|
||||||
import { type InferSelectModel, type SQL, eq, sql } from "drizzle-orm";
|
|
||||||
import type { ApplicationType } from "~/classes/database/application.ts";
|
|
||||||
import type { EmojiWithInstance } from "~/classes/database/emoji.ts";
|
import type { EmojiWithInstance } from "~/classes/database/emoji.ts";
|
||||||
import type { Token } from "./token.ts";
|
|
||||||
|
|
||||||
export type UserType = InferSelectModel<typeof Users>;
|
export type UserType = InferSelectModel<typeof Users>;
|
||||||
|
|
||||||
|
|
@ -31,23 +23,7 @@ export type UserWithRelations = UserType & {
|
||||||
roles: InferSelectModel<typeof Roles>[];
|
roles: InferSelectModel<typeof Roles>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userRelations: {
|
export const userRelations = {
|
||||||
instance: true;
|
|
||||||
emojis: {
|
|
||||||
with: {
|
|
||||||
emoji: {
|
|
||||||
with: {
|
|
||||||
instance: true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
roles: {
|
|
||||||
with: {
|
|
||||||
role: true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} = {
|
|
||||||
instance: true,
|
instance: true,
|
||||||
emojis: {
|
emojis: {
|
||||||
with: {
|
with: {
|
||||||
|
|
@ -63,7 +39,7 @@ export const userRelations: {
|
||||||
role: true,
|
role: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
export const userExtras = {
|
export const userExtras = {
|
||||||
followerCount:
|
followerCount:
|
||||||
|
|
@ -103,19 +79,10 @@ export const userExtrasTemplate = (
|
||||||
|
|
||||||
export interface AuthData {
|
export interface AuthData {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
token: string;
|
token: Token | null;
|
||||||
application: ApplicationType | null;
|
application: Application | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFromHeader = async (value: string): Promise<AuthData> => {
|
|
||||||
const token = value.split(" ")[1];
|
|
||||||
|
|
||||||
const { user, application } =
|
|
||||||
await retrieveUserAndApplicationFromToken(token);
|
|
||||||
|
|
||||||
return { user, token, application };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const transformOutputToUserWithRelations = (
|
export const transformOutputToUserWithRelations = (
|
||||||
user: Omit<UserType, "endpoints"> & {
|
user: Omit<UserType, "endpoints"> & {
|
||||||
followerCount: unknown;
|
followerCount: unknown;
|
||||||
|
|
@ -180,52 +147,6 @@ export const findManyUsers = async (
|
||||||
return output.map((user) => transformOutputToUserWithRelations(user));
|
return output.map((user) => transformOutputToUserWithRelations(user));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const retrieveUserAndApplicationFromToken = async (
|
|
||||||
accessToken: string,
|
|
||||||
): Promise<{
|
|
||||||
user: User | null;
|
|
||||||
application: ApplicationType | null;
|
|
||||||
}> => {
|
|
||||||
if (!accessToken) {
|
|
||||||
return { user: null, application: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = (
|
|
||||||
await db
|
|
||||||
.select({
|
|
||||||
token: Tokens,
|
|
||||||
application: Applications,
|
|
||||||
})
|
|
||||||
.from(Tokens)
|
|
||||||
.leftJoin(Applications, eq(Tokens.applicationId, Applications.id))
|
|
||||||
.where(eq(Tokens.accessToken, accessToken))
|
|
||||||
.limit(1)
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
if (!output?.token.userId) {
|
|
||||||
return { user: null, application: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await User.fromId(output.token.userId);
|
|
||||||
|
|
||||||
return { user, application: output.application ?? null };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const retrieveToken = async (
|
|
||||||
accessToken: string,
|
|
||||||
): Promise<Token | null> => {
|
|
||||||
if (!accessToken) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
(await db.query.Tokens.findFirst({
|
|
||||||
where: (tokens, { eq }): SQL | undefined =>
|
|
||||||
eq(tokens.accessToken, accessToken),
|
|
||||||
})) ?? null
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const followRequestToVersia = (
|
export const followRequestToVersia = (
|
||||||
follower: User,
|
follower: User,
|
||||||
followee: User,
|
followee: User,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
// biome-ignore lint/performance/noBarrelFile: <explanation>
|
// biome-ignore lint/performance/noBarrelFile: <explanation>
|
||||||
export { User } from "~/classes/database/user";
|
export { User } from "~/classes/database/user.ts";
|
||||||
export { Role } from "~/classes/database/role";
|
export { Role } from "~/classes/database/role.ts";
|
||||||
export { Attachment } from "~/classes/database/attachment";
|
export { Attachment } from "~/classes/database/attachment.ts";
|
||||||
export { Emoji } from "~/classes/database/emoji";
|
export { Emoji } from "~/classes/database/emoji.ts";
|
||||||
export { Instance } from "~/classes/database/instance";
|
export { Instance } from "~/classes/database/instance.ts";
|
||||||
export { Note } from "~/classes/database/note";
|
export { Note } from "~/classes/database/note.ts";
|
||||||
export { Timeline } from "~/classes/database/timeline";
|
export { Timeline } from "~/classes/database/timeline.ts";
|
||||||
export { Application } from "~/classes/database/application";
|
export { Application } from "~/classes/database/application.ts";
|
||||||
export { db } from "~/drizzle/db";
|
export { db } from "~/drizzle/db.ts";
|
||||||
export { Relationship } from "~/classes/database/relationship";
|
export { Relationship } from "~/classes/database/relationship.ts";
|
||||||
export { Like } from "~/classes/database/like";
|
export { Like } from "~/classes/database/like.ts";
|
||||||
|
export { Token } from "~/classes/database/token.ts";
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -79,7 +79,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: "jwt=invalid-jwt",
|
Cookie: "jwt=invalid-jwt",
|
||||||
},
|
},
|
||||||
|
|
@ -118,7 +118,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -160,7 +160,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -200,7 +200,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response2 = await fakeRequest("/oauth/authorize", {
|
const response2 = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt2}`,
|
Cookie: `jwt=${jwt2}`,
|
||||||
},
|
},
|
||||||
|
|
@ -245,7 +245,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -289,7 +289,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -331,7 +331,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
@ -373,7 +373,7 @@ describe("/oauth/authorize", () => {
|
||||||
const response = await fakeRequest("/oauth/authorize", {
|
const response = await fakeRequest("/oauth/authorize", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Cookie: `jwt=${jwt}`,
|
Cookie: `jwt=${jwt}`,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import { auth, jsonOrForm } from "@/api";
|
import { auth, jsonOrForm } from "@/api";
|
||||||
import { randomString } from "@/math";
|
import { randomString } from "@/math";
|
||||||
import { Application, User, db } from "@versia/kit/db";
|
import { Application, Token, User } from "@versia/kit/db";
|
||||||
import { RolePermissions, Tokens } from "@versia/kit/tables";
|
import { RolePermissions } from "@versia/kit/tables";
|
||||||
import { type JWTPayload, SignJWT, jwtVerify } from "jose";
|
import { type JWTPayload, SignJWT, jwtVerify } from "jose";
|
||||||
import { JOSEError } from "jose/errors";
|
import { JOSEError } from "jose/errors";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { TokenType } from "~/classes/functions/token";
|
|
||||||
import type { PluginType } from "../index.ts";
|
import type { PluginType } from "../index.ts";
|
||||||
|
|
||||||
const schemas = {
|
const schemas = {
|
||||||
|
|
@ -282,11 +281,11 @@ export default (plugin: PluginType): void =>
|
||||||
.setProtectedHeader({ alg: "EdDSA" })
|
.setProtectedHeader({ alg: "EdDSA" })
|
||||||
.sign(keys.private);
|
.sign(keys.private);
|
||||||
|
|
||||||
await db.insert(Tokens).values({
|
await Token.insert({
|
||||||
accessToken: randomString(64, "base64url"),
|
accessToken: randomString(64, "base64url"),
|
||||||
code,
|
code,
|
||||||
scope: scope ?? application.data.scopes,
|
scope: scope ?? application.data.scopes,
|
||||||
tokenType: TokenType.Bearer,
|
tokenType: "Bearer",
|
||||||
applicationId: application.id,
|
applicationId: application.id,
|
||||||
redirectUri: redirect_uri ?? application.data.redirectUri,
|
redirectUri: redirect_uri ?? application.data.redirectUri,
|
||||||
expiresAt: new Date(
|
expiresAt: new Date(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
import { randomString } from "@/math.ts";
|
import { randomString } from "@/math.ts";
|
||||||
import { setCookie } from "@hono/hono/cookie";
|
import { setCookie } from "@hono/hono/cookie";
|
||||||
import { createRoute, z } from "@hono/zod-openapi";
|
import { createRoute, z } from "@hono/zod-openapi";
|
||||||
import { User, db } from "@versia/kit/db";
|
import { Token, User, db } from "@versia/kit/db";
|
||||||
import { type SQL, and, eq, isNull } from "@versia/kit/drizzle";
|
import { type SQL, and, eq, isNull } from "@versia/kit/drizzle";
|
||||||
import {
|
import { OpenIdAccounts, RolePermissions, Users } from "@versia/kit/tables";
|
||||||
OpenIdAccounts,
|
|
||||||
RolePermissions,
|
|
||||||
Tokens,
|
|
||||||
Users,
|
|
||||||
} from "@versia/kit/tables";
|
|
||||||
import { SignJWT } from "jose";
|
import { SignJWT } from "jose";
|
||||||
import { TokenType } from "~/classes/functions/token.ts";
|
|
||||||
import type { PluginType } from "../../index.ts";
|
import type { PluginType } from "../../index.ts";
|
||||||
import { automaticOidcFlow } from "../../utils.ts";
|
import { automaticOidcFlow } from "../../utils.ts";
|
||||||
|
|
||||||
|
|
@ -314,11 +308,11 @@ export default (plugin: PluginType): void => {
|
||||||
|
|
||||||
const code = randomString(32, "hex");
|
const code = randomString(32, "hex");
|
||||||
|
|
||||||
await db.insert(Tokens).values({
|
await Token.insert({
|
||||||
accessToken: randomString(64, "base64url"),
|
accessToken: randomString(64, "base64url"),
|
||||||
code,
|
code,
|
||||||
scope: flow.application.scopes,
|
scope: flow.application.scopes,
|
||||||
tokenType: TokenType.Bearer,
|
tokenType: "Bearer",
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
applicationId: flow.application.id,
|
applicationId: flow.application.id,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, describe, expect, test } from "bun:test";
|
||||||
import { Application, db } from "@versia/kit/db";
|
import { Application, Token } from "@versia/kit/db";
|
||||||
import { eq } from "@versia/kit/drizzle";
|
|
||||||
import { Tokens } from "@versia/kit/tables";
|
|
||||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||||
|
|
||||||
const { deleteUsers, users } = await getTestUsers(1);
|
const { deleteUsers, users } = await getTestUsers(1);
|
||||||
|
|
@ -13,9 +11,7 @@ const application = await Application.insert({
|
||||||
secret: "test-secret",
|
secret: "test-secret",
|
||||||
name: "Test Application",
|
name: "Test Application",
|
||||||
});
|
});
|
||||||
|
const token = await Token.insert({
|
||||||
beforeAll(async () => {
|
|
||||||
await db.insert(Tokens).values({
|
|
||||||
code: "test-code",
|
code: "test-code",
|
||||||
redirectUri: application.data.redirectUri,
|
redirectUri: application.data.redirectUri,
|
||||||
clientId: application.data.clientId,
|
clientId: application.data.clientId,
|
||||||
|
|
@ -26,15 +22,12 @@ beforeAll(async () => {
|
||||||
scope: application.data.scopes,
|
scope: application.data.scopes,
|
||||||
userId: users[0].id,
|
userId: users[0].id,
|
||||||
applicationId: application.id,
|
applicationId: application.id,
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await deleteUsers();
|
await deleteUsers();
|
||||||
await application.delete();
|
await application.delete();
|
||||||
await db
|
await token.delete();
|
||||||
.delete(Tokens)
|
|
||||||
.where(eq(Tokens.clientId, application.data.clientId));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("/oauth/revoke", () => {
|
describe("/oauth/revoke", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { jsonOrForm } from "@/api";
|
import { jsonOrForm } from "@/api";
|
||||||
import { createRoute, z } from "@hono/zod-openapi";
|
import { createRoute, z } from "@hono/zod-openapi";
|
||||||
import { db } from "@versia/kit/db";
|
import { Token, db } from "@versia/kit/db";
|
||||||
import { type SQL, eq } from "@versia/kit/drizzle";
|
import { and, eq } from "@versia/kit/drizzle";
|
||||||
import { Tokens } from "@versia/kit/tables";
|
import { Tokens } from "@versia/kit/tables";
|
||||||
import type { PluginType } from "../../index.ts";
|
import type { PluginType } from "../../index.ts";
|
||||||
|
|
||||||
|
|
@ -62,16 +62,12 @@ export default (plugin: PluginType): void => {
|
||||||
const { client_id, client_secret, token } =
|
const { client_id, client_secret, token } =
|
||||||
context.req.valid("json");
|
context.req.valid("json");
|
||||||
|
|
||||||
const foundToken = await db.query.Tokens.findFirst({
|
const foundToken = await Token.fromSql(
|
||||||
where: (tokenTable, { eq, and }): SQL | undefined =>
|
|
||||||
and(
|
and(
|
||||||
eq(tokenTable.accessToken, token ?? ""),
|
eq(Tokens.accessToken, token ?? ""),
|
||||||
eq(tokenTable.clientId, client_id),
|
eq(Tokens.clientId, client_id),
|
||||||
),
|
),
|
||||||
with: {
|
);
|
||||||
application: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!(foundToken && token)) {
|
if (!(foundToken && token)) {
|
||||||
return context.json(
|
return context.json(
|
||||||
|
|
@ -85,7 +81,7 @@ export default (plugin: PluginType): void => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the client secret is correct
|
// Check if the client secret is correct
|
||||||
if (foundToken.application?.secret !== client_secret) {
|
if (foundToken.data.application?.secret !== client_secret) {
|
||||||
return context.json(
|
return context.json(
|
||||||
{
|
{
|
||||||
error: "unauthorized_client",
|
error: "unauthorized_client",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, describe, expect, test } from "bun:test";
|
||||||
import { Application, db } from "@versia/kit/db";
|
import { Application, Token } from "@versia/kit/db";
|
||||||
import { eq } from "@versia/kit/drizzle";
|
|
||||||
import { Tokens } from "@versia/kit/tables";
|
|
||||||
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
import { fakeRequest, getTestUsers } from "~/tests/utils";
|
||||||
|
|
||||||
const { deleteUsers, users } = await getTestUsers(1);
|
const { deleteUsers, users } = await getTestUsers(1);
|
||||||
|
|
@ -13,9 +11,7 @@ const application = await Application.insert({
|
||||||
secret: "test-secret",
|
secret: "test-secret",
|
||||||
name: "Test Application",
|
name: "Test Application",
|
||||||
});
|
});
|
||||||
|
const token = await Token.insert({
|
||||||
beforeAll(async () => {
|
|
||||||
await db.insert(Tokens).values({
|
|
||||||
code: "test-code",
|
code: "test-code",
|
||||||
redirectUri: application.data.redirectUri,
|
redirectUri: application.data.redirectUri,
|
||||||
clientId: application.data.clientId,
|
clientId: application.data.clientId,
|
||||||
|
|
@ -25,15 +21,12 @@ beforeAll(async () => {
|
||||||
tokenType: "Bearer",
|
tokenType: "Bearer",
|
||||||
scope: application.data.scopes,
|
scope: application.data.scopes,
|
||||||
userId: users[0].id,
|
userId: users[0].id,
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await deleteUsers();
|
await deleteUsers();
|
||||||
await application.delete();
|
await application.delete();
|
||||||
await db
|
await token.delete();
|
||||||
.delete(Tokens)
|
|
||||||
.where(eq(Tokens.clientId, application.data.clientId));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("/oauth/token", () => {
|
describe("/oauth/token", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { jsonOrForm } from "@/api";
|
import { jsonOrForm } from "@/api";
|
||||||
import { createRoute, z } from "@hono/zod-openapi";
|
import { createRoute, z } from "@hono/zod-openapi";
|
||||||
import { Application, db } from "@versia/kit/db";
|
import { Application, Token } from "@versia/kit/db";
|
||||||
import { type SQL, eq } from "@versia/kit/drizzle";
|
import { and, eq } from "@versia/kit/drizzle";
|
||||||
import { Tokens } from "@versia/kit/tables";
|
import { Tokens } from "@versia/kit/tables";
|
||||||
import type { PluginType } from "../../index.ts";
|
import type { PluginType } from "../../index.ts";
|
||||||
|
|
||||||
|
|
@ -154,17 +154,13 @@ export default (plugin: PluginType): void => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = await db.query.Tokens.findFirst({
|
const token = await Token.fromSql(
|
||||||
where: (token, { eq, and }): SQL | undefined =>
|
|
||||||
and(
|
and(
|
||||||
eq(token.code, code),
|
eq(Tokens.code, code),
|
||||||
eq(
|
eq(Tokens.redirectUri, decodeURI(redirect_uri)),
|
||||||
token.redirectUri,
|
eq(Tokens.clientId, client_id),
|
||||||
decodeURI(redirect_uri),
|
|
||||||
),
|
),
|
||||||
eq(token.clientId, client_id),
|
);
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return context.json(
|
return context.json(
|
||||||
|
|
@ -177,28 +173,22 @@ export default (plugin: PluginType): void => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate the code
|
// Invalidate the code
|
||||||
await db
|
await token.update({ code: null });
|
||||||
.update(Tokens)
|
|
||||||
.set({ code: null })
|
|
||||||
.where(eq(Tokens.id, token.id));
|
|
||||||
|
|
||||||
return context.json(
|
return context.json(
|
||||||
{
|
{
|
||||||
access_token: token.accessToken,
|
...token.toApi(),
|
||||||
token_type: "Bearer",
|
expires_in: token.data.expiresAt
|
||||||
expires_in: token.expiresAt
|
|
||||||
? Math.floor(
|
? Math.floor(
|
||||||
(new Date(token.expiresAt).getTime() -
|
(new Date(
|
||||||
|
token.data.expiresAt,
|
||||||
|
).getTime() -
|
||||||
Date.now()) /
|
Date.now()) /
|
||||||
1000,
|
1000,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
id_token: token.idToken,
|
id_token: token.data.idToken,
|
||||||
refresh_token: null,
|
refresh_token: null,
|
||||||
scope: token.scope,
|
|
||||||
created_at: Math.floor(
|
|
||||||
new Date(token.createdAt).getTime() / 1000,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
200,
|
200,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ describe("/api/v1/sso/:id", () => {
|
||||||
const response = await fakeRequest("/api/v1/sso/unknown", {
|
const response = await fakeRequest("/api/v1/sso/unknown", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ describe("/api/v1/sso/:id", () => {
|
||||||
const response2 = await fakeRequest("/api/v1/sso/unknown", {
|
const response2 = await fakeRequest("/api/v1/sso/unknown", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ describe("/api/v1/sso", () => {
|
||||||
const response = await fakeRequest("/api/v1/sso", {
|
const response = await fakeRequest("/api/v1/sso", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ describe("/api/v1/sso", () => {
|
||||||
const response = await fakeRequest("/api/v1/sso", {
|
const response = await fakeRequest("/api/v1/sso", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0]?.accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/statuses", {
|
const response = await fakeRequest("/api/v1/statuses", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
|
|
@ -42,7 +42,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${tokens[0].accessToken}`,
|
Authorization: `Bearer ${tokens[0].data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: getFormData({
|
body: getFormData({
|
||||||
display_name: "New Display Name",
|
display_name: "New Display Name",
|
||||||
|
|
@ -59,7 +59,7 @@ describe("API Tests", () => {
|
||||||
"/api/v1/accounts/verify_credentials",
|
"/api/v1/accounts/verify_credentials",
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -106,7 +106,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -132,7 +132,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -156,7 +156,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/blocks", {
|
const response = await fakeRequest("/api/v1/blocks", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -179,7 +179,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -205,7 +205,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -231,7 +231,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -257,7 +257,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ comment: "This is a new note" }),
|
body: JSON.stringify({ comment: "This is a new note" }),
|
||||||
|
|
@ -283,7 +283,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -314,7 +314,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/profile/avatar", {
|
const response = await fakeRequest("/api/v1/profile/avatar", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -335,7 +335,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/profile/header", {
|
const response = await fakeRequest("/api/v1/profile/header", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -358,7 +358,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
|
|
@ -371,13 +371,13 @@ describe("API Tests", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should return an array of objects with id and accounts properties, where id is a string and accounts is an array of APIAccount objects", async () => {
|
test("should return no familiar followers", async () => {
|
||||||
const response = await fakeRequest(
|
const response = await fakeRequest(
|
||||||
`/api/v1/accounts/familiar_followers?id[]=${user2.id}`,
|
`/api/v1/accounts/familiar_followers?id[]=${user2.id}`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -393,7 +393,9 @@ describe("API Tests", () => {
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
expect(Array.isArray(familiarFollowers)).toBe(true);
|
expect(Array.isArray(familiarFollowers)).toBe(true);
|
||||||
expect(familiarFollowers.length).toBe(0);
|
expect(familiarFollowers.length).toBe(1);
|
||||||
|
expect(familiarFollowers[0].id).toBe(user2.id);
|
||||||
|
expect(familiarFollowers[0].accounts).toBeArrayOfSize(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v2/media", {
|
const response = await fakeRequest("/api/v2/media", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
@ -52,7 +52,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/statuses", {
|
const response = await fakeRequest("/api/v1/statuses", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "Hello, world!",
|
status: "Hello, world!",
|
||||||
|
|
@ -94,7 +94,7 @@ describe("API Tests", () => {
|
||||||
const response = await fakeRequest("/api/v1/statuses", {
|
const response = await fakeRequest("/api/v1/statuses", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
status: "This is a reply!",
|
status: "This is a reply!",
|
||||||
|
|
@ -139,7 +139,7 @@ describe("API Tests", () => {
|
||||||
`/api/v1/statuses/${status?.id}`,
|
`/api/v1/statuses/${status?.id}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -184,7 +184,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -209,7 +209,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -232,7 +232,7 @@ describe("API Tests", () => {
|
||||||
`/api/v1/statuses/${status?.id}/context`,
|
`/api/v1/statuses/${status?.id}/context`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -259,7 +259,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -289,7 +289,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -306,7 +306,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -330,7 +330,7 @@ describe("API Tests", () => {
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token.accessToken}`,
|
Authorization: `Bearer ${token.data.accessToken}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { generateChallenge } from "@/challenges";
|
import { generateChallenge } from "@/challenges";
|
||||||
import { randomString } from "@/math";
|
import { randomString } from "@/math";
|
||||||
import { Note, User, db } from "@versia/kit/db";
|
import { Note, Token, User, db } from "@versia/kit/db";
|
||||||
import { Notes, Tokens, Users } from "@versia/kit/tables";
|
import { Notes, Users } from "@versia/kit/tables";
|
||||||
import { solveChallenge } from "altcha-lib";
|
import { solveChallenge } from "altcha-lib";
|
||||||
import { asc, inArray, like } from "drizzle-orm";
|
import { asc, inArray, like } from "drizzle-orm";
|
||||||
import { appFactory } from "~/app";
|
import { appFactory } from "~/app";
|
||||||
import type { Status } from "~/classes/functions/status";
|
import type { Status } from "~/classes/functions/status";
|
||||||
import type { Token } from "~/classes/functions/token";
|
|
||||||
import { searchManager } from "~/classes/search/search-manager";
|
import { searchManager } from "~/classes/search/search-manager";
|
||||||
import { setupDatabase } from "~/drizzle/db";
|
import { setupDatabase } from "~/drizzle/db";
|
||||||
import { config } from "~/packages/config-manager";
|
import { config } from "~/packages/config-manager";
|
||||||
|
|
@ -60,9 +59,7 @@ export const getTestUsers = async (
|
||||||
users.push(user);
|
users.push(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokens = await db
|
const tokens = await Token.insertMany(
|
||||||
.insert(Tokens)
|
|
||||||
.values(
|
|
||||||
users.map((u) => ({
|
users.map((u) => ({
|
||||||
accessToken: randomString(32, "hex"),
|
accessToken: randomString(32, "hex"),
|
||||||
tokenType: "bearer",
|
tokenType: "bearer",
|
||||||
|
|
@ -71,12 +68,15 @@ export const getTestUsers = async (
|
||||||
code: randomString(32, "hex"),
|
code: randomString(32, "hex"),
|
||||||
scope: "read write follow push",
|
scope: "read write follow push",
|
||||||
})),
|
})),
|
||||||
)
|
);
|
||||||
.returning();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users,
|
users,
|
||||||
tokens,
|
// Order tokens in the same order as users
|
||||||
|
// The first token belongs to the first user, the second token belongs to the second user, etc.
|
||||||
|
tokens: users.map(
|
||||||
|
(u) => tokens.find((t) => t.data.userId === u.id) as Token,
|
||||||
|
),
|
||||||
passwords,
|
passwords,
|
||||||
deleteUsers: async (): Promise<void> => {
|
deleteUsers: async (): Promise<void> => {
|
||||||
await db.delete(Users).where(
|
await db.delete(Users).where(
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ import type {
|
||||||
Unfollow,
|
Unfollow,
|
||||||
User,
|
User,
|
||||||
} from "@versia/federation/types";
|
} from "@versia/federation/types";
|
||||||
import type { Application, User as DatabaseUser } from "@versia/kit/db";
|
|
||||||
import type { RolePermissions } from "@versia/kit/tables";
|
import type { RolePermissions } from "@versia/kit/tables";
|
||||||
import type { SocketAddress } from "bun";
|
import type { SocketAddress } from "bun";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import type { AuthData } from "~/classes/functions/user";
|
||||||
import type { Config } from "~/packages/config-manager";
|
import type { Config } from "~/packages/config-manager";
|
||||||
|
|
||||||
export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
||||||
|
|
@ -52,11 +52,7 @@ export const ErrorSchema = z.object({
|
||||||
export type HonoEnv = {
|
export type HonoEnv = {
|
||||||
Variables: {
|
Variables: {
|
||||||
config: Config;
|
config: Config;
|
||||||
auth: {
|
auth: AuthData;
|
||||||
user: DatabaseUser | null;
|
|
||||||
token: string | null;
|
|
||||||
application: Application | null;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
Bindings: {
|
Bindings: {
|
||||||
ip?: SocketAddress | null;
|
ip?: SocketAddress | null;
|
||||||
|
|
|
||||||
43
utils/api.ts
43
utils/api.ts
|
|
@ -2,7 +2,7 @@ import type { Context, MiddlewareHandler } from "@hono/hono";
|
||||||
import { createMiddleware } from "@hono/hono/factory";
|
import { createMiddleware } from "@hono/hono/factory";
|
||||||
import type { OpenAPIHono } from "@hono/zod-openapi";
|
import type { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import { getLogger } from "@logtape/logtape";
|
import { getLogger } from "@logtape/logtape";
|
||||||
import { Application, type User, db } from "@versia/kit/db";
|
import { Application, Token, db } from "@versia/kit/db";
|
||||||
import { Challenges } from "@versia/kit/tables";
|
import { Challenges } from "@versia/kit/tables";
|
||||||
import { extractParams, verifySolution } from "altcha-lib";
|
import { extractParams, verifySolution } from "altcha-lib";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
|
@ -24,7 +24,7 @@ import {
|
||||||
import { type ParsedQs, parse } from "qs";
|
import { type ParsedQs, parse } from "qs";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
import { type AuthData, getFromHeader } from "~/classes/functions/user";
|
import type { AuthData } from "~/classes/functions/user";
|
||||||
import { config } from "~/packages/config-manager/index.ts";
|
import { config } from "~/packages/config-manager/index.ts";
|
||||||
import type { ApiRouteMetadata, HonoEnv, HttpVerb } from "~/types/api";
|
import type { ApiRouteMetadata, HonoEnv, HttpVerb } from "~/types/api";
|
||||||
|
|
||||||
|
|
@ -178,20 +178,12 @@ const checkRouteNeedsAuth = (
|
||||||
auth: AuthData | null,
|
auth: AuthData | null,
|
||||||
authData: ApiRouteMetadata["auth"],
|
authData: ApiRouteMetadata["auth"],
|
||||||
context: Context,
|
context: Context,
|
||||||
):
|
): Response | AuthData => {
|
||||||
| Response
|
if (auth?.user && auth?.token) {
|
||||||
| {
|
|
||||||
user: User | null;
|
|
||||||
token: string | null;
|
|
||||||
application: Application | null;
|
|
||||||
} => {
|
|
||||||
if (auth?.user) {
|
|
||||||
return {
|
return {
|
||||||
user: auth.user as User,
|
user: auth.user,
|
||||||
token: auth.token as string,
|
token: auth.token,
|
||||||
application: auth.application
|
application: auth.application,
|
||||||
? new Application(auth.application)
|
|
||||||
: null,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
|
@ -295,8 +287,19 @@ export const auth = (
|
||||||
): MiddlewareHandler<HonoEnv, string> =>
|
): MiddlewareHandler<HonoEnv, string> =>
|
||||||
createMiddleware<HonoEnv>(async (context, next) => {
|
createMiddleware<HonoEnv>(async (context, next) => {
|
||||||
const header = context.req.header("Authorization");
|
const header = context.req.header("Authorization");
|
||||||
|
const tokenString = header?.split(" ")[1];
|
||||||
|
|
||||||
const auth = header ? await getFromHeader(header) : null;
|
const token = tokenString
|
||||||
|
? await Token.fromAccessToken(tokenString)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const auth: AuthData = {
|
||||||
|
token,
|
||||||
|
application: token?.data.application
|
||||||
|
? new Application(token?.data.application)
|
||||||
|
: null,
|
||||||
|
user: (await token?.getUser()) ?? null,
|
||||||
|
};
|
||||||
|
|
||||||
// Only exists for type casting, as otherwise weird errors happen with Hono
|
// Only exists for type casting, as otherwise weird errors happen with Hono
|
||||||
const fakeResponse = context.json({});
|
const fakeResponse = context.json({});
|
||||||
|
|
@ -325,11 +328,7 @@ export const auth = (
|
||||||
|
|
||||||
const authCheck = checkRouteNeedsAuth(auth, authData, context) as
|
const authCheck = checkRouteNeedsAuth(auth, authData, context) as
|
||||||
| typeof fakeResponse
|
| typeof fakeResponse
|
||||||
| {
|
| AuthData;
|
||||||
user: User | null;
|
|
||||||
token: string | null;
|
|
||||||
application: Application | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (authCheck instanceof Response) {
|
if (authCheck instanceof Response) {
|
||||||
return authCheck;
|
return authCheck;
|
||||||
|
|
@ -385,7 +384,7 @@ async function parseUrlEncoded(context: Context): Promise<ParsedQs> {
|
||||||
|
|
||||||
export const qsQuery = (): MiddlewareHandler => {
|
export const qsQuery = (): MiddlewareHandler => {
|
||||||
return createMiddleware(async (context, next) => {
|
return createMiddleware(async (context, next) => {
|
||||||
const parsed = parse(context.req.query(), {
|
const parsed = parse(new URL(context.req.url).searchParams.toString(), {
|
||||||
parseArrays: true,
|
parseArrays: true,
|
||||||
interpretNumericEntities: true,
|
interpretNumericEntities: true,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue