From 97d349f79b2d7b227c5c043157e3685a12d7ee86 Mon Sep 17 00:00:00 2001 From: electron271 <66094410+electron271@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:18:30 -0600 Subject: [PATCH] add new api endpoint --- .env.example | 3 ++- nginx.conf | 3 +++ prisma/schema.prisma | 1 + src/bot.js | 28 +++++++++++++++------------- src/express.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/.env.example b/.env.example index 45d177a..81c18c2 100644 --- a/.env.example +++ b/.env.example @@ -7,4 +7,5 @@ DISCORD_CHANNEL_ID="123456789012345678" # this bot is only designed to work in o ENCRYPTION_KEY="dontsharethis!" # openssl rand -base64 32 BOT_OWNER="123456789012345678" ACTIVITY="s$help for commands" -PREFIX="s$" \ No newline at end of file +PREFIX="s$" +ALLOWED_ROLES="123456789012345678,123456789012345678" # comma separated list of role ids for /api/roles endpoint \ No newline at end of file diff --git a/nginx.conf b/nginx.conf index 538f06a..7b4bcb9 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,6 +9,9 @@ http { location / { proxy_pass http://app:8000; } + location /api { + proxy_pass http://app:8000; + } # Serve static files in /data location /data { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9e06db2..21c4871 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -25,5 +25,6 @@ model UserLookup { username String @default("") anonymous Boolean @default(true) fullOptOut Boolean @default(false) // this can severely impact the graph functionality and should be used sparingly + roles String[] @default([]) @@id([id]) } diff --git a/src/bot.js b/src/bot.js index 990eabd..268c641 100644 --- a/src/bot.js +++ b/src/bot.js @@ -9,6 +9,17 @@ const { expressMain } = require('./express'); // Initialize Prisma Client const prisma = new PrismaClient(); +// Create the Discord client +const client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildPresences, + ], +}); + // Utility: Encrypt user ID function anonymousId(id) { @@ -25,10 +36,12 @@ function anonymousId(id) { // Utility: Update user in the database or create if not exists async function updateUserLookup(prisma, user) { if (!user) return; + // get user as guild member + const member = await user.client.guilds.cache.get(process.env.DISCORD_SERVER_ID)?.members.fetch(user.id); await prisma.userLookup.upsert({ where: { id: BigInt(user.id) }, - update: { username: user.username, fullOptOut: false }, - create: { id: BigInt(user.id), username: user.username }, + update: { username: user.username, fullOptOut: false, roles: member?.roles.cache.map((role) => role.id) }, + create: { id: BigInt(user.id), username: user.username, roles: member?.roles.cache.map((role) => role.id) }, }); } @@ -88,17 +101,6 @@ async function generateGEXF() { } } -// Create the Discord client -const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildPresences, - ], -}); - // On client ready client.once(Events.ClientReady, (readyClient) => { console.log(`Ready! Logged in as ${readyClient.user.tag}`); diff --git a/src/express.js b/src/express.js index e7ebd8f..f14ce8d 100644 --- a/src/express.js +++ b/src/express.js @@ -1,4 +1,5 @@ const express = require('express') +const { Client } = require('discord.js'); const app = express() const port = 8000 @@ -13,12 +14,18 @@ Total users who left and got opted out: <6> Endpoints ========= / - This page +GET > text/plain + /data/graph.gexf - GEXF graph data +GET > text/plain + +/api/roles - provide select role data +POST json (user_id: int) > json (user_id: int, roles: [int]) powered by graphology, express.js, prisma, and discord.js ` -function expressMain(prisma) { +function expressMain(prisma, client) { app.get('/', async (req, res) => { const totalUsers = await prisma.userLookup.count(); const totalUniqueMentions = await prisma.mention.count(); @@ -29,6 +36,41 @@ function expressMain(prisma) { res.send(statsTemplate.replace('<2>', totalUsers).replace('<3>', totalUniqueMentions).replace('<4>', totalNonAnonymousUsers).replace('<5>', totalAnonymousUsers).replace('<6>', totalOptOutUsers)); }); + app.use(express.json()); // Ensure this middleware is added + + app.post('/api/roles', async (req, res) => { + const userId = req.body?.user_id; // Safely access user_id + if (!userId) { + res.status(400).send({ error: 'Missing user_id in request body' }); + return; + } + + try { + // Fetch user roles from database + const userRoles = await prisma.userLookup.findUnique({ + where: { id: BigInt(userId) }, + select: { roles: true } // Only fetch roles + }); + + if (!userRoles) { + res.status(404).send({ error: 'User not found' }); + return; + } + + // Filter roles based on allowed roles + const allowedRoles = process.env.ALLOWED_ROLES.split(','); + const filteredRoles = userRoles.roles.filter((role) => + allowedRoles.includes(role) + ); + + res.status(200).send({ user_id: userId, roles: filteredRoles }); + } catch (error) { + console.error(error); + res.status(500).send({ error: 'Internal server error' }); + } + }); + + app.listen(port, () => { console.log(`Express server listening at http://localhost:${port}!`); });