From 1062d22b17aada1244c4f3b0e442737166908e4f Mon Sep 17 00:00:00 2001 From: Cristiano Pires Date: Tue, 14 Mar 2023 19:37:08 +0000 Subject: [PATCH] Add YTfeeds to dashboards --- commands/admin/setFeedId.js | 4 +- controller/api.js | 140 ++++++++++++++++++++++++++- models/feeds.js | 1 + public/css/dashboard.css | 104 ++++++++++++++++++++- public/js/dashboard.js | 182 ++++++++++++++++++++++++++++++++++-- routes/routes.js | 6 ++ views/dashboard.ejs | 35 +++---- 7 files changed, 444 insertions(+), 28 deletions(-) diff --git a/commands/admin/setFeedId.js b/commands/admin/setFeedId.js index 7d4023a..49d692f 100644 --- a/commands/admin/setFeedId.js +++ b/commands/admin/setFeedId.js @@ -19,6 +19,7 @@ class setYTFeed extends Command{ const validationResult = await this.confirmArgs(message, args); if (validationResult.error) return new ErrorMessage(this.client).send(ErrorType.Arguments, message, [validationResult.error]) var feed = new feedM(); + feed.gID = message.guildId; feed.ChannelId = validationResult.channelId feed.YTChannelId = validationResult.YTChannelId; feed.CostumMessage = args[3]?args.splice(2).join(' '):'New video:'; @@ -131,4 +132,5 @@ async function getChannelId(url) { return data ? data.split('https://www.youtube.com/feeds/videos.xml?channel_id=')[1].split('"')[0] : false; } -} \ No newline at end of file +} + diff --git a/controller/api.js b/controller/api.js index 45d2cf3..1cff5a5 100644 --- a/controller/api.js +++ b/controller/api.js @@ -1,5 +1,7 @@ const GuildM = require('../models/guilds'); -const roleRulesM = require('../models/autoRoleRule') +const roleRulesM = require('../models/autoRoleRule'); +const feedsM = require('../models/feeds') +const xmlparser = require('xml-js') exports.getUser = (io)=> { @@ -113,6 +115,7 @@ exports.getMessage = (bot)=> { 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)=> @@ -230,3 +233,138 @@ exports.updateRule = (bot)=> return {mID, roleID, roleEmoji, roleName, gID} } } +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.getChannelName = async (req,res)=> +{ + var payload = await fetch('https://www.youtube.com/feeds/videos.xml?channel_id='+req.headers.channelid, + { + method: "GET", + mode: "cors", + }) + .then(response=> + { + if(response.ok) 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; + }); + res.json(payload); + +} + +exports.addFeed = (bot)=> +{ + return async (req, res)=> + { + var headers= req.headers; + var args = [headers.gid, headers.dcchannelid, headers.ytchannelid] + const validationResult = await confirmArgs(args, bot); + if(headers.isnew=="true") + { + if (validationResult.error) return res.json({error:validationResult.error}) + 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=> + { + console.log('here', 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) +{ + var channelId = args[1]; + var channelURL = args[2] + async function getChannelId(url) + { + 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; + } + } + + const YTChannelId = await getChannelId(channelURL); + const exists = await bot.channels.fetch(channelId).then(channel=>{return channel }).catch(()=>{return null}); + if(!exists) return {error:'Provided 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;}); + if(!name) return {error:'Provided Youtube channel does not exist.'} + const channelInUse = await feedsM.findOne({ChannelId:channelId}).then(channel=>{return channel}).catch(()=>{return []}); + if(channelInUse) return {error:'Discord channel already in use. Please choose another.'} + return {YTChannelId, channelId, name, channelName:exists.name} +} +exports.deleteFeed = (req,res) => +{ + feedsM.findOneAndDelete({_id:req.headers.feedid}).then(()=>{res.json({success:true})}).catch(error=>{res.json({error})}) +} diff --git a/models/feeds.js b/models/feeds.js index d5475ab..6238c07 100644 --- a/models/feeds.js +++ b/models/feeds.js @@ -7,6 +7,7 @@ new Schema( ChannelId: {type:String, required: true}, YTChannelId: {type:String, required: true}, CostumMessage:{type:String, required:false}, + gID:{type:String, required:false}, } ); diff --git a/public/css/dashboard.css b/public/css/dashboard.css index 48f2b12..5dcd3c9 100644 --- a/public/css/dashboard.css +++ b/public/css/dashboard.css @@ -339,7 +339,6 @@ body { aspect-ratio: 16/9; position:absolute; top:-50%; - left:0; font-size:1em; top:50%; left:50%; @@ -415,7 +414,6 @@ p { font-weight:bold; font-family: 'Lato'; - } input { @@ -483,4 +481,106 @@ input margin-right:0.5em; margin-top:0.5em; cursor:pointer; +} +#ChannelName +{ + position: absolute; + color: ivory; + top: 1.5vh; + left: 50%; + transform: translateX(-50%); + font-family: 'lato'; +} + +.FeedWrapper +{ + height: 20em; + aspect-ratio: 16/9; + 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 +{ + position:absolute; + top:50%; +} +.labeldc +{ + left:10% +} +.labelyt +{ + right:10% +} +.dc +{ + left:10%; + transform:translateY(250%); + background-color:#00000054; + border:2px solid transparent; + color:ivory; + text-align:right; + width: 37.5%; +} +.yt +{ + right:10%; + transform:translateY(250%); + background-color:#00000054; + border:2px solid transparent; + color:ivory; + text-align:right; + width: 37.5%; +} + +.feeds +{ + border: 2px solid #020608; + height: 20vh; + position: absolute; + top:1%; + overflow-y: scroll; + width: 60%; + left: 20%; + background-color:#071c24de; + color: ivory; + border-radius: 5px; +} +.rules p +{ + cursor: pointer; +} +.feeds p +{ + 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; + resize: none; } \ No newline at end of file diff --git a/public/js/dashboard.js b/public/js/dashboard.js index 69929de..c8dabd8 100644 --- a/public/js/dashboard.js +++ b/public/js/dashboard.js @@ -71,7 +71,7 @@ function handleSettigns(event) function handleClose(element) { - if(element.parentNode.id == 'roleRuleWrapper') document.getElementById('popup').classList.remove('hidden'); + if(element.parentNode.id == 'roleRuleWrapper' || element.parentNode.id == 'FeedWrapper') document.getElementById('popup').classList.remove('hidden'); element.parentNode.classList.add('hidden'); } async function requestChange() @@ -178,13 +178,103 @@ async function handleToggleRules(element) cancel -

New Role

+

New Rule

${ruleArr.join('')} ` rulesElement.classList.remove('hidden') } -function handleToggleFeeds(element) +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(`

${ytchannelname}

`) + } + + feedElement.innerHTML = ` + + cancel + +

New Feed

+ ${ruleArr.join('')} + ` + feedElement.classList.remove('hidden'); + } function deleteRule(element) @@ -242,7 +332,6 @@ function updateRule(element) .then(result => result.json()) .then(res => { - console.log(res); if(res.success) { element.parentNode.classList.add('hidden') @@ -294,9 +383,88 @@ async function changeRule(element) 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').placeholder = rule.roleID; - document.getElementById('emojiID').placeholder = rule.roleEmoji; - document.getElementById('messageID').placeholder = rule.mID; + 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) +{ + 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 = ''; +} +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('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 = feed.YTChannelId; + document.getElementById('CostumMessageI').value = feed.CostumMessage; +} + +function deleteFeed(element) +{ + var feedID = document.getElementById('ChannelName').classList[1]; + 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); +} + +function _updateFeed(element) +{ + var isNew=false; + if(element.parentNode.children[1].innerText == 'New Feed') isNew = true; + var feedID; + if(!isNew) feedID = document.getElementById('ChannelName').classList[1]; + console.log('fid', feedID) + var gid = document.getElementsByClassName('guildname')[0].id; + console.log('gid', gid) + var DCchannelID = document.getElementById('DCchannelID').value; + var YTchannelID = document.getElementById('YTchannelID').value; + var CostumMessageI = document.getElementById('CostumMessageI').value; + fetch(`${window.location.origin}/api/addFeed`, + { + method: "POST", + mode: "cors", + headers: {DCchannelID, YTchannelID, CostumMessageI, gid,isNew, 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); } \ No newline at end of file diff --git a/routes/routes.js b/routes/routes.js index 98186fe..6ab53b0 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -9,7 +9,13 @@ module.exports = (io, bot)=> 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/updateRule').post(api.updateRule(bot)); router.route('/api/deleteRule').post(api.deleteRule); router.route('/dashboard').get(dash.get(io)) diff --git a/views/dashboard.ejs b/views/dashboard.ejs index b953bad..7ac24c6 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -35,12 +35,11 @@

Role rules

Feeds

+ + - - - - - - - - +