Rewrite of API + Dashboard - Now it uses ejs properly, and htmx - Dashboard is 10* faster

master
masterhc 1 year ago
parent 989bb5d671
commit 2994b57978

@ -2,301 +2,232 @@ const GuildM = require('../models/guilds');
const STRIKES = require('../models/strikes'); const STRIKES = require('../models/strikes');
const roleRulesM = require('../models/autoRoleRule'); const roleRulesM = require('../models/autoRoleRule');
const feedsM = require('../models/feeds'); const feedsM = require('../models/feeds');
const xmlparser = require('xml-js') const xmlparser = require('xml-js');
const {isValidObjectId} = require('mongoose') const {DiscordAPI, getRules, confirmArgsForYTFeed} = require('../lib')
exports.home = async (req,res)=>
{
res.render('home.ejs');
}
exports.getUser = (io)=> exports.redirect = async (req, res)=>
{ {
return(req,res)=> res.render('redirect.ejs');
{ }
fetch('https://discord.com/api/users/@me',
{
headers: {
authorization: req.headers.authorization,
},
})
.then(result=>result.json())
.then(response =>
{
res.json(response);
})
}
};
exports.guildData = (io,bot)=> exports.dashboard = (bot)=>
{ {
return async (req, res)=> return async (req, res)=>
{ {
let userGuilds = await fetch('https://discord.com/api/users/@me/guilds',
{ const userPlaceholder =
headers: { {
authorization: req.headers.authorization, id:'',
}, username:'placeholder',
}) avatar:'',
.then(result => result.json())
.then(response =>
{
if(response.message) return response.message
return response.filter(x=>x.owner==true);
})
var promises = [];
if(typeof userGuilds == 'string') return res.json({Error:userGuilds})
for(var guild of userGuilds) {
promises.push(new Promise((resolve, reject) => {
(async (guild)=>
{
var aux = await getSpecificGuildData(guild.id);
var roleRules = aux ? await getRoleRules(guild.id):null;
var guildTextChannels = aux ? aux.TextChannels:null;
var emojis = aux ? aux.emojis:null;
var roles = aux ? aux.roles:null;
const dataObject =
{
id:guild.id,
music:aux.guild?aux.guild.guild[0].music:false,
strikes:aux.guild?aux.guild.guild[0].strikes:false,
allowInvites:aux?.guild?.guild[0]?.allowInvites,
name:guild.name,
icon:guild.icon?`https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp`:'https://cdn3.iconfinder.com/data/icons/popular-services-brands-vol-2/512/discord-512.png',
features:guild.features,
hasRem:aux.extra?true:false,
memberCount:aux.extra?aux.extra.memberCount:null,
roleRules,
guildTextChannels,
emojis,
roles
};
resolve(dataObject);
})(guild)
}));
} }
Promise.all(promises).then((values) => { if(!req.headers.cookie) return res.render('dashboard.ejs', {user:userPlaceholder, guilds:guildsPlaceholder});
return res.json(values); const connector = new DiscordAPI(req.headers.cookie, bot);
}); const user = await connector.getUser();
const guilds = await connector.getGuildsFull();
res.render('dashboard.ejs',{user, guilds});
} }
async function getSpecificGuildData(guildID) }
exports.getModerator = (bot)=>
{
return async (req,res)=>
{ {
var extra = bot.guilds.cache.get(guildID) const modId = {moderatorid} = req.params;
var guild = await GuildM.find({gID:guildID}) const user = await bot.users.cache.get('1203446477024927764');
.then((guild,err)=> res.render('user.ejs', {user})
{
if(err || guild.length==0) return;
return {guild};
});
var TextChannels = [];
var emojis = [];
var roles = [];
if(extra)
{
for(var channel of extra.channels.cache)
{
if(channel[1].type==0)
{
TextChannels.push(
{
'id':channel[0],
'name':channel[1].name
});
}
}
for(var emoji of extra.emojis.cache)
{
emojis.push(
{
'id':emoji[0],
'name':emoji[1].name
});
}
for(var role of extra.roles.cache)
{
roles.push(
{
'id':role[0],
'name':role[1].name
});
}
}
return {guild, extra, TextChannels, emojis, roles};
} }
}
async function getRoleRules(guildid) exports.guilds = (bot)=>
{
return async (req, res) =>
{ {
return await roleRulesM.find({gID:guildid}).then((err, rules)=> try {
{ const connector = new DiscordAPI(req.headers.cookie, bot);
if(err || rules.length==0) return const userGuilds = await connector.getUserGuilds();
return rules const guilds = await connector.getGuildsFull(userGuilds);
}) res.render('guilds.ejs', { guilds });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
} }
} }
exports.updateGuild = (io)=> exports.gDash = (bot)=>
{ {
return (req, res)=>
return async (req, res)=>
{ {
GuildM.findOne({gID:req.body.guildID}) const userid = await new DiscordAPI(req.headers.cookie, bot).getUserId();
.then( const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.id);
(guild, err)=> res.render('guildPopup.ejs', {guild, userid})
{
if(err || guild.length) return res.json({Error:'No guild'});
guild[`${req.body.property}`] =! guild[`${req.body.property}`];
GuildM.updateOne({gID:req.body.guildID}, guild).then(()=>
{
return res.json(guild);
})
})
} }
} }
exports.guildUpdate = (bot)=>
exports.getMessage = (bot)=>
{ {
return async (req, res)=> return async (req, res)=>
{ {
if(!req.headers.guildid && !req.headers.messageid) return res.json({error:'No gid or messageid or both.'}) /**
const TextChannels = bot.guilds.cache.get(req.headers.guildid).channels.cache.filter(x=>x.type==0); * ! /gdash/:id/:setting?'
TextChannels.forEach(channel => { */
(async (channel)=> const original = await GuildM.find({gID:req.params.id}).then(guild=>{return guild[0]});
{ var aux = {}
var message aux[req.params.setting] = !original[req.params.setting]
try { const updated = await GuildM.findOneAndUpdate({gID:req.params.id}, aux)
message = await channel.messages.fetch(req.headers.messageid); const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.id);
} catch (error) { res.render('guildPopup.ejs', {guild})
//message doesn't exist on this channel or at all
}
if(message)
{
message = message.content
if(message.split('***').length %2 == 1) message = message.replaceAll('***', '');
if(message.split('**').length %2 == 1) message = message.replaceAll('**', '');
if(message.split('*').length %2 == 1) message = message.replaceAll('*', '');
if(message.split('~~').length %2 == 1) message = message.replaceAll('~~', '');
if(message.split('```').length %2 == 1) message = message.replaceAll('```', '');
if(message.split('``').length %2 == 1) message = message.replaceAll('``', '');
if(message.split('`').length %2 == 1) message = message.replaceAll('`', '');
res.json({message})
}
})(channel)
});
} }
} }
exports.getRules = async (req,res)=>
exports.rDash = (bot)=>
{ {
var payload; //! /rolerulesdash/:id -> Discord Guild Id (GuildId)
if(req.headers.guildid) return async (req, res)=>
{ {
payload = await roleRulesM.find({gID:req.headers.guildid}) const roles = await getRules(req.params.id);
.then(rules =>{return rules}) res.render('roleRules.ejs', {roles, id:req.params.id});
.catch(()=>{return null})
return res.json(payload);
} }
payload = await roleRulesM.findOne({_id:req.headers.id})
.then(rule=>{return rule})
.catch(()=>{return null})
return res.json(payload);
} }
exports.deleteRule = async (req, res)=> exports.roleChange = (bot)=>
{ {
var deleted = await roleRulesM.findByIdAndDelete(req.headers.ruleid) //! '/roleChange/:id/:guildid'
.then(()=>{return {success:'Done'}}) return async (req, res)=>
.catch(()=>{return {error:'Failed to delete'}}); {
res.json(deleted); const role = await getRules(req.params.id);
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
res.render('rolePopup.ejs', {role, id:req.params.id, guild});
}
} }
exports.updateRule = (bot)=> exports.saveRoleChange = (bot)=>
{ {
//! '/rolechange
return async (req, res)=> return async (req, res)=>
{ {
let args = req.headers; const body = req.body;
if(args.isnew == 'true') if(!body.roleid || !body.emojiid || !body.messageid || !body.guildid) return res.status(400).send('Bad Request');
const extra = await getRoleName(req.body, bot)
if(extra.error) return res.status(400).send(`Bad Request - ${extra.error}`)
var rule =
{ {
const validationResult = await confirmArgs(args); gID:body.guildid,
if (validationResult.error) return res.json({error:validationResult.error}) mID:body.messageid,
var rule = new roleRulesM(); roleID:body.roleid,
rule.gID = validationResult.gID; roleEmoji:body.emojiid,
rule.mID = validationResult.mID; roleName:extra.roleName,
rule.roleID = validationResult.roleID;
rule.roleEmoji = validationResult.roleEmoji;
rule.roleName = validationResult.roleName;
rule.save(err=>
{
if(err)res.json(err);
res.json({success:true,rule})
})
} }
else const updatedRule = await roleRulesM.findOneAndUpdate({_id:req.params.id}, rule);
{ const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
const validationResult = await confirmArgs(args); res.render('rolePopup.ejs', {role:updatedRule, id:body.id, guild});
if (validationResult.error) return res.json({error:validationResult.error}) }
roleRulesM.findOne({id:args.id}).then(rule=>
{
if(!rule) return res.json({error:'DB Error'}); }
rule.gID = validationResult.gID; exports.deleteRole = async (req, res)=>
rule.mID = validationResult.mID; {
rule.roleID = validationResult.roleID; const deleted = await roleRulesM.findOneAndDelete({_id:req.params.id});
rule.roleEmoji = validationResult.roleEmoji; const roles = await getRules(req.params.guildid);
rule.roleName = validationResult.roleName; res.render('roleRules.ejs', {roles, id:req.params.guildid});
roleRulesM.updateOne({_id:rule.id}, rule,{upsert:true}).then(updatedG=> }
{
res.json({success:true, rule})
})
}) exports.newRoleRule = (bot)=>
} {
//! '/newrolerule/:guildid'
return async (req, res)=>
{
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildData(req.params.guildid);
const role = 'N/A';
res.render('rolePopup.ejs', {guild, role,id:req.params.guildid})
} }
async function confirmArgs(args) }
exports.newRule = (bot)=>
{
return async (req, res)=>
{ {
var mID = args.messageid; const body = req.body;
var roleID = args.roleid; if(!body.roleid || !body.emojiid || !body.messageid || !body.guildid) return res.status(400).send('Bad Request');
var roleEmoji = args.emojiid; const extra = await getRoleName(req.body, bot)
var gID = args.gid; if(extra.error) return res.status(400).send(`Bad Request - ${extra.error}`)
var roleName; var rule =
if(!mID) return {error:'Message ID'}
if(!roleID) return {error:'Role ID'}
if(!roleEmoji) return {error:'Emoji ID'}
if(!gID) return {error:'Guild ID'}
var m = await (async ()=>
{ {
for(const [id, channel] of bot.channels.cache) gID:body.guildid,
mID:body.messageid,
roleID:body.roleid,
roleEmoji:body.emojiid,
roleName:extra.roleName,
}
const newRule = await roleRulesM.create(rule); //Might need it later, not sure what for tho.
const roles = await getRules(body.guildid);
/**
* exports.rDash = (bot)=>
{ {
if(channel.type == 0) //! /rolerulesdash/:id -> Discord Guild Id (GuildId)
return async (req, res)=>
{ {
try { const roles = await getRules(req.params.id);
const exists = await bot.channels.cache.get(id).messages.fetch(mID); res.render('roleRules.ejs', {roles, id:req.params.id});
if(exists) return m = true;
} catch (error) {}
} }
} }
})(); */
const r = bot.guilds.cache.get(gID).roles.cache.get(roleID); res.render('roleRules.ejs', {roles, id:body.guildid});
const e = bot.guilds.cache.get(gID).emojis.cache.get(roleEmoji);
bot.guilds.cache.get(gID).emojis.cache.forEach(emoji=>
{
if(emoji.name == 'tuturu') console.log(emoji)
})
console.log('Emoji', roleEmoji, e)
if(!m || !r || !e) return m?(r?(e?false:{error:'Emoji ID'}):{error:'Role ID'}):{error:'Message ID'}
roleName = r.name;
return {mID, roleID, roleEmoji, roleName, gID}
} }
} }
exports.getFeeds = async (req, res)=> async function getRoleName(args, bot)
{ {
var payload = await feedsM.find({gID:req.headers.guildid}).then(res=>{return res}).catch(err=>{return err}); var mID = args.messageid;
res.json(payload) var roleID = args.roleid;
var roleEmoji = args.emojiid;
var gID = args.guildid;
var roleName;
const guild = bot.guilds.cache.get(gID);
var m = await (async ()=>
{
for(const [id, channel] of bot.channels.cache)
{
if(channel.type == 0)
{
try {
const exists = await bot.channels.cache.get(id).messages.fetch(mID);
if(exists) return m = true;
} catch (error) {}
}
}
})();
const r = guild.roles.cache.get(roleID);
const e = guild.emojis.cache.get(roleEmoji);
if(!m || !r || !e) return m?(r?(e?false:{error:'Emoji ID'}):{error:'Role ID'}):{error:'Message ID'}
roleName = r.name;
return {roleName}
} }
exports.getFeed = async (req, res)=>
exports.fDash = (bot)=>
{ {
var payload = await feedsM.find({_id:req.headers.feedid}).then(res=>{return res}).catch(err=>{return err}); //! /feedsdash/:guildid'
res.json(payload) return async (req, res)=>
{
const preFeeds = await feedsM.find({gID:req.params.guildid}).then(feeds=>{return feeds});
var feeds = [];
await Promise.all(preFeeds.map(async (feed) => {
feed['channelName'] = await getChannelName(feed.YTChannelId);
feeds.push(feed);
}));
feeds.sort((a, b) => {
return a.channelName.localeCompare(b.channelName);
});
res.render('feeds.ejs', {feeds, id:req.params.guildid});
}
} }
exports.getChannelName = async (req,res)=> async function getChannelName(channelID)
{ {
var payload = await fetch('https://www.youtube.com/feeds/videos.xml?channel_id='+req.headers.channelid, return await fetch('https://www.youtube.com/feeds/videos.xml?channel_id='+channelID,
{ {
method: "GET", method: "GET",
mode: "cors", mode: "cors",
@ -319,169 +250,139 @@ exports.getChannelName = async (req,res)=>
{ {
return error; return error;
}); });
res.json(payload);
} }
exports.checkChannel = async (req, res)=> exports.feedChange = (bot)=>
{ {
var url = req.headers.id; //! /feedChange/:id/:guildid?
var regExp = '^(?:(?:https?:)?\/\/)?(?:www\.|(m\.)?)(youtube\.com|youtu\.be)(\/[^\s]*)?$'; return async (req, res)=>
var rE = new RegExp(regExp);
if (rE.test(url)) {
url = req.headers.id;
}
else
{ {
url = 'https://www.youtube.com/'+req.headers.id var feed = await feedsM.find({_id:req.params.id}).then(feed=>{return feed[0]});
feed.channelName = await getChannelName(feed.YTChannelId);
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
res.render('feedPopup.ejs', {feed, id:req.params.id, guild});
} }
var isValid = await fetch(url,
{
method: "GET",
mode: "cors",
})
.then(response=>
{
if(response.ok) return response.text();
})
.then(data=>
{
return data ? true :false
})
.catch(error=>
{
return error;
});
res.json(isValid)
} }
exports.addFeed = (bot)=> exports.addFeed = (bot)=>
{ {
//! /feedChange/:guildid?
return async (req, res)=> return async (req, res)=>
{ {
var headers= req.headers; const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
var args = [headers.gid, headers.dcchannelid, headers.ytchannelid] res.render('feedPopup.ejs', {feed:null, id:req.params.id, guild});
const validationResult = await confirmArgs(args, bot);
// console.log('Before new or old check', validationResult)
if (validationResult.error) return res.json({error:validationResult.error});
if(!headers.feedid)
{
//new
var feed = new feedsM();
feed.gID = headers.gid;
feed.ChannelId = validationResult.channelId
feed.YTChannelId = validationResult.YTChannelId;
feed.CostumMessage = headers.costummessagei!=''?headers.costummessagei:'New video:';
feed.save(err=>
{
if(err)res.json({error:err});
res.json({success:true, feed})
})
}
else
{
feedsM.findOne({id:args.id}).then(feed=>
{
if(!feed) return res.json({error:'DB Error'});
feed.gID = headers.gid;
feed.ChannelId = validationResult.channelId
feed.YTChannelId = validationResult.YTChannelId;
feed.CostumMessage = headers.costummessagei!=''?headers.costummessagei:'New video:';
feedsM.updateOne({_id:feed.id}, feed,{upsert:true}).then(updatedG=>
{
res.json({success:true, feed})
})
})
}
} }
} }
async function confirmArgs(args, bot) exports.saveNewFeed = (bot)=>
{ {
var channelId = args[1]; //! /feedChange/:guildid?
var channelURL = args[2] return async (req, res)=>
async function getChannelId(url)
{ {
if(url.split('@').length<1) return const {DCchannelID, ytchannel, costummessage} = req.body
return await fetch(url) const {guildid} = req.params;
.then(handleResponse) const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
.then(handleData) var feed = {
.catch(handleError); ChannelId: '',
function handleResponse(response) YTChannelId: '',
{ CostumMessage:'',
if(response.ok) return response.text(); gID:guildid
} };
function handleError(error) if(!costummessage && !ytchannel && !DCchannelID) return res.status(400).send('Bad Request');
{ const validated = await confirmArgsForYTFeed([guildid, DCchannelID, ytchannel],bot);
return {error:'Bad youtube channel link.'}; if(validated.error) return res.status(400).send('Bad Request');
} feed.ChannelId=validated.channelId;
function handleData(data) feed.YTChannelId = validated.YTChannelId;
{ feed.CostumMessage = costummessage;
return data ? data.split('https://www.youtube.com/feeds/videos.xml?channel_id=')[1].split('"')[0] : false; const newFeed = await feedsM.create(feed).then(f=>{return f}).catch(err=>{console.log(err)});
} newFeed.channelName = validated.channelName;
res.render('feedPopup.ejs', {feed:newFeed, id:req.params.id, guild});
} }
}
const YTChannelId = await getChannelId(channelURL); exports.deleteFeed = (bot)=>
if(YTChannelId.error) return {error:YTChannelId.error} {
const discordChannel = await bot.channels.fetch(channelId).then(channel=>{return channel }).catch(()=>{return null}); //! /feedChange/:id/:guildid?
if(!discordChannel) return {error:'Provided discord channel id does not exist.'} return async (req, res)=>
var name = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelId}`) {
.then(response => const deleted = await feedsM.findByIdAndDelete(req.params.id).then(deleted => {return deleted}).catch(err=>console.log(err));
{ const preFeeds = await feedsM.find({gID:req.params.guildid}).then(feeds=>{return feeds});
return response.text() var feeds = [];
}) await Promise.all(preFeeds.map(async (feed) => {
.then(data=> feed['channelName'] = await getChannelName(feed.YTChannelId);
{ feeds.push(feed);
}));
data = xmlparser.xml2json(data, feeds.sort((a, b) => {
{ return a.channelName.localeCompare(b.channelName);
compact: true, });
space: 4 res.render('feeds.ejs', {feeds, id:req.params.guildid});
}); }
data = JSON.parse(data);
return data.feed.author.name._text
})
.catch(error=>{return error;});
return {YTChannelId, channelId, name, channelName:discordChannel.name}
} }
exports.deleteFeed = (req,res) => exports.updateFeed = (bot)=>
{ {
feedsM.findOneAndDelete({_id:req.headers.feedid}).then(()=>{res.json({success:true})}).catch(error=>{res.json({error})}) //! /feedChange/:id/:guildid?
return async (req, res)=>
{
const {DCchannelID, ytchannel, costummessage} = req.body
const {guildid} = req.params;
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
var feed = {
ChannelId: '',
YTChannelId: '',
CostumMessage:'',
gID:guildid
};
if(!costummessage && !ytchannel && !DCchannelID) return res.status(400).send('Bad Request');
const validated = await confirmArgsForYTFeed([guildid, DCchannelID, ytchannel],bot);
if(validated.error) return res.status(400).send('Bad Request');
feed.ChannelId=validated.channelId;
feed.YTChannelId = validated.YTChannelId;
feed.CostumMessage = costummessage;
const newFeed = await feedsM.findOneAndUpdate({_id:req.params.id}, feed).then(f =>{return f}).catch(err=>{console.log(err)});
res.render('feedPopup.ejs', {feed:newFeed, id:req.params.id, guild});
}
} }
/**
*
*! '/strikes/:id/:userid/:strikeid?'
*/
exports.strikeDashboard = (bot)=> exports.strikeDashboard = (bot)=>
{ {
return async (req, res)=> return async (req, res)=>
{ {
// const user = bot.users.cache.get(req.params.userid) // const user = bot.users.cache.get(req.params.userid)
const guild = bot.guilds.cache.get(req.params.id); const guild = bot.guilds.cache.get(req.params.id);
const strikes = await STRIKES.find({guildID:req.params.id}) const strikeList = await STRIKES.find({guildID:req.params.id})
const moderator = req.params.userid; const moderator = req.params.userid;
var strikes = [];
await Promise.all(strikeList.map(async (strike) => {
var aux = {...strike._doc }
if(strike.validated)
{
if(strike.validatedBy)
{
const user = bot.users.cache.get(strike.validatedBy);
const moderator = {
username:user.username,
avatar:user.avatar,
id:user.id
};
aux = {...aux, moderator};
}
}
strikes.push(aux);
}));
// console.log(strikes)
res.render('strikesDashboard.ejs', {strikes, guild, moderator}) res.render('strikesDashboard.ejs', {strikes, guild, moderator})
} }
} }
exports.getStrikes = (bot)=>
{
return async (req,res)=>
{
var strikes = await STRIKES.find({guildID:req.params.id});
const moderator = req.params.userid
res.render('strikelist.ejs', {strikes})
}
}
exports.updateStrikes = (bot)=> exports.updateStrikes = (bot)=>
{ {
return async (req,res)=> return async (req,res)=>
{ {
const strike = await STRIKES.findByIdAndUpdate(req.params.strikeid, {validated:true});
const strikes = await STRIKES.find({guildID:req.params.id})
const moderator = req.params.userid; const moderator = req.params.userid;
const strike = await STRIKES.findByIdAndUpdate(req.params.strikeid, {validated:true, validatedBy:moderator});
const strikes = await STRIKES.find({guildID:req.params.id})
res.render('strikelist.ejs', {strikes, moderator}) res.render('strikelist.ejs', {strikes, moderator})
} }
} }

249
lib.js

@ -1325,3 +1325,252 @@ class Strikes
} }
} }
module.exports.Strikes = Strikes; module.exports.Strikes = Strikes;
exports.DiscordAPI = class DiscordAPI
{
constructor (cookie, bot)
{
this.authorization = this.AuthStringMaker(cookie);
this.bot = bot;
this.userId = '';
}
async getUser ()
{
return await fetch('https://discord.com/api/users/@me',
{
headers: {
authorization: this.authorization,
},
})
.then(result=>result.json())
.then(response =>
{
return response;
})
}
async getUserId()
{
return this.userId = await this.getUser().then(user=>{return user.id});
}
async getUserGuilds()
{
return await fetch('https://discord.com/api/users/@me/guilds',
{
headers: {
authorization: this.authorization,
},
})
.then(result => result.json())
.then(response =>
{
if(response.message) return response.message
return response.filter(x=>x.owner==true);
})
}
async getGuildsFull()
{
var userGuilds = await this.getUserGuilds()
var promises = [];
for(var guild of userGuilds) {
promises.push(new Promise((resolve, reject) => {
(async (guild)=>
{
var aux = await this.getSpecificGuildData(guild.id);
var roleRules = aux ? await this.getRoleRules(guild.id):null;
var guildTextChannels = aux ? aux.TextChannels:null;
var emojis = aux ? aux.emojis:null;
var roles = aux ? aux.roles:null;
const dataObject =
{
id:guild.id,
music:aux.guild?aux.guild.music:false,
strikes:aux.guild?aux.guild.strikes:false,
allowInvites:aux?.guild?.allowInvites,
name:guild.name,
icon:guild.icon?`https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp`:'https://cdn3.iconfinder.com/data/icons/popular-services-brands-vol-2/512/discord-512.png',
features:guild.features,
hasRem:aux.extra?true:false,
memberCount:aux.extra?aux.extra.memberCount:null,
roleRules,
guildTextChannels,
emojis,
roles
};
resolve(dataObject);
})(guild)
}));
}
const guilds = await Promise.all(promises).then((values) =>
{
return values
});
return guilds;
}
async getSpecificGuildData(guildID)
{
var extra = this.bot.guilds.cache.get(guildID)
var guild = await GuildM.find({gID:guildID})
.then((guild,err)=>
{
if(err || guild.length==0) return;
return {guild};
});
var TextChannels = [];
var emojis = [];
var roles = [];
if(extra)
{
for(var channel of extra.channels.cache)
{
if(channel[1].type==0)
{
TextChannels.push(
{
'id':channel[0],
'name':channel[1].name
});
}
}
for(var emoji of extra.emojis.cache)
{
emojis.push(
{
'id':emoji[0],
'name':emoji[1].name
});
}
for(var role of extra.roles.cache)
{
roles.push(
{
'id':role[0],
'name':role[1].name
});
}
}
try{
guild= guild.guild[0];
}
catch (err)
{
console.log('There was an error fetching the guild', err)
}
return {guild, extra, TextChannels, emojis, roles};
}
async getRoleRules(guildid)
{
return await roleRulesM.find({gID:guildid}).then((rules, err)=>
{
if(err || rules.length==0) return
return rules
})
}
AuthStringMaker(cookieString)
{
const splitCookie = cookieString.split('; ');
const tokenType = splitCookie[1].split('=')[1];
const accessToken = splitCookie[0].split('=')[1];
return `${tokenType} ${accessToken}`
}
/**
*
* @param {String} id GuildID
* @returns
*/
async getSpecificGuildDataForDash(id)
{
const aux = await this.getSpecificGuildData(id);
const roleRules = aux ? await this.getRoleRules(id):null;
const guildTextChannels = aux ? aux.TextChannels:null;
const emojis = aux ? aux.emojis:null;
const roles = aux ? aux.roles:null;
return {
id,
music:aux.guild?aux.guild.music:false,
strikes:aux.guild?aux.guild.strikes:false,
allowInvites:aux?.guild?.allowInvites,
name:aux.guild.name,
icon:aux.icon?`https://cdn.discordapp.com/icons/${aux.id}/${aux.icon}.webp`:'https://cdn3.iconfinder.com/data/icons/popular-services-brands-vol-2/512/discord-512.png',
hasRem:aux.extra?true:false,
memberCount:aux.extra?aux.extra.memberCount:null,
roleRules,
guildTextChannels,
emojis,
roles
};
}
}
/**
*
* @param {String|String} id - Discord Guild Id (GuildId) | Mongo Record ID (ruleID)
* @returns {Array<Object>|String} payload
*/
exports.getRules = async function getRules(id)
{
if(!id) return 'Error: No Guild or Rule Id '
if(mongoose.Types.ObjectId.isValid(id)) return await roleRulesM.find({_id:id}).then(rule=>{return rule[0]})
return await roleRulesM.find({gID:id})
.then(rules =>{return rules})
.catch(()=>{return null})
}
/**
* @param {Array.<string, string,string>} args - [Discord Guildid,Discord channelId, YT channelURL]
* @param {_Client} bot
* @returns
*/
exports.confirmArgsForYTFeed = async function confirmArgs(args, bot)
{
var channelId = args[1];
var channelURL = args[2];
async function getChannelId(url)
{
if(url.split('@').length<1) return
return await fetch(url)
.then(handleResponse)
.then(handleData)
.catch(handleError);
function handleResponse(response)
{
if(response.ok) return response.text();
}
function handleError(error)
{
return {error:'Bad youtube channel link.'};
}
function handleData(data)
{
return data ? data.split('https://www.youtube.com/feeds/videos.xml?channel_id=')[1].split('"')[0] : false;
}
}
const YTChannelId = await getChannelId(channelURL);
if(YTChannelId.error) return {error:YTChannelId.error}
const discordChannel = await bot.channels.fetch(channelId).then(channel=>{return channel }).catch(()=>{return null});
if(!discordChannel) return {error:'Provided discord channel id does not exist.'}
var name = await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelId}`)
.then(response =>
{
return response.text()
})
.then(data=>
{
data = xmlparser.xml2json(data,
{
compact: true,
space: 4
});
data = JSON.parse(data);
return data.feed.author.name._text
})
.catch(error=>{return error;});
return {YTChannelId, channelId, channelName:name}
}

@ -13,6 +13,7 @@ new Schema(
guildID:{type:String, required: true}, guildID:{type:String, required: true},
reason:{type:String, required:true}, reason:{type:String, required:true},
validated:{type:Object, required:false}, validated:{type:Object, required:false},
validatedBy:{type:String, required:false},
date:{type:Date, required:true}, date:{type:Date, required:true},
expireAt:{type:Date, required:true}, expireAt:{type:Date, required:true},
} }

@ -2,23 +2,28 @@
body body
{ {
display: flex; display: flex;
width: 100%; flex-direction: column;
align-items: center; width: 100%;
justify-content: center; height: 100%;
background-color: #071c24; align-items: center;
justify-content: center;
background-color: #071c24;
margin: 0px;
overflow-y: hidden;
overflow-x: hidden;
padding: 0px;
} }
#userWrapper #userWrapper
{ {
position: absolute;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 1em; gap: 1em;
justify-content: center; justify-content: center;
top:3vh; margin-top:5vh;
left:50%; left:50%;
transform: translateX(-50%);
height: 15vh; height: 15vh;
width: 80%; width: 80%;
background-color: var(--card-color); background-color: var(--card-color);
@ -57,30 +62,16 @@ body
white-space: pre-wrap; white-space: pre-wrap;
color: rgb(15, 98, 131); color: rgb(15, 98, 131);
} }
.DiscordAddBtn .info:hover .tooltip{
{ visibility: visible;
position: relative;
transform: translateY(calc(50% - 1vh));
left:calc(50% - 6vw);
height: 2vh;
width:9vw;
background-image: url("../images/add-to-discord.png");
background-repeat: no-repeat;
background-size: 9vw 2vh;
cursor:pointer;
}
.close, .checkBox
{
cursor: pointer;
} }
.close .PopUpContainer
{ {
position: relative; position: absolute;
top:-0.1em; top:25%;
right:1vh; left:10%;
float:right; width: 80%;
height: 100%;
} }
.popup .checkBox .popup .checkBox
{ {
@ -109,38 +100,67 @@ body
z-index: 1; z-index: 1;
} }
.info:hover .tooltip{
visibility: visible;
}
.popup .popup
{ {
position: absolute;
min-height: 30%;
max-height: 50%;
width: 50%;
top:calc(50% - 15%);
background-color: rgba(210, 252, 253, 0.295); background-color: rgba(210, 252, 253, 0.295);
border-radius: 5px; border-radius: 5px;
border: 2px solid #020608; border: 3px solid #020608;
z-index: 10;
text-align: center; text-align: center;
backdrop-filter: blur(3px); backdrop-filter: blur(3px);
} height: 50%;
.popup p overflow: auto ;
{
margin-top: 0.5em;
margin-bottom: 0.5em;
} }
.popup h3 .popup h3
{ {
margin-bottom: 1.7em; margin-bottom: 1.7em;
} }
.popup > p:hover
{
background-color: darkslategray;
width: 50%;
margin-left: 25%;
}
.popup > p
{
margin-top: 0.5em;
margin-bottom: 0.5em;
cursor: pointer;
background-color: #00345e69;
border-radius: 25px;
border: 2px solid #00345eb5;
width: 50%;
margin-left: 25%;
}
h1 h1
{ {
font-family: 'Lato'; font-family: 'Lato';
position: relative; position: relative;
top: -50%; top: -50%;
} }
.roleRuleWrapper > h1 , .FeedWrapper > h1
{
top:0;
}
#newRole
{
background-color: rgba(20, 43, 65, 0.678);
}
#newFeed
{
background-color: rgba(20, 43, 65, 0.678);
}
#newRole:hover
{
background-color:rgb(20, 43, 65) ;
}
#newFeed:hover
{
background-color:rgb(20, 43, 65) ;
}
.guildname .guildname
{ {
margin-top: 0.6em; margin-top: 0.6em;
@ -175,10 +195,12 @@ p
} }
#close_bt #close_bt
{ {
position: relative; position: absolute;
top:1vh; top:1vh;
right:1vh; right:1vh;
cursor:pointer;
} }
#Feeds #Feeds
{ {
cursor:pointer; cursor:pointer;
@ -190,6 +212,10 @@ p
width: 80%; width: 80%;
height: 60%; height: 60%;
position: absolute; position: absolute;
display:flex;
gap: 1em;
justify-content: space-evenly;
align-items: center;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translateY(-50%) translateX(-50%); transform: translateY(-50%) translateX(-50%);
@ -222,7 +248,7 @@ p
filter:grayscale(0); filter:grayscale(0);
} }
.card
/* width */ /* width */
::-webkit-scrollbar { ::-webkit-scrollbar {
@ -247,12 +273,6 @@ p
:root { :root {
--card-color: rgb(23, 23, 23); --card-color: rgb(23, 23, 23);
} }
body {
margin: 0px;
overflow-y: scroll;
overflow-x: hidden;
padding: 0px;
}
#cards { #cards {
@ -404,45 +424,41 @@ body {
background-color:#071c24de; background-color:#071c24de;
color: ivory; color: ivory;
border-radius: 5px; border-radius: 5px;
background-color:#5a8786;
} }
.roleRuleWrapper .roleRuleWrapper
{ {
height: 20em; height: 20em;
border: 1px solid ivory; border: 1px solid ivory;
aspect-ratio: 16/9;
position:absolute;
top:-50%;
font-size:1em; font-size:1em;
top:50%;
left:50%;
transform: translateX(-50%) translateY(-50%);
text-align:center; text-align:center;
border-radius: 10px; border-radius: 10px;
overflow: hidden; background-color: rgba(210, 252, 253, 0.295);
border-radius: 5px;
border: 3px solid #020608;
text-align: center;
backdrop-filter: blur(3px);
} }
.roleRuleWrapper:before
/* .roleRuleWrapper:before
{ {
content:''; content:'';
height: 20em; height: 100%;
aspect-ratio: 16/9; aspect-ratio: 16/9;
position:absolute; position:absolute;
top:0; top:0;
left:0; left:0;
background-color:#5a8786; } */
z-index:-1; /* .roleRuleWrapper:after
}
.roleRuleWrapper:after
{ {
content:attr(data-before); content:attr(data-before);
height: 9em; height: 9em;
font-family: 'Lato'; font-family: 'Lato';
aspect-ratio: 16/9;
position:absolute; position:absolute;
top:48%; top:48%;
left:50%; left:50%;
transform:translateX(-50%) translateY(-50%); transform:translateX(-50%) translateY(-50%);
z-index:-1;
filter: blur(1px); filter: blur(1px);
background-image: linear-gradient(ivory, #2a2a291f); background-image: linear-gradient(ivory, #2a2a291f);
background-size: 100%; background-size: 100%;
@ -450,17 +466,13 @@ body {
-moz-background-clip: text; -moz-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
-moz-text-fill-color: transparent; -moz-text-fill-color: transparent;
} } */
.roleRule .roleRule
{ {
color: ivory; color: ivory;
font-family: 'Lato'; font-family: 'Lato';
font-weight: bolder; font-weight: bolder;
margin-top: 1em; margin-top: 1em;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
} }
.role .role
@ -502,13 +514,6 @@ input
text-align:right; text-align:right;
width: 37.5%; width: 37.5%;
} }
.message
{
color:ivory;
position:absolute;
left: 30%;
top:40%;
}
.messageID .messageID
{ {
transform:translateY(250%); transform:translateY(250%);
@ -538,7 +543,7 @@ input
} }
#change2 #change2
{ {
left:70%;
} }
#delete #delete
{ {
@ -572,72 +577,81 @@ input
.FeedWrapper .FeedWrapper
{ {
height: 20em; height: 45vh;
aspect-ratio: 16/9;
border: 1px solid ivory; border: 1px solid ivory;
position:absolute;
top:50%;
left:50%;
font-size:1em; font-size:1em;
font-family:'lato'; font-family:'lato';
color:ivory; color:ivory;
transform: translateX(-50%) translateY(-50%);
text-align:center; text-align:center;
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
background-color:#5a8786; background-color:#5a8786;
} }
.channel .FeedWrapper > form
{ {
position:absolute; margin-top:4em;
top:50%; display: flex;
flex-wrap: wrap;
} }
.labeldc .FeedWrapper > p
{ {
left:10% padding:0;
} }
.labelyt .FeedWrapper > form > section > input, .FeedWrapper > form > section > textarea, .FeedWrapper > form > section > input
{ {
right:10% background-color: #00000054;
color:white;
} }
.dc .costumMessageSection
{ {
left:10%; width: 100%;
transform:translateY(250%);
background-color:#00000054;
border:2px solid transparent;
color:ivory;
text-align:center;
width: 37.5%;
} }
option .dcSection
{ {
background:#087575; width: 50%;
} }
.yt .ytChannelSection
{ {
right:10%; width: 50%;
transform:translateY(250%); }
background-color:#00000054; .buttonsSection
border:2px solid transparent; {
width: 100%;
height: 3em;
margin-top: 3em;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-evenly;
align-content: center;
}
.buttonsSection > .button
{
width:20%;
height:1.5em;
background-color: #00345e69;
border-radius: 25px;
border: 2px solid #00345eb5;
color:ivory; color:ivory;
text-align:right; cursor:pointer;
width: 37.5%; font-weight: bold;
font-family: 'lato';
} }
.feeds .dc
{ {
border: 2px solid #020608; background-color: #00000054;
height: 20vh; border: 2px solid transparent;
position: absolute; border-radius: 4px;
top:1%;
overflow-y: scroll;
width: 60%;
left: 20%;
background-color:#071c24de;
color: ivory; color: ivory;
border-radius: 5px; text-align: center;
}
option
{
background:#087575;
} }
.rules p .rules p
{ {
cursor: pointer; cursor: pointer;
@ -646,24 +660,17 @@ option
{ {
cursor: pointer; cursor: pointer;
} }
.message
{
position: absolute;
top: 20%;
}
.CostumMessage .CostumMessage
{ {
color:ivory; color:ivory;
} }
.CostumMessageI .CostumMessageI
{ {
transform: translateY(80%);
background-color: #00000054;
border: 2px solid transparent; border: 2px solid transparent;
color: ivory; color: ivory;
text-overflow: wrap; text-overflow: wrap;
width: 37.5%; width: 80%;
height: 4em; height: 3em;
resize: none; resize: none;
} }
@ -703,3 +710,14 @@ option
:root { :root {
--glow-color: rgba(0, 4, 255, 0.8); --glow-color: rgba(0, 4, 255, 0.8);
} }
#container
{
width: 100%;
height: 100%;
}
.material-symbols-outlined
{
cursor: pointer;
}

@ -107,7 +107,7 @@ body
.strike-info { .strike-info {
flex: 4; flex: 4;
} }
.strike-info > h3 > span> img .strike-info > h3 > span> img, .strike-info > h4 > span> img
{ {
border: none; border: none;
border-radius: 50%; border-radius: 50%;
@ -115,7 +115,7 @@ body
height: 1em; height: 1em;
transform: translateY(0.25em); transform: translateY(0.25em);
} }
.strike-info > h3 > span .strike-info > h3 > span, .strike-info > h4 > span
{ {
background-color: rgb(44, 151, 238); background-color: rgb(44, 151, 238);
height: 5em; height: 5em;
@ -125,7 +125,7 @@ body
padding-right: 0.2em; padding-right: 0.2em;
padding-bottom: 0.2em; padding-bottom: 0.2em;
} }
.strike-info > h3 > span.striked .strike-info > h3 > span.stroke
{ {
background-color: rgb(58, 23, 23); background-color: rgb(58, 23, 23);
} }

@ -1,139 +1,47 @@
var userID;
var guildsCache = new Map();
window.onload = async () => window.onload = async () =>
{ {
const fragment = new URLSearchParams(window.location.hash.slice(1)); const fragment = new URLSearchParams(window.location.hash.slice(1));
const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')]; const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')];
if (!accessToken) return window.location.href = '/'; if (!accessToken) return window.location.href = '/';
updateUser(accessToken, tokenType); const expirationDate = new Date( Date.now() + (24 * 60 * 60 * 1000));// 24 hours
updateGuildData(accessToken, tokenType); // document.cookie = 'accessToken' + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;';
document.getElementById('RoleRules').onclick = handleToggleRules; // document.cookie = 'tokenType' + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;';
}; const wasEmpty = document.cookie =='';
document.cookie = `accessToken=${accessToken}; expires=${expirationDate.toUTCString()}; path=/`;
function updateUser(accessToken, tokenType) document.cookie = `tokenType=${tokenType}; expires=${expirationDate.toUTCString()}; path=/`;
{ if(wasEmpty) window.location.reload();
const avatar = document.getElementById('avatar'); createListeners();
const userName = document.getElementById('userName');
fetch(`${window.location.origin}/api/getUser`,
{
method: "POST",
headers: {
authorization: `${tokenType} ${accessToken}`,
},
})
.then(result => result.json())
.then(response =>
{
userID = response.id;
avatar.style.backgroundImage = `url(https://cdn.discordapp.com/avatars/${response.id}/${response.avatar}.jpeg)`
userName.textContent = response.username+"'s servers"
})
.catch(console.error);
}
function updateGuildData(accessToken, tokenType)
{
fetch(`${window.location.origin}/api/getGuildData`,
{
method: "POST",
headers: {
authorization: `${tokenType} ${accessToken}`,
},
})
.then(result => result.json())
.then(guilds =>
{
if(guilds.Error) return console.log(guilds.Error)
guildsCache = new Map();
guilds.forEach(guild => {
console.log(guild)
guildsCache.set(guild.id, guild)
});
makeCards(guilds);
})
.catch(console.error);
}
function handleSettigns(event)
{
var popup = document.getElementById('popup');
var guild = guildsCache.get(event.target.id);
if(!guild.hasRem) return window.open('https://discord.com/api/oauth2/authorize?client_id=356104008366030863&permissions=8&scope=bot')
popup.classList.remove('hidden');
popup.children[1].textContent = guild.name;
popup.children[1].id = guild.id;
let music = document.getElementById('music');
music.textContent = guild.music? 'check_box' :'check_box_outline_blank';
let strikes = document.getElementById('strikes');
strikes.textContent = guild.strikes? 'check_box' :'check_box_outline_blank';
let allowInvites = document.getElementById('allowInvites');
allowInvites.textContent = guild.allowInvites? 'check_box' : 'check_box_outline_blank';
music.onclick = requestChange;
strikes.onclick = requestChange;
allowInvites.onclick = requestChange;
}
function handleClose(element) };
function togglePopup(element)
{ {
if(element.parentNode.id == 'roleRuleWrapper' || element.parentNode.id == 'FeedWrapper') if(element.classList.contains('hidden'))
{ {
document.getElementById('popup').classList.remove('hidden'); element.classList.remove('hidden');
document.getElementById('change').innerText = 'Change'; return document.addEventListener('click', clickListener);
document.getElementById('change2').innerText = 'Change';
} }
if(element.parentNode.id =="FeedWrapper") document.getElementById('ChannelName').classList = ''; element.classList.add('hidden');
element.parentNode.classList.add('hidden');
} }
async function requestChange() let clickListener = function handleClickOutside(event)
{ {
return await fetch(`${window.location.origin}/api/change`, if (!document.getElementById('PopUpContainer').contains(event.target) && !event.target.classList.contains('card'))
{
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({guildID:event.target.parentNode.parentNode.children[1].id,userID, property:event.target.id}), // body data type must match "Content-Type" header
})
.then(result => result.json())
.then(res =>
{ {
if(!res.error) document.getElementById('PopUpContainer').classList.add('hidden');
{ document.removeEventListener('click', clickListener);
let music = document.getElementById('music') }
music.textContent = res.music? 'check_box' :'check_box_outline_blank';
let strikes = document.getElementById('strikes')
strikes.textContent = res.strikes? 'check_box' :'check_box_outline_blank';
let allowInvites = document.getElementById('allowInvites');
allowInvites.textContent = res.allowInvites? 'check_box' : 'check_box_outline_blank';
}
})
.catch(console.error);
} }
async function makeCards(data) function createListeners()
{ {
const canvas = document.createElement('div') document.getElementById("Guilds").onmousemove = e =>
canvas.classList.add('cards');
canvas.id = 'cards';
for(var item of data)
{ {
(async ()=> for(var card of document.getElementsByClassName("card"))
{
var card = await makeCard(item);
canvas.appendChild(card);
})(item)
}
document.getElementById('Guilds').appendChild(canvas)
document.getElementById("cards").onmousemove = e =>
{
for(const card of document.getElementsByClassName("card"))
{ {
const rect = card.getBoundingClientRect(), const rect = card.getBoundingClientRect(),
x = e.clientX - rect.left, x = e.clientX - rect.left,
y = e.clientY - rect.top; y = e.clientY - rect.top;
card.style.setProperty("--mouse-x", `${x}px`); card.style.setProperty("--mouse-x", `${x}px`);
card.style.setProperty("--mouse-y", `${y}px`); card.style.setProperty("--mouse-y", `${y}px`);
let interval = null; let interval = null;
@ -169,403 +77,14 @@ async function makeCards(data)
{ {
clearInterval(interval); clearInterval(interval);
target.innerText = target.dataset.value; target.innerText = target.dataset.value;
//reset
}) })
} }
} }
document.getElementById('cards').onclick = handleSettigns;
}
async function makeCard(guild)
{
const card = document.createElement('div')
card.innerHTML = ` <div id='${guild.id}'class="card">
<div class="card-content ">
<div class="card-image ">
<div class="img img${guild.hasRem}" style="background-image:url(${guild.icon});" ></div>
</div>
<div class="card-info-wrapper ${guild.hasRem}">
<div class="card-info">
<div class="card-info-title">
<h3 data-value="${guild.name}" class="fancy">${guild.name}</h3>
<h4>${guild.memberCount?guild.memberCount + ' users on the server.':'Rem is not on this server yet.'} </h4>
</div>
</div>
</div>
</div>
</div>`
return card
//background-position:0%; filter:grayscale(${guild.hasRem?0.4:0.7})
}
async function getRules(guildID)
{
return await fetch(`${window.location.origin}/api/getRules`,
{
method: "GET",
mode: "cors",
headers: {guildID},
})
.then(result => result.json())
.then(res =>
{
return res
})
.catch(console.error);
}
async function handleToggleRules(element)
{
var guildID = element.target.parentNode.getElementsByTagName('h3')[0].id;
var rulesElement=document.getElementById('rules');
var rules = await getRules(guildID);
document.getElementById('roleID').innerHTML = '';
for(var role of guildsCache.get(guildID).roles)
{
document.getElementById('roleID').innerHTML += `<option value="${role.id}">${role.name}</option>`;
}
document.getElementById('emojiID').innerHTML = '';
for(var emoji of guildsCache.get(guildID).emojis)
{
document.getElementById('emojiID').innerHTML += `<option value="${emoji.id}">${emoji.name}</option>`;
}
if(!rules) return
var ruleArr = []
for(var rule of rules)
{
ruleArr.push(`<p id="${rule._id}" onclick="changeRule(this)" class="addRoleName">${rule.roleName}</p>`)
}
rulesElement.innerHTML = `
<i onclick="handleClose(this)" class="close material-symbols-outlined" id="close_bt">
cancel
</i>
<p id="newRole" onclick="addRule(this)">New Rule</p>
${ruleArr.join('')}
`
rulesElement.classList.remove('hidden')
}
async function getFeeds(gid)
{
return await fetch(`${window.location.origin}/api/getFeeds`,
{
method: "GET",
mode: "cors",
headers: {guildid:gid},
})
.then(result => result.json())
.then(res =>
{
return res
})
.catch(console.error);
}
async function getFeed(feedID)
{
return await fetch(`${window.location.origin}/api/getFeed`,
{
method: "GET",
mode: "cors",
headers: {feedID},
})
.then(result => result.json())
.then(res =>
{
return res[0]
})
.catch(console.error);
}
async function getChannelID(id)
{
if(url.split('@').length<1) return false
return await fetch(url)
.then(handleResponse)
.then(handleData)
.catch(handleError);
function handleResponse(response)
{
if(response.ok) return response.text();
}
function handleError(error)
{
return error;
}
function handleData(data)
{
return data ? data.split('https://www.youtube.com/feeds/videos.xml?channel_id=')[1].split('"')[0] : false;
}
}
async function getChannelName(channelID)
{
return await fetch(`${window.location.origin}/api/getChannelName`,
{
method: "GET",
mode: "cors",
headers: {channelID},
})
.then(response=>
{
if(response.ok) return response.text();
})
.then(data=>
{
return data.replaceAll('"','')
})
.catch(error=>
{
return error;
});
}
async function handleToggleFeeds(element)
{
var guildID = element.parentNode.getElementsByTagName('h3')[0].id;
var feedElement=document.getElementById('feeds');
var feeds = await getFeeds(guildID);
if(!feeds) return
var ruleArr = [];
for (let i = 0; i < feeds.length; i++) {
var ytchannelname = await getChannelName(feeds[i].YTChannelId)
ruleArr.push(`<p id="${feeds[i]._id}" onclick="updateFeed(this)">${ytchannelname}</p>`)
}
feedElement.innerHTML = `
<i onclick="handleClose(this)" class="close material-symbols-outlined" id="close_bt">
cancel
</i>
<p id="newFeed" onclick="addFeed(this)">New Feed</p>
${ruleArr.join('')}
`
feedElement.classList.remove('hidden');
}
function deleteRule(element)
{
var ruleID = document.getElementById('roleRule').classList[1];
fetch(`${window.location.origin}/api/deleteRule`,
{
method: "POST",
mode: "cors",
headers: {ruleID},
})
.then(result => result.json())
.then(res =>
{
console.log(res);
if(res.success)
{
element.parentNode.classList.add('hidden')
document.getElementById('popup').classList.remove('hidden');
}
else alert(res.error);
})
.catch(console.error);
}
function addRule(element)
{
element.parentNode.classList.add('hidden');
element.parentNode.parentNode.classList.add('hidden');
var ruleWrapper = document.getElementById('roleRuleWrapper');
ruleWrapper.classList.remove('hidden');
document.getElementsByClassName('roleRuleWrapper')[0].setAttribute('data-before','Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in elit vel nisi sagittis egestas. Donec a laoreet justo. Morbi interdum orci quis tempor tempor. Aenean tempus urna eget placerat maximus. Maecenas vitae condimentum felis, et mollis velit. Duis diam arcu, volutpat ut lectus et, aliquam vestibulum ante. Mauris dignissim libero quis condimentum interdum. Morbi dictum ex faucibus mi vehicula, sed blandit ex molestie. Pellentesque lacinia blandit pellentesque. Nullam at nisl dui.')
document.getElementById('roleRule').innerText = 'New Rule'
document.getElementById('roleID').placeholder = 'Role ID'
document.getElementById('emojiID').placeholder = 'Emoji ID'
document.getElementById('messageID').placeholder = 'Message ID'
document.getElementById('emojiImg').src = 'images/favicon.ico';
document.getElementById('change').innerText = 'Add';
}
function updateRule(element)
{
var isNew=false;
if(element.parentNode.children[1].innerText == 'New Rule') isNew = true;
var ruleID;
if(!isNew) ruleID = document.getElementById('roleRule').classList[1];
var messageid = document.getElementById('messageID').value;
var roleid =document.getElementById('roleID').value;
var emojiid =document.getElementById('emojiID').value;
var gid = document.getElementsByClassName('guildname')[0].id;
fetch(`${window.location.origin}/api/updateRule`,
{
method: "POST",
mode: "cors",
headers: {messageid, roleid, emojiid, gid,isNew, ruleID},
})
.then(result => result.json())
.then(res =>
{
if(res.success)
{
element.parentNode.classList.add('hidden')
document.getElementById('popup').classList.remove('hidden');
}
else alert(res.error);
})
.catch(console.error);
}
async function getRule(id)
{
return await fetch(`${window.location.origin}/api/getRules`,
{
method: "GET",
mode: "cors",
headers: {id},
})
.then(result => result.json())
.then(res =>
{
return res
})
.catch(console.error);
}
async function getMessage(guildid, messageid)
{
return await fetch(`${window.location.origin}/api/getMessage`,
{
method: "GET",
mode: "cors",
headers: {guildid, messageid},
})
.then(result => result.json())
.then(res =>
{
return res
})
.catch(console.error);
}
async function changeRule(element)
{
var rule = await getRule(element.id)
var message = await getMessage(rule.gID,rule.mID);
message = message.message;
element.parentNode.classList.add('hidden');
element.parentNode.parentNode.classList.add('hidden')
var ruleWrapper = document.getElementById('roleRuleWrapper');
ruleWrapper.classList.remove('hidden');
document.getElementsByClassName('roleRuleWrapper')[0].setAttribute('data-before', message)
document.getElementById('roleRule').innerText = rule.roleName;
document.getElementById('roleRule').classList = 'roleRule';
document.getElementById('roleRule').classList.add(rule._id);
document.getElementById('roleID').value = rule.roleID;
document.getElementById('emojiID').value = rule.roleEmoji;
document.getElementById('messageID').value = rule.mID;
document.getElementById('emojiImg').src = `https://cdn.discordapp.com/emojis/${rule.roleEmoji}.webp`;
}
function addFeed(element)
{
document.getElementById('DCchannelID').innerHTML = '';
for(var channel of guildsCache.get(element.parentNode.parentNode.childNodes[3].id).guildTextChannels)
{
document.getElementById('DCchannelID').innerHTML += `<option value="${channel.id}">${channel.name}</option>`;
}
element.parentNode.classList.add('hidden');
element.parentNode.parentNode.classList.add('hidden');
var FeedWrapper = document.getElementById('FeedWrapper');
FeedWrapper.classList.remove('hidden');
document.getElementById('ChannelName').innerText = 'New Feed'
// document.getElementById('DCchannelID').placeholder = '';
document.getElementById('YTchannelID').placeholder = '';
document.getElementById('CostumMessageI').placeholder = '';
document.getElementById('change2').innerText = 'Add';
}
async function updateFeed(element)
{
var feed = await getFeed(element.id)
element.parentNode.classList.add('hidden');
element.parentNode.parentNode.classList.add('hidden');
var FeedWrapper = document.getElementById('FeedWrapper');
FeedWrapper.classList.remove('hidden');
document.getElementById('DCchannelID').innerHTML = '';
for(var channel of guildsCache.get(element.parentNode.parentNode.childNodes[3].id).guildTextChannels)
{
document.getElementById('DCchannelID').innerHTML += `<option value="${channel.id}">${channel.name}</option>`;
}
document.getElementById('ChannelName').innerText = element.textContent;
document.getElementById('ChannelName').classList ='';
document.getElementById('ChannelName').classList.add(element.id);
document.getElementById('DCchannelID').value = feed.ChannelId;
document.getElementById('YTchannelID').value = 'https://www.youtube.com/@' + await getChannelName(feed.YTChannelId);
document.getElementById('CostumMessageI').value = feed.CostumMessage;
}
function deleteFeed(element)
{
var feedID = document.getElementById('ChannelName').classList[0];
fetch(`${window.location.origin}/api/deleteFeed`,
{
method: "POST",
mode: "cors",
headers: {feedID},
})
.then(result => result.json())
.then(res =>
{
if(res.success)
{
element.parentNode.classList.add('hidden')
document.getElementById('popup').classList.remove('hidden');
}
else alert(res.error);
})
.catch(console.error);
}
async function _updateFeed(element)
{
feedID = document.getElementById('ChannelName').classList.value;
var gid = document.getElementsByClassName('guildname')[0].id;
var DCchannelID = document.getElementById('DCchannelID').value;
var YTchannelID = document.getElementById('YTchannelID').value;
var CostumMessageI = document.getElementById('CostumMessageI').value;
var YTValid = await channelCheck(YTchannelID);
if(!YTValid) return handleWrongLink();
fetch(`${window.location.origin}/api/addFeed`,
{
method: "POST",
mode: "cors",
headers: {DCchannelID, YTchannelID, CostumMessageI, gid, feedID},
})
.then(result => result.json())
.then(res =>
{
if(res.success)
{
element.parentNode.classList.add('hidden')
document.getElementById('popup').classList.remove('hidden');
}
else alert(res.error);
})
.catch(console.error);
}
function handleWrongLink()
{
window.alert('Youtube channel not found, verify the link.')
return document.getElementById('YTchannelID').style = "border: 2px solid red"
} }
async function channelCheck(yt) function addRem()
{ {
var res = await fetch(`${window.location.origin}/api/checkChannel`, window.open('https://discord.com/oauth2/authorize?client_id=356104008366030863&permissions=8&scope=bot', '_blank')
{
method: "GET",
mode: "cors",
headers: {id:yt},
})
.then(response=>
{
if(response.ok) return response.text();
})
.then(data=>
{
return data.replaceAll('"','')
})
.catch(error=>
{
return error;
});
return res
} }
function handleStrikesDashboard(element)
{
const guildID = element.parentNode.getElementsByTagName('h3')[0].id;
window.open(`${window.location.origin}/strikes/${guildID}/${userID}`, '_blank');
}

@ -2,9 +2,7 @@ const url = "https://discord.com/api/oauth2/authorize?client_id=3561040083660308
window.onload = ()=> window.onload = ()=>
{ {
console.log('Loaded');
setTimeout(() => { setTimeout(() => {
console.log('InTimeOut')
window.location.href = url; window.location.href = url;
}, 10000); }, 10000);
} }

@ -4,31 +4,35 @@ const dash = require('../controller/dashboard.js');
const api = require('../controller/api.js'); const api = require('../controller/api.js');
module.exports = (io, bot)=> module.exports = (io, bot)=>
{ {
router.route('/').get(homeController.home(io));
router.route('/redirect').get(homeController.redirect) router.route('/redirect').get(homeController.redirect)
router.route('/api/getUser').post(api.getUser(io));
router.route('/api/getGuildData/').post(api.guildData(io, bot));
router.route('/api/Change/').post(api.updateGuild(io));
router.route('/api/getRules').get(api.getRules);
router.route('/api/getFeeds').get(api.getFeeds);
router.route('/api/getFeed').get(api.getFeed);
router.route('/api/deleteFeed').post(api.deleteFeed);
router.route('/api/addFeed').post(api.addFeed(bot));
router.route('/api/updateFeed').post(api.addFeed(bot));
router.route('/api/getMessage').get(api.getMessage(bot));
router.route('/api/getChannelName').get(api.getChannelName);
router.route('/api/checkChannel').get(api.checkChannel);
router.route('/api/updateRule').post(api.updateRule(bot));
router.route('/api/deleteRule').post(api.deleteRule);
router.route('/dashboard').get(dash.get(io))
.post(dash.post(io));
router.route('/getMessage').get(api.getMessage(bot));
//! Using ? on a param makes it optional
router.route('/strikes/:id/:userid/:strikeid?').get(api.strikeDashboard(bot))
.post(api.getStrikes(bot))
.put(api.updateStrikes(bot))
.delete(api.deleteStrikes(bot));
router.route('/dc').get(homeController.dc); router.route('/dc').get(homeController.dc);
router.route('/addtodiscord').get(homeController.addtodiscord) router.route('/addtodiscord').get(homeController.addtodiscord)
router.route('/').get(api.home)
router.route('/redirect').get(api.redirect)
router.route('/dashboard').get(api.dashboard(bot))
router.route('/moderator/:moderatorid?').get(api.dashboard(bot))
router.route('/gdash/:id/:setting?').get(api.gDash(bot))
.put(api.guildUpdate(bot))
router.route('/feedsdash/:guildid').get(api.fDash(bot));
router.route('/feedChange/:id/:guildid?').get(api.feedChange(bot))
.delete(api.deleteFeed(bot))
.put(api.updateFeed(bot));
router.route('/newFeed/:guildid').get(api.addFeed(bot))
.put(api.saveNewFeed(bot));
router.route('/rolerulesdash/:id').get(api.rDash(bot))
router.route('/rolechange/:id?/:guildid?').get(api.roleChange(bot))
.put(api.saveRoleChange(bot))
.delete(api.deleteRole)
router.route('/newrule').put(api.newRule(bot))
router.route('/newrolerule/:guildid').get(api.newRoleRule(bot))
router.route('/guilds').get(api.guilds(bot));
router.route('/strikes/:id/:userid/:strikeid?').get(api.strikeDashboard(bot))
.put(api.updateStrikes(bot))
.delete(api.deleteStrikes(bot));
return router; return router;
}; };

@ -3,90 +3,30 @@
<head> <head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" href="/images/favicon.ico"/> <link rel="icon" type="image/ico" href="images/favicon.ico"/>
<title>Rem-chan at your service</title> <title>Rem-chan at your service</title>
<script src="js/dashboard.js"></script> <script src="js/dashboard.js"></script>
<link rel="scr" type="text/js" href="js/dashboard.js"/> <link rel="scr" type="text/js" href="js/dashboard.js"/>
<link rel="stylesheet" type="text/css" href="/css/dashboard.css" id="pagesheet"/> <link rel="stylesheet" type="text/css" href="/css/dashboard.css" id="pagesheet"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head> </head>
<body> <body>
</body> </body>
<div id="userWrapper"> <div id="userWrapper">
<div id="avatar"></div> <div id="avatar" style="background-image: url(&quot;https://cdn.discordapp.com/avatars/<%= user.id %>/<%= user.avatar %>.jpeg&quot;);"></div>
<div class="userNameWrapper"> <div class="userNameWrapper">
<p id="userName">USERNAME</p> <p id="userName"><%= user.username %> </p>
</div> </div>
</div> </div>
<div id="Guilds"> <div id="container">
<%- include('guilds.ejs') %>
</div> </div>
<div class="popup hidden" id= 'popup'> <div id="PopUpContainer" class="PopUpContainer hidden">
<i onclick="handleClose(this)" class="close material-symbols-outlined" id="close_bt">
cancel
</i>
<h3 id="guild" class="guildname">PLACEHOLDER</h3>
<p>Activate Music: <span class="material-symbols-outlined info">
info
<span class="tooltip"> Allow your server to use music (Temporarly does nothing as its a WIP[work in progress]).</span>
</span>
<span class="material-symbols-outlined checkBox" id="music">check_box_outline_blank</span>
</p>
<p>Activate Strikes:<span class="material-symbols-outlined info">
info
<span class="tooltip"> Activate a 3 strike system before automatic ban. (Theese are to be validated before they are self-actionable)</span>
</span>
<span class="material-symbols-outlined checkBox" id="strikes">check_box_outline_blank </span>
</p>
<p>Activate Invites:<span class="material-symbols-outlined info">
info
<span class="tooltip"> Allow invites to other servers on your server.</span>
</span>
<span class="material-symbols-outlined checkBox" id="allowInvites">check_box_outline_blank </span>
</p>
<p id="RoleRules" onclick="handleToggleRules(this)">Role rules</p>
<p id="Feeds" onclick="handleToggleFeeds(this)">Feeds</p>
<p id="Strikes" onclick="handleStrikesDashboard(this)">Strikes Dashboard</p>
<div id="rules" class="rules hidden">
</div>
<div id="feeds" class="feeds hidden">
</div>
</div> </div>
<div id="roleRuleWrapper"class="roleRuleWrapper hidden">
<i onclick="handleClose(this)" class="close material-symbols-outlined" id="close_bt2">
cancel
</i>
<h1 id="roleRule" class="roleRule"> New Rule </h1>
<p id="role" class="role"> Role:</p>
<p id='emoji' class="emoji"><img id='emojiImg'></img>Emoji:</p>
<p id="message" class="message"> Message ID:</p>
<input id ="messageID" class='message messageID'></input>
<select id ="roleID" class='role roleID'>
</select>
<select id = "emojiID" class ="emoji emojiID">
</select>
<button id="change" class="bt" onclick='updateRule(this)'>Change</button>
<button id="delete" class="bt" onclick='deleteRule(this)'>Delete</button>
</div>
<div id="FeedWrapper" class="FeedWrapper hidden">
<h1 id="ChannelName">Feed</h1>
<i onclick="handleClose(this)" class="close material-symbols-outlined" id="close_bt2">
cancel
</i>
<p id='DCchannel' class="channel labeldc">Discord Channel:</p>
<select id ="DCchannelID" class='channel dc'>
</select>
<p id="YTchannel" class="channel labelyt">Youtube Channel:</p>
<p id="CostumMessage" class="message CostumMessage">Costum message:</p>
<input id ="YTchannelID" class='channel yt'></input>
<textarea id="CostumMessageI" class='message CostumMessageI' cols="40" rows="5"></textarea>
<button id="delete" class="bt" onclick='deleteFeed(this)'>Delete</button>
<button id="change2" class="bt" onclick='_updateFeed(this)'>Change</button>
</div>
</body> </body>
</html> </html>

@ -0,0 +1,51 @@
<div id="FeedWrapper" class="FeedWrapper">
<h1 id="ChannelName"><%= feed?feed.channelName:'New Feed' %> </h1>
<i hx-get="/feedsdash/<%= guild.id %>" hx-target="#PopUpContainer" hx-trigger="click" class="close material-symbols-outlined" id="close_bt2">
cancel
</i>
<form>
<section class="costumMessageSection">
<p id="CostumMessage" class="message CostumMessage">Costum message:</p>
<textarea
id="CostumMessageI"
name="costummessage"
class='message CostumMessageI'
cols="40"
rows="5"><%=feed?feed.CostumMessage:'' %></textarea>
</section>
<section class="dcSection">
<p id='DCchannel' class="channel labeldc">Discord Channel:</p>
<select id ="DCchannelID" name="DCchannelID" class='channel dc'>
<% guild.guildTextChannels = guild.guildTextChannels.sort((a, b) => {return a.name.localeCompare(b.name);});%>
<% guild.guildTextChannels.forEach((c)=>{%>
<option value="<%= c.id %>" <% if(feed?.ChannelId==c.id) {%> selected <% } %> ><%= c.name%></option>
<%}) %>
</select>
</section>
<section class="ytChannelSection">
<p id="YTchannel" class="channel labelyt">Youtube Channel:</p>
<input id ="YTchannelID" class='channel yt' name="ytchannel" value="<%= feed?`https://www.youtube.com/@${feed.channelName}`:`` %>" \>
</section>
<section class="buttonsSection">
<%if(feed){%>
<button id="delete2" class="button"
hx-delete=<%=`/feedchange/${feed._id}/${guild.id}`%>
hx-trigger="click"
hx-target="#PopUpContainer">
Delete
</button>
<%}%>
<button id="change2" class="button"
hx-trigger="click"
hx-target="#PopUpContainer"
hx-put=<%= feed?`/feedchange/${feed._id}/${guild.id}`:`/newfeed/${guild.id}` %>
<%if(!feed){%>
style="left:50% !important;"
<%}%>\
type="submit">
<%= !feed?"Add":"Change" %>
</button>
</section>
</form>
</div>

@ -0,0 +1,18 @@
<div id="feeds" class="popup">
<section style="margin-top: 2em;"></section>
<i hx-get="/gdash/<%= id %>" hx-trigger="click" hx-target="#PopUpContainer" class="close material-symbols-outlined" id="close_bt">
cancel
</i>
<p id="newFeed"
hx-get="/newFeed/<%= id %>"
hx-trigger="click"
hx-target="#PopUpContainer"
>New Feed</p>
<% feeds.forEach(feed=>{ %>
<p id= "<%= feeds._id %>"
hx-get="/feedChange/<%=feed._id %>/<%= id %>"
hx-trigger="click"
hx-target="#PopUpContainer"
><%= feed.channelName %></p>
<% }) %>
</div>

@ -0,0 +1,22 @@
<div id="<%= guild.id%>"
class="card"
hx-get=<%= guild.hasRem?"/gdash/"+guild.id:"" %>
hx-target="#PopUpContainer"
hx-trigger="click"
onclick=<%= guild.hasRem?"togglePopup(document.getElementById('PopUpContainer'))": "addRem()"%>>
<div class="card-content" >
<div class="card-image ">
<div class="img img<%= guild.hasRem %>" style="background-image:url(<%=guild.icon%>);" ></div>
</div>
<div class="card-info-wrapper <%=guild.hasRem %>">
<div class="card-info">
<div class="card-info-title">
<h3 data-value="<%= guild.name %> " class="fancy"><%= guild.name%></h3>
<h4><%= guild.memberCount?guild.memberCount + ' users on the server.':'Rem is not on this server yet.'%></h4>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,46 @@
<div class="popup" id= 'popup' >
<i onclick="togglePopup(document.getElementById('PopUpContainer'))" id="close_bt" class="close material-symbols-outlined">
cancel
</i>
<h3 id="guild" class="guildname"><%= guild.name%></h3>
<p
hx-put="/gdash/<%= guild.id %>/music"
hx-trigger="click"
hx-target="#PopUpContainer">
Activate Music: <span class="material-symbols-outlined info">
info
<span class="tooltip"> Allow your server to use music (Temporarly does nothing as its a WIP[work in progress]).</span>
</span>
<span class="material-symbols-outlined checkBox" id="music"><%= guild.music?"check_box":"check_box_outline_blank" %></span>
</p>
<p
hx-put="/gdash/<%= guild.id %>/strikes"
hx-trigger="click"
hx-target="#PopUpContainer">
Activate Strikes:<span class="material-symbols-outlined info">
info
<span class="tooltip"> Activate a 3 strike system before automatic ban. (Theese are to be validated before they are self-actionable)</span>
</span>
<span class="material-symbols-outlined checkBox" id="strikes"><%= guild.strikes?"check_box":"check_box_outline_blank" %></span>
</p>
<p
hx-put="/gdash/<%= guild.id %>/allowInvites"
hx-trigger="click"
hx-target="#PopUpContainer"
>
Activate Invites:<span class="material-symbols-outlined info">
info
<span class="tooltip"> Allow invites to other servers on your server.</span>
</span>
<span class="material-symbols-outlined checkBox" id="allowInvites"><%= guild.allowInvites?"check_box":"check_box_outline_blank" %> </span>
</p>
<p id="RoleRules" hx-get="/rolerulesdash/<%= guild.id %>" hx-target="#PopUpContainer" hx-trigger="click">Role rules</p>
<p id="Feeds" hx-get="/feedsdash/<%=guild.id%>" hx-target="#PopUpContainer" hx-trigger="click">Feeds</p>
<p id="Strikes" hx-get="/strikes/<%=guild.id%>/<%= userid %> " hx-target="body" hx-trigger="click">Strikes Dashboard</p>
<div id="rules" class="rules hidden">
</div>
<div id="feeds" class="feeds hidden">
</div>
</div>

@ -0,0 +1,5 @@
<div id="Guilds" >
<% guilds.forEach(guild => {%>
<%- include('guildCard.ejs', {guild}) %>
<% }); %>
</div>

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="shortcut icon" href="/images/favicon.ico"/> <link rel="shortcut icon" href="/images/favicon.ico"/>
<title>Rem-chan at your service</title> <title>Rem-chan at your service</title>
<script type="text/javascript" src="js/index.js"></script> <script type="text/javascript" src="js/home.js"></script>
<link rel="stylesheet" type="text/css" href="css/index.css" id="pagesheet"/> <link rel="stylesheet" type="text/css" href="css/home.css" id="pagesheet"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
</head> </head>

@ -0,0 +1,46 @@
<div id="roleRuleWrapper"class="roleRuleWrapper">
<i hx-get="/rolerulesdash/<%= role!='N/A'?role.gID:guild.extra.id %>" hx-target="#PopUpContainer" hx-trigger="click" class="close material-symbols-outlined" id="close_bt2">
cancel
</i>
<h1 id="roleRule" class="roleRule"> <%= role=='N/A'?'New Rule':role.name %></h1>
<form>
<p id="role" class="role"> Role:</p>
<p id='emoji' class="emoji">
<% if(role=='N/A'){ %>
<img id='emojiImg' src="images/favicon.ico"></img>
<%} else {%>
<img id='emojiImg' src="https://cdn.discordapp.com/emojis/<%= role.roleEmoji %>.webp" ></img>
<% } %>
Emoji:</p>
<p id="message" class="message" > Message ID:</p>
<input id ="messageID" name="messageid" class='message messageID' value="<%= role=='N/A'?'':role.mID %>"></input>
<select id ="roleID" name="roleid" class='role roleID'>
<% guild.roles.forEach((r)=>{%>
<option value="<%= r.id %>" <% if(role.roleID==r.id) {%> selected <% } %> ><%= r.name%></option>
<%}) %>
</select>
<select id = "emojiID" name="emojiid" class ="emoji emojiID">
<% guild.emojis.forEach((emoji)=>{%>
<option value="<%= emoji.id %>"<% if(role.roleEmoji==emoji.id) {%> selected <% } %>><%= emoji.name%></option>
<%}) %>
</select>
<input class="hidden" name="guildid" value=<%= role!='N/A'?role.gID:guild.extra.id %>></input>
<button id="change" class="bt"
hx-trigger="click"
hx-target="#PopUpContainer"
hx-put=<%= role!='N/A'?`/rolechange/${role._id}/${role.gID}`:"/newrule" %>
type="submit">
<%= role=='N/A'?"Add":"Change" %>
</button>
<button id="delete" class="bt"
<%if(role!='N/A'){%>
hx-delete=<%=`/rolechange/${role._id}/${role.gID}`%>
hx-trigger="click"
hx-target="#PopUpContainer"
<%}%>
type="submit">
Delete
</button>
</form>
</div>

@ -0,0 +1,11 @@
<div id="rules" class="popup">
<i hx-get="/gdash/<%= id %>" hx-trigger="click" hx-target="#PopUpContainer" class="close material-symbols-outlined" id="close_bt">
cancel
</i>
<!-- <h1 style="color:black; margin-top: 0.5em; font-weight: bolder;">Rules:</h1> -->
<p id="newRole" hx-get="/newrolerule/<%= id %>" hx-trigger="click" hx-target="#PopUpContainer">Add new Rule</p>
<% roles.forEach((role)=>{%>
<p id="<%=role._id %> " hx-get="/roleChange/<%=role._id %>/<%= id %>" hx-trigger="click" hx-target="#PopUpContainer" class="addRoleName"><%= role.roleName%></p>
<% }); %>
</div>

@ -0,0 +1,30 @@
<div class="strike">
<div class="strike-info">
<h3> User:
<%- include('user.ejs', {user:{username:strike.strokedName,avatar:strike.strokedAvatar,id:strike.strokedID }, stroke:true}) %>
was struck
</h3>
<h3> by:
<%- include('user.ejs', {user:{username:strike.strikerName,avatar:strike.strikerAvatar,id:strike.strikerID}, stroke:false}) %>
</h3>
<h3> With the reason: <%= strike.reason %> </h3>
<h5> Lasting until: <%=new Date(strike.expireAt).toDateString()%> </h5>
<%if(strike.validated){%>
<%if(strike.validatedBy){%>
<h4 id="validator"> Validated by:
<%- include('user.ejs', {user:strike.moderator, stroke:false}) %>
</h4>
<% } %>
<% } %>
</div>
<% if(!strike.validated){ %>
<div class="actions">
<div>
<h4 hx-put="/strikes/<%= strike.guildID %>/<%= moderator%>/<%= strike._id %>" hx-target="#maindisplay"> Validate ✔</h4>
</div>
<div>
<h4 hx-delete="/strikes/<%= strike.guildID %>/<%= moderator%>/<%= strike._id %>" hx-target="#maindisplay"> Remove ❌</h4>
</div>
</div>
<% } %>
</div>

@ -1,44 +1,9 @@
<% strikes.forEach(strike=>{%> <% strikes.forEach(strike=>{%>
<div class="strike">
<div class="strike-info"> <%- include('strike.ejs', {strike, moderator}) %>
<h3> User:
<span class="striked">
<% if (strike.strokedAvatar !== 'NOAVATAR') { %>
<img src="https://cdn.discordapp.com/avatars/<%= strike.strokedID %>/<%= strike.strokedAvatar %>.jpeg" alt="Striker Avatar">
<% } %>
<%= strike.strokedName %>
</span>
was struck
</h3>
<h3> by:
<span>
<% if (strike.strikerAvatar !== 'NOAVATAR') { %>
<img src="https://cdn.discordapp.com/avatars/<%= strike.strikerID %>/<%= strike.strikerAvatar %>.jpeg" alt="Striker Avatar">
<% } %>
<%= strike.strikerName %>
</span>
</h3>
<h3> With the reason: <%= strike.reason %> </h3>
<h5> Lasting until: <%=new Date(strike.expireAt).toDateString()%> </h5>
<%if(strike.validated){%>
<h4>Validated</h4>
<% } %>
</div>
<% if(!strike.validated){ %>
<div class="actions">
<div>
<h4 hx-put="/strikes/<%= strike.guildID %>/<%= moderator%>/<%= strike._id %>" hx-target="#maindisplay"> Validate ✔</h4>
</div>
<div>
<h4 hx-delete="/strikes/<%= strike.guildID %>/<%= moderator%>/<%= strike._id %>" hx-target="#maindisplay"> Remove ❌</h4>
</div>
</div>
<% } %>
</div>
<% });%> <% });%>
<%if(strikes.length==0){%> <%if(strikes.length==0){%>
<div class="NoStrikes"> <div class="NoStrikes">
<h2> THERE ARE NO STRIKES</h2> <h2> THERE ARE NO STRIKES</h2>
</div> </div>
<% } %> <% } %>

@ -1,26 +1,14 @@
<!DOCTYPE html> <div id="userWrapper">
<html lang="en-US"> <link rel="stylesheet" type="text/css" href="/css/strikesdashboard.css" id="pagesheet"/>
<head> <i hx-get="/dashboard" hx-trigger="click" hx-target="body" id="close_bt" class="close material-symbols-outlined">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> cancel
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> </i>
<link rel="shortcut icon" href="/images/favicon.ico"/> <div id="avatar" style="background-image: url(https://cdn.discordapp.com/icons/<%= guild.id %>/<%= guild.icon%>.webp)"></div> <!--it works somehow -->
<title>Rem-chan at your service</title> <div class="userNameWrapper">
<link rel="stylesheet" type="text/css" href="/css/strikesdashboard.css" id="pagesheet"/> <p id="userName"><%= guild.name%></p>
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
</body>
<div id="userWrapper">
<div id="avatar" style="background-image: url(https://cdn.discordapp.com/icons/<%= guild.id %>/<%= guild.icon%>.webp)"></div> <!--it works somehow -->
<div class="userNameWrapper">
<p id="userName"><%= guild.name%></p>
</div>
</div>
<div id="maindisplay">
<%- include('strikelist.ejs') %>
</div> </div>
</body> </div>
<div id="maindisplay">
</html> <%- include('strikelist.ejs') %>
</div>

@ -0,0 +1,10 @@
<span
<% if(stroke){ %>
class="stroke"
<% } %> >
<% if (user.avatar !== 'NOAVATAR') { %>
<img src="https://cdn.discordapp.com/avatars/<%= user.id %>/<%= user.avatar %>.jpeg" alt="Validator is <%= user.username %> ">
<% } %>
<%= user.username %>
</span>
Loading…
Cancel
Save