diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-12-08 11:02:59 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-12-08 11:02:59 +0000 |
| commit | 69a756aadd94c7a3f648373e1315edb8a245f20d (patch) | |
| tree | 3bc26cb1009d356d525abc7dc505ad90cf671dc4 | |
| parent | 6886385ce239f63271639f047093ba307c87f2e6 (diff) | |
| download | karakeep-69a756aadd94c7a3f648373e1315edb8a245f20d.tar.zst | |
feat(cli): Add ability to list users for the admin in the CLImain
| -rw-r--r-- | apps/cli/src/commands/admin.ts | 89 | ||||
| -rw-r--r-- | apps/cli/src/index.ts | 2 |
2 files changed, 91 insertions, 0 deletions
diff --git a/apps/cli/src/commands/admin.ts b/apps/cli/src/commands/admin.ts new file mode 100644 index 00000000..181126f0 --- /dev/null +++ b/apps/cli/src/commands/admin.ts @@ -0,0 +1,89 @@ +import { getGlobalOptions } from "@/lib/globals"; +import { printErrorMessageWithReason, printObject } from "@/lib/output"; +import { getAPIClient } from "@/lib/trpc"; +import { Command } from "@commander-js/extra-typings"; +import { getBorderCharacters, table } from "table"; + +export const adminCmd = new Command() + .name("admin") + .description("admin commands"); + +function toHumanReadableSize(size: number): string { + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (size === 0) return "0 Bytes"; + const i = Math.floor(Math.log(size) / Math.log(1024)); + return (size / Math.pow(1024, i)).toFixed(2) + " " + sizes[i]; +} + +const usersCmd = new Command() + .name("users") + .description("user management commands"); + +usersCmd + .command("list") + .description("list all users") + .action(async () => { + const api = getAPIClient(); + + try { + const [usersResp, userStats] = await Promise.all([ + api.users.list.query(), + api.admin.userStats.query(), + ]); + + if (getGlobalOptions().json) { + printObject({ + users: usersResp.users.map((u) => ({ + ...u, + numBookmarks: userStats[u.id]?.numBookmarks ?? 0, + assetSizes: userStats[u.id]?.assetSizes ?? 0, + })), + }); + } else { + const data: string[][] = [ + [ + "Name", + "Email", + "Num Bookmarks", + "Asset Sizes", + "Role", + "Local User", + ], + ]; + + usersResp.users.forEach((user) => { + const stats = userStats[user.id] ?? { + numBookmarks: 0, + assetSizes: 0, + }; + + const numBookmarksDisplay = `${stats.numBookmarks} / ${user.bookmarkQuota?.toString() ?? "Unlimited"}`; + const assetSizesDisplay = `${toHumanReadableSize(stats.assetSizes)} / ${user.storageQuota ? toHumanReadableSize(user.storageQuota) : "Unlimited"}`; + + data.push([ + user.name, + user.email, + numBookmarksDisplay, + assetSizesDisplay, + user.role ?? "", + user.localUser ? "✓" : "✗", + ]); + }); + + console.log( + table(data, { + border: getBorderCharacters("ramac"), + drawHorizontalLine: (lineIndex, rowCount) => { + return ( + lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount + ); + }, + }), + ); + } + } catch (error) { + printErrorMessageWithReason("Failed to list all users", error as object); + } + }); + +adminCmd.addCommand(usersCmd); diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index df7d9512..8158c0b8 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -1,3 +1,4 @@ +import { adminCmd } from "@/commands/admin"; import { bookmarkCmd } from "@/commands/bookmarks"; import { dumpCmd } from "@/commands/dump"; import { listsCmd } from "@/commands/lists"; @@ -31,6 +32,7 @@ const program = new Command() : "0.0.0", ); +program.addCommand(adminCmd); program.addCommand(bookmarkCmd); program.addCommand(listsCmd); program.addCommand(tagsCmd); |
