Add CLI and CLI tests

This commit is contained in:
Jesse Wierzbinski 2023-11-20 13:58:39 -10:00
parent 7dbe5dfecd
commit 5287ceb99e
No known key found for this signature in database
5 changed files with 294 additions and 1 deletions

169
cli.ts Normal file
View file

@ -0,0 +1,169 @@
import chalk from "chalk";
import { client } from "~database/datasource";
import { createNewLocalUser } from "~database/entities/User";
const args = process.argv;
const help = `
${chalk.bold(`Usage: bun cli <command> ${chalk.blue("[...flags]")} [...args]`)}
${chalk.bold("Commands:")}
${chalk.blue("help")} ${chalk.gray(
"................."
)} Show this help message
${chalk.blue("user")} ${chalk.gray(".................")} Manage users
${chalk.blue("create")} ${chalk.gray("...........")} Create a new user
${chalk.green("username")} ${chalk.gray(
"....."
)} Username of the user
${chalk.green("password")} ${chalk.gray(
"....."
)} Password of the user
${chalk.green("email")} ${chalk.gray("........")} Email of the user
${chalk.yellow("--admin")} ${chalk.gray(
"......"
)} Make the user an admin (optional)
${chalk.bold("Example:")} ${chalk.bgGray(
`bun cli user create admin password123 admin@gmail.com --admin`
)}
${chalk.blue("delete")} ${chalk.gray("...........")} Delete a user
${chalk.green("username")} ${chalk.gray(
"....."
)} Username of the user
${chalk.bold("Example:")} ${chalk.bgGray(
`bun cli user delete admin`
)}
${chalk.blue("list")} ${chalk.gray(".............")} List all users
${chalk.yellow("--admins")} ${chalk.gray(
"....."
)} List only admins (optional)
${chalk.bold("Example:")} ${chalk.bgGray(`bun cli user list`)}
`;
if (args.length < 3) {
console.log(help);
process.exit(0);
}
const command = args[2];
switch (command) {
case "help":
console.log(help);
break;
case "user":
switch (args[3]) {
case "create": {
// Check if --admin flag is provided
const argsWithFlags = args.filter(arg => arg.startsWith("--"));
const argsWithoutFlags = args.filter(
arg => !arg.startsWith("--")
);
const username = argsWithoutFlags[4];
const password = argsWithoutFlags[5];
const email = argsWithoutFlags[6];
const admin = argsWithFlags.includes("--admin");
// Check if username, password and email are provided
if (!username || !password || !email) {
console.log(
`${chalk.red(``)} Missing username, password or email`
);
process.exit(1);
}
// Check if user already exists
const user = await client.user.findFirst({
where: {
OR: [{ username }, { email }],
},
});
if (user) {
console.log(`${chalk.red(``)} User already exists`);
process.exit(1);
}
// Create user
const newUser = await createNewLocalUser({
email: email,
password: password,
username: username,
admin: admin,
});
console.log(
`${chalk.green(``)} Created user ${chalk.blue(
newUser.username
)}`
);
break;
}
case "delete": {
const username = args[4];
if (!username) {
console.log(`${chalk.red(``)} Missing username`);
process.exit(1);
}
const user = await client.user.findFirst({
where: {
username: username,
},
});
if (!user) {
console.log(`${chalk.red(``)} User not found`);
process.exit(1);
}
await client.user.delete({
where: {
id: user.id,
},
});
console.log(
`${chalk.green(``)} Deleted user ${chalk.blue(
user.username
)}`
);
break;
}
case "list": {
const admins = args.includes("--admins");
const users = await client.user.findMany({
where: {
isAdmin: admins || undefined,
},
});
console.log(
`${chalk.green(``)} Found ${chalk.blue(
users.length
)} users`
);
for (const user of users) {
console.log(
`\t${chalk.blue(user.username)} ${chalk.gray(
user.email
)} ${chalk.green(user.isAdmin ? "Admin" : "User")}`
);
}
break;
}
default:
console.log(`Unknown command ${chalk.blue(command)}`);
break;
}
break;
default:
console.log(`Unknown command ${chalk.blue(command)}`);
break;
}

View file

@ -207,6 +207,7 @@ export const createNewLocalUser = async (data: {
bio?: string;
avatar?: string;
header?: string;
admin?: boolean;
}) => {
const config = getConfig();
@ -221,6 +222,7 @@ export const createNewLocalUser = async (data: {
note: data.bio ?? "",
avatar: data.avatar ?? config.defaults.avatar,
header: data.header ?? config.defaults.avatar,
isAdmin: data.admin ?? false,
uri: "",
publicKey: keys.public_key,
privateKey: keys.private_key,

View file

@ -8,6 +8,8 @@ import "reflect-metadata";
import { AuthData, getFromRequest } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
import { mkdir } from "fs/promises";
import { client } from "~database/datasource";
import { PrismaClientInitializationError } from "@prisma/client/runtime/library";
const router = new Bun.FileSystemRouter({
style: "nextjs",
@ -25,6 +27,20 @@ if (!(await requests_log.exists())) {
await Bun.write(process.cwd() + "/logs/requests.log", "");
}
// Check if database is reachable
const postCount = 0;
try {
await client.status.count();
} catch (e) {
const error = e as PrismaClientInitializationError;
console.error(
`${chalk.red(``)} ${chalk.bold(
"Error while connecting to database: "
)} ${error.message}`
);
process.exit(1);
}
Bun.serve({
port: config.http.bind_port,
hostname: config.http.bind || "0.0.0.0", // defaults to "0.0.0.0"
@ -153,3 +169,14 @@ console.log(
)}`
)}`
);
console.log(
`${chalk.green(``)} ${chalk.bold(`Database is ${chalk.blue("online")}`)}`
);
// Print "serving x posts"
console.log(
`${chalk.green(``)} ${chalk.bold(
`Serving ${chalk.blue(postCount)} posts`
)}`
);

View file

@ -37,7 +37,8 @@
"migrate-dev": "bunx prisma migrate dev",
"migrate": "bunx prisma migrate deploy",
"lint": "eslint --config .eslintrc.cjs --ext .ts .",
"generate": "bunx prisma generate"
"generate": "bunx prisma generate",
"cli": "bun run cli.ts"
},
"trustedDependencies": [
"sharp",

94
tests/cli.test.ts Normal file
View file

@ -0,0 +1,94 @@
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);
});
});