Merge pull request #17 from Fretuks/fix-guilds-api-errors-on-login
Cache user guilds and improve guild endpoint error handling
This commit is contained in:
+44
-5
@@ -58,6 +58,8 @@ console.log('[oauth config]', {
|
|||||||
const DISCORD_API_BASE = 'https://discord.com/api';
|
const DISCORD_API_BASE = 'https://discord.com/api';
|
||||||
const DISCORD_OAUTH_BASE = 'https://discord.com/oauth2';
|
const DISCORD_OAUTH_BASE = 'https://discord.com/oauth2';
|
||||||
const COMMANDS_PATH = path.join(__dirname, 'commands.json');
|
const COMMANDS_PATH = path.join(__dirname, 'commands.json');
|
||||||
|
const GUILD_CACHE_TTL_MS = 5 * 60 * 1000;
|
||||||
|
const BOT_TOKEN_ERROR_MESSAGE = 'Missing Discord bot token.';
|
||||||
|
|
||||||
const sessionStore = new Map();
|
const sessionStore = new Map();
|
||||||
|
|
||||||
@@ -212,7 +214,7 @@ const fetchDiscordUserGuilds = async (accessToken) => {
|
|||||||
|
|
||||||
const fetchDiscordGuildRoles = async (guildId) => {
|
const fetchDiscordGuildRoles = async (guildId) => {
|
||||||
if (!DISCORD_BOT_TOKEN) {
|
if (!DISCORD_BOT_TOKEN) {
|
||||||
throw new Error('Missing Discord bot token.');
|
throw new Error(BOT_TOKEN_ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await axios.get(`${DISCORD_API_BASE}/guilds/${guildId}/roles`, {
|
const response = await axios.get(`${DISCORD_API_BASE}/guilds/${guildId}/roles`, {
|
||||||
@@ -224,6 +226,27 @@ const fetchDiscordGuildRoles = async (guildId) => {
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cacheSessionGuilds = (session, guilds) => {
|
||||||
|
session.guilds = guilds;
|
||||||
|
session.guildsFetchedAt = Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCachedGuilds = (session) => {
|
||||||
|
if (!Array.isArray(session.guilds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session.guildsFetchedAt) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Date.now() - session.guildsFetchedAt > GUILD_CACHE_TTL_MS) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session.guilds;
|
||||||
|
};
|
||||||
|
|
||||||
const parsePermissionBits = (permissionValue) => {
|
const parsePermissionBits = (permissionValue) => {
|
||||||
if (!permissionValue) {
|
if (!permissionValue) {
|
||||||
return 0n;
|
return 0n;
|
||||||
@@ -291,7 +314,11 @@ const ensureSession = (req, res, next) => {
|
|||||||
|
|
||||||
const ensureManageableGuild = async (req, res, next) => {
|
const ensureManageableGuild = async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const guilds = await fetchDiscordUserGuilds(req.session.accessToken);
|
let guilds = getCachedGuilds(req.session);
|
||||||
|
if (!guilds) {
|
||||||
|
guilds = await fetchDiscordUserGuilds(req.session.accessToken);
|
||||||
|
cacheSessionGuilds(req.session, guilds);
|
||||||
|
}
|
||||||
const guild = guilds.find((entry) => entry.id === req.params.guildId);
|
const guild = guilds.find((entry) => entry.id === req.params.guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
return res.status(404).json({error: 'Guild not found'});
|
return res.status(404).json({error: 'Guild not found'});
|
||||||
@@ -399,6 +426,7 @@ const createDashboardApp = () => {
|
|||||||
app.get('/api/guilds', ensureSession, async (req, res) => {
|
app.get('/api/guilds', ensureSession, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const guilds = await fetchDiscordUserGuilds(req.session.accessToken);
|
const guilds = await fetchDiscordUserGuilds(req.session.accessToken);
|
||||||
|
cacheSessionGuilds(req.session, guilds);
|
||||||
const manageableGuilds = guilds.filter(canManageGuild);
|
const manageableGuilds = guilds.filter(canManageGuild);
|
||||||
return res.json({guilds: manageableGuilds});
|
return res.json({guilds: manageableGuilds});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -415,7 +443,11 @@ const createDashboardApp = () => {
|
|||||||
const permissions = await getGuildPermissions(req.params.guildId);
|
const permissions = await getGuildPermissions(req.params.guildId);
|
||||||
return res.json({permissions});
|
return res.json({permissions});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(500).json({error: 'Failed to fetch permissions'});
|
console.error('Failed to fetch guild permissions', {
|
||||||
|
guildId: req.params.guildId,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
return res.status(503).json({error: 'Permissions store unavailable'});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -432,7 +464,11 @@ const createDashboardApp = () => {
|
|||||||
});
|
});
|
||||||
return res.json({permissions});
|
return res.json({permissions});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(500).json({error: 'Failed to update permissions'});
|
console.error('Failed to update guild permissions', {
|
||||||
|
guildId: req.params.guildId,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
return res.status(503).json({error: 'Permissions store unavailable'});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -446,7 +482,10 @@ const createDashboardApp = () => {
|
|||||||
const roles = await fetchDiscordGuildRoles(req.params.guildId);
|
const roles = await fetchDiscordGuildRoles(req.params.guildId);
|
||||||
return res.json({roles});
|
return res.json({roles});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(500).json({error: 'Failed to fetch roles'});
|
if (error.message === BOT_TOKEN_ERROR_MESSAGE) {
|
||||||
|
return res.status(503).json({error: 'Discord bot token not configured'});
|
||||||
|
}
|
||||||
|
return sendDiscordApiError(res, error, 'Failed to fetch roles');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user