Compare commits
2 Commits
2f059ceaff
...
2665fa1c02
Author | SHA1 | Date |
---|---|---|
pinks | 2665fa1c02 | |
pinks | 083f6bc01c |
|
@ -0,0 +1,9 @@
|
|||
import { createEndpoint, createMethodFilter } from "t_rest/server";
|
||||
import { bot } from "../bot/mod.ts";
|
||||
|
||||
export const botRoute = createMethodFilter({
|
||||
GET: createEndpoint({ query: null, body: null }, async () => {
|
||||
const username = bot.botInfo.username;
|
||||
return { status: 200, body: { type: "application/json", data: { username } } };
|
||||
}),
|
||||
});
|
|
@ -2,8 +2,7 @@ import { deepMerge } from "std/collections/deep_merge.ts";
|
|||
import { info } from "std/log/mod.ts";
|
||||
import { createEndpoint, createMethodFilter } from "t_rest/server";
|
||||
import { configSchema, getConfig, setConfig } from "../app/config.ts";
|
||||
import { bot } from "../bot/mod.ts";
|
||||
import { sessions } from "./sessionsRoute.ts";
|
||||
import { withUser } from "./withUser.ts";
|
||||
|
||||
export const paramsRoute = createMethodFilter({
|
||||
GET: createEndpoint(
|
||||
|
@ -23,23 +22,13 @@ export const paramsRoute = createMethodFilter({
|
|||
},
|
||||
},
|
||||
async ({ query, body }) => {
|
||||
const session = sessions.get(query.sessionId);
|
||||
if (!session?.userId) {
|
||||
return { status: 401, body: { type: "text/plain", data: "Must be logged in" } };
|
||||
}
|
||||
const chat = await bot.api.getChat(session.userId);
|
||||
if (chat.type !== "private") throw new Error("Chat is not private");
|
||||
if (!chat.username) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must have a username" } };
|
||||
}
|
||||
const config = await getConfig();
|
||||
if (!config?.adminUsernames?.includes(chat.username)) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must be an admin" } };
|
||||
}
|
||||
info(`User ${chat.username} updated default params: ${JSON.stringify(body.data)}`);
|
||||
const defaultParams = deepMerge(config.defaultParams ?? {}, body.data);
|
||||
await setConfig({ defaultParams });
|
||||
return { status: 200, body: { type: "application/json", data: config.defaultParams } };
|
||||
return withUser(query, async (chat) => {
|
||||
const config = await getConfig();
|
||||
info(`User ${chat.username} updated default params: ${JSON.stringify(body.data)}`);
|
||||
const defaultParams = deepMerge(config.defaultParams ?? {}, body.data);
|
||||
await setConfig({ defaultParams });
|
||||
return { status: 200, body: { type: "application/json", data: config.defaultParams } };
|
||||
}, { admin: true });
|
||||
},
|
||||
),
|
||||
});
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import {
|
||||
createEndpoint,
|
||||
createLoggerMiddleware,
|
||||
createMethodFilter,
|
||||
createPathFilter,
|
||||
} from "t_rest/server";
|
||||
import { createLoggerMiddleware, createPathFilter } from "t_rest/server";
|
||||
import { botRoute } from "./botRoute.ts";
|
||||
import { jobsRoute } from "./jobsRoute.ts";
|
||||
import { paramsRoute } from "./paramsRoute.ts";
|
||||
import { sessionsRoute } from "./sessionsRoute.ts";
|
||||
import { statsRoute } from "./statsRoute.ts";
|
||||
import { usersRoute } from "./usersRoute.ts";
|
||||
import { workersRoute } from "./workersRoute.ts";
|
||||
import { bot } from "../bot/mod.ts";
|
||||
|
||||
export const serveApi = createLoggerMiddleware(
|
||||
createPathFilter({
|
||||
|
@ -20,13 +15,7 @@ export const serveApi = createLoggerMiddleware(
|
|||
"settings/params": paramsRoute,
|
||||
"stats": statsRoute,
|
||||
"workers": workersRoute,
|
||||
"bot": createMethodFilter({
|
||||
// deno-lint-ignore require-await
|
||||
GET: createEndpoint({ query: null, body: null }, async () => {
|
||||
const username = bot.botInfo.username;
|
||||
return { status: 200, body: { type: "application/json", data: { username } } };
|
||||
}),
|
||||
}),
|
||||
"bot": botRoute,
|
||||
}),
|
||||
{ filterStatus: (status) => status >= 400 },
|
||||
);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// deno-lint-ignore-file require-await
|
||||
import { createEndpoint, createMethodFilter, createPathFilter } from "t_rest/server";
|
||||
import { ulid } from "ulid";
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { Chat } from "grammy_types";
|
||||
import { Output } from "t_rest/client";
|
||||
import { getConfig } from "../app/config.ts";
|
||||
import { bot } from "../bot/mod.ts";
|
||||
import { sessions } from "./sessionsRoute.ts";
|
||||
|
||||
export async function withUser<O extends Output>(
|
||||
query: { sessionId: string },
|
||||
cb: (user: Chat.PrivateGetChat) => Promise<O>,
|
||||
options?: { admin?: boolean },
|
||||
) {
|
||||
const session = sessions.get(query.sessionId);
|
||||
if (!session?.userId) {
|
||||
return { status: 401, body: { type: "text/plain", data: "Must be logged in" } } as const;
|
||||
}
|
||||
const chat = await bot.api.getChat(session.userId);
|
||||
if (chat.type !== "private") throw new Error("Chat is not private");
|
||||
if (options?.admin) {
|
||||
if (!chat.username) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must have a username" } } as const;
|
||||
}
|
||||
const config = await getConfig();
|
||||
if (!config?.adminUsernames?.includes(chat.username)) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must be an admin" } } as const;
|
||||
}
|
||||
}
|
||||
return cb(chat);
|
||||
}
|
|
@ -3,14 +3,16 @@ import { Model } from "indexed_kv";
|
|||
import createOpenApiFetch from "openapi_fetch";
|
||||
import { info } from "std/log/mod.ts";
|
||||
import { createEndpoint, createMethodFilter, createPathFilter } from "t_rest/server";
|
||||
import { getConfig } from "../app/config.ts";
|
||||
import { activeGenerationWorkers } from "../app/generationQueue.ts";
|
||||
import { generationStore } from "../app/generationStore.ts";
|
||||
import * as SdApi from "../app/sdApi.ts";
|
||||
import { WorkerInstance, workerInstanceStore } from "../app/workerInstanceStore.ts";
|
||||
import { bot } from "../bot/mod.ts";
|
||||
import {
|
||||
WorkerInstance,
|
||||
workerInstanceSchema,
|
||||
workerInstanceStore,
|
||||
} from "../app/workerInstanceStore.ts";
|
||||
import { getAuthHeader } from "../utils/getAuthHeader.ts";
|
||||
import { sessions } from "./sessionsRoute.ts";
|
||||
import { withUser } from "./withUser.ts";
|
||||
|
||||
export type WorkerData = Omit<WorkerInstance, "sdUrl" | "sdAuth"> & {
|
||||
id: string;
|
||||
|
@ -69,7 +71,6 @@ export const workersRoute = createPathFilter({
|
|||
async () => {
|
||||
const workerInstances = await workerInstanceStore.getAll();
|
||||
const workers = await Promise.all(workerInstances.map(getWorkerData));
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: workers satisfies WorkerData[] },
|
||||
|
@ -83,51 +84,18 @@ export const workersRoute = createPathFilter({
|
|||
},
|
||||
body: {
|
||||
type: "application/json",
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
key: { type: "string" },
|
||||
name: { type: ["string", "null"] },
|
||||
sdUrl: { type: "string" },
|
||||
sdAuth: {
|
||||
type: ["object", "null"],
|
||||
properties: {
|
||||
user: { type: "string" },
|
||||
password: { type: "string" },
|
||||
},
|
||||
required: ["user", "password"],
|
||||
},
|
||||
},
|
||||
required: ["key", "name", "sdUrl", "sdAuth"],
|
||||
},
|
||||
schema: workerInstanceSchema,
|
||||
},
|
||||
},
|
||||
async ({ query, body }) => {
|
||||
const session = sessions.get(query.sessionId);
|
||||
if (!session?.userId) {
|
||||
return { status: 401, body: { type: "text/plain", data: "Must be logged in" } };
|
||||
}
|
||||
const chat = await bot.api.getChat(session.userId);
|
||||
if (chat.type !== "private") throw new Error("Chat is not private");
|
||||
if (!chat.username) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must have a username" } };
|
||||
}
|
||||
const config = await getConfig();
|
||||
if (!config?.adminUsernames?.includes(chat.username)) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must be an admin" } };
|
||||
}
|
||||
const workerInstance = await workerInstanceStore.create({
|
||||
key: body.data.key,
|
||||
name: body.data.name,
|
||||
sdUrl: body.data.sdUrl,
|
||||
sdAuth: body.data.sdAuth,
|
||||
});
|
||||
info(`User ${chat.username} created worker ${workerInstance.id}`);
|
||||
const worker = await getWorkerData(workerInstance);
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: worker satisfies WorkerData },
|
||||
};
|
||||
return withUser(query, async (chat) => {
|
||||
const workerInstance = await workerInstanceStore.create(body.data);
|
||||
info(`User ${chat.username} created worker ${workerInstance.id}`);
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: await getWorkerData(workerInstance) },
|
||||
};
|
||||
}, { admin: true });
|
||||
},
|
||||
),
|
||||
}),
|
||||
|
@ -141,10 +109,9 @@ export const workersRoute = createPathFilter({
|
|||
if (!workerInstance) {
|
||||
return { status: 404, body: { type: "text/plain", data: `Worker not found` } };
|
||||
}
|
||||
const worker: WorkerData = await getWorkerData(workerInstance);
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: worker satisfies WorkerData },
|
||||
body: { type: "application/json", data: await getWorkerData(workerInstance) },
|
||||
};
|
||||
},
|
||||
),
|
||||
|
@ -155,22 +122,7 @@ export const workersRoute = createPathFilter({
|
|||
},
|
||||
body: {
|
||||
type: "application/json",
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
key: { type: "string" },
|
||||
name: { type: ["string", "null"] },
|
||||
sdUrl: { type: "string" },
|
||||
auth: {
|
||||
type: ["object", "null"],
|
||||
properties: {
|
||||
user: { type: "string" },
|
||||
password: { type: "string" },
|
||||
},
|
||||
required: ["user", "password"],
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: { ...workerInstanceSchema, required: [] },
|
||||
},
|
||||
},
|
||||
async ({ params, query, body }) => {
|
||||
|
@ -178,37 +130,18 @@ export const workersRoute = createPathFilter({
|
|||
if (!workerInstance) {
|
||||
return { status: 404, body: { type: "text/plain", data: `Worker not found` } };
|
||||
}
|
||||
const session = sessions.get(query.sessionId);
|
||||
if (!session?.userId) {
|
||||
return { status: 401, body: { type: "text/plain", data: "Must be logged in" } };
|
||||
}
|
||||
const chat = await bot.api.getChat(session.userId);
|
||||
if (chat.type !== "private") throw new Error("Chat is not private");
|
||||
if (!chat.username) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must have a username" } };
|
||||
}
|
||||
const config = await getConfig();
|
||||
if (!config?.adminUsernames?.includes(chat.username)) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must be an admin" } };
|
||||
}
|
||||
if (body.data.name !== undefined) {
|
||||
workerInstance.value.name = body.data.name;
|
||||
}
|
||||
if (body.data.sdUrl !== undefined) {
|
||||
workerInstance.value.sdUrl = body.data.sdUrl;
|
||||
}
|
||||
if (body.data.auth !== undefined) {
|
||||
workerInstance.value.sdAuth = body.data.auth;
|
||||
}
|
||||
info(
|
||||
`User ${chat.username} updated worker ${params.workerId}: ${JSON.stringify(body.data)}`,
|
||||
);
|
||||
await workerInstance.update();
|
||||
const worker = await getWorkerData(workerInstance);
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: worker satisfies WorkerData },
|
||||
};
|
||||
return withUser(query, async (chat) => {
|
||||
info(
|
||||
`User ${chat.username} updated worker ${params.workerId}: ${
|
||||
JSON.stringify(body.data)
|
||||
}`,
|
||||
);
|
||||
await workerInstance.update(body.data);
|
||||
return {
|
||||
status: 200,
|
||||
body: { type: "application/json", data: await getWorkerData(workerInstance) },
|
||||
};
|
||||
}, { admin: true });
|
||||
},
|
||||
),
|
||||
DELETE: createEndpoint(
|
||||
|
@ -223,22 +156,11 @@ export const workersRoute = createPathFilter({
|
|||
if (!workerInstance) {
|
||||
return { status: 404, body: { type: "text/plain", data: `Worker not found` } };
|
||||
}
|
||||
const session = sessions.get(query.sessionId);
|
||||
if (!session?.userId) {
|
||||
return { status: 401, body: { type: "text/plain", data: "Must be logged in" } };
|
||||
}
|
||||
const chat = await bot.api.getChat(session.userId);
|
||||
if (chat.type !== "private") throw new Error("Chat is not private");
|
||||
if (!chat.username) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must have a username" } };
|
||||
}
|
||||
const config = await getConfig();
|
||||
if (!config?.adminUsernames?.includes(chat.username)) {
|
||||
return { status: 403, body: { type: "text/plain", data: "Must be an admin" } };
|
||||
}
|
||||
info(`User ${chat.username} deleted worker ${params.workerId}`);
|
||||
await workerInstance.delete();
|
||||
return { status: 200, body: { type: "application/json", data: null } };
|
||||
return withUser(query, async (chat) => {
|
||||
info(`User ${chat.username} deleted worker ${params.workerId}`);
|
||||
await workerInstance.delete();
|
||||
return { status: 200, body: { type: "application/json", data: null } };
|
||||
}, { admin: true });
|
||||
},
|
||||
),
|
||||
}),
|
||||
|
|
|
@ -9,6 +9,13 @@
|
|||
"fmt": {
|
||||
"lineWidth": 100
|
||||
},
|
||||
"lint": {
|
||||
"rules": {
|
||||
"exclude": [
|
||||
"require-await"
|
||||
]
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"@date-fns/utc": "https://cdn.skypack.dev/@date-fns/utc@1.1.0?dts",
|
||||
"async": "https://deno.land/x/async@v2.0.2/mod.ts",
|
||||
|
|
|
@ -249,7 +249,7 @@ function WorkerListItem(props: { worker: WorkerData; sessionId?: string }) {
|
|||
body: {
|
||||
type: "application/json",
|
||||
data: {
|
||||
auth: user && password ? { user, password } : null,
|
||||
sdAuth: user && password ? { user, password } : null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow: /
|
Loading…
Reference in New Issue