feat(api): Implement /v1/instance/rules and /v1/instance/extended_description

This commit is contained in:
Jesse Wierzbinski 2024-04-14 19:08:16 -10:00
parent 5b0d2014ff
commit 96a2fbf178
No known key found for this signature in database
11 changed files with 140 additions and 6 deletions

3
.gitignore vendored
View file

@ -173,4 +173,5 @@ uploads/
pages/dist
log.txt
*.log
build
build
config/extended_description_test.md

View file

@ -2,5 +2,5 @@
"typescript.tsdk": "node_modules/typescript/lib",
"jest.jestCommandLine": "/home/jessew/.bun/bin/bun test",
"jest.rootPath": ".",
"conventionalCommits.scopes": ["database", "frontend", "build"]
"conventionalCommits.scopes": ["database", "frontend", "build", "api"]
}

View file

@ -286,6 +286,9 @@ avatars = []
[instance]
name = "Lysand"
description = "A test instance of Lysand"
# Path to a file containing a longer description of your instance
# This will be parsed as Markdown
extended_description_path = ""
# URL to your instance logo (jpg files should be renamed to jpeg)
logo = ""
# URL to your instance banner (jpg files should be renamed to jpeg)

View file

@ -13,7 +13,7 @@ cd /app/dist
# Parse first argument
case "$1" in
"start")
NITRO_PORT=5173 bun run ./frontend/server/index.mjs & NODE_ENV=production bun run ./index.js --prod
NODE_ENV=production bun run ./index.js --prod
;;
"cli")
# Start the CLI

View file

@ -1,14 +1,23 @@
import { dualLogger } from "@loggers";
import { connectMeili } from "@meilisearch";
import { config } from "config-manager";
import { count } from "drizzle-orm";
import { LogLevel } from "log-manager";
import { LogLevel, LogManager, type MultiLogManager } from "log-manager";
import { db, setupDatabase } from "~drizzle/db";
import { status } from "~drizzle/schema";
import { createServer } from "~server";
const timeAtStart = performance.now();
const isEntry = import.meta.path === Bun.main;
let dualLogger: LogManager | MultiLogManager = new LogManager(
Bun.file("/dev/null"),
);
if (isEntry) {
dualLogger = (await import("@loggers")).dualLogger;
}
await dualLogger.log(LogLevel.INFO, "Lysand", "Starting Lysand...");
await setupDatabase(dualLogger);

View file

@ -315,6 +315,9 @@ export interface Config {
/** @default "A test instance of Lysand" */
description: string;
/** @default "" */
extended_description_path: string;
/** @default "" */
logo: string;
@ -589,6 +592,7 @@ export const defaultConfig: Config = {
instance: {
name: "Lysand",
description: "A test instance of Lysand",
extended_description_path: "",
logo: "",
banner: "",
},

View file

@ -0,0 +1,23 @@
import { describe, expect, test } from "bun:test";
import { meta } from "./extended_description";
import { sendTestRequest } from "~tests/utils";
import { config } from "config-manager";
// /api/v1/instance/extended_description
describe(meta.route, () => {
test("should return extended description", async () => {
const response = await sendTestRequest(
new Request(new URL(meta.route, config.http.base_url)),
);
expect(response.status).toBe(200);
const json = await response.json();
expect(json).toEqual({
updated_at: new Date(2024, 0, 0).toISOString(),
// This is a [Lysand](https://lysand.org) server with the default extended description.
content:
'<p>This is a <a href="https://lysand.org">Lysand</a> server with the default extended description.</p>\n',
});
});
});

View file

@ -0,0 +1,47 @@
import { apiRoute, applyConfig } from "@api";
import { dualLogger } from "@loggers";
import { jsonResponse } from "@response";
import { parse } from "marked";
import { LogLevel } from "~packages/log-manager";
export const meta = applyConfig({
allowedMethods: ["GET"],
route: "/api/v1/instance/extended_description",
ratelimits: {
max: 300,
duration: 60,
},
auth: {
required: false,
},
});
export default apiRoute(async (req, matchedRoute, extraData) => {
const config = await extraData.configManager.getConfig();
let extended_description = parse(
"This is a [Lysand](https://lysand.org) server with the default extended description.",
);
let lastModified = new Date(2024, 0, 0);
const extended_description_file = Bun.file(
config.instance.extended_description_path,
);
if (await extended_description_file.exists()) {
extended_description =
(await parse(
(await extended_description_file.text().catch(async (e) => {
await dualLogger.logError(LogLevel.ERROR, "Routes", e);
return "";
})) ||
"This is a [Lysand](https://lysand.org) server with the default extended description.",
)) || "";
lastModified = new Date(extended_description_file.lastModified);
}
return jsonResponse({
updated_at: lastModified.toISOString(),
content: extended_description,
});
});

View file

@ -0,0 +1,23 @@
import { describe, expect, test } from "bun:test";
import { meta } from "./rules";
import { sendTestRequest } from "~tests/utils";
import { config } from "config-manager";
// /api/v1/instance/rules
describe(meta.route, () => {
test("should return rules", async () => {
const response = await sendTestRequest(
new Request(new URL(meta.route, config.http.base_url)),
);
expect(response.status).toBe(200);
const json = await response.json();
expect(json).toEqual(
config.signups.rules.map((rule, index) => ({
id: String(index),
text: rule,
})),
);
});
});

View file

@ -0,0 +1,25 @@
import { apiRoute, applyConfig } from "@api";
import { jsonResponse } from "@response";
export const meta = applyConfig({
allowedMethods: ["GET"],
route: "/api/v1/instance/rules",
ratelimits: {
max: 300,
duration: 60,
},
auth: {
required: false,
},
});
export default apiRoute(async (req, matchedRoute, extraData) => {
const config = await extraData.configManager.getConfig();
return jsonResponse(
config.signups.rules.map((rule, index) => ({
id: String(index),
text: rule,
})),
);
});

View file

@ -9,7 +9,6 @@ import {
import { db } from "~drizzle/db";
import { status, token, user } from "~drizzle/schema";
import { server } from "~index";
/**
* This allows us to send a test request to the server even when it isnt running
* CURRENTLY NOT WORKING, NEEDS TO BE FIXED