From 2a278a51edc6bf4add158be24537c88abbb62ac8 Mon Sep 17 00:00:00 2001 From: Shni Date: Wed, 15 Oct 2025 10:16:06 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20Agregar=20l=C3=B3gica=20para=20obtener?= =?UTF-8?q?=20roles=20de=20un=20gremio=20y=20renderizar=20la=20vista=20del?= =?UTF-8?q?=20panel=20de=20control?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/check_roles_render.js | 42 +++++++ src/server/server.ts | 110 +++++++++++++++++- 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 scripts/collab-tests/dashboard/check_roles_render.js diff --git a/scripts/collab-tests/dashboard/check_roles_render.js b/scripts/collab-tests/dashboard/check_roles_render.js new file mode 100644 index 0000000..252720e --- /dev/null +++ b/scripts/collab-tests/dashboard/check_roles_render.js @@ -0,0 +1,42 @@ +const ejs = require('ejs'); +const path = require('path'); + +(async ()=>{ + try{ + const cwd = process.cwd(); + const viewsDir = path.join(cwd,'src','server','views'); + const pageFile = path.join(viewsDir,'pages','dashboard.ejs'); + const layoutFile = path.join(viewsDir,'layouts','layout.ejs'); + + const mockRoles = [ + { id: '111', name: 'Admin', color: '#ff0000' }, + { id: '222', name: 'Mods', color: '#00ff00' }, + ]; + + const locals = { + appName: 'amayo', + user: { username: 'test', id: '1' }, + guilds: [], + selectedGuild: 'guild1', + selectedGuildId: 'guild1', + selectedGuildName: 'Guild One', + guildConfig: { staff: ['111'] }, + guildRoles: mockRoles, + useDashboardNav: true, + hideNavbar: false, + page: 'settings' + }; + + const pageBody = await ejs.renderFile(pageFile, locals, { async: true, views:[viewsDir] }); + const html = await ejs.renderFile(layoutFile, {...locals, body: pageBody, dashboardNav: null, navbar: null, title: 'Dashboard test', version: 'test'}, { async: true, views:[viewsDir] }); + + const hasAdmin = html.indexOf('Admin') !== -1; + const hasMods = html.indexOf('Mods') !== -1; + const hasSwatch = html.indexOf('background:#ff0000') !== -1 || html.indexOf('background:#00ff00') !== -1; + console.log({ hasAdmin, hasMods, hasSwatch, length: html.length }); + process.exit(hasAdmin && hasMods && hasSwatch ? 0 : 2); + }catch(err){ + console.error(err && err.stack ? err.stack : err); + process.exit(3); + } +})(); diff --git a/src/server/server.ts b/src/server/server.ts index bcd4c5d..9212b80 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1069,6 +1069,100 @@ export const server = createServer( } // Dashboard routes + // Dev-only helper: fetch roles for a guild (requires COLLAB_TEST=1 and DISCORD_BOT_TOKEN) + if (url.pathname.startsWith("/__dev/fetch-roles")) { + if (process.env.COLLAB_TEST !== "1") { + res.writeHead( + 403, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end(JSON.stringify({ ok: false, error: "disabled" })); + return; + } + const gid = url.searchParams.get("guild"); + if (!gid) { + res.writeHead( + 400, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end(JSON.stringify({ ok: false, error: "missing guild param" })); + return; + } + const botToken = process.env.DISCORD_BOT_TOKEN; + if (!botToken) { + res.writeHead( + 500, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end( + JSON.stringify({ ok: false, error: "no bot token configured" }) + ); + return; + } + try { + const rolesRes = await fetch( + `https://discord.com/api/guilds/${encodeURIComponent( + String(gid) + )}/roles`, + { headers: { Authorization: `Bot ${botToken}` } } + ); + if (!rolesRes.ok) { + res.writeHead( + rolesRes.status, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end( + JSON.stringify({ + ok: false, + status: rolesRes.status, + statusText: rolesRes.statusText, + }) + ); + console.warn( + `__dev fetch-roles: got ${rolesRes.status} ${rolesRes.statusText} for guild ${gid}` + ); + return; + } + const rolesJson = await rolesRes.json(); + res.writeHead( + 200, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end( + JSON.stringify({ + ok: true, + count: Array.isArray(rolesJson) ? rolesJson.length : 0, + roles: rolesJson, + }) + ); + console.info( + `__dev fetch-roles: fetched ${ + Array.isArray(rolesJson) ? rolesJson.length : 0 + } roles for guild ${gid}` + ); + } catch (err) { + res.writeHead( + 500, + applySecurityHeadersForRequest(req, { + "Content-Type": "application/json", + }) + ); + res.end(JSON.stringify({ ok: false, error: String(err) })); + console.warn("__dev fetch-roles error", err); + } + return; + } + if ( url.pathname === "/dashboard" || url.pathname.startsWith("/dashboard") @@ -1136,7 +1230,7 @@ export const server = createServer( if (url.pathname === "/dashboard" || url.pathname === "/dashboard/") { // determine whether bot is in each guild (if we have a bot token) try { - const botToken = process.env.TOKEN; + const botToken = process.env.TOKEN; // No existe env var DISCORD_BOT_TOKEN si no TOKEN (compatibilidad) if (botToken && Array.isArray(guilds) && guilds.length) { await Promise.all( guilds.map(async (g: any) => { @@ -1201,7 +1295,7 @@ export const server = createServer( // Attempt to fetch guild roles via Discord Bot API if token available let guildRoles: Array<{ id: string; name: string }> = []; try { - const botToken = process.env.DISCORD_BOT_TOKEN; + const botToken = process.env.TOKEN; // No existe env var DISCORD_BOT_TOKEN si no TOKEN (compatibilidad) if (botToken) { const rolesRes = await fetch( `https://discord.com/api/guilds/${encodeURIComponent( @@ -1216,7 +1310,19 @@ export const server = createServer( id: String(r.id), name: String(r.name || r.id), })); + // Debug: log number of roles fetched for observability in dev + try { + console.info( + `dashboard: fetched ${guildRoles.length} roles for guild ${guildId}` + ); + } catch (e) { + /* ignore logging errors */ + } } + } else { + console.warn( + `dashboard: roles fetch returned ${rolesRes.status} ${rolesRes.statusText} for guild ${guildId}` + ); } } } catch (err) {