Remove Prisma once and for all

This commit is contained in:
Jesse Wierzbinski 2024-04-13 14:46:33 -10:00
parent 90d522eaa3
commit a65249b79d
No known key found for this signature in database
18 changed files with 112 additions and 563 deletions

View file

@ -13,7 +13,6 @@ await $`rm -rf dist && mkdir dist`;
await Bun.build({
entrypoints: [
`${process.cwd()}/index.ts`,
`${process.cwd()}/prisma.ts`,
`${process.cwd()}/cli.ts`,
// Force Bun to include endpoints
...Object.values(rawRoutes),
@ -22,7 +21,7 @@ await Bun.build({
target: "bun",
splitting: true,
minify: true,
external: ["bullmq", "@prisma/client", "frontend"],
external: ["bullmq", "frontend"],
}).then((output) => {
if (!output.success) {
console.log(output.logs);
@ -33,14 +32,6 @@ await Bun.build({
// I apologize for this
await $`sed -i 's|import("node_modules/|import("./node_modules/|g' dist/*.js`;
// Copy generated Prisma client to dist
await $`mkdir -p dist/node_modules/@prisma`;
await $`cp -r ${process.cwd()}/node_modules/@prisma dist/node_modules/`;
await $`cp -r ${process.cwd()}/node_modules/.prisma dist/node_modules`;
await $`mkdir -p dist/node_modules/.bin`;
await $`cp -r ${process.cwd()}/node_modules/.bin/prisma dist/node_modules/.bin`;
await $`cp -r ${process.cwd()}/node_modules/prisma dist/node_modules/`;
// Copy Sharp to dist
await $`mkdir -p dist/node_modules/@img`;
await $`cp -r node_modules/@img/sharp-libvips-linux-* dist/node_modules/@img`;

BIN
bun.lockb

Binary file not shown.

22
cli.ts
View file

@ -3,26 +3,25 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import { Parser } from "@json2csv/plainjs";
import { MeiliIndexType, rebuildSearchIndexes } from "@meilisearch";
import type { Prisma } from "@prisma/client";
import chalk from "chalk";
import { CliBuilder, CliCommand } from "cli-parser";
import Table from "cli-table";
import { type SQL, eq, inArray, isNotNull, isNull, like } from "drizzle-orm";
import extract from "extract-zip";
import { MediaBackend } from "media-manager";
import { lookup } from "mime-types";
import { getUrl } from "~database/entities/Attachment";
import { findFirstStatuses, findManyStatuses } from "~database/entities/Status";
import {
type User,
createNewLocalUser,
findFirstUser,
findManyUsers,
type User,
} from "~database/entities/User";
import { CliParameterType } from "~packages/cli-parser/cli-builder.type";
import { config } from "~packages/config-manager";
import { db } from "~drizzle/db";
import { emoji, openIdAccount, status, user } from "~drizzle/schema";
import { type SQL, eq, inArray, isNotNull, isNull, like } from "drizzle-orm";
import { findFirstStatuses, findManyStatuses } from "~database/entities/Status";
import { CliParameterType } from "~packages/cli-parser/cli-builder.type";
import { config } from "~packages/config-manager";
const args = process.argv;
@ -949,17 +948,6 @@ const cliBuilder = new CliBuilder([
return 1;
}
const queries: Prisma.StatusWhereInput[] = [];
for (const field of fields) {
queries.push({
[field]: {
contains: query,
mode: caseSensitive ? "default" : "insensitive",
},
});
}
let instanceQuery: SQL<unknown> | undefined = isNull(
status.instanceId,
);

View file

@ -1,10 +1,4 @@
// import { Queue } from "bullmq";
import { PrismaClient } from "@prisma/client";
import { config } from "config-manager";
const client = new PrismaClient({
datasourceUrl: `postgresql://${config.database.username}:${config.database.password}@${config.database.host}:${config.database.port}/${config.database.database}`,
});
/* const federationQueue = new Queue("federation", {
connection: {
@ -14,5 +8,3 @@ const client = new PrismaClient({
db: config.redis.queue.database || undefined,
},
}); */
export { client /* federationQueue */ };

View file

@ -1,111 +0,0 @@
import type { Prisma } from "@prisma/client";
export const userRelations: Prisma.UserInclude = {
emojis: true,
instance: true,
likes: true,
relationships: true,
relationshipSubjects: true,
pinnedNotes: true,
_count: {
select: {
statuses: true,
likes: true,
},
},
};
export const statusAndUserRelations: Prisma.StatusInclude = {
author: {
include: userRelations,
},
application: true,
emojis: true,
inReplyToPost: {
include: {
author: {
include: userRelations,
},
application: true,
emojis: true,
inReplyToPost: {
include: {
author: true,
},
},
instance: true,
mentions: true,
pinnedBy: true,
_count: {
select: {
replies: true,
},
},
},
},
reblogs: true,
attachments: true,
instance: true,
mentions: {
include: userRelations,
},
pinnedBy: true,
_count: {
select: {
replies: true,
likes: true,
reblogs: true,
},
},
reblog: {
include: {
author: {
include: userRelations,
},
application: true,
emojis: true,
inReplyToPost: {
include: {
author: true,
},
},
instance: true,
mentions: {
include: userRelations,
},
pinnedBy: true,
_count: {
select: {
replies: true,
},
},
},
},
quotingPost: {
include: {
author: {
include: userRelations,
},
application: true,
emojis: true,
inReplyToPost: {
include: {
author: true,
},
},
instance: true,
mentions: true,
pinnedBy: true,
_count: {
select: {
replies: true,
},
},
},
},
likes: {
include: {
liker: true,
},
},
};

View file

@ -2,7 +2,6 @@ import { exists, mkdir, writeFile } from "node:fs/promises";
import { dirname } from "node:path";
import { connectMeili } from "@meilisearch";
import { moduleIsEntry } from "@module";
import { initializeRedisCache } from "@redis";
import { config } from "config-manager";
import { count, sql } from "drizzle-orm";
import { LogLevel, LogManager, MultiLogManager } from "log-manager";
@ -39,8 +38,6 @@ await dualLogger.log(LogLevel.INFO, "Lysand", "Starting Lysand...");
const isProd =
process.env.NODE_ENV === "production" || process.argv.includes("--prod");
const redisCache = await initializeRedisCache();
if (config.meilisearch.enabled) {
await connectMeili(dualLogger);
}

View file

@ -43,7 +43,7 @@
"prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma",
"generate": "bun prisma generate",
"benchmark:timeline": "bun run benchmarks/timelines.ts",
"cloc": "cloc . --exclude-dir node_modules,dist",
"cloc": "cloc . --exclude-dir node_modules,dist,.output,.nuxt,meta,logs --exclude-ext sql,log",
"cli": "bun run cli.ts"
},
"trustedDependencies": [
@ -51,14 +51,11 @@
"@fortawesome/fontawesome-common-types",
"@fortawesome/free-regular-svg-icons",
"@fortawesome/free-solid-svg-icons",
"@prisma/client",
"@prisma/engines",
"es5-ext",
"esbuild",
"json-editor-vue",
"msgpackr-extract",
"nuxt-app",
"prisma",
"sharp",
"vue-demi"
],
@ -99,7 +96,6 @@
"@aws-sdk/client-s3": "^3.461.0",
"@iarna/toml": "^2.2.5",
"@json2csv/plainjs": "^7.0.6",
"@prisma/client": "^5.6.0",
"blurhash": "^2.0.5",
"bullmq": "latest",
"chalk": "^5.3.0",
@ -128,9 +124,6 @@
"next-route-matcher": "^1.0.1",
"oauth4webapi": "^2.4.0",
"pg": "^8.11.5",
"prisma": "^5.6.0",
"prisma-json-types-generator": "^3.0.4",
"prisma-redis-middleware": "^4.8.0",
"request-parser": "workspace:*",
"semver": "^7.5.4",
"sharp": "^0.33.3",

View file

@ -14,9 +14,9 @@ import {
validateAuthResponse,
} from "oauth4webapi";
import { TokenType } from "~database/entities/Token";
import { findFirstUser } from "~database/entities/User";
import { db } from "~drizzle/db";
import { token } from "~drizzle/schema";
import { findFirstUser } from "~database/entities/User";
export const meta = applyConfig({
allowedMethods: ["GET"],

View file

@ -1,74 +1,19 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import type { Token } from "@prisma/client";
import { config } from "config-manager";
import { inArray } from "drizzle-orm";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import { eq } from "drizzle-orm";
import { db } from "~drizzle/db";
import { application, user } from "~drizzle/schema";
import { emoji } from "~drizzle/schema";
import type { APIEmoji } from "~types/entities/emoji";
import type { APIInstance } from "~types/entities/instance";
import { sendTestRequest, wrapRelativeUrl } from "./utils";
import { getTestUsers, sendTestRequest, wrapRelativeUrl } from "./utils";
const base_url = config.http.base_url;
let token: Token;
let dummyUser: UserWithRelations;
const { tokens, deleteUsers } = await getTestUsers(1);
describe("API Tests", () => {
beforeAll(async () => {
await db.delete(user).where(inArray(user.username, ["test", "test2"]));
await db
.delete(application)
.where(inArray(application.clientId, ["test"]));
// Initialize test user
dummyUser = await createNewLocalUser({
email: "test@test.com",
username: "test",
password: "test",
display_name: "",
});
if (!dummyUser) {
throw new Error("Failed to create test user");
}
token = await client.token.create({
data: {
access_token: "test",
application: {
create: {
client_id: "test",
name: "Test Application",
redirect_uris: "https://example.com",
scopes: "read write",
secret: "test",
website: "https://example.com",
vapid_key: null,
},
},
code: "test",
scope: "read write",
token_type: TokenType.BEARER,
user: {
connect: {
id: dummyUser.id,
},
},
},
});
});
afterAll(async () => {
await db.delete(user).where(inArray(user.username, ["test", "test2"]));
await db
.delete(application)
.where(inArray(application.clientId, ["test"]));
await deleteUsers();
});
describe("GET /api/v1/instance", () => {
@ -111,14 +56,11 @@ describe("API Tests", () => {
describe("GET /api/v1/custom_emojis", () => {
beforeAll(async () => {
await client.emoji.create({
data: {
instanceId: null,
url: "https://example.com/test.png",
content_type: "image/png",
await db.insert(emoji).values({
shortcode: "test",
visible_in_picker: true,
},
url: "https://example.com/test.png",
contentType: "image/png",
visibleInPicker: true,
});
});
@ -132,7 +74,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${tokens[0].accessToken}`,
},
},
),
@ -151,11 +93,7 @@ describe("API Tests", () => {
});
afterAll(async () => {
await client.emoji.deleteMany({
where: {
shortcode: "test",
},
});
await db.delete(emoji).where(eq(emoji.shortcode, "test"));
});
});
});

View file

@ -1,86 +1,19 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import type { Token } from "@prisma/client";
import { config } from "config-manager";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import { sendTestRequest, wrapRelativeUrl } from "~tests/utils";
import { getTestUsers, sendTestRequest, wrapRelativeUrl } from "~tests/utils";
import type { APIAccount } from "~types/entities/account";
import type { APIRelationship } from "~types/entities/relationship";
import type { APIStatus } from "~types/entities/status";
const base_url = config.http.base_url;
let token: Token;
let user: UserWithRelations;
let user2: UserWithRelations;
beforeAll(async () => {
await client.user.deleteMany({
where: {
username: {
in: ["test", "test2"],
},
},
});
user = await createNewLocalUser({
email: "test@test.com",
username: "test",
password: "test",
display_name: "",
});
user2 = await createNewLocalUser({
email: "test2@test.com",
username: "test2",
password: "test2",
display_name: "",
});
token = await client.token.create({
data: {
access_token: "test",
application: {
create: {
client_id: "test",
name: "Test Application",
redirect_uris: "https://example.com",
scopes: "read write",
secret: "test",
website: "https://example.com",
vapid_key: null,
},
},
code: "test",
scope: "read write",
token_type: TokenType.BEARER,
user: {
connect: {
id: user.id,
},
},
},
});
});
const { users, tokens, deleteUsers } = await getTestUsers(2);
const user = users[0];
const user2 = users[1];
const token = tokens[0];
afterAll(async () => {
await client.user.deleteMany({
where: {
username: {
in: ["test", "test2"],
},
},
});
await client.application.deleteMany({
where: {
client_id: "test",
},
});
await deleteUsers();
});
describe("API Tests", () => {
@ -92,7 +25,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -117,7 +50,7 @@ describe("API Tests", () => {
{
method: "PATCH",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
@ -149,7 +82,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -199,7 +132,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -228,7 +161,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -259,7 +192,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -290,7 +223,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -321,7 +254,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -347,7 +280,7 @@ describe("API Tests", () => {
new Request(wrapRelativeUrl("/api/v1/blocks", base_url), {
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
}),
);
@ -375,7 +308,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -406,7 +339,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ notifications: true }),
@ -436,7 +369,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ notifications: false }),
@ -463,7 +396,7 @@ describe("API Tests", () => {
new Request(wrapRelativeUrl("/api/v1/mutes", base_url), {
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
}),
);
@ -492,7 +425,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -523,7 +456,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -554,7 +487,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -585,7 +518,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ comment: "This is a new note" }),
@ -616,7 +549,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
},
),
@ -651,7 +584,7 @@ describe("API Tests", () => {
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -678,7 +611,7 @@ describe("API Tests", () => {
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -708,7 +641,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
@ -732,7 +665,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
},
),

View file

@ -1,13 +1,12 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import type { Token } from "@prisma/client";
import { afterAll, describe, expect, test } from "bun:test";
import { config } from "config-manager";
import { client } from "~database/datasource";
import { TokenType } from "~database/entities/Token";
import { statusToAPI } from "~database/entities/Status";
import {
type UserWithRelations,
createNewLocalUser,
} from "~database/entities/User";
import { sendTestRequest, wrapRelativeUrl } from "~tests/utils";
getTestStatuses,
getTestUsers,
sendTestRequest,
wrapRelativeUrl,
} from "~tests/utils";
import type { APIAccount } from "~types/entities/account";
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
import type { APIContext } from "~types/entities/context";
@ -15,69 +14,16 @@ import type { APIStatus } from "~types/entities/status";
const base_url = config.http.base_url;
let token: Token;
let user: UserWithRelations;
const { users, tokens, deleteUsers } = await getTestUsers(1);
const user = users[0];
const token = tokens[0];
let status: APIStatus | null = null;
let status2: APIStatus | null = null;
let media1: APIAsyncAttachment | null = null;
describe("API Tests", () => {
beforeAll(async () => {
await client.user.deleteMany({
where: {
username: {
in: ["test", "test2"],
},
},
});
user = await createNewLocalUser({
email: "test@test.com",
username: "test",
password: "test",
display_name: "",
});
token = await client.token.create({
data: {
access_token: "test",
application: {
create: {
client_id: "test",
name: "Test Application",
redirect_uris: "https://example.com",
scopes: "read write",
secret: "test",
website: "https://example.com",
vapid_key: null,
},
},
code: "test",
scope: "read write",
token_type: TokenType.BEARER,
user: {
connect: {
id: user.id,
},
},
},
});
});
afterAll(async () => {
await client.user.deleteMany({
where: {
username: {
in: ["test", "test2"],
},
},
});
await client.application.deleteMany({
where: {
client_id: "test",
},
});
await deleteUsers();
});
describe("POST /api/v2/media", () => {
@ -91,7 +37,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
body: formData,
},
@ -119,7 +65,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
@ -167,7 +113,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
@ -220,7 +166,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -271,7 +217,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -302,7 +248,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -332,7 +278,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -365,7 +311,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -394,7 +340,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -430,7 +376,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -452,7 +398,7 @@ describe("API Tests", () => {
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -483,7 +429,7 @@ describe("API Tests", () => {
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
"Content-Type": "application/json",
},
},
@ -513,7 +459,7 @@ describe("API Tests", () => {
{
method: "DELETE",
headers: {
Authorization: `Bearer ${token.access_token}`,
Authorization: `Bearer ${token.accessToken}`,
},
},
),

View file

@ -1,94 +0,0 @@
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { client } from "~database/datasource";
import { createNewLocalUser } from "~database/entities/User";
describe("cli.ts", () => {
describe("User creation", () => {
it("should execute user create command without admin flag", async () => {
afterAll(async () => {
await client.user.deleteMany({
where: {
username: "testuser297",
email: "testuser297@gmail.com",
},
});
});
// Run command and wait for it to finish
Bun.spawnSync([
"bun",
"run",
"cli.ts",
"user",
"create",
"testuser297",
"password123",
"testuser297@gmail.com",
]);
const createdUser = await client.user.findFirst({
where: {
username: "testuser297",
email: "testuser297@gmail.com",
},
});
expect(createdUser).toBeDefined();
});
it("should execute user create command with admin flag", async () => {
afterAll(async () => {
await client.user.deleteMany({
where: {
username: "testuser297",
email: "testuser297@gmail.com",
},
});
});
// Run command and wait for it to finish
Bun.spawnSync([
"bun",
"run",
"cli.ts",
"user",
"create",
"testuser297",
"password123",
"testuser297@gmail.com",
"--admin",
]);
const createdUser = await client.user.findFirst({
where: {
username: "testuser297",
email: "testuser297@gmail.com",
isAdmin: true,
},
});
expect(createdUser).toBeDefined();
});
});
it("should execute user delete command", async () => {
beforeAll(async () => {
await createNewLocalUser({
username: "bob124",
password: "jesus",
email: "bob124@bob124.com",
});
});
Bun.spawnSync(["bun", "run", "cli", "user", "delete", "bob124"]);
const userExists = await client.user.findFirst({
where: {
username: "bob124",
email: "bob124@bob124.com",
},
});
expect(!!userExists).toBe(false);
});
});

View file

@ -1,6 +1,6 @@
import { describe, expect, it } from "bun:test";
import { checkIfOauthIsValid } from "@oauth";
import type { Application } from "@prisma/client";
import type { Application } from "~database/entities/Application";
describe("checkIfOauthIsValid", () => {
it("should return true when routeScopes and application.scopes are empty", () => {

View file

@ -1,26 +1,25 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import type { Application, Token } from "@prisma/client";
import { client } from "~database/datasource";
import { createNewLocalUser } from "~database/entities/User";
import { sendTestRequest, wrapRelativeUrl } from "./utils";
import { afterAll, describe, expect, test } from "bun:test";
import type { APIApplication } from "~types/entities/application";
import {
deleteOldTestUsers,
getTestUsers,
sendTestRequest,
wrapRelativeUrl,
} from "./utils";
import type { APIToken } from "~types/entities/token";
const base_url = "http://lysand.localhost:8080"; //config.http.base_url;
let client_id: string;
let client_secret: string;
let code: string;
let token: Token;
let token: APIToken;
const { users, passwords, deleteUsers } = await getTestUsers(1);
beforeAll(async () => {
// Init test user
await createNewLocalUser({
email: "test@test.com",
username: "test",
password: "test",
display_name: "",
});
afterAll(async () => {
await deleteUsers();
await deleteOldTestUsers();
});
describe("POST /api/v1/apps/", () => {
test("should create an application", async () => {
const formData = new FormData();
@ -61,8 +60,10 @@ describe("POST /api/auth/login/", () => {
test("should get a code", async () => {
const formData = new FormData();
formData.append("email", "test@test.com");
formData.append("password", "test");
console.log(users[0]?.email ?? "");
formData.append("email", users[0]?.email ?? "");
formData.append("password", passwords[0]);
const response = await sendTestRequest(
new Request(
@ -139,20 +140,9 @@ describe("GET /api/v1/apps/verify_credentials", () => {
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe("application/json");
const credentials = (await response.json()) as Partial<Application>;
const credentials = (await response.json()) as Partial<APIApplication>;
expect(credentials.name).toBe("Test Application");
expect(credentials.website).toBe("https://example.com");
expect(credentials.redirect_uris).toBe("https://example.com");
expect(credentials.scopes).toBe("read write");
});
});
afterAll(async () => {
// Clean up user
await client.user.delete({
where: {
username: "test",
},
});
});

View file

@ -1,6 +1,6 @@
import { randomBytes } from "node:crypto";
import { inArray, like } from "drizzle-orm";
import type { Status } from "~database/entities/Status";
import { type Status, findManyStatuses } from "~database/entities/Status";
import {
type User,
type UserWithRelations,
@ -31,19 +31,22 @@ export const deleteOldTestUsers = async () => {
export const getTestUsers = async (count: number) => {
const users: UserWithRelations[] = [];
const passwords: string[] = [];
for (let i = 0; i < count; i++) {
const password = randomBytes(32).toString("hex");
const user = await createNewLocalUser({
username: `test-${randomBytes(32).toString("hex")}`,
email: `${randomBytes(32).toString("hex")}@test.com`,
password: randomBytes(32).toString("hex"),
skipPasswordHash: true,
password,
});
if (!user) {
throw new Error("Failed to create test user");
}
passwords.push(password);
users.push(user);
}
@ -64,6 +67,7 @@ export const getTestUsers = async (count: number) => {
return {
users,
tokens,
passwords,
deleteUsers: async () => {
await db.delete(user).where(
inArray(
@ -104,5 +108,14 @@ export const getTestStatuses = async (
statuses.push(newStatus);
}
return statuses.toSorted((a, b) => a.id.localeCompare(b.id));
const statusesWithRelations = await findManyStatuses({
where: (status, { inArray }) =>
inArray(
status.id,
statuses.map((s) => s.id),
),
orderBy: (status, { asc }) => asc(status.id),
});
return statusesWithRelations;
};

28
types.d.ts vendored
View file

@ -1,28 +0,0 @@
import type { LysandObject } from "@prisma/client";
import type { APIAccount } from "~types/entities/account";
import type { APIField } from "~types/entities/field";
import type { ContentFormat } from "~types/lysand/Object";
declare namespace global {
namespace PrismaJson {
type InstanceLogo = ContentFormat[];
type ObjectData = LysandObject;
type ObjectExtensions = LysandObject["extensions"];
interface UserEndpoints {
inbox: string;
liked: string;
outbox: string;
disliked: string;
featured: string;
followers: string;
following: string;
}
interface UserSource {
note: string;
fields: APIField[];
privacy: APIAccount["privacy"];
language: string;
sensitive: boolean;
}
}
}

View file

@ -1,4 +1,4 @@
import type { Application } from "@prisma/client";
import type { Application } from "~database/entities/Application";
/**
* Check if an OAuth application is valid for a route

View file

@ -1,4 +1,4 @@
import type { Prisma } from "@prisma/client";
/* import type { Prisma } from "@prisma/client";
import chalk from "chalk";
import { config } from "config-manager";
import Redis from "ioredis";
@ -56,3 +56,4 @@ export const initializeRedisCache = async () => {
return null;
};
*/