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,261 +2,191 @@ const GuildM = require('../models/guilds');
const STRIKES = require('../models/strikes');
const roleRulesM = require('../models/autoRoleRule');
const feedsM = require('../models/feeds');
const xmlparser = require('xml-js')
const {isValidObjectId} = require('mongoose')
const xmlparser = require('xml-js');
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)=>
{
fetch('https://discord.com/api/users/@me',
{
headers: {
authorization: req.headers.authorization,
},
})
.then(result=>result.json())
.then(response =>
{
res.json(response);
})
}
};
res.render('redirect.ejs');
}
exports.guildData = (io,bot)=>
exports.dashboard = (bot)=>
{
return async (req, res)=>
{
let userGuilds = await fetch('https://discord.com/api/users/@me/guilds',
{
headers: {
authorization: req.headers.authorization,
},
})
.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)=>
const userPlaceholder =
{
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)
}));
id:'',
username:'placeholder',
avatar:'',
}
Promise.all(promises).then((values) => {
return res.json(values);
});
if(!req.headers.cookie) return res.render('dashboard.ejs', {user:userPlaceholder, guilds:guildsPlaceholder});
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)
{
var extra = 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(
}
exports.getModerator = (bot)=>
{
return async (req,res)=>
{
'id':emoji[0],
'name':emoji[1].name
});
const modId = {moderatorid} = req.params;
const user = await bot.users.cache.get('1203446477024927764');
res.render('user.ejs', {user})
}
for(var role of extra.roles.cache)
{
roles.push(
}
exports.guilds = (bot)=>
{
return async (req, res) =>
{
'id':role[0],
'name':role[1].name
});
}
try {
const connector = new DiscordAPI(req.headers.cookie, bot);
const userGuilds = await connector.getUserGuilds();
const guilds = await connector.getGuildsFull(userGuilds);
res.render('guilds.ejs', { guilds });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
return {guild, extra, TextChannels, emojis, roles};
}
async function getRoleRules(guildid)
{
return await roleRulesM.find({gID:guildid}).then((err, rules)=>
{
if(err || rules.length==0) return
return rules
})
}
}
exports.updateGuild = (io)=>
exports.gDash = (bot)=>
{
return (req, res)=>
{
GuildM.findOne({gID:req.body.guildID})
.then(
(guild, err)=>
return async (req, res)=>
{
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(()=>
const userid = await new DiscordAPI(req.headers.cookie, bot).getUserId();
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.id);
res.render('guildPopup.ejs', {guild, userid})
}
}
exports.guildUpdate = (bot)=>
{
return async (req, res)=>
{
return res.json(guild);
})
})
/**
* ! /gdash/:id/:setting?'
*/
const original = await GuildM.find({gID:req.params.id}).then(guild=>{return guild[0]});
var aux = {}
aux[req.params.setting] = !original[req.params.setting]
const updated = await GuildM.findOneAndUpdate({gID:req.params.id}, aux)
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.id);
res.render('guildPopup.ejs', {guild})
}
}
exports.getMessage = (bot)=>
exports.rDash = (bot)=>
{
//! /rolerulesdash/:id -> Discord Guild Id (GuildId)
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);
TextChannels.forEach(channel => {
(async (channel)=>
{
var message
try {
message = await channel.messages.fetch(req.headers.messageid);
} catch (error) {
//message doesn't exist on this channel or at all
const roles = await getRules(req.params.id);
res.render('roleRules.ejs', {roles, id:req.params.id});
}
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.roleChange = (bot)=>
{
//! '/roleChange/:id/:guildid'
return async (req, res)=>
{
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.getRules = async (req,res)=>
exports.saveRoleChange = (bot)=>
{
var payload;
if(req.headers.guildid)
//! '/rolechange
return async (req, res)=>
{
payload = await roleRulesM.find({gID:req.headers.guildid})
.then(rules =>{return rules})
.catch(()=>{return null})
return res.json(payload);
const body = req.body;
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 =
{
gID:body.guildid,
mID:body.messageid,
roleID:body.roleid,
roleEmoji:body.emojiid,
roleName:extra.roleName,
}
const updatedRule = await roleRulesM.findOneAndUpdate({_id:req.params.id}, rule);
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
res.render('rolePopup.ejs', {role:updatedRule, id:body.id, guild});
}
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.deleteRole = async (req, res)=>
{
var deleted = await roleRulesM.findByIdAndDelete(req.headers.ruleid)
.then(()=>{return {success:'Done'}})
.catch(()=>{return {error:'Failed to delete'}});
res.json(deleted);
const deleted = await roleRulesM.findOneAndDelete({_id:req.params.id});
const roles = await getRules(req.params.guildid);
res.render('roleRules.ejs', {roles, id:req.params.guildid});
}
exports.updateRule = (bot)=>
exports.newRoleRule = (bot)=>
{
//! '/newrolerule/:guildid'
return async (req, res)=>
{
let args = req.headers;
if(args.isnew == 'true')
{
const validationResult = await confirmArgs(args);
if (validationResult.error) return res.json({error:validationResult.error})
var rule = new roleRulesM();
rule.gID = validationResult.gID;
rule.mID = validationResult.mID;
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})
})
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})
}
else
}
exports.newRule = (bot)=>
{
return async (req, res)=>
{
const validationResult = await confirmArgs(args);
if (validationResult.error) return res.json({error:validationResult.error})
roleRulesM.findOne({id:args.id}).then(rule=>
const body = req.body;
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 =
{
if(!rule) return res.json({error:'DB Error'});
rule.gID = validationResult.gID;
rule.mID = validationResult.mID;
rule.roleID = validationResult.roleID;
rule.roleEmoji = validationResult.roleEmoji;
rule.roleName = validationResult.roleName;
roleRulesM.updateOne({_id:rule.id}, rule,{upsert:true}).then(updatedG=>
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)=>
{
res.json({success:true, rule})
})
})
//! /rolerulesdash/:id -> Discord Guild Id (GuildId)
return async (req, res)=>
{
const roles = await getRules(req.params.id);
res.render('roleRules.ejs', {roles, id:req.params.id});
}
}
async function confirmArgs(args)
{
*/
res.render('roleRules.ejs', {roles, id:body.guildid});
}
}
async function getRoleName(args, bot)
{
var mID = args.messageid;
var roleID = args.roleid;
var roleEmoji = args.emojiid;
var gID = args.gid;
var gID = args.guildid;
var roleName;
if(!mID) return {error:'Message ID'}
if(!roleID) return {error:'Role ID'}
if(!roleEmoji) return {error:'Emoji ID'}
if(!gID) return {error:'Guild ID'}
const guild = bot.guilds.cache.get(gID);
var m = await (async ()=>
{
for(const [id, channel] of bot.channels.cache)
@ -270,33 +200,34 @@ exports.updateRule = (bot)=>
}
}
})();
const r = bot.guilds.cache.get(gID).roles.cache.get(roleID);
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)
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 {mID, roleID, roleEmoji, roleName, gID}
}
return {roleName}
}
exports.getFeeds = async (req, res)=>
{
var payload = await feedsM.find({gID:req.headers.guildid}).then(res=>{return res}).catch(err=>{return err});
res.json(payload)
}
exports.getFeed = async (req, res)=>
{
var payload = await feedsM.find({_id:req.headers.feedid}).then(res=>{return res}).catch(err=>{return err});
res.json(payload)
exports.fDash = (bot)=>
{
//! /feedsdash/:guildid'
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",
mode: "cors",
@ -319,141 +250,101 @@ exports.getChannelName = async (req,res)=>
{
return error;
});
res.json(payload);
}
exports.checkChannel = async (req, res)=>
exports.feedChange = (bot)=>
{
var url = req.headers.id;
var regExp = '^(?:(?:https?:)?\/\/)?(?:www\.|(m\.)?)(youtube\.com|youtu\.be)(\/[^\s]*)?$';
var rE = new RegExp(regExp);
if (rE.test(url)) {
url = req.headers.id;
}
else
//! /feedChange/:id/:guildid?
return async (req, res)=>
{
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)=>
{
//! /feedChange/:guildid?
return async (req, res)=>
{
var headers= req.headers;
var args = [headers.gid, headers.dcchannelid, headers.ytchannelid]
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})
})
const guild = await new DiscordAPI(req.headers.cookie, bot).getSpecificGuildDataForDash(req.params.guildid);
res.render('feedPopup.ejs', {feed:null, id:req.params.id, guild});
}
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];
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)
//! /feedChange/:guildid?
return async (req, res)=>
{
return data ? data.split('https://www.youtube.com/feeds/videos.xml?channel_id=')[1].split('"')[0] : false;
}
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.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);
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,
exports.deleteFeed = (bot)=>
{
//! /feedChange/:id/:guildid?
return async (req, res)=>
{
compact: true,
space: 4
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});
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);
});
data = JSON.parse(data);
return data.feed.author.name._text
})
.catch(error=>{return error;});
return {YTChannelId, channelId, name, channelName:discordChannel.name}
res.render('feeds.ejs', {feeds, id:req.params.guildid});
}
}
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)=>
{
@ -461,27 +352,37 @@ exports.strikeDashboard = (bot)=>
{
// const user = bot.users.cache.get(req.params.userid)
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;
res.render('strikesDashboard.ejs', {strikes, guild, moderator})
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};
}
}
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})
}
strikes.push(aux);
}));
// console.log(strikes)
res.render('strikesDashboard.ejs', {strikes, guild, moderator})
}
}
exports.updateStrikes = (bot)=>
{
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 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})
}
}

249
lib.js

@ -1325,3 +1325,252 @@ class 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},
reason:{type:String, required:true},
validated:{type:Object, required:false},
validatedBy:{type:String, required:false},
date:{type:Date, required:true},
expireAt:{type:Date, required:true},
}

@ -3,22 +3,27 @@
body
{
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background-color: #071c24;
margin: 0px;
overflow-y: hidden;
overflow-x: hidden;
padding: 0px;
}
#userWrapper
{
position: absolute;
display: flex;
flex-wrap: wrap;
gap: 1em;
justify-content: center;
top:3vh;
margin-top:5vh;
left:50%;
transform: translateX(-50%);
height: 15vh;
width: 80%;
background-color: var(--card-color);
@ -57,30 +62,16 @@ body
white-space: pre-wrap;
color: rgb(15, 98, 131);
}
.DiscordAddBtn
{
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;
.info:hover .tooltip{
visibility: visible;
}
.close
.PopUpContainer
{
position: relative;
top:-0.1em;
right:1vh;
float:right;
position: absolute;
top:25%;
left:10%;
width: 80%;
height: 100%;
}
.popup .checkBox
{
@ -109,38 +100,67 @@ body
z-index: 1;
}
.info:hover .tooltip{
visibility: visible;
}
.popup
{
position: absolute;
min-height: 30%;
max-height: 50%;
width: 50%;
top:calc(50% - 15%);
background-color: rgba(210, 252, 253, 0.295);
border-radius: 5px;
border: 2px solid #020608;
z-index: 10;
border: 3px solid #020608;
text-align: center;
backdrop-filter: blur(3px);
height: 50%;
overflow: auto ;
}
.popup p
{
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.popup h3
{
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
{
font-family: 'Lato';
position: relative;
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
{
margin-top: 0.6em;
@ -175,10 +195,12 @@ p
}
#close_bt
{
position: relative;
position: absolute;
top:1vh;
right:1vh;
cursor:pointer;
}
#Feeds
{
cursor:pointer;
@ -190,6 +212,10 @@ p
width: 80%;
height: 60%;
position: absolute;
display:flex;
gap: 1em;
justify-content: space-evenly;
align-items: center;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
@ -222,7 +248,7 @@ p
filter:grayscale(0);
}
.card
/* width */
::-webkit-scrollbar {
@ -247,12 +273,6 @@ p
:root {
--card-color: rgb(23, 23, 23);
}
body {
margin: 0px;
overflow-y: scroll;
overflow-x: hidden;
padding: 0px;
}
#cards {
@ -404,45 +424,41 @@ body {
background-color:#071c24de;
color: ivory;
border-radius: 5px;
background-color:#5a8786;
}
.roleRuleWrapper
{
height: 20em;
border: 1px solid ivory;
aspect-ratio: 16/9;
position:absolute;
top:-50%;
font-size:1em;
top:50%;
left:50%;
transform: translateX(-50%) translateY(-50%);
text-align:center;
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:'';
height: 20em;
height: 100%;
aspect-ratio: 16/9;
position:absolute;
top:0;
left:0;
background-color:#5a8786;
z-index:-1;
}
.roleRuleWrapper:after
} */
/* .roleRuleWrapper:after
{
content:attr(data-before);
height: 9em;
font-family: 'Lato';
aspect-ratio: 16/9;
position:absolute;
top:48%;
left:50%;
transform:translateX(-50%) translateY(-50%);
z-index:-1;
filter: blur(1px);
background-image: linear-gradient(ivory, #2a2a291f);
background-size: 100%;
@ -450,17 +466,13 @@ body {
-moz-background-clip: text;
-webkit-text-fill-color: transparent;
-moz-text-fill-color: transparent;
}
} */
.roleRule
{
color: ivory;
font-family: 'Lato';
font-weight: bolder;
margin-top: 1em;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
}
.role
@ -502,13 +514,6 @@ input
text-align:right;
width: 37.5%;
}
.message
{
color:ivory;
position:absolute;
left: 30%;
top:40%;
}
.messageID
{
transform:translateY(250%);
@ -538,7 +543,7 @@ input
}
#change2
{
left:70%;
}
#delete
{
@ -572,72 +577,81 @@ input
.FeedWrapper
{
height: 20em;
aspect-ratio: 16/9;
height: 45vh;
border: 1px solid ivory;
position:absolute;
top:50%;
left:50%;
font-size:1em;
font-family:'lato';
color:ivory;
transform: translateX(-50%) translateY(-50%);
text-align:center;
border-radius: 10px;
overflow: hidden;
background-color:#5a8786;
}
.channel
.FeedWrapper > form
{
position:absolute;
top:50%;
margin-top:4em;
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%;
transform:translateY(250%);
background-color:#00000054;
border:2px solid transparent;
color:ivory;
text-align:center;
width: 37.5%;
width: 100%;
}
option
.dcSection
{
background:#087575;
width: 50%;
}
.yt
.ytChannelSection
{
right:10%;
transform:translateY(250%);
background-color:#00000054;
border:2px solid transparent;
width: 50%;
}
.buttonsSection
{
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;
text-align:right;
width: 37.5%;
cursor:pointer;
font-weight: bold;
font-family: 'lato';
}
.feeds
.dc
{
border: 2px solid #020608;
height: 20vh;
position: absolute;
top:1%;
overflow-y: scroll;
width: 60%;
left: 20%;
background-color:#071c24de;
background-color: #00000054;
border: 2px solid transparent;
border-radius: 4px;
color: ivory;
border-radius: 5px;
text-align: center;
}
option
{
background:#087575;
}
.rules p
{
cursor: pointer;
@ -646,24 +660,17 @@ option
{
cursor: pointer;
}
.message
{
position: absolute;
top: 20%;
}
.CostumMessage
{
color:ivory;
}
.CostumMessageI
{
transform: translateY(80%);
background-color: #00000054;
border: 2px solid transparent;
color: ivory;
text-overflow: wrap;
width: 37.5%;
height: 4em;
width: 80%;
height: 3em;
resize: none;
}
@ -703,3 +710,14 @@ option
:root {
--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 {
flex: 4;
}
.strike-info > h3 > span> img
.strike-info > h3 > span> img, .strike-info > h4 > span> img
{
border: none;
border-radius: 50%;
@ -115,7 +115,7 @@ body
height: 1em;
transform: translateY(0.25em);
}
.strike-info > h3 > span
.strike-info > h3 > span, .strike-info > h4 > span
{
background-color: rgb(44, 151, 238);
height: 5em;
@ -125,7 +125,7 @@ body
padding-right: 0.2em;
padding-bottom: 0.2em;
}
.strike-info > h3 > span.striked
.strike-info > h3 > span.stroke
{
background-color: rgb(58, 23, 23);
}

@ -1,139 +1,47 @@
var userID;
var guildsCache = new Map();
window.onload = async () =>
{
const fragment = new URLSearchParams(window.location.hash.slice(1));
const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')];
if (!accessToken) return window.location.href = '/';
updateUser(accessToken, tokenType);
updateGuildData(accessToken, tokenType);
document.getElementById('RoleRules').onclick = handleToggleRules;
};
const expirationDate = new Date( Date.now() + (24 * 60 * 60 * 1000));// 24 hours
// document.cookie = 'accessToken' + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;';
// 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=/`;
document.cookie = `tokenType=${tokenType}; expires=${expirationDate.toUTCString()}; path=/`;
if(wasEmpty) window.location.reload();
createListeners();
function updateUser(accessToken, tokenType)
{
const avatar = document.getElementById('avatar');
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');
document.getElementById('change').innerText = 'Change';
document.getElementById('change2').innerText = 'Change';
element.classList.remove('hidden');
return document.addEventListener('click', clickListener);
}
if(element.parentNode.id =="FeedWrapper") document.getElementById('ChannelName').classList = '';
element.parentNode.classList.add('hidden');
element.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)
{
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';
document.getElementById('PopUpContainer').classList.add('hidden');
document.removeEventListener('click', clickListener);
}
})
.catch(console.error);
}
async function makeCards(data)
function createListeners()
{
const canvas = document.createElement('div')
canvas.classList.add('cards');
canvas.id = 'cards';
for(var item of data)
document.getElementById("Guilds").onmousemove = e =>
{
(async ()=>
{
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"))
for(var card of document.getElementsByClassName("card"))
{
const rect = card.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
card.style.setProperty("--mouse-x", `${x}px`);
card.style.setProperty("--mouse-y", `${y}px`);
let interval = null;
@ -169,403 +77,14 @@ async function makeCards(data)
{
clearInterval(interval);
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)
{
var res = await fetch(`${window.location.origin}/api/checkChannel`,
{
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)
function addRem()
{
const guildID = element.parentNode.getElementsByTagName('h3')[0].id;
window.open(`${window.location.origin}/strikes/${guildID}/${userID}`, '_blank');
window.open('https://discord.com/oauth2/authorize?client_id=356104008366030863&permissions=8&scope=bot', '_blank')
}

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

@ -4,31 +4,35 @@ const dash = require('../controller/dashboard.js');
const api = require('../controller/api.js');
module.exports = (io, bot)=>
{
router.route('/').get(homeController.home(io));
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('/dc').get(homeController.dc);
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))
.post(api.getStrikes(bot))
.put(api.updateStrikes(bot))
.delete(api.deleteStrikes(bot));
router.route('/dc').get(homeController.dc);
router.route('/addtodiscord').get(homeController.addtodiscord)
return router;
};

@ -3,90 +3,30 @@
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
<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>
<script src="js/dashboard.js"></script>
<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" 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" />
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
</body>
<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">
<p id="userName">USERNAME</p>
<p id="userName"><%= user.username %> </p>
</div>
</div>
<div id="Guilds">
</div>
<div class="popup hidden" id= 'popup'>
<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 id="container">
<%- include('guilds.ejs') %>
</div>
<div id="PopUpContainer" class="PopUpContainer hidden">
</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>
</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"/>
<link rel="shortcut icon" href="/images/favicon.ico"/>
<title>Rem-chan at your service</title>
<script type="text/javascript" src="js/index.js"></script>
<link rel="stylesheet" type="text/css" href="css/index.css" id="pagesheet"/>
<script type="text/javascript" src="js/home.js"></script>
<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" />
</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,41 +1,6 @@
<% strikes.forEach(strike=>{%>
<div class="strike">
<div class="strike-info">
<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>
<%- include('strike.ejs', {strike, moderator}) %>
<% });%>
<%if(strikes.length==0){%>
<div class="NoStrikes">

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