const router = require("express").Router(), RL = require("express-rate-limit"); module.exports = (app, config, themeConfig) => { const RateLimits = config.rateLimits || {}; const RateFunctions = {}; const NoRL = (req, res, next) => next(); if (RateLimits.manage) { RateFunctions.manage = RL.rateLimit({ windowMs: RateLimits.manage.windowMs, max: RateLimits.manage.max, message: RateLimits.manage.message, store: RateLimits.manage.store || new RL.MemoryStore(), }); } if (RateLimits.guildPage) { RateFunctions.guildPage = RL.rateLimit({ windowMs: RateLimits.guildPage.windowMs, max: RateLimits.guildPage.max, message: RateLimits.guildPage.message, store: RateLimits.guildPage.store || new RL.MemoryStore(), }); } if (RateLimits.settingsUpdatePostAPI) { RateFunctions.settingsUpdatePostAPI = RL.rateLimit({ windowMs: RateLimits.settingsUpdatePostAPI.windowMs, max: RateLimits.settingsUpdatePostAPI.max, message: RateLimits.settingsUpdatePostAPI.message, store: RateLimits.settingsUpdatePostAPI.store || new RL.MemoryStore(), }); } router.get("/manage", RateFunctions.manage ? RateFunctions.manage : NoRL, async (req, res) => { if (!req.session.user) return res.redirect("/discord?r=/manage"); let customThemeOptions; if (themeConfig?.customThemeOptions?.manage) { customThemeOptions = await themeConfig.customThemeOptions.manage({ req: req, res: res, config: config, }); } res.render("guilds", { req: req, bot: config.bot, themeConfig: req.themeConfig, customThemeOptions: customThemeOptions || {}, config, }); }); router.get("/guild/:id", RateFunctions.guildPage ? RateFunctions.guildPage : NoRL, async (req, res) => { res.redirect("/settings/" + req.params.id); if (!req.session.user) return res.redirect("/discord?r=/guild/" + req.params.id); let customThemeOptions; if (themeConfig?.customThemeOptions?.getGuild) { customThemeOptions = await themeConfig.customThemeOptions.getGuild({ req: req, res: res, config: config, guildId: req.params.id, }); } const bot = config.bot; if (!bot.guilds.cache.get(req.params.id)) { try { await bot.guilds.fetch(req.params.id); } catch (e) { /* ... */ } } if (!bot.guilds.cache.get(req.params.id)) return res.redirect("/manage?error=noPermsToManageGuild"); if (!bot.guilds.cache.get(req.params.id).members.cache.get(req.session.user.id)) { try { await bot.guilds.cache.get(req.params.id).members.fetch(req.session.user.id); } catch (e) { /* ... */ } } if (!bot.guilds.cache.get(req.params.id).members.cache.get(req.session.user.id).permissions.has(config.requiredPermissions)) return res.redirect("/manage?error=noPermsToManageGuild"); if (bot.guilds.cache.get(req.params.id).channels.cache.size < 1) { try { await bot.guilds.cache.get(req.params.id).channels.fetch(); } catch (e) { /* ... */ } } if (bot.guilds.cache.get(req.params.id).roles.cache.size < 2) { try { await bot.guilds.cache.get(req.params.id).roles.fetch(); } catch (e) { /* ... */ } } const actual = {}; const canUseList = {}; if (!config.useCategorySet) for (const s of config.settings) { if (!canUseList[s.categoryId]) canUseList[s.categoryId] = {}; for (const c of s.categoryOptionsList) { if (c.allowedCheck) { const canUse = await c.allowedCheck({ guild: { id: req.params.id }, user: { id: req.session.user.id }, }); if (typeof canUse != "object") throw new TypeError(`${s.categoryId} category option with id ${c.optionId} allowedCheck function need to return {allowed: Boolean, errorMessage: String | null}`); canUseList[s.categoryId][c.optionId] = canUse; } else { canUseList[s.categoryId][c.optionId] = { allowed: true, errorMessage: null, }; } if (c.optionType.type === "spacer" || c.optionType.type === "multiRow" || c.optionType.type === "embedBuilder") { /* ... */ } else { if (!actual[s.categoryId]) actual[s.categoryId] = {}; if (!actual[s.categoryId][c.optionId]) { actual[s.categoryId][c.optionId] = await c.getActualSet({ guild: { id: req.params.id, object: bot.guilds.cache.get(req.params.id), }, user: { id: req.session.user.id, object: bot.guilds.cache.get(req.params.id).members.cache.get(req.session.user.id), }, }); } } } } else for (const category of config.settings) { if (!canUseList[category.categoryId]) canUseList[category.categoryId] = {}; const catGAS = await category.getActualSet({ guild: { id: req.params.id, object: bot.guilds.cache.get(req.params.id), }, user: { id: req.session.user.id, object: bot.guilds.cache.get(req.params.id).members.cache.get(req.session.user.id), }, }); for (const o of catGAS) { if (!o || !o?.optionId) console.log("WARNING: You haven't set the optionId for a category option in your config. This is required for the category option to work."); else { const option = category.categoryOptionsList.find((c) => c.optionId == o.optionId); if (option) { if (option.allowedCheck) { const canUse = await option.allowedCheck({ guild: { id: req.params.id }, user: { id: req.session.user.id }, }); if (typeof canUse != "object") throw new TypeError(`${category.categoryId} category option with id ${option.optionId} allowedCheck function need to return {allowed: Boolean, errorMessage: String | null}`); canUseList[category.categoryId][option.optionId] = canUse; } else { canUseList[category.categoryId][option.optionId] = { allowed: true, errorMessage: null, }; } if (option.optionType !== "spacer") { if (!actual[category.categoryId]) actual[category.categoryId] = {}; if (!actual[category.categoryId][option.optionId]) actual[category.categoryId][option.optionId] = o.data; } } else console.log(`WARNING: Option ${o.optionId} in category ${category.categoryId} doesn't exist in your config.`); } } } let errors; let success; if (req.session.errors) if (String(req.session.errors).includes("%is%")) { errors = req.session.errors.split("%and%"); } if (req.session.success) { if (typeof req.session.success == "boolean") { success = true; } else { if (String(req.session.success).includes("%is%")) success = req.session.success.split("%and%"); } } req.session.errors = null; req.session.success = null; res.render("guild", { successes: success, errors: errors, settings: config.settings, actual: actual, canUseList, bot: config.bot, req: req, guildid: req.params.id, themeConfig: req.themeConfig, customThemeOptions: customThemeOptions || {}, config, }); }); router.post("/settings/update/:guildId/:categoryId", RateFunctions.settingsUpdatePostAPI ? RateFunctions.settingsUpdatePostAPI : NoRL, async (req, res) => { if (!req.session.user) return res.redirect("/discord?r=/guild/" + req.params.guildId); // let customThemeOptions; // if (themeConfig?.customThemeOptions?.settingsUpdate) { // customThemeOptions = // await themeConfig.customThemeOptions.settingsUpdate({ // req: req, // config: config, // guildId: req.params.id, // categoryId: req.params.categoryId, // }); // } const bot = config.bot; const member = bot.guilds.cache.get(req.params.guildId).members.cache.get(req.session.user.id); if (!bot.guilds.cache.get(req.params.guildId)) return res.redirect("/manage?error=noPermsToManageGuild"); await bot.guilds.cache.get(req.params.guildId).members.fetch(req.session.user.id); if (!member.permissions.has(config.requiredPermissions)) return res.redirect("/manage?error=noPermsToManageGuild"); const cid = req.params.categoryId; const settings = config.settings; const category = settings.find(c => c.categoryId == cid); if (!category) return res.send({ error: true, message: "No category found", }); let setNewRes; const errors = []; let successes = []; const catO = []; const userGuildMemberObject = bot.guilds.cache.get(req.params.guildId).members.cache.get(req.session.user.id); const guildObject = bot.guilds.cache.get(req.params.guildId); for (const option of category.categoryOptionsList) { let canUse = {}; if (option.allowedCheck) { canUse = await option.allowedCheck({ guild: { id: req.params.guildId }, user: { id: req.session.user.id }, }); } else { canUse = { allowed: true, errorMessage: null, }; } if (canUse.allowed == false) { setNewRes = { error: canUse.errorMessage, }; errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); } else if (option.optionType != "spacer") { if (config.useCategorySet) { if (option.optionType.type == "rolesMultiSelect" || option.optionType.type == "channelsMultiSelect" || option.optionType.type == "multiSelect") { if (!req.body[option.optionId] || req.body[option.optionId] == null || req.body[option.optionId] == undefined) catO.push({ optionId: option.optionId, data: [], }); else if (typeof req.body[option.optionId] != "object") catO.push({ optionId: option.optionId, data: [req.body[option.optionId]], }); else catO.push({ optionId: option.optionId, data: req.body[option.optionId], }); } else if (option.optionType.type == "switch") { if (req.body[option.optionId] || req.body[option.optionId] == null || req.body[option.optionId] == undefined) { if (req.body[option.optionId] == null || req.body[option.optionId] == undefined) catO.push({ optionId: option.optionId, data: false, }); else catO.push({ optionId: option.optionId, data: true, }); } } else if (option.optionType.type == "embedBuilder") { if (req.body[option.optionId] == null || req.body[option.optionId] == undefined) catO.push({ optionId: option.optionId, data: option.optionType.data, }); else { try { const parsedResponse = JSON.parse(req.body[option.optionId]); catO.push({ optionId: option.optionId, data: parsedResponse, }); } catch (err) { catO.push({ optionId: option.optionId, data: option.optionType.data, }); } } } else { if (req.body[option.optionId] == undefined || req.body[option.optionId] == null) catO.push({ optionId: option.optionId, data: null, }); else catO.push({ optionId: option.optionId, data: req.body[option.optionId], }); } } else { if (option.optionType.type == "rolesMultiSelect" || option.optionType.type == "channelsMultiSelect" || option.optionType.type == "multiSelect") { if (!req.body[option.optionId] || req.body[option.optionId] == null || req.body[option.optionId] == undefined) { setNewRes = await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: [], }); setNewRes ? null : (setNewRes = {}); if (setNewRes.error) { errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); } else successes.push(option.optionName); } else if (typeof req.body[option.optionId] != "object") { setNewRes = await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: [req.body[option.optionId]], }); setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } else { setNewRes = await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: req.body[option.optionId], }); setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } } else if (option.optionType.type == "switch") { if (req.body[option.optionId] || req.body[option.optionId] == null || req.body[option.optionId] == undefined) { if (req.body[option.optionId] == null || req.body[option.optionId] == undefined) { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: false, })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } else { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: true, })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } } } else if (option.optionType.type == "embedBuilder") { if (req.body[option.optionId] == null || req.body[option.optionId] == undefined) { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: option.optionType.data, })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } else { try { const parsedResponse = JSON.parse(req.body[option.optionId]); setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: parsedResponse, })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } catch (err) { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: option.optionType.data, })) || {}; setNewRes = { error: "JSON parse for embed builder went wrong, your settings have been reset.", }; if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } } } else { if (req.body[option.optionId] == undefined || req.body[option.optionId] == null) { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: null, })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } else { setNewRes = (await option.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, newData: req.body[option.optionId], })) || {}; setNewRes ? null : (setNewRes = {}); if (setNewRes.error) errors.push(option.optionName + "%is%" + setNewRes.error + "%is%" + option.optionId); else successes.push(option.optionName); } } } } } if (config.useCategorySet && catO.length) { let sNR = await category.setNew({ guild: { id: req.params.guildId, object: guildObject }, user: { id: req.session.user.id, object: userGuildMemberObject }, data: catO, }); sNR ? null : (sNR = {}); if (sNR.error) errors.push(category.categoryId + "%is%" + sNR.error); else successes.push(category.categoryId); } const successesForDBDEvent = []; const errorsForDBDEvent = []; successes.forEach(item => { if (typeof item == "string") successesForDBDEvent.push(item.split("%is%")); }); errors.forEach(item => { if (typeof item == "string") errorsForDBDEvent.push(item.split("%is%")); }); req.DBDEvents.emit("guildSettingsUpdated", { user: req.session.user, changes: { successesForDBDEvent, errorsForDBDEvent, }, guildId: req.params.guildId, }); if (errors[0]) { if (!successes) successes = []; req.session.success = successes.join("%and%"); req.session.errors = errors.join("%and%"); return res.redirect("/guild/" + req.params.guildId); } else { req.session.success = true; req.session.errors = false; return res.redirect("/guild/" + req.params.guildId); } }); return router; };