Initial upload of discord-contrib-advanced repo
This commit is contained in:
27
discord/discord-token.html
Normal file
27
discord/discord-token.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discord-token', {
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value:"", required: true},
|
||||
},
|
||||
credentials: {
|
||||
token: {type: "text"},
|
||||
},
|
||||
exportable: false,
|
||||
label: function() {
|
||||
return this.name;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="discord-token">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-token"><i class="icon-bookmark"></i> Token</label>
|
||||
<input type="text" id="node-config-input-token">
|
||||
<p>You can find the Discord API token for one of your bots on <a href="https://discordapp.com/developers/applications" target="_blank">your developer page</a>.</p>
|
||||
</div>
|
||||
</script>
|
||||
12
discord/discord-token.js
Normal file
12
discord/discord-token.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = function(RED) {
|
||||
function DiscordTokenNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.token = this.credentials.token;
|
||||
this.name = n.name;
|
||||
}
|
||||
RED.nodes.registerType("discord-token", DiscordTokenNode, {
|
||||
credentials: {
|
||||
token: {type:"text"}
|
||||
}
|
||||
});
|
||||
};
|
||||
98
discord/discordActivity.html
Normal file
98
discord/discordActivity.html
Normal file
@@ -0,0 +1,98 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordActivity', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: { value: "", required: false },
|
||||
atext: { value: "", required: false},
|
||||
aurl: { value: "", required: false },
|
||||
atype: { value: "", required: false },
|
||||
astatus:{value: "", required: false},
|
||||
token: { value: "", required: true, type: "discord-token" }
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordActivity";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordActivity">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-atext"><i class="icon-tag"></i> Text</label>
|
||||
<input type="text" id="node-input-atext" placeholder="Text to Show">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-aurl"><i class="icon-tag"></i> Youtube or Twitch</label>
|
||||
<input type="text" id="node-input-aurl" placeholder="Url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-atype"><i class="icon-tag"></i>type</label>
|
||||
<select id="node-input-atype">
|
||||
<option value="0">Playing</option>
|
||||
<option value="1">Streaming</option>
|
||||
<option value="2">Listening</option>
|
||||
<option value="3">Watching</option>
|
||||
<option value="4">Custom (Not Working on Bots)</option>
|
||||
<option value="5">Competing</option>
|
||||
<option value="6">Reset Activities</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-status"><i class="icon-tag"></i> Show The Bot As</label>
|
||||
<select id="node-input-astatus">
|
||||
<option value="online">Online</option>
|
||||
<option value="idle">Afk</option>
|
||||
<option value="invisible">Offline</option>
|
||||
<option value="dnd">dnd</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordActivity">
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>text
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The Status Text of the Bot</dd>
|
||||
<dt>status
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The Online Status can be set to: online,idle,invisible,dnd</dd>
|
||||
|
||||
<dt>type
|
||||
<span class="property-type">enum</span>
|
||||
</dt>
|
||||
<dd>
|
||||
Playing: 0 <br>
|
||||
Streaming: 1<br>
|
||||
Listening: 2 <br>
|
||||
Watching: 3 <br>
|
||||
Custom: 4 (ATM Not Work on Bot)<br>
|
||||
Competing: 5<br>
|
||||
Reset Activities: 6<br>
|
||||
</dd>
|
||||
<dt>url
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The url of Twitch or Youtube</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
48
discord/discordActivity.js
Normal file
48
discord/discordActivity.js
Normal file
@@ -0,0 +1,48 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
function discordActivity(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', function (msg) {
|
||||
try {
|
||||
const types = msg.type || Number(config.atype)|| null;
|
||||
const status = msg.status ||config.astatus || 'online';
|
||||
const url = msg.url ||config.aurl || null;
|
||||
const statustext= msg.text || config.atext || null;
|
||||
|
||||
bot.user.setPresence({ activities: [{ name: statustext, type: types, url: url }], status: status });
|
||||
|
||||
msg.payload = {
|
||||
status: bot.presence['status'],
|
||||
bot: bot.presence.activities[0],
|
||||
}
|
||||
|
||||
node.status({ fill: "green", shape: "dot", text: "Bot Activities Changed" });
|
||||
node.send(msg);
|
||||
} catch (error) {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordActivity", discordActivity);
|
||||
};
|
||||
50
discord/discordChannelName.html
Normal file
50
discord/discordChannelName.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordChannelName',{
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {value: "", required: false},
|
||||
channel: {value: null,required: false},
|
||||
token: {value: "", required: true, type: "discord-token"}
|
||||
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 0,
|
||||
icon: "discord.png",
|
||||
label: function() {
|
||||
return this.name||"discordChannelName";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordChannelName">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-channel"><i class="icon-tag"></i> Channel</label>
|
||||
<input type="text" id="node-input-channel" name="ch" placeholder="Channel ID">
|
||||
<p>(leave 'channel' blank to use <code>msg.channel</code> as channel ID to send to)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordChannelName">
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>channel
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The Channel id of the channel to change the name of</dd>
|
||||
<dt>name
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The name you Whant give The channel</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
36
discord/discordChannelName.js
Normal file
36
discord/discordChannelName.js
Normal file
@@ -0,0 +1,36 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
function discordChannelName(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', function (msg) {
|
||||
try {
|
||||
const channel = config.channel || msg.channel || null;
|
||||
bot.channels.cache.get(channel).setName(msg.name);
|
||||
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: `Channel name was changed`
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
RED.nodes.registerType("discordChannelName", discordChannelName);
|
||||
};
|
||||
30
discord/discordClient.html
Normal file
30
discord/discordClient.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordClient',{
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {value: "", required: false},
|
||||
token: {value: "", required: true, type: "discord-token"}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function() {
|
||||
return this.name||"discordClient";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordClient">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordClient">
|
||||
<div class="alert alert-danger"><strong>DEPRECATED!</strong> THIS NODE IS DANGEROUS AND CAN CAUSE NODE-RED TO CRASH. USE AT YOUR OWN RISK!</div>
|
||||
<p>Sets <code>msg.discord</code> to the Discord.js <a href="https://discord.js.org/#/docs/main/stable/class/Client" target="_blank">Client</a> associated with the configured token. Use this node to inject a Discord client into a message, which you can then perform actions on manually in nodes that follow.</p>
|
||||
</script>
|
||||
26
discord/discordClient.js
Normal file
26
discord/discordClient.js
Normal file
@@ -0,0 +1,26 @@
|
||||
module.exports = function(RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
|
||||
function discordClient(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
discordBotManager.getBot(configNode).then(function(bot){
|
||||
node.on('input', function(msg) {
|
||||
msg.discord = bot;
|
||||
node.send(msg);
|
||||
});
|
||||
node.on('close', function() {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordClient", discordClient);
|
||||
};
|
||||
75
discord/discordCommandManager.html
Normal file
75
discord/discordCommandManager.html
Normal file
@@ -0,0 +1,75 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordCommandManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
guild: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordCommandManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordCommandManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-guild"><i class="icon-tag"></i> Guild</label>
|
||||
<input type="text" id="node-input-guild" name="guild" placeholder="Guild ID">
|
||||
<p>(leave 'guild' blank to use <code>msg.guild</code> as guild ID to send to)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordCommandManager">
|
||||
<p>Node to set the application commands for the bot, as well as delete specific commands or all commands, by guild or globally.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The action to do, can be: set, or delete.</dd>
|
||||
<dt>guild
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The guild object or ID.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">Object</span>
|
||||
<dt>
|
||||
<dd>When setting the commands it will return an array of the commands created. It will be the type of the application command (https://discord.js.org/docs/packages/discord.js/14.15.3/ApplicationCommand:Class) or guild command if the guildId is set.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node can set and delete application commands.<p>
|
||||
|
||||
<h4>Setting commands<h4>
|
||||
<p>To set commands simply set msg.commands to an array of the commands you'd like to set for the bot. The array objects must be of the slash command form. An example can be found using the slash command builder (https://discordjs.guide/creating-your-bot/slash-commands.html#individual-command-files). If the guild is not set then it will be applied globally, if guild is set then its applied only to that guild.</p>
|
||||
|
||||
<h4>Setting commands<h4>
|
||||
<p>To delete a specific command set commandId to the id of the command you wish to be deleted (which can be found by remembering the output of the add command, or by going into server and checking the intergration, right clicking will get the application command id (https://discordjs.guide/slash-commands/deleting-commands.html#deleting-specific-commands)). Note the command Id must be in the form of a string, e.g. '123534523423423'. To delete all commands do not set msg.commandId. Similiarly to the set command, you can set a guild to delete a command in a specific guild, or by not setting guild the command will be deleted across all guilds.</p>
|
||||
|
||||
</script>
|
||||
208
discord/discordCommandManager.js
Normal file
208
discord/discordCommandManager.js
Normal file
@@ -0,0 +1,208 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('node-red-contrib-discord-advanced/discord/lib/discordBotManager.js');
|
||||
const { checkIdOrObject } = require('./lib/discordFramework.js');
|
||||
const Flatted = require('flatted');
|
||||
const { REST, Routes } = require('discord.js');
|
||||
|
||||
|
||||
function discordCommandManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
|
||||
var bot = discordBotManager.getBot(configNode)
|
||||
|
||||
bot.then(function (bot) {
|
||||
node.on('input', async function (msg, send, done) {
|
||||
const _guildId = config.guild || msg.guild || msg.guildId || null;
|
||||
const _action = msg.action || null;
|
||||
const _commands = msg.commands || msg.command || msg.commandId || null;
|
||||
const _commandID = msg.commandId || null;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage, data) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
msg.payload = Flatted.parse(Flatted.stringify(data));
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
|
||||
const deleteCommand = async () => {
|
||||
try {
|
||||
|
||||
let commandId = _commandID;
|
||||
const rest = new REST().setToken(bot.token);
|
||||
const guildId = checkIdOrObject(_guildId);
|
||||
|
||||
let data = null;
|
||||
|
||||
if (guildId) {
|
||||
data = await rest.delete(Routes.applicationGuildCommand(bot.id, guildId, commandId));
|
||||
}
|
||||
else {
|
||||
data = await rest.delete(Routes.applicationCommand(bot.id, commandId))
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
setError(`Could not delete application (/) command '${commandId}'.`);
|
||||
}
|
||||
else {
|
||||
setSuccess(`Successfully deleted application (/) command '${commandId}'.`, data);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const getCommands = async () => {
|
||||
try {
|
||||
|
||||
const rest = new REST().setToken(bot.token);
|
||||
const commandId = checkIdOrObject(_commandID);
|
||||
const guildId = checkIdOrObject(_guildId);
|
||||
|
||||
let data = null;
|
||||
|
||||
if (guildId) {
|
||||
if(commandId){
|
||||
data = await rest.get(Routes.applicationGuildCommand(bot.id, guildId, commandId));
|
||||
}
|
||||
else{
|
||||
data = await rest.get(Routes.applicationGuildCommands(bot.id, guildId));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (commandId)
|
||||
{
|
||||
data = await rest.get(Routes.applicationCommand(bot.id, commandId));
|
||||
}
|
||||
else{
|
||||
data = await rest.get(Routes.applicationCommands(bot.id));
|
||||
}
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
setError(`Could not get application (/) command '${commandId}'.`);
|
||||
}
|
||||
else {
|
||||
setSuccess(`Successfully get application (/) command '${commandId}'.`, data);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const deleteAllCommand = async () => {
|
||||
try {
|
||||
const rest = new REST().setToken(bot.token);
|
||||
const guildId = checkIdOrObject(_guildId);
|
||||
|
||||
let data = null;
|
||||
|
||||
if (guildId) {
|
||||
data = await rest.put(Routes.applicationGuildCommands(bot.id, guildId), { body: [] })
|
||||
}
|
||||
else {
|
||||
data = await rest.put(Routes.applicationCommands(bot.id), { body: [] })
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
setError(`Could not delete all application (/) commands.`);
|
||||
}
|
||||
else {
|
||||
setSuccess(`Successfully deleted all application (/) commands.`, data);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const setCommand = async () => {
|
||||
try {
|
||||
|
||||
let commands = _commands;
|
||||
|
||||
if (commands == null) {
|
||||
setError(`msg.commands wasn't set correctly`);
|
||||
return;
|
||||
}
|
||||
|
||||
const rest = new REST().setToken(bot.token);
|
||||
const guildId = checkIdOrObject(_guildId);
|
||||
|
||||
let data = null;
|
||||
|
||||
if (guildId) {
|
||||
data = await rest.post(
|
||||
Routes.applicationGuildCommands(bot.id, guildId),
|
||||
{ body: commands },
|
||||
);
|
||||
}
|
||||
else {
|
||||
data = await rest.post(
|
||||
Routes.applicationCommands(bot.id),
|
||||
{ body: commands },
|
||||
);
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
setError("Could not set application commands");
|
||||
}
|
||||
else {
|
||||
setSuccess(`Successfully reloaded ${data.length} application (/) commands.`, data);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (_action == null) {
|
||||
setError(`msg.action has no value`)
|
||||
}
|
||||
else {
|
||||
switch (_action.toLowerCase()) {
|
||||
case 'set':
|
||||
await setCommand();
|
||||
break;
|
||||
case 'delete':
|
||||
await deleteCommand();
|
||||
break;
|
||||
case 'deleteall':
|
||||
await deleteAllCommand();
|
||||
break;
|
||||
case 'get':
|
||||
await getCommands();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
}
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordCommandManager", discordCommandManager);
|
||||
};
|
||||
104
discord/discordEventManager.html
Normal file
104
discord/discordEventManager.html
Normal file
@@ -0,0 +1,104 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordEventManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
guild: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
event: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordEventManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordEventManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-guild"><i class="icon-tag"></i> Guild</label>
|
||||
<input type="text" id="node-input-guild" name="ch" placeholder="Guild ID">
|
||||
<p>(leave 'guild' blank to use <code>msg.guild</code> as Guild ID)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-event"><i class="icon-tag"></i> Event</label>
|
||||
<input type="text" id="node-input-event" name="ch" placeholder="Event ID">
|
||||
<p>(leave 'event' blank to use <code>msg.event</code> as Event ID)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordEventManager">
|
||||
<p>Node to create, delete scheduled events as well as obtain info about a specific event or all events in a guild.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The action to do, can be: create, delete, info, all. If not set, node will default to info.</dd>
|
||||
<dt>guild
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The guild Object or channel id for creating, obtaining and deleting events.</dd>
|
||||
<dt>event
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The event Object or channel id for obtaining and deleting events.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">Object</span>
|
||||
<dt>
|
||||
<dd>The event that was created, obtained, or deleted. In the case of search for all events, payload will be an array of events.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>Node to create, delete scheduled events as well as obtain info about a specific event or all events in a guild.</p>
|
||||
|
||||
<h4>Obtaining event info</h4>
|
||||
<p>When obtaining info an event both <code>msg.event</code> and <code>msg.guild</code> are required. The output will be the raw event data provided by discord JS.<p>
|
||||
|
||||
<h4>Obtaining all events<h4>
|
||||
<p>When obtaining all the events in a guild <code>msg.guild</code> is required. The output will be an array of events provided by discord JS.</p>
|
||||
|
||||
<h4>Deleting events</h4>
|
||||
<p>When deleting an event both <code>msg.event</code> and <code>msg.guild</code> are required.<p>
|
||||
|
||||
|
||||
<h4>Creating events</h4>
|
||||
<p>Creating an event requires many provided fields, namely: <code>msg.event</code>, <code>msg.eventName</code>, <code>msg.eventScheduledStartTime</code>, and <code>msg.eventType</code>.
|
||||
When <code>msg.eventType</code> is set to 'external', then <code>msg.eventLocation</code> must be provided as well as <code>msg.eventScheduledEndTime</code>.
|
||||
When <code>msg.eventType</code> is set to 'voice', then <code>msg.eventChannel</code> must be provided, where the eventChannel is the ID of the corrosponding voice channel
|
||||
|
||||
Both <code>msg.eventScheduledStartTime</code> and <code>msg.eventScheduledEndTime</code> are parsed directly as javascript Date object. The Date object can take miliseconds directly as the date object.
|
||||
<code>msg.reason</code> and <code>msg.description</code> are optional fields.
|
||||
|
||||
<p>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
202
discord/discordEventManager.js
Normal file
202
discord/discordEventManager.js
Normal file
@@ -0,0 +1,202 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
var discordFramework = require('./lib/discordFramework.js');
|
||||
const Flatted = require('flatted');
|
||||
const {
|
||||
GuildScheduledEventEntityType,
|
||||
GuildScheduledEventPrivacyLevel,
|
||||
} = require('discord.js');
|
||||
|
||||
|
||||
function discordEventManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', async function (msg, send, done) {
|
||||
|
||||
const _guildID = config.guild || msg.guild || null;
|
||||
const _eventID = config.event || msg.event || null;
|
||||
const _action = msg.action || "info";
|
||||
|
||||
const _eventName = msg.eventName || null;
|
||||
const _eventScheduledStartTime = msg.scheduledStartTime || null;
|
||||
const _eventScheduledEndTime = msg.scheduledEndTime || null;
|
||||
const _eventEventType = msg.eventType || "external";
|
||||
const _eventChannel = msg.channel || null;
|
||||
const _eventImage = null; //To-do.....
|
||||
const _eventReason = msg.reason || null;
|
||||
const _eventDescription = msg.description || null;
|
||||
const _eventLocation = msg.eventLocation || null;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage, data) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
msg.payload = Flatted.parse(Flatted.stringify(data));
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const infoEvent = async () => {
|
||||
try {
|
||||
let eventManager = await discordFramework.getEventManager(bot, _guildID)
|
||||
|
||||
const eventID = discordFramework.checkIdOrObject(_eventID);
|
||||
|
||||
let event = await eventManager.fetch(eventID)
|
||||
|
||||
setSuccess(`event ${event.id} info obtained`, event);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const getEvents = async () => {
|
||||
try {
|
||||
let eventManager = await discordFramework.getEventManager(bot, _guildID)
|
||||
|
||||
let events = await eventManager.fetch()
|
||||
|
||||
setSuccess(`events [${events.size}] obtained`, events);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const deleteEvent = async () => {
|
||||
try {
|
||||
let eventManager = await discordFramework.getEventManager(bot, _guildID)
|
||||
|
||||
const eventID = discordFramework.checkIdOrObject(_eventID);
|
||||
|
||||
let event = await eventManager.fetch(eventID)
|
||||
let deleted = await eventManager.delete(event)
|
||||
|
||||
setSuccess(`event ${event.id} deleted`, deleted);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const createEvent = async () => {
|
||||
|
||||
try {
|
||||
|
||||
let eventManager = await discordFramework.getEventManager(bot, _guildID)
|
||||
const eventName = discordFramework.checkIdOrObject(_eventName)
|
||||
const eventChannel = discordFramework.checkIdOrObject(_eventChannel)
|
||||
|
||||
|
||||
if (!eventName) {
|
||||
throw (`msg.eventName wasn't set correctly`);
|
||||
}
|
||||
|
||||
if (_eventScheduledStartTime == null) {
|
||||
throw (`msg.scheduledStartTime wasn't set correctly`);
|
||||
}
|
||||
|
||||
if ( _eventEventType == "external" ){
|
||||
|
||||
if ( _eventLocation == null ){
|
||||
|
||||
throw (`msg.eventLocation wasn't set correctly, is required when event type is set to external`);
|
||||
|
||||
}
|
||||
|
||||
if ( _eventScheduledEndTime == null ){
|
||||
|
||||
throw (`msg.eventScheduledEndTime wasn't set correctly, is required when event type is set to external`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if ( _eventEventType == "voice" ){
|
||||
|
||||
if ( !eventChannel ){
|
||||
|
||||
throw (`msg.channel wasn't set correctly, is required when event type is set to voice`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
throw (`msg.eventType wasn't set correctly, ${_eventEventType} is not a valid event type`)
|
||||
|
||||
}
|
||||
|
||||
const eventMetadata = {
|
||||
location: _eventLocation
|
||||
};
|
||||
|
||||
eventScheduledEndTime = new Date(_eventScheduledEndTime) || null
|
||||
|
||||
let event = await eventManager.create({
|
||||
name: eventName,
|
||||
scheduledStartTime: new Date(_eventScheduledStartTime),
|
||||
scheduledEndTime: new Date(eventScheduledEndTime),
|
||||
privacyLevel: GuildScheduledEventPrivacyLevel.GuildOnly,
|
||||
entityType: _eventEventType == "voice" ? GuildScheduledEventEntityType.Voice : GuildScheduledEventEntityType.External,
|
||||
description: _eventDescription,
|
||||
channel: _eventChannel,
|
||||
image: null,
|
||||
reason: _eventReason,
|
||||
entityMetadata: eventMetadata
|
||||
});
|
||||
|
||||
setSuccess(`event ${event.id} created`, event);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch (_action.toLowerCase()) {
|
||||
case 'info':
|
||||
await infoEvent();
|
||||
break;
|
||||
case 'all':
|
||||
await getEvents();
|
||||
break;
|
||||
case 'create':
|
||||
await createEvent();
|
||||
break;
|
||||
case 'delete':
|
||||
await deleteEvent();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordEventManager", discordEventManager);
|
||||
};
|
||||
75
discord/discordGuildManager.html
Normal file
75
discord/discordGuildManager.html
Normal file
@@ -0,0 +1,75 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordGuildManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
guild: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordGuildManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordGuildManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-guild"><i class="icon-tag"></i> Guild</label>
|
||||
<input type="text" id="node-input-guild" name="guild" placeholder="Guild ID">
|
||||
<p>(leave 'guild' blank to use <code>msg.guild</code> as guild ID to send to)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordGuildManager">
|
||||
<p>Node to retrieve info from a guild, as well as an action to rename the guild.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The action to do, can be: name, info. If not set, node will default to info.</dd>
|
||||
<dt>guild
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The guild object or ID.</dd>
|
||||
<dt>name
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The new name of the guild if performing the name operation.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">Object</span>
|
||||
<dt>
|
||||
<dd>The guild object containing all of the information listed in discord JS guild class</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node provides information on a given guild, it can also rename the guild.<p>
|
||||
|
||||
<h4>Renaming the guild<h4>
|
||||
<p>To rename the guild you must set <code>msg.name</code> as the name you desire to set the guild to as a string.</p>
|
||||
</script>
|
||||
124
discord/discordGuildManager.js
Normal file
124
discord/discordGuildManager.js
Normal file
@@ -0,0 +1,124 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('node-red-contrib-discord-advanced/discord/lib/discordBotManager.js');
|
||||
var messagesFormatter = require('node-red-contrib-discord-advanced/discord/lib/messagesFormatter.js');
|
||||
const Flatted = require('flatted');
|
||||
const {
|
||||
ChannelType
|
||||
} = require('discord.js');
|
||||
|
||||
const checkString = (field) => typeof field === 'string' ? field : false;
|
||||
|
||||
function discordMessageManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', async function (msg, send, done) {
|
||||
const _guild = config.guild || msg.guild || null;
|
||||
const _action = msg.action || 'info';
|
||||
|
||||
const _name = msg.name || null;
|
||||
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage, data) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
msg.payload = Flatted.parse(Flatted.stringify(data));
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
|
||||
const checkIdOrObject = (check) => {
|
||||
try {
|
||||
if (typeof check !== 'string') {
|
||||
if (check.hasOwnProperty('id')) {
|
||||
return check.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return check;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const getGuild = async (id) => {
|
||||
const guildId = checkIdOrObject(id);
|
||||
if (!guildId) {
|
||||
throw (`msg.guild wasn't set correctly`);
|
||||
}
|
||||
return await bot.guilds.fetch(guildId);
|
||||
}
|
||||
|
||||
|
||||
const infoGuild = async () => {
|
||||
try {
|
||||
let guild = await getGuild(_guild)
|
||||
setSuccess(`guild ${_guild} info obtained`, guild);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const setGuildName = async () => {
|
||||
|
||||
let guild = await getGuild(_guild)
|
||||
let name = checkIdOrObject(_name)
|
||||
|
||||
if (!name) {
|
||||
setError(`msg.name wasn't set correctly`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
guild.setName(name).then(updated => setSuccess(`Updated guild name to ${updated.name}`,updated) )
|
||||
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (_action.toLowerCase()) {
|
||||
case 'info':
|
||||
await infoGuild();
|
||||
break;
|
||||
case 'name':
|
||||
await setGuildName();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordGuildManager", discordMessageManager);
|
||||
};
|
||||
181
discord/discordInteraction.html
Normal file
181
discord/discordInteraction.html
Normal file
@@ -0,0 +1,181 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordInteraction', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
},
|
||||
interactionType: {
|
||||
value: "all",
|
||||
required: false
|
||||
},
|
||||
custom_id: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
commandResponse: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
interactionObject: {
|
||||
value: false,
|
||||
required: false
|
||||
},
|
||||
ephemeral: {
|
||||
value: false,
|
||||
required: false
|
||||
},
|
||||
responseType: {
|
||||
value: "update",
|
||||
required: false
|
||||
},
|
||||
commandResponseType: {
|
||||
value: "defersReply",
|
||||
required: false
|
||||
},
|
||||
},
|
||||
inputs: 0,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
oneditprepare: () => {
|
||||
$("#node-input-interactionType").typedInput({
|
||||
types: [
|
||||
{
|
||||
value: "all",
|
||||
options: [
|
||||
{ value: "all", label: "All" },
|
||||
{ value: "button", label: "Button" },
|
||||
{ value: "command", label: "Command" },
|
||||
{ value: "selectMenu", label: "Select Menu" },
|
||||
{ value: "autoComplete", label: "Autocomplete" },
|
||||
{ value: "modalSubmit", label: "Modal Submit" },
|
||||
{ value: "messageContextMenu", label: "Message Context Menu" }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
$("#node-input-responseType").typedInput({
|
||||
types: [
|
||||
{
|
||||
value: "update",
|
||||
options: [
|
||||
{ value: "update", label: "Update Interaction" },
|
||||
{ value: "reply", label: "Reply Interaction" }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
$("#node-input-commandResponseType").typedInput({
|
||||
types: [
|
||||
{
|
||||
value: "defersReply",
|
||||
options: [
|
||||
{ value: "defersReply", label: "Defers Reply" },
|
||||
{ value: "nothing", label: "Do nothing" }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
$("#node-input-interactionType").change(function () {
|
||||
if ($("#node-input-interactionType").val() == "command" || $("#node-input-interactionType").val() == "messageContextMenu") {
|
||||
$("#node-input-custom_id-lbl").text("Command names");
|
||||
$("#node-row-responseType").prop("style", "display:none;");
|
||||
if ($("#node-input-interactionType").val() == "command")
|
||||
{
|
||||
$("#node-row-ephemeral").prop("style", "");
|
||||
$("#node-row-commandResponseType").prop("style", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#node-row-ephemeral").prop("style", "display:none;");
|
||||
$("#node-row-commandResponseType").prop("style", "display:none;");
|
||||
}
|
||||
}
|
||||
else if ($("#node-input-interactionType").val() == "autoComplete" ||
|
||||
$("#node-input-interactionType").val() == "modalSubmit"){
|
||||
$("#node-row-responseType").prop("style", "display:none;");
|
||||
}
|
||||
else{
|
||||
$("#node-input-custom_id-lbl").text("Custom Ids");
|
||||
$("#node-row-ephemeral").prop("style", "display:none;");
|
||||
$("#node-row-responseType").prop("style", "");
|
||||
}
|
||||
});
|
||||
},
|
||||
label: function () {
|
||||
return this.name || "discordInteraction";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordInteraction">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-interactionType"><i class="icon-tag"></i> Interaction type</label>
|
||||
<input type="text" id="node-input-interactionType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-custom_id" id="node-input-custom_id-lbl"><i class="icon-tag"></i> Custom Id</label>
|
||||
<input type="text" id="node-input-custom_id" placeholder="customid1,customid2,etc">
|
||||
<p>(leave blank to not filter by custom_id/commandName, or separated by ',' for more than one custom_id/commandName)</p>
|
||||
</div>
|
||||
<div class="form-row" id="node-row-ephemeral" style="display:none;">
|
||||
<input type="checkbox" id="node-input-ephemeral" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-ephemeral" style="width: 70%;"> Ephemeral</label>
|
||||
</div>
|
||||
<div class="form-row" id="node-row-responseType" style="display:none;">
|
||||
<label for="node-input-responseType"><i class="icon-tag"></i> Response type</label>
|
||||
<input type="text" id="node-input-responseType">
|
||||
</div>
|
||||
<div class="form-row" id="node-row-commandResponseType" style="display:none;">
|
||||
<label for="node-input-commandResponseType"><i class="icon-tag"></i> Response type</label>
|
||||
<input type="text" id="node-input-commandResponseType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-interactionObject" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-interactionObject" style="width: 70%;"> Inject interaction object</label>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordInteraction">
|
||||
<p>Node to recieve discord interactions</p>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing general info of the interaction</dd>
|
||||
<dt>payload.user <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing info of discord interaction user</dd>
|
||||
<dt>payload.member <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing info of the guild member, user related</dd>
|
||||
<dt>payload.message <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing info of the original message</dd>
|
||||
<dt>payload.options <span class="property-type">Array</span></dt>
|
||||
<dd>an Object containing info about the selected options in the command</dd>
|
||||
<dt>interactionObject<span class="property-type">Object</span></dt>
|
||||
<dd>an Original Interaction Object</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>Triggers whenever a interaction was created on Discord.</p>
|
||||
<p><code>msg.payload</code> will be set to the interaction info</p>
|
||||
<p><code>msg.payload.user</code> will be set to an Object containing info on the <a href="https://discord.js.org/#/docs/main/stable/class/User" target="_blank">user</a> that sent the interaction (does not contain any discord.js functions)</p>
|
||||
<p><code>msg.payload.member</code> will be set to an Object containing info on the <a href="https://discord.js.org/#/docs/discord.js/stable/class/GuildMember" target="_blank">guildmember</a> that sent the interaction, guild related data (does not contain any discord.js functions)</p>
|
||||
<p><code>msg.payload.message</code> will be set to the original message when type of interaction is Button or MenuSelected</p>
|
||||
<p><code>msg.payload.options</code> will be set to an Array containing the options selected on a Slash Command</p>
|
||||
<p><code>msg.interactionObject</code> will be set to the original interaction object, only when option in the editor is checked.</p>
|
||||
</script>
|
||||
158
discord/discordInteraction.js
Normal file
158
discord/discordInteraction.js
Normal file
@@ -0,0 +1,158 @@
|
||||
const Flatted = require('flatted');
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
var discordInterationManager = require('./lib/interactionManager.js');
|
||||
|
||||
function discordInteraction(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
let interactionType = config.interactionType || "all";
|
||||
let custom_id = config.custom_id;
|
||||
let injectInteractionObject = config.interactionObject || false;
|
||||
let ephemeral = config.ephemeral || false;
|
||||
let responseType = config.responseType || "update";
|
||||
let commandResponseType = config.commandResponseType || "defersReply";
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
var callbacks = [];
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "ready"
|
||||
});
|
||||
|
||||
const matchInteractionType = (interaction) => {
|
||||
switch (interactionType) {
|
||||
case "button":
|
||||
return interaction.isButton();
|
||||
case "selectMenu":
|
||||
return interaction.isStringSelectMenu();
|
||||
case "command":
|
||||
return interaction.isCommand();
|
||||
case "messageContextMenu":
|
||||
return interaction.isMessageContextMenuCommand();
|
||||
case "autoComplete":
|
||||
return interaction.isAutocomplete();
|
||||
case "modalSubmit":
|
||||
return interaction.isModalSubmit();
|
||||
case "all":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var registerCallback = function (eventName, listener) {
|
||||
callbacks.push({
|
||||
'eventName': eventName,
|
||||
'listener': listener
|
||||
});
|
||||
bot.on(eventName, listener);
|
||||
}
|
||||
|
||||
registerCallback("interactionCreate", async interaction => {
|
||||
try {
|
||||
if (!matchInteractionType(interaction)) return;
|
||||
discordInterationManager.registerInteraction(interaction);
|
||||
|
||||
// -- Processing ways to handle interactions for each type --
|
||||
|
||||
if (interaction.isCommand() || interaction.isMessageContextMenuCommand()) {
|
||||
if (custom_id && custom_id.split(",").indexOf(interaction.commandName) < 0) return;
|
||||
|
||||
if(commandResponseType == "defersReply")
|
||||
{
|
||||
await interaction.deferReply({ephemeral: ephemeral});
|
||||
}
|
||||
}
|
||||
else if(interaction.isModalSubmit())
|
||||
{
|
||||
if (custom_id && custom_id.split(",").indexOf(interaction.customId) < 0) return;
|
||||
|
||||
await interaction.deferReply();
|
||||
}
|
||||
else if(interaction.isAutocomplete())
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else {
|
||||
if (custom_id && custom_id.split(",").indexOf(interaction.customId) < 0) return;
|
||||
if(responseType == "update")
|
||||
await interaction.deferUpdate();
|
||||
else
|
||||
await interaction.deferReply();
|
||||
}
|
||||
|
||||
|
||||
// -- Building response for each type --
|
||||
|
||||
let message = {};
|
||||
message.payload = Flatted.parse(Flatted.stringify(interaction));
|
||||
message.payload.user = Flatted.parse(Flatted.stringify(interaction.user));
|
||||
|
||||
if(interaction.member !== null) {
|
||||
message.payload.member = Flatted.parse(Flatted.stringify(interaction.member));
|
||||
message.payload.member.guild = Flatted.parse(Flatted.stringify(interaction.member.guild));
|
||||
}
|
||||
else {
|
||||
message.payload.member = null;
|
||||
}
|
||||
|
||||
if (injectInteractionObject)
|
||||
message.interactionObject = interaction;
|
||||
|
||||
if (interaction.isCommand() || interaction.isMessageContextMenuCommand()) {
|
||||
message.payload.options = Flatted.parse(Flatted.stringify(interaction.options));
|
||||
}
|
||||
else if(interaction.isAutocomplete())
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else if(interaction.isModalSubmit())
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else {
|
||||
message.payload.message = Flatted.parse(Flatted.stringify(interaction.message));
|
||||
message.payload.message.author = Flatted.parse(Flatted.stringify(interaction.message.author));
|
||||
}
|
||||
|
||||
node.send(message);
|
||||
} catch (error) {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
registerCallback('error', err => {
|
||||
node.error(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
callbacks.forEach(function (cb) {
|
||||
bot.removeListener(cb.eventName, cb.listener);
|
||||
});
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
|
||||
}).catch(function (err) {
|
||||
node.error(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: "wrong token?"
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordInteraction", discordInteraction);
|
||||
};
|
||||
53
discord/discordInteractionManager.html
Normal file
53
discord/discordInteractionManager.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordInteractionManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: { value: "", required: false },
|
||||
token: { value: "", required: true, type: "discord-token" }
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordInteractionManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordInteractionManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordInteractionManager">
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action<span class="property-type">string</span></dt>
|
||||
<dd>The action you wish to perform. When not set edit is default.</dd>
|
||||
|
||||
<dt>interactionId<span class="property-type">number</span></dt>
|
||||
<dd>Interaction identificator number.</dd>
|
||||
|
||||
<dt>payload<span class="property-type">string</span></dt>
|
||||
<dd>The string you wish to send or the new content of a message when editing.</dd>
|
||||
|
||||
<dt>embeds<span class="property-type">Object/Array</span></dt>
|
||||
<dd>An embed object or an array of embed objects.</dd>
|
||||
|
||||
<dt>attachments<span class="property-type">String/Object/Array</span></dt>
|
||||
<dd>A location to an attachment. Can be online by URL, an object with a buffer payload or a file in the local filesystem.</dd>
|
||||
|
||||
<dt>autoCompleteChoices<span class="property-type">Array</span></dt>
|
||||
<dd>Optional. In autocomplete interactions, the filtered or non-filtered options to respond.</dd>
|
||||
|
||||
<dt>components<span class="property-type">Array</span></dt>
|
||||
<dd>An array of component objects.</dd>
|
||||
</dl>
|
||||
|
||||
</script>
|
||||
175
discord/discordInteractionManager.js
Normal file
175
discord/discordInteractionManager.js
Normal file
@@ -0,0 +1,175 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
var discordInterationManager = require('./lib/interactionManager.js');
|
||||
var messagesFormatter = require('./lib/messagesFormatter.js');
|
||||
const { ModalBuilder } = require('discord.js');
|
||||
const Flatted = require('flatted');
|
||||
|
||||
const checkString = (field) => typeof field === 'string' ? field : false;
|
||||
|
||||
function discordInteractionManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', async (msg) => {
|
||||
try {
|
||||
const content = msg.payload?.content || checkString(msg.payload) || ' ';
|
||||
const inputEmbeds = msg.payload?.embeds || msg.payload?.embed || msg.embeds || msg.embed;
|
||||
const inputAttachments = msg.payload?.attachments || msg.payload?.attachment || msg.attachments || msg.attachment;
|
||||
const inputComponents = msg.payload?.components || msg.components;
|
||||
const interactionId = msg.interactionId;
|
||||
const action = msg.action || 'edit';
|
||||
const autoCompleteChoices = msg.autoCompleteChoices || [];
|
||||
const customId = msg.customId;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
node.error(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage, data) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
msg.payload = Flatted.parse(Flatted.stringify(data));
|
||||
node.send(msg);
|
||||
}
|
||||
|
||||
const editInteractionReply = async () => {
|
||||
await interaction.editReply({
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
});
|
||||
|
||||
const newMsg = {
|
||||
interaction: Flatted.parse(Flatted.stringify(interaction))
|
||||
};
|
||||
|
||||
|
||||
setSuccess(`interaction ${interactionId} edited`, newMsg);
|
||||
}
|
||||
|
||||
const replyInteraction = async () => {
|
||||
await interaction.reply({
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
});
|
||||
|
||||
const newMsg = {
|
||||
interaction: Flatted.parse(Flatted.stringify(interaction))
|
||||
};
|
||||
|
||||
setSuccess(`interaction ${interactionId} replied`, newMsg);
|
||||
}
|
||||
|
||||
const showModal = async () => {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId(customId || 'myModal')
|
||||
.setTitle(content || 'Modal');
|
||||
|
||||
console.log(`Modal ${customId}`);
|
||||
|
||||
modal.addComponents(components);
|
||||
interaction.showModal(modal);
|
||||
|
||||
const newMsg = {
|
||||
interaction: Flatted.parse(Flatted.stringify(interaction))
|
||||
};
|
||||
|
||||
setSuccess(`interaction ${interactionId} modal showed`, newMsg);
|
||||
}
|
||||
|
||||
const respondAutocomplete = async () => {
|
||||
if (!interaction.isAutocomplete()) {
|
||||
setError("Error: not autocomplete Interaction");
|
||||
return;
|
||||
}
|
||||
|
||||
const focusedValue = interaction.options.getFocused();
|
||||
console.log(`Search ${focusedValue}`);
|
||||
const filtered = autoCompleteChoices.filter(choice => choice.startsWith(focusedValue));
|
||||
|
||||
await interaction.respond(filtered.map(choice => ({ name: choice, value: choice })));
|
||||
|
||||
const newMsg = {
|
||||
interaction: Flatted.parse(Flatted.stringify(interaction))
|
||||
};
|
||||
|
||||
|
||||
setSuccess(`interaction ${interactionId} filtered`, newMsg);
|
||||
}
|
||||
|
||||
let interaction = await discordInterationManager.getInteraction(interactionId);
|
||||
|
||||
let attachments, embeds, components;
|
||||
try {
|
||||
attachments = messagesFormatter.formatAttachments(inputAttachments);
|
||||
embeds = messagesFormatter.formatEmbeds(inputEmbeds);
|
||||
components = inputComponents;
|
||||
} catch (error) {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action.toLowerCase()) {
|
||||
case 'reply':
|
||||
await replyInteraction();
|
||||
break;
|
||||
case 'edit':
|
||||
await editInteractionReply();
|
||||
break;
|
||||
case 'showmodal':
|
||||
await showModal();
|
||||
break;
|
||||
case 'respondautocomplete':
|
||||
await respondAutocomplete();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("discordInteractionManager", discordInteractionManager);
|
||||
};
|
||||
42
discord/discordMember.html
Normal file
42
discord/discordMember.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordMember',{
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {value: "", required: false},
|
||||
token: {value: "", required: true, type: "discord-token"}
|
||||
|
||||
},
|
||||
inputs: 0,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function() {
|
||||
return this.name||"discordMember";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordMember">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordMember">
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
non </dl>
|
||||
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
Alle Mammber Information On Join And Leave event
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
51
discord/discordMember.js
Normal file
51
discord/discordMember.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const Flatted = require('flatted');
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
|
||||
function discordMember(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
var callbacks = [];
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "ready"
|
||||
});
|
||||
|
||||
var registerCallback = function (eventName, listener) {
|
||||
callbacks.push({
|
||||
'eventName': eventName,
|
||||
'listener': listener
|
||||
});
|
||||
bot.on(eventName, listener);
|
||||
};
|
||||
|
||||
registerCallback('guildMemberAdd', message => {
|
||||
var msgid = RED.util.generateId();
|
||||
var msg = {
|
||||
_msgid: msgid
|
||||
}
|
||||
msg.payload = Flatted.parse(Flatted.stringify(message));
|
||||
msg.payload.event = "guildMemberAdd";
|
||||
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
registerCallback('guildMemberRemove', message => {
|
||||
var msgid = RED.util.generateId();
|
||||
var msg = {
|
||||
_msgid: msgid
|
||||
}
|
||||
msg.payload = Flatted.parse(Flatted.stringify(message));
|
||||
msg.payload.event = "guildMemberRemove";
|
||||
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
RED.nodes.registerType("discordMember", discordMember);
|
||||
};
|
||||
69
discord/discordMessage.html
Normal file
69
discord/discordMessage.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordMessage', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
channelIdFilter: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 0,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordMessage";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordMessage">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-channelIdFilter"><i class="icon-tag"></i> Channel Filter</label>
|
||||
<input type="text" id="node-input-channelIdFilter" placeholder="Channel Id Filter">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordMessage">
|
||||
<p>Node to recieve discord messages</p>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload <span class="property-type">string</span></dt>
|
||||
<dd>the textual content of the message</dd>
|
||||
<dt>channel <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing info on the channel the message was sent in</dd>
|
||||
<dt>author <span class="property-type">Object</span></dt>
|
||||
<dd>an Object containing info on the author of the message</dd>
|
||||
<dt>memberRoleNames <span class="property-type">Array</span></dt>
|
||||
<dd>an array of all the roles names the author has</dd>
|
||||
<dt>memberRoleIDs <span class="property-type">Array</span></dt>
|
||||
<dd>an array of all the roles IDs the author has</dd>
|
||||
<dt>data <span class="property-type">Object</span></dt>
|
||||
<dd>the full message Object sent by discord</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>Triggers whenever a message was received on Discord.</p>
|
||||
<p><code>msg.payload</code> will be set to the textual content of the message.</p>
|
||||
<p><code>msg.channel</code> will be set to an Object containing info on the <a href="https://discord.js.org/#/docs/main/stable/class/TextChannel" target="_blank">channel</a> the message was received from (does not contain any discord.js functions)</p>
|
||||
<p><code>msg.author</code> will be set to an Object containing info on the <a href="https://discord.js.org/#/docs/main/stable/class/User" target="_blank">user</a> that sent the message (does not contain any discord.js functions)</p>
|
||||
<p><code>msg.memberRoleIDs</code> will be set to an Array of all the ID's of the roles the author has</p>
|
||||
<p><code>msg.memberRoleNames</code> will be set to an Array of all the names of the roles the author has</p>
|
||||
<p><code>msg.data</code> <em>may</em> be set to an Object containing info on the <a href="https://discord.js.org/#/docs/main/stable/class/Message" target="_blank">message</a> that was received, but again without any of the discord.js functions.</p>
|
||||
</script>
|
||||
126
discord/discordMessage.js
Normal file
126
discord/discordMessage.js
Normal file
@@ -0,0 +1,126 @@
|
||||
const Flatted = require('flatted');
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
|
||||
function discordMessage(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var channelFilterList = cleanChannelFilterList(config.channelIdFilter);
|
||||
var node = this;
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
var callbacks = [];
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "ready"
|
||||
});
|
||||
|
||||
var registerCallback = function (eventName, listener) {
|
||||
callbacks.push({
|
||||
'eventName': eventName,
|
||||
'listener': listener
|
||||
});
|
||||
bot.on(eventName, listener);
|
||||
}
|
||||
|
||||
registerCallback('messageCreate', message => {
|
||||
if (message.author !== bot.user) {
|
||||
var msgid = RED.util.generateId();
|
||||
var msg = {
|
||||
_msgid: msgid
|
||||
}
|
||||
msg.payload = message.content;
|
||||
msg.channel = Flatted.parse(Flatted.stringify(message.channel));
|
||||
msg.member = Flatted.parse(Flatted.stringify(message.member));
|
||||
msg.memberRoleNames = message.member ? message.member.roles.cache.each(function (item) {
|
||||
return item.name
|
||||
}) : null;
|
||||
msg.memberRoleIDs = message.member ? message.member.roles.cache.each(function (item) {
|
||||
return item.id
|
||||
}) : null;
|
||||
|
||||
try {
|
||||
msg.data = Flatted.parse(Flatted.stringify(message));
|
||||
msg.data.attachments = Flatted.parse(Flatted.stringify(message.attachments));
|
||||
msg.data.reference = message.reference;
|
||||
} catch (e) {
|
||||
node.warn("Could not set `msg.data`: JSON serialization failed");
|
||||
}
|
||||
|
||||
if (channelFilterList && !channelFilterList.includes(msg.channel.id)){
|
||||
return;
|
||||
} else if (message.author.bot) {
|
||||
msg.author = {
|
||||
id: message.author.id,
|
||||
bot: message.author.bot,
|
||||
system: message.author.system,
|
||||
flags: message.author.flags,
|
||||
username: message.author.bot,
|
||||
discriminator: message.author.discriminator,
|
||||
avatar: message.author.avatar,
|
||||
createdTimestamp: message.author.createdTimestamp,
|
||||
tag: message.author.tag,
|
||||
}
|
||||
node.send(msg);
|
||||
} else {
|
||||
message.author.fetch(true).then(author => {
|
||||
msg.author = Flatted.parse(Flatted.stringify(author));
|
||||
node.send(msg);
|
||||
}).catch(error => {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerCallback('error', error => {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
});
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
callbacks.forEach(function (cb) {
|
||||
bot.removeListener(cb.eventName, cb.listener);
|
||||
});
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
|
||||
}).catch(function (err) {
|
||||
node.error(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordMessage", discordMessage);
|
||||
};
|
||||
|
||||
function cleanChannelFilterList(channelFilterList)
|
||||
{
|
||||
if (!channelFilterList)
|
||||
return;
|
||||
|
||||
var cleanedChannelFilterList = null;
|
||||
if (channelFilterList.startsWith(',') && channelFilterList.endsWith(','))
|
||||
{
|
||||
cleanedChannelFilterList = channelFilterList.slice(1, -1);
|
||||
} else if (channelFilterList.startsWith(',')) {
|
||||
cleanedChannelFilterList = channelFilterList.slice(1);
|
||||
} else if (channelFilterList.endsWith(',')) {
|
||||
cleanedChannelFilterList = channelFilterList.slice(0, -1);
|
||||
} else {
|
||||
cleanedChannelFilterList = channelFilterList;
|
||||
}
|
||||
return cleanedChannelFilterList.split(',');
|
||||
}
|
||||
132
discord/discordMessageManager.html
Normal file
132
discord/discordMessageManager.html
Normal file
@@ -0,0 +1,132 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordMessageManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
channel: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordMessageManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordMessageManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-channel"><i class="icon-tag"></i> Channel</label>
|
||||
<input type="text" id="node-input-channel" name="ch" placeholder="Channel ID">
|
||||
<p>(leave 'channel' blank to use <code>msg.channel</code> as channel ID to send to)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordMessageManager">
|
||||
<p>Node to send, edit, reply, react, crosspost, obtain info, search, or delete messages in Discord</p>
|
||||
<p>More support can be found <a href="https://github.com/Markoudstaal/node-red-contrib-discord-advanced/wiki/discordMessageManager">here</a>.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The text content for the message.</dd>
|
||||
<dt>action
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The action to do, can be: create, edit, delete, reply, react, crosspost, search, or info. If not set, node will default to create.</dd>
|
||||
<dt>channel
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The channel Object or channel id for creating, editing and deleting messages.</dd>
|
||||
<dt>user
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The user Object or id if you want to send a private message.</dd>
|
||||
<dt>message
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The message Object or id of the message that should be edited or deleted, if this is desired</dd>
|
||||
<dt>embeds
|
||||
<span class="property-type">Object or Array</span>
|
||||
</dt>
|
||||
<dd>Either an array of, or an Embed Object.</dd>
|
||||
<dt>components
|
||||
<span class="property-type">Object or Array</span>
|
||||
</dt>
|
||||
<dd>Either an array of, or an Component Object.</dd>
|
||||
<dt class="optional">attachments
|
||||
<span class="property-type">string or Array</span>
|
||||
</dt>
|
||||
<dd>The url or local path to an attachment, or an array of urls.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">Object</span>
|
||||
<dt>
|
||||
<dd>The message that was created, edited or deleted. In the case of a search, payload will be an array of messages.</dd>
|
||||
|
||||
<dt>request
|
||||
<span class="property-type">Object</span>
|
||||
<dt>
|
||||
<dd>The msg object that was input.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node provides a way to send messages to a discord channel or a user. It also allows messages to be edited and deleted. It also returns the Object of the message that was created, edited or deleted.<p>
|
||||
|
||||
<h4>Sending messages to a Discord channel</h4>
|
||||
<p>When sending a message to a channel, both <code>msg.payload</code> and <code>msg.channel</code> are required.<p>
|
||||
|
||||
<h4>Sending private messages<h4>
|
||||
<p>When sending a private message <code>msg.user</code> and <code>msg.payload</code> are required.</p>
|
||||
|
||||
<h4>Sending embeds<h4>
|
||||
<p>To send an embed message you'll have to set <code>msg.embeds</code> as either an Embed Object or an Array of Embed Objects.
|
||||
How the embed object can be created and what options it has can be found <a href="https://v12.discordjs.guide/popular-topics/embeds.html#using-an-embed-object">here</a>.</p>
|
||||
|
||||
<h4>Editing messages</h4>
|
||||
<p>Editing messages is only possible in channels. Set <code>msg.action</code> to 'edit'. Also <code>msg.channel</code>, <code>msg.message</code> and <code>msg.payload</code> are required.<p>
|
||||
|
||||
<h4>Editing embeds</h4>
|
||||
<p>To edit an embed message or turn a regular message into an embed message you'll have to do the same actions as with editing normal messages.
|
||||
However, <code>msg.embed</code> needs to be either an Embed Object or an Array of Embed Objects. </p>
|
||||
|
||||
<h4>Deleting messages</h4>
|
||||
<p>To delete messages set <code>msg.action</code> to 'delete'. Also <code>msg.channel</code> and <code>msg.message</code> are required.</p>
|
||||
|
||||
<h4>Obtaining messages</h4>
|
||||
<p>To obtain a message object given its message ID set <code>msg.action</code> to 'info'. Also <code>msg.channel</code> and <code>msg.message</code> are required. The node will then return the message if it exists.</p>
|
||||
|
||||
<h4>Searching messages</h4>
|
||||
<p>It is possible to search for messages given a channel. To search for messages set <code>msg.action</code> to 'search'. It will retrieve the last 64 messages unless overriden by <code>msg.searchLimit</code>. The search can also be filtered setting <code>msg.author</code>. Note that the search limit is applied before the filtering, e.g. in the default scenario it will not search for the last 64 messages by the user, but rather the last 64 messages and return an array containing the messages by the author.</p>
|
||||
|
||||
|
||||
<h4>Attachments</h4>
|
||||
<p>It's possible to add an attachment by url but this node does not check if that url is valid. Discord might bounce invalid urls. This doesn't work for editing messages.</p>
|
||||
|
||||
<h4>Sending components<h4>
|
||||
<p>To send an component you'll have to set <code>msg.components</code> as an Array of Component Objects.
|
||||
How the component object can be created and what options it has can be found <a href="https://discord.com/developers/docs/interactions/message-components">here</a>.</p>
|
||||
</script>
|
||||
288
discord/discordMessageManager.js
Normal file
288
discord/discordMessageManager.js
Normal file
@@ -0,0 +1,288 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
var messagesFormatter = require('./lib/messagesFormatter.js');
|
||||
var discordFramework = require('./lib/discordFramework.js');
|
||||
const Flatted = require('flatted');
|
||||
const {
|
||||
ChannelType
|
||||
} = require('discord.js');
|
||||
|
||||
const checkString = (field) => typeof field === 'string' ? field : false;
|
||||
|
||||
function discordMessageManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', async function (msg, send, done) {
|
||||
const channel = config.channel || msg.channel || null;
|
||||
const action = msg.action || 'create';
|
||||
const user = msg.user || null;
|
||||
const content = msg.payload?.content || checkString(msg.payload) || ' ';
|
||||
const messageId = msg.message || null;
|
||||
const inputEmbeds = msg.payload?.embeds || msg.payload?.embed || msg.embeds || msg.embed;
|
||||
const inputAttachments = msg.payload?.attachments || msg.payload?.attachment || msg.attachments || msg.attachment;
|
||||
const inputComponents = msg.payload?.components || msg.components;
|
||||
const crosspost = msg.crosspost || false;
|
||||
const _author = msg.author || false;
|
||||
const _searchLimit = msg.searchLimit || 64;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage, data) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
msg.payload = Flatted.parse(Flatted.stringify(data));
|
||||
send(msg);
|
||||
done();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const createPrivateMessage = async () => {
|
||||
const userID = discordFramework.checkIdOrObject(user);
|
||||
if (!userID) {
|
||||
setError(`msg.user wasn't set correctly`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let user = await bot.users.fetch(userID);
|
||||
let messageObject = {
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
};
|
||||
let resultMessage = await user.send(messageObject);
|
||||
setSuccess(`message sent to ${resultMessage.channel.recipient.username}`, resultMessage);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const createChannelMessage = async () => {
|
||||
try {
|
||||
let channelInstance = await discordFramework.getChannel(bot, channel);
|
||||
let messageObject = {
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
};
|
||||
let resultMessage = await channelInstance.send(messageObject);
|
||||
let resultCrossPosting = "";
|
||||
|
||||
if(crosspost)
|
||||
{
|
||||
if (resultMessage.channel.type === ChannelType.GuildAnnouncement)
|
||||
await resultMessage.crosspost();
|
||||
else
|
||||
resultCrossPosting = "Not published";
|
||||
}
|
||||
|
||||
setSuccess(`message sent, id = ${resultMessage.id} ${resultCrossPosting}`, resultMessage);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const createMessage = async () => {
|
||||
if (user) {
|
||||
await createPrivateMessage();
|
||||
} else if (channel) {
|
||||
await createChannelMessage();
|
||||
} else {
|
||||
setError('to send messages either msg.channel or msg.user needs to be set');
|
||||
}
|
||||
}
|
||||
|
||||
const editMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId)
|
||||
let messageObject = {
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
};
|
||||
message = await message.edit(messageObject);
|
||||
setSuccess(`message ${message.id} edited`, message);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const infoMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId)
|
||||
setSuccess(`message ${message.id} info obtained`, message);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const searchMessages = async () => {
|
||||
try {
|
||||
|
||||
//Lets see if the author ID was provided, if not get all messages in a channel
|
||||
const author = discordFramework.checkIdOrObject(_author);
|
||||
let channelInstance = await bot.channels.fetch(channel);
|
||||
|
||||
if (!author) {
|
||||
|
||||
channelInstance.messages.fetch({ limit: _searchLimit }).then(messages => {
|
||||
|
||||
setSuccess(`messages (n=${messages.length}) obtained`, messages);
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
channelInstance.messages.fetch({ limit: _searchLimit }).then(messages => {
|
||||
|
||||
let array = Array.from(messages, ([name, value]) => ({ name, value }));
|
||||
let authorMessages = array.filter(msg => msg.value.author.id === author);
|
||||
authorMessages = authorMessages.map(function(obj) {
|
||||
return obj.value;
|
||||
});
|
||||
|
||||
setSuccess(`Messages (n=${authorMessages.length}) obtained`, authorMessages);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId);
|
||||
let resultMessage = await message.delete();
|
||||
setSuccess(`message ${resultMessage.id} deleted`, resultMessage);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const replyMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId)
|
||||
let messageObject = {
|
||||
embeds: embeds,
|
||||
content: content,
|
||||
files: attachments,
|
||||
components: components
|
||||
};
|
||||
message = await message.reply(messageObject);
|
||||
setSuccess(`message ${message.id} replied`, message);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const reactToMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId);
|
||||
const emoji = message.guild.emojis.cache.find(emoji => emoji.name === content);
|
||||
let reaction = await message.react(emoji || content);
|
||||
const newMsg = {
|
||||
emoji: reaction._emoji.name,
|
||||
animated: reaction.emoji.animated,
|
||||
count: reaction.count,
|
||||
message: Flatted.parse(Flatted.stringify(message))
|
||||
};
|
||||
|
||||
setSuccess(`message ${message.id} reacted`, newMsg);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
const crosspostMessage = async () => {
|
||||
try {
|
||||
let message = await discordFramework.getMessage(bot, channel, messageId);
|
||||
if (message.channel.type === ChannelType.GuildAnnouncement)
|
||||
await message.crosspost();
|
||||
else
|
||||
throw "It's not a Announcement channel";
|
||||
|
||||
const newMsg = {
|
||||
message: Flatted.parse(Flatted.stringify(message))
|
||||
};
|
||||
|
||||
setSuccess(`message ${message.id} crossposted`, newMsg);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
|
||||
let attachments, embeds, components;
|
||||
try {
|
||||
attachments = messagesFormatter.formatAttachments(inputAttachments);
|
||||
embeds = messagesFormatter.formatEmbeds(inputEmbeds);
|
||||
components = messagesFormatter.formatComponents(inputComponents);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action.toLowerCase()) {
|
||||
case 'create':
|
||||
await createMessage();
|
||||
break;
|
||||
case 'edit':
|
||||
await editMessage();
|
||||
break;
|
||||
case 'delete':
|
||||
await deleteMessage();
|
||||
break;
|
||||
case 'reply':
|
||||
await replyMessage();
|
||||
break;
|
||||
case 'react':
|
||||
await reactToMessage();
|
||||
break;
|
||||
case 'crosspost':
|
||||
await crosspostMessage();
|
||||
break;
|
||||
case 'info':
|
||||
await infoMessage();
|
||||
break;
|
||||
case 'search':
|
||||
await searchMessages();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordMessageManager", discordMessageManager);
|
||||
};
|
||||
74
discord/discordPermissions.html
Normal file
74
discord/discordPermissions.html
Normal file
@@ -0,0 +1,74 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordPermissions', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordPermissions";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordPermissions">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordPermissions">
|
||||
<p>Node to check user permissions in Discord.</p>
|
||||
<p>More support can be found <a href="https://github.com/Markoudstaal/node-red-contrib-discord-advanced/wiki#support">here</a>.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>action
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The action to do, can be: get, set, remove. If not set, node will default to get.</dd>
|
||||
<dt>user
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The user ID whose roles you want to check.</dd>
|
||||
<dt>role
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The role ID if you set <code>msg.action</code> to set or remove.</dd>
|
||||
<dt>guild
|
||||
<span class="property-type">string</span>
|
||||
<dd>The Guild ID the user is in and where you want to check the roles.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">Array</span>
|
||||
</dt>
|
||||
<dd>The payload contains an array with all roles the user has in the specified guild.</dd>
|
||||
<dt>user
|
||||
<span class="property-type">Object</span>
|
||||
</dt>
|
||||
<dd>The full user Object of the user that was specified.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node is able to output all roles a user has in a specific guild. Additionally it can add (set) and remove singular roles from a user in a specific guild.<p>
|
||||
<p>To get the roles a user has in a guild send <code>msg.user</code> and <code>msg.guild</code> and it will return the roles the user has.</p>
|
||||
<p>To remove a role send <code>msg.user</code>, <code>msg.guild</code>, <code>msg.action = "remove"</code> and <code>msg.role</code>. It will remove the role the user has.</p>
|
||||
<p>To add a role send <code>msg.user</code>, <code>msg.guild</code>, <code>msg.action = "set"</code> and <code>msg.role</code>. It add the role to the user.</p>
|
||||
</script>
|
||||
158
discord/discordPermissions.js
Normal file
158
discord/discordPermissions.js
Normal file
@@ -0,0 +1,158 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
|
||||
function discordPermissions(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.on('input', async function (msg, send, done) {
|
||||
const action = msg.action || 'get';
|
||||
const user = msg.user || null;
|
||||
const guild = msg.guild || null;
|
||||
const role = msg.role || null;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
done();
|
||||
}
|
||||
|
||||
const checkIdOrObject = (check) => {
|
||||
try {
|
||||
if (typeof check !== 'string') {
|
||||
if (check.hasOwnProperty('id')) {
|
||||
return check.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return check;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const sendRoles = async () => {
|
||||
const userID = checkIdOrObject(user);
|
||||
const guildID = checkIdOrObject(guild);
|
||||
|
||||
if (!userID) {
|
||||
setError(`msg.user wasn't set correctly`);
|
||||
} else if (!guildID) {
|
||||
setError(`msg.guild wasn't set correctly`);
|
||||
} else {
|
||||
|
||||
try {
|
||||
const guildObject = await bot.guilds.fetch(guildID);
|
||||
const userObject = await guildObject.members.fetch(userID);
|
||||
|
||||
let roles = [];
|
||||
userObject.roles.cache.each(role => {
|
||||
roles.push(role);
|
||||
});
|
||||
msg.payload = roles;
|
||||
msg.user = userObject;
|
||||
send(msg);
|
||||
setSuccess(`roles sent`);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const setRole = async () => {
|
||||
const userID = checkIdOrObject(user);
|
||||
const guildID = checkIdOrObject(guild);
|
||||
const roleID = checkIdOrObject(role);
|
||||
|
||||
if (!userID) {
|
||||
setError(`msg.user wasn't set correctly`);
|
||||
} else if (!guildID) {
|
||||
setError(`msg.guild wasn't set correctly`);
|
||||
} else if (!roleID) {
|
||||
setError(`msg.role wasn't set correctly`);
|
||||
} else {
|
||||
try {
|
||||
const guildObject = await bot.guilds.fetch(guildID);
|
||||
const userObject = await guildObject.members.fetch(userID);
|
||||
|
||||
await userObject.roles.add(roleID);
|
||||
msg.payload = "role set";
|
||||
send(msg);
|
||||
setSuccess(`role set`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const removeRole = async () => {
|
||||
const userID = checkIdOrObject(user);
|
||||
const guildID = checkIdOrObject(guild);
|
||||
const roleID = checkIdOrObject(role);
|
||||
|
||||
if (!userID) {
|
||||
setError(`msg.user wasn't set correctly`);
|
||||
} else if (!guildID) {
|
||||
setError(`msg.guild wasn't set correctly`);
|
||||
} else if (!roleID) {
|
||||
setError(`msg.role wasn't set correctly`);
|
||||
} else {
|
||||
try {
|
||||
const guildObject = await bot.guilds.fetch(guildID);
|
||||
const userObject = await guildObject.members.fetch(userID);
|
||||
|
||||
await userObject.roles.remove(roleID);
|
||||
msg.payload = "role removed";
|
||||
send(msg);
|
||||
setSuccess(`role removed`);
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (action.toLowerCase()) {
|
||||
case 'get':
|
||||
await sendRoles();
|
||||
break;
|
||||
case 'set':
|
||||
await setRole();
|
||||
break;
|
||||
case 'remove':
|
||||
await removeRole();
|
||||
break;
|
||||
default:
|
||||
setError(`msg.action has an incorrect value`)
|
||||
}
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("discordPermissions", discordPermissions);
|
||||
}
|
||||
84
discord/discordReactionManager.html
Normal file
84
discord/discordReactionManager.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('discordReactionManager', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 1,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordReactionManager";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordReactionManager">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordReactionManager">
|
||||
<p>Node that collects reactions (emoji's) on a specific message.</p>
|
||||
<p>More support can be found <a href="https://github.com/Markoudstaal/node-red-contrib-discord-advanced/wiki#support">here</a>.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>message
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The message Object or id of the message that you want to collect reactions on.</dd>
|
||||
<dt>channel
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The channel Object or channel id the message is in.</dd>
|
||||
<dt class="optional">time
|
||||
<span class="property-type">number</span>
|
||||
</dt>
|
||||
<dd>The time in milliseconds to listen for reactions. Default is 10 minutes.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>payload
|
||||
<span class="property-type">string</span>
|
||||
</dt>
|
||||
<dd>The payload contains the emoji that was reacted with.</dd>
|
||||
<dt>count
|
||||
<span class="property-type">number</span>
|
||||
</dt>
|
||||
<dd>The count how many times that emoji was reacted.</dd>
|
||||
<dt>message
|
||||
<span class="property-type">object</span>
|
||||
</dt>
|
||||
<dd>The message the reaction was created on.</dd>
|
||||
<dt>user
|
||||
<span class="property-type">object</span>
|
||||
</dt>
|
||||
<dd>The user that reacted.</dd>
|
||||
<dt>_originalFlowMessage
|
||||
<span class="property-type">object</span>
|
||||
</dt>
|
||||
<dd>The original input object of the node</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node will listen for reactions to a specified message.<p>
|
||||
<p>To start the process you will have to supply the <code>msg.message</code> and <code>msg.channel</code> for the message you want to listen on.
|
||||
Optionally you can set <code>msg.time</code> with the time in milliseconds to keep on listening for reactions.
|
||||
The node will output data for every individual reaction made on the message that was supplied. Keep in mind that after a node-red restart
|
||||
you will have to resend the message data.</p>
|
||||
</script>
|
||||
162
discord/discordReactionManager.js
Normal file
162
discord/discordReactionManager.js
Normal file
@@ -0,0 +1,162 @@
|
||||
const Flatted = require('flatted');
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
|
||||
function discordReactionManager(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
var node = this;
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "Ready"
|
||||
});
|
||||
|
||||
var reactionCollectors = [];
|
||||
|
||||
const checkIdOrObject = (check) => {
|
||||
try {
|
||||
if (typeof check !== 'string') {
|
||||
if (check.hasOwnProperty('id')) {
|
||||
return check.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return check;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const setError = (error, done) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const getMessage = async (message, channel) => {
|
||||
let channelInstance = await bot.channels.fetch(channel);
|
||||
return await channelInstance.messages.fetch(message);
|
||||
}
|
||||
|
||||
node.on('input', async function (msg, send, done) {
|
||||
const message = checkIdOrObject(msg.message);
|
||||
const channel = checkIdOrObject(msg.channel);
|
||||
const collectionTime = msg.time || 600000;
|
||||
|
||||
if (!channel) {
|
||||
setError("msg.channel isn't a string or object", done);
|
||||
return;
|
||||
}
|
||||
if (!message) {
|
||||
setError("msg.message isn't a string or object", done);
|
||||
return;
|
||||
}
|
||||
|
||||
let messageObject;
|
||||
try {
|
||||
messageObject = await getMessage(message, channel);
|
||||
} catch (error) {
|
||||
node.error(error);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: "channel or message missing?"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const collector = messageObject.createReactionCollector({
|
||||
time: collectionTime,
|
||||
dispose: true,
|
||||
remove: true,
|
||||
});
|
||||
|
||||
reactionCollectors.push(collector);
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "Collector created"
|
||||
});
|
||||
|
||||
collector.on('remove', async (reaction, user) => {
|
||||
try {
|
||||
let messageUser = await bot.users.fetch(reaction.message.author.id);
|
||||
let reactor = await user.fetch(true);
|
||||
|
||||
const newMsg = {
|
||||
payload: reaction._emoji.name,
|
||||
count: reaction.count,
|
||||
type: "remove",
|
||||
message: Flatted.parse(Flatted.stringify(reaction.message)),
|
||||
user: Flatted.parse(Flatted.stringify(reactor)),
|
||||
_originalFlowMessage: msg
|
||||
}
|
||||
newMsg.message.user = Flatted.parse(Flatted.stringify(messageUser));
|
||||
|
||||
send(newMsg);
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "Reaction remove"
|
||||
});
|
||||
} catch (error) {
|
||||
setError(error, done);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
collector.on('collect', async (reaction, user) => {
|
||||
try {
|
||||
let messageUser = await bot.users.fetch(reaction.message.author.id);
|
||||
let reactor = await user.fetch(true);
|
||||
|
||||
const newMsg = {
|
||||
payload: reaction._emoji.name,
|
||||
count: reaction.count,
|
||||
type: "set",
|
||||
message: Flatted.parse(Flatted.stringify(reaction.message)),
|
||||
user: Flatted.parse(Flatted.stringify(reactor)),
|
||||
_originalFlowMessage: msg
|
||||
}
|
||||
newMsg.message.user = Flatted.parse(Flatted.stringify(messageUser));
|
||||
|
||||
send(newMsg);
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: "Reaction sent"
|
||||
});
|
||||
} catch (error) {
|
||||
setError(error, done);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
node.on('close', function () {
|
||||
reactionCollectors.forEach(function (collector) {
|
||||
collector.stop();
|
||||
});
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
|
||||
}).catch(function (err) {
|
||||
node.error(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("discordReactionManager", discordReactionManager);
|
||||
}
|
||||
57
discord/discordTyping.html
Normal file
57
discord/discordTyping.html
Normal file
@@ -0,0 +1,57 @@
|
||||
a<script type="text/javascript">
|
||||
RED.nodes.registerType('discordTyping', {
|
||||
category: 'discord',
|
||||
color: '#7289da',
|
||||
defaults: {
|
||||
name: {
|
||||
value: "",
|
||||
required: false
|
||||
},
|
||||
channel: {
|
||||
value: null,
|
||||
required: false
|
||||
},
|
||||
token: {
|
||||
value: "",
|
||||
required: true,
|
||||
type: "discord-token"
|
||||
}
|
||||
},
|
||||
inputs: 1,
|
||||
outputs: 0,
|
||||
icon: "discord.png",
|
||||
label: function () {
|
||||
return this.name || "discordTyping";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="discordTyping">
|
||||
<div class="form-row">
|
||||
<label for="node-input-token"><i class="icon-tag"></i> token</label>
|
||||
<input type="text" id="node-input-token" placeholder="token">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-channel"><i class="icon-tag"></i> Channel</label>
|
||||
<input type="text" id="node-input-channel" name="ch" placeholder="Channel ID">
|
||||
<p>(leave 'channel' blank to use <code>msg.channel</code> as channel ID to send to)</p>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/x-red" data-help-name="discordTyping">
|
||||
<p>Node to start bot is typing message in channel.</p>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<dl class="message-properties">
|
||||
<dt>channel
|
||||
<span class="property-type">Object or string</span>
|
||||
</dt>
|
||||
<dd>The channel Object or channel id for creating, editing and deleting messages.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Details</h3>
|
||||
<p>This node allows the user to send the discordJS sendTyping function. This creates a 'bot is typing...' message in the corrosponding channel. It will continue to do so for 10 seconds or until a message is sent in said channel.<p>
|
||||
|
||||
</script>
|
||||
89
discord/discordTyping.js
Normal file
89
discord/discordTyping.js
Normal file
@@ -0,0 +1,89 @@
|
||||
module.exports = function (RED) {
|
||||
var discordBotManager = require('./lib/discordBotManager.js');
|
||||
const Flatted = require('flatted');
|
||||
|
||||
function discordTyping(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var configNode = RED.nodes.getNode(config.token);
|
||||
|
||||
discordBotManager.getBot(configNode).then(function (bot) {
|
||||
|
||||
node.on('input', async function (msg, done) {
|
||||
|
||||
const channel = config.channel || msg.channel || null;
|
||||
|
||||
const setError = (error) => {
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: error
|
||||
})
|
||||
done(error);
|
||||
}
|
||||
|
||||
const setSuccess = (succesMessage) => {
|
||||
node.status({
|
||||
fill: "green",
|
||||
shape: "dot",
|
||||
text: succesMessage
|
||||
});
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
const checkIdOrObject = (check) => {
|
||||
try {
|
||||
if (typeof check !== 'string') {
|
||||
if (check.hasOwnProperty('id')) {
|
||||
return check.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return check;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const getChannel = async (id) => {
|
||||
const channelID = checkIdOrObject(id);
|
||||
if (!channelID) {
|
||||
throw (`msg.channel wasn't set correctly`);
|
||||
}
|
||||
return await bot.channels.fetch(channelID);
|
||||
}
|
||||
|
||||
let channelInstance = null;
|
||||
|
||||
try {
|
||||
channelInstance = await getChannel(channel);
|
||||
}
|
||||
catch( err2 ){
|
||||
setError(err2);
|
||||
}
|
||||
|
||||
if ( channelInstance != null ){
|
||||
await channelInstance.sendTyping();
|
||||
setSuccess("Typing signal sent")
|
||||
|
||||
node.on('close', function () {
|
||||
discordBotManager.closeBot(bot);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
node.status({
|
||||
fill: "red",
|
||||
shape: "dot",
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("discordTyping", discordTyping);
|
||||
};
|
||||
BIN
discord/icons/discord.png
Normal file
BIN
discord/icons/discord.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 522 B |
3
discord/lib/bigint-compat.js
Normal file
3
discord/lib/bigint-compat.js
Normal file
@@ -0,0 +1,3 @@
|
||||
BigInt.prototype.toJSON = function () {
|
||||
return this.toString()
|
||||
}
|
||||
66
discord/lib/discordBotManager.js
Normal file
66
discord/lib/discordBotManager.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const { Client, GatewayIntentBits, Partials } = require('discord.js');
|
||||
require('./bigint-compat');
|
||||
|
||||
var bots = new Map();
|
||||
var getBot = function (configNode) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
var bot = undefined;
|
||||
if (bots.get(configNode) === undefined) {
|
||||
bot = new Client({
|
||||
shards: 'auto',
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.GuildMessageReactions,
|
||||
GatewayIntentBits.DirectMessages,
|
||||
GatewayIntentBits.DirectMessageReactions,
|
||||
GatewayIntentBits.MessageContent
|
||||
],
|
||||
partials: [
|
||||
Partials.Channel,
|
||||
Partials.User,
|
||||
Partials.Message
|
||||
]
|
||||
});
|
||||
bots.set(configNode, bot);
|
||||
bot.token = configNode.token
|
||||
bot.numReferences = (bot.numReferences || 0) + 1;
|
||||
bot.login(configNode.token)
|
||||
.then(() => {
|
||||
return bot.application.fetch(); // Fetch the application to get the ID
|
||||
})
|
||||
.then((app) => {
|
||||
bot.id = app.id; // Set the application ID as a property on the bot object
|
||||
resolve(bot);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
bot = bots.get(configNode);
|
||||
bot.numReferences = (bot.numReferences || 0) + 1;
|
||||
resolve(bot);
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
var closeBot = function (bot) {
|
||||
bot.numReferences -= 1;
|
||||
setTimeout(function () {
|
||||
if (bot.numReferences === 0) {
|
||||
try {
|
||||
bot.destroy(); // if a bot is not connected, destroy() won't work, so let's just wrap it in a try-catch..
|
||||
} catch (e) {}
|
||||
for (var i of bots.entries()) {
|
||||
if (i[1] === bot) {
|
||||
bots.delete(i[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
module.exports = {
|
||||
getBot: getBot,
|
||||
closeBot: closeBot
|
||||
}
|
||||
62
discord/lib/discordFramework.js
Normal file
62
discord/lib/discordFramework.js
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
const { GuildScheduledEventManager } = require('discord.js');
|
||||
|
||||
const checkIdOrObject = (check) => {
|
||||
try {
|
||||
if (typeof check !== 'string') {
|
||||
if (check.hasOwnProperty('id')) {
|
||||
return check.id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return check;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const getGuild = async (bot, id) => {
|
||||
const guildId = checkIdOrObject(id);
|
||||
if (!guildId) {
|
||||
throw (`msg.guild wasn't set correctly`);
|
||||
}
|
||||
return await bot.guilds.fetch(guildId);
|
||||
}
|
||||
|
||||
const getEventManager = async (bot, id) => {
|
||||
|
||||
guild = await getGuild(bot,id)
|
||||
return new GuildScheduledEventManager(guild);
|
||||
}
|
||||
|
||||
const getChannel = async (bot, id) => {
|
||||
const channelID = checkIdOrObject(id);
|
||||
if (!channelID) {
|
||||
throw (`msg.channel wasn't set correctly`);
|
||||
}
|
||||
return await bot.channels.fetch(channelID);
|
||||
}
|
||||
|
||||
const getMessage = async (bot, channel, message) => {
|
||||
const channelID = checkIdOrObject(channel);
|
||||
const messageID = checkIdOrObject(message);
|
||||
if (!channelID) {
|
||||
throw (`msg.channel wasn't set correctly`);
|
||||
} else if (!messageID) {
|
||||
throw (`msg.message wasn't set correctly`)
|
||||
}
|
||||
|
||||
let channelInstance = await bot.channels.fetch(channelID);
|
||||
return await channelInstance.messages.fetch(messageID);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkIdOrObject: checkIdOrObject,
|
||||
getMessage: getMessage,
|
||||
getGuild: getGuild,
|
||||
getChannel: getChannel,
|
||||
getEventManager: getEventManager
|
||||
};
|
||||
16
discord/lib/interactionManager.js
Normal file
16
discord/lib/interactionManager.js
Normal file
@@ -0,0 +1,16 @@
|
||||
let interactions = {};
|
||||
|
||||
const registerInteraction = (interaction) => {
|
||||
interactions[interaction.id]=interaction;
|
||||
}
|
||||
|
||||
const getInteraction = (interactionId) => {
|
||||
let interaction = interactions[interactionId];
|
||||
//delete interactions[interactionId];
|
||||
return interaction;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
registerInteraction: registerInteraction,
|
||||
getInteraction: getInteraction
|
||||
}
|
||||
73
discord/lib/messagesFormatter.js
Normal file
73
discord/lib/messagesFormatter.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const {
|
||||
AttachmentBuilder,
|
||||
ButtonBuilder,
|
||||
ActionRowBuilder,
|
||||
StringSelectMenuBuilder
|
||||
} = require('discord.js');
|
||||
|
||||
const formatAttachments = (inputAttachments) => {
|
||||
let attachments = [];
|
||||
if (inputAttachments) {
|
||||
if (typeof inputAttachments === 'string') {
|
||||
attachments.push(new AttachmentBuilder(inputAttachments));
|
||||
} else if (Array.isArray(inputAttachments)) {
|
||||
inputAttachments.forEach(attachment => {
|
||||
if (typeof attachment === 'string') {
|
||||
attachments.push(new AttachmentBuilder(attachment));
|
||||
} else if (typeof attachment === 'object') {
|
||||
attachments.push(new AttachmentBuilder(attachment.buffer, { name: attachment.name}));
|
||||
}
|
||||
});
|
||||
} else if (typeof inputAttachments === 'object') {
|
||||
attachments.push(new AttachmentBuilder(inputAttachments.buffer, {name: inputAttachments.name}));
|
||||
} else {
|
||||
throw "msg.attachments isn't a string or array";
|
||||
}
|
||||
}
|
||||
return attachments;
|
||||
}
|
||||
|
||||
const formatEmbeds = (inputEmbeds) => {
|
||||
let embeds = [];
|
||||
if (inputEmbeds) {
|
||||
if (Array.isArray(inputEmbeds)) {
|
||||
inputEmbeds.forEach(embed => {
|
||||
embeds.push(embed);
|
||||
});
|
||||
} else if (typeof inputEmbeds === 'object') {
|
||||
embeds.push(inputEmbeds);
|
||||
} else {
|
||||
throw "msg.embeds isn't a string or array";
|
||||
}
|
||||
}
|
||||
return embeds;
|
||||
}
|
||||
|
||||
const formatComponents = (inputComponents) => {
|
||||
let components = [];
|
||||
if (inputComponents) {
|
||||
inputComponents.forEach(component => {
|
||||
if (component.type == 1) {
|
||||
var actionRow = new ActionRowBuilder();
|
||||
component.components.forEach(subComponentData => {
|
||||
switch (subComponentData.type) {
|
||||
case 2:
|
||||
actionRow.addComponents(new ButtonBuilder(subComponentData));
|
||||
break;
|
||||
case 3:
|
||||
actionRow.addComponents(new StringSelectMenuBuilder(subComponentData));
|
||||
break;
|
||||
}
|
||||
});
|
||||
components.push(actionRow);
|
||||
}
|
||||
});
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatComponents: formatComponents,
|
||||
formatAttachments: formatAttachments,
|
||||
formatEmbeds: formatEmbeds
|
||||
}
|
||||
Reference in New Issue
Block a user