diff --git a/src/api/routes/policies/stats.ts b/src/api/routes/policies/stats.ts
new file mode 100644
index 00000000..5ef4c3c6
--- /dev/null
+++ b/src/api/routes/policies/stats.ts
@@ -0,0 +1,22 @@
+import { route } from "@fosscord/api";
+import { Config, getRights, Guild, Member, Message, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
+const router = Router();
+
+router.get("/", route({}), async (req: Request, res: Response) => {
+ if (!Config.get().security.statsWorldReadable) {
+ const rights = await getRights(req.user_id);
+ rights.hasThrow("VIEW_SERVER_STATS");
+ }
+
+ res.json({
+ counts: {
+ user: await User.count(),
+ guild: await Guild.count(),
+ message: await Message.count(),
+ members: await Member.count(),
+ }
+ });
+});
+
+export default router;
diff --git a/src/util/config/types/SecurityConfiguration.ts b/src/util/config/types/SecurityConfiguration.ts
index 22fe74df..ca610216 100644
--- a/src/util/config/types/SecurityConfiguration.ts
+++ b/src/util/config/types/SecurityConfiguration.ts
@@ -13,4 +13,5 @@ export class SecurityConfiguration {
forwadedFor: string | null = null;
ipdataApiKey: string | null = "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9";
mfaBackupCodeCount: number = 10;
+ statsWorldReadable: boolean = true;
}
diff --git a/src/util/util/Rights.ts b/src/util/util/Rights.ts
index 6ba06d0e..8e54a04f 100644
--- a/src/util/util/Rights.ts
+++ b/src/util/util/Rights.ts
@@ -78,6 +78,10 @@ export class Rights extends BitField {
SEND_BACKDATED_EVENTS: BitFlag(42), // can send backdated events
USE_MASS_INVITES: BitFlag(43), // added per @xnacly's request — can accept mass invites
ACCEPT_INVITES: BitFlag(44), // added per @xnacly's request — can accept user-specific invites and DM requests
+ SELF_EDIT_FLAGS: BitFlag(45), // can modify own flags
+ EDIT_FLAGS: BitFlag(46), // can set others' flags
+ MANAGE_GROUPS: BitFlag(47), // can manage others' groups
+ VIEW_SERVER_STATS: BitFlag(48) // added per @chrischrome's request — can view server stats)
};
any(permission: RightResolvable, checkOperator = true) {
|