Update help command to use buttons & text input

also, move messages / "custom commands" to JSON file
This commit is contained in:
spiral 2021-07-16 19:35:06 -04:00
parent c096deb1d0
commit a4892d854b
No known key found for this signature in database
GPG key ID: A6059F0CA0E1BD31
18 changed files with 396 additions and 691 deletions

3
bot.js
View file

@ -74,6 +74,9 @@ const botProcess = () => {
Command.init(); Command.init();
const help = require("./model/command/help");
bot.ws.on('INTERACTION_CREATE', help.interactionHandler);
bot.on('ready', () => { bot.on('ready', () => {
fs.readdirSync('./event/bot/') fs.readdirSync('./event/bot/')
.filter(filename => filename.endsWith('.js')) .filter(filename => filename.endsWith('.js'))

216
messages.js Normal file
View file

@ -0,0 +1,216 @@
// interface Message {
// name string[];
// description string;
// title string;
// text string;
// }
module.exports = [
{
names: [
"add-friend",
"add-friends",
"addfriend",
"af",
],
description: 'Explains how to troubleshoot not being able to add a friend.',
title: "Add friend",
"text":
'If you and your friends are unable to add each other as friends, or can\'t find each other as friends, ' +
'make sure that you are using a case sensitive username when adding each other. Additionally, it is ' +
'currently not possible to add people by their user ID, so if you are using a user id to add them as ' +
'friend this currently does not work but will in the future.'
},
{
names: [
"add-set-front",
'addsetfront',
'addset-front',
'add-setfront',
'add-set',
'addset',
'add-front',
'addfront',
'set-front',
'setfront',
'asf',
],
description: 'Talks about how to set who is fronting in the application.',
title: "Add / set front",
text:
'There are two ways in-app to show a member as fronting. Set as front, and add to front.\n' +
'\n' +
'Using set as front will clear all members from your front list, and then add that member. Add to front ' +
'won\'t remove anyone from the list, but it will add the member whose add icon you tapped. You can ' +
'individually remove members by tapping the downward facing arrow next to their name.'
},
{
names: [
"custom-fields",
"customfields",
"customfield",
"cfi",
],
description: 'Talks about the "custom fields" feature.',
title: "Custom fields",
text:
'The ability to change the fields shown on your member lists is planned. This feature will also bring ' +
'the ability to remove and add fields, as well as make fields private, public, or show them to only ' +
'trusted friends.'
},
{
names: [
"custom-front",
"custom-fronts",
"customfront",
"customfronts",
"cf",
],
description: 'Explains what "custom front" is.',
title: "Custom fronts",
text:
'Custom fronts is a kind of status for fronts, like "blurred", "unknown member", "dissociated", etc... \n' +
'\n' +
'You don\'t want those to show up as real members in your system list but you still want to be able to ' +
'set front as one of them — that\'s where custom fronts kick in.\n' +
'\n' +
'They\'re highly customizable (as per popular request) so you can name them anything you want.'
},
{
names: [
"front-history-importing",
'fronthistoryimporting',
'fronthistory-importing',
'front-historyimporting',
'fronthistoryimport',
'fronthistory-import',
'front-historyimport',
'front-history',
'fronthistory',
'front-importing',
'frontimporting',
'front-import',
'frontimport',
'fhi',
],
description: 'Talks about importing the front history from PluralKit.',
title: "Front history importing",
text:
'Importing your front history to and from PluralKit is planned in the future, but is currently ' +
'impossible to give any front entries to or take entries from PluralKit until APIv2 for PluralKit is ' +
'finished. This feature also takes a lower priority than features unique to Simply Plural.'
},
{
names: [
"messaging",
],
description: 'Talks about the possibility of having a messaging feature.',
title: "Messaging",
text:
'The feature of messaging other systems within the app is out of scope, the app is not meant to be a ' +
'social community app but a tool for you and your friends. Adding messages between systems would need ' +
'us to implement moderation tools, moderation team and the actual feature, which is not the direction ' +
'we are taking the app in right now.\n' +
'\n' +
'Messaging within the system, between headmates, is planned for the future so you can communicate more ' +
'easily within the system.'
},
{
names: [
"notifications",
"notification",
],
description: 'Explains how your friends can get notifications from your system.',
title: "Notifications",
text:
'If your friends are not getting notifications, make sure that you go into the settings of the friend ' +
'by going on their profile and clicking the cog wheel on the right top. Press "They can get ' +
'notifications". As a second step your friend(s) have to opt-in to get notifications from you, they ' +
'have to go to your profile in their friends and click "Get notifications if they change front".'
},
{
names: [
"see-members",
"seemembers",
"seembmer",
"sm",
],
description: 'Explains how to allow your friends to see your members.',
title: "See members",
text:
'If your friends cannot see your members, you have to go into the friend their profile, click on the ' +
'cogwheel on the right top and press "They can see your shared members", this will allow them to see ' +
'your public members'
},
{
names: [
'sync-members-pluralkit',
'sync-member-pluralkit',
'syncmemberpluralkit',
'syncmember-pluralkit',
'sync-memberpluralkit',
'syncmemberspluralkit',
'syncmembers-pluralkit',
'sync-memberspluralkit',
'sync-member-plural-kit',
'syncmemberplural-kit',
'syncmember-plural-kit',
'sync-memberplural-kit',
'syncmembersplural-kit',
'syncmembers-plural-kit',
'sync-membersplural-kit',
'sync-member',
'syncmember',
'sync-members',
'syncmembers',
'sync-pluralkit',
'syncpluralkit',
'sync-plural-kit',
'syncplural-kit',
'smp',
'smpk',
],
description: 'Talks about syncing your members to PluralKit.',
title: "Sync members to PluralKit",
text:
'If you wish to sync your members to PluralKit, go into the settings page -> Integrations -> PluralKit ' +
'and fill in your PluralKit token, you can get this token by typing pk;token anywhere and PluralKit ' +
'will message you the token in a DM. \n' +
'\n' +
'Once filled out, you can go to actions in the members page and press Sync (rebooting app may be ' +
'required to see this option after adding the token). You will be prompted with the option to sync to ' +
'and from pk. \n' +
'\n' +
'Pay attention that they are linked by the plural kit id found in the individual member settings in ' +
'Simply Plural. If you make a member on Simply Plural and you make the same member on PluralKit you ' +
'will have to go into the individual member settings of Simply Plural and fill in the PluralKit user id ' +
'in the settings. If you don\'t do this you will end up with duplicate members on Plural Kit.'
},
{
names: [
"system-relationsips",
"system-relationship",
"systemrelationships",
"sr",
],
description: 'Explains what "system relationships" are.',
title: "System relationships",
text:
'This is an open-ended field meant to describe what relationships a headmate has. It can be used to ' +
'describe the member\'s relationship to the system as a whole, their inner system relationships such as ' +
'being family, friends, or romantic partners, or it can describe their outer-system relationships with ' +
'people in the outer world, such as family, friends, and romantic partners.'
},
{
names: [
"website",
],
title: "Website",
description: 'Talks about the possibility of having a web portal for Simply Plural.',
text:
'A web portal for Simply Plural is unlikely to be made at the moment. The framework that Simply Plural ' +
'has been created with has the capability of web development, but it is currently experimental, which ' +
'would make it buggy and unstable to use. This decision may change later in the year when the framework ' +
'becomes more stable and once the app is more complete.'
}
]

View file

@ -1,10 +1,7 @@
const CommandCategory = { const CommandCategory = {
MODERATION: 'moderation', MODERATION: 'moderation',
ADMINISTRATION: 'administration',
BOT_MANAGEMENT: 'bot_management', BOT_MANAGEMENT: 'bot_management',
FUN: 'fun', FUN: 'fun',
INFO: 'info',
ROLE: 'role',
RESOURCE: 'resource' RESOURCE: 'resource'
}; };

View file

@ -3,6 +3,8 @@ const Discord = require('discord.js');
const Config = require('../config.json'); const Config = require('../config.json');
const Guild = require('./guild'); const Guild = require('./guild');
const customMessages = require("./messages");
const cachelessRequire = (path) => { const cachelessRequire = (path) => {
if (typeof path === 'string') { if (typeof path === 'string') {
delete require.cache[require.resolve(path)]; delete require.cache[require.resolve(path)];
@ -44,37 +46,32 @@ const Command = {
* @returns {boolean} * @returns {boolean}
*/ */
parseMessage: async (message) => { parseMessage: async (message) => {
let isCommand = false; if (!message.content.toLowerCase().startsWith(Config.prefix))
return false;
if (message.content.toLowerCase().substr(0, Config.prefix.length) === Config.prefix) { let content = message.content.substr(Config.prefix.length).trim().split(' ');
let content = message.content.substr(Config.prefix.length).trim().split(' '); const calledCommand = content.shift().toLowerCase();
const calledCommand = content.shift().toLowerCase();
if (await Command.isValid(calledCommand, message)) { if (embed = customMessages.getEmbed(calledCommand))
const member = await Guild.getMemberFromMessage(message); return await message.channel.send({embed});
if (member === null) { if (!await Command.isValid(calledCommand, message)) return;
message.reply('sorry, you do not seem to be on the server.');
} else {
let commandName = calledCommand;
isCommand = true;
if (Command.commandAliases.hasOwnProperty(calledCommand)) { const member = await Guild.getMemberFromMessage(message);
commandName = Command.commandAliases[calledCommand]; if (member === null)
} return message.reply('sorry, you do not seem to be on the server.');
const commandInstance = cachelessRequire(Command.commandList.get(commandName)); let commandName = calledCommand;
if (commandInstance !== null) { if (Command.commandAliases.hasOwnProperty(calledCommand))
commandInstance.process(message, content, Command); commandName = Command.commandAliases[calledCommand];
} else {
Command.commandList.delete(commandName);
}
}
}
}
return isCommand; const commandInstance = cachelessRequire(Command.commandList.get(commandName));
if (commandInstance !== null)
commandInstance.process(message, content, Command);
else
Command.commandList.delete(commandName);
}, },
/** /**

View file

@ -1,40 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class AddFriend
{
static instance = null;
constructor() {
if (AddFriend.instance !== null) {
return AddFriend.instance;
}
this.aliases = ['add-friends', 'addfriends', 'addfriend', 'af'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Explains how to troubleshoot not being able to add a friend.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Add friend', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'If you and your friends are unable to add each other as friends, or can\'t find each other as friends, ' +
'make sure that you are using a case sensitive username when adding each other. Additionally, it is ' +
'currently not possible to add people by their user ID, so if you are using a user id to add them as ' +
'friend this currently does not work but will in the future.'
);
return message.channel.send(embed);
}
}
module.exports = new AddFriend();

View file

@ -1,52 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class AddSetFront
{
static instance = null;
constructor() {
if (AddSetFront.instance !== null) {
return AddSetFront.instance;
}
this.aliases = [
'addsetfront',
'addset-front',
'add-setfront',
'add-set',
'addset',
'add-front',
'addfront',
'set-front',
'setfront',
'asf',
];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about how to set who is fronting in the application.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Add / set front', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'There are two ways in-app to show a member as fronting. Set as front, and add to front.\n' +
'\n' +
'Using set as front will clear all members from your front list, and then add that member. Add to front ' +
'won\'t remove anyone from the list, but it will add the member whose add icon you tapped. You can ' +
'individually remove members by tapping the downward facing arrow next to their name.'
);
return message.channel.send(embed);
}
}
module.exports = new AddSetFront();

View file

@ -1,39 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class CustomFields
{
static instance = null;
constructor() {
if (CustomFields.instance !== null) {
return CustomFields.instance;
}
this.aliases = ['custom-fields', 'customfields', 'customfield', 'cfi'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about the "custom fields" feature.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Custom fields', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'The ability to change the fields shown on your member lists is planned. This feature will also bring ' +
'the ability to remove and add fields, as well as make fields private, public, or show them to only ' +
'trusted friends.'
);
return message.channel.send(embed);
}
}
module.exports = new CustomFields();

View file

@ -1,42 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class CustomFront
{
static instance = null;
constructor() {
if (CustomFront.instance !== null) {
return CustomFront.instance;
}
this.aliases = ['custom-fronts', 'customfronts', 'customfront', 'cf'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Explains what "custom front" is.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Custom fronts', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'Custom fronts is a kind of status for fronts, like "blurred", "unknown member", "dissociated", etc... \n' +
'\n' +
'You don\'t want those to show up as real members in your system list but you still want to be able to ' +
'set front as one of them — that\'s where custom fronts kick in.\n' +
'\n' +
'They\'re highly customizable (as per popular request) so you can name them anything you want.'
);
return message.channel.send(embed);
}
}
module.exports = new CustomFront();

View file

@ -140,7 +140,7 @@ class Embed
} }
this.aliases = []; this.aliases = [];
this.category = CommandCategory.RESOURCE; this.category = CommandCategory.MODERATION;
this.isAllowedForContext = CommandPermission.isMemberModOrHelper; this.isAllowedForContext = CommandPermission.isMemberModOrHelper;
this.description = 'Allows to post an embed'; this.description = 'Allows to post an embed';
} }

View file

@ -1,53 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class FrontHistoryImporting
{
static instance = null;
constructor() {
if (FrontHistoryImporting.instance !== null) {
return FrontHistoryImporting.instance;
}
this.aliases = [
'fronthistoryimporting',
'fronthistory-importing',
'front-historyimporting',
'fronthistoryimport',
'fronthistory-import',
'front-historyimport',
'front-history',
'fronthistory',
'front-importing',
'frontimporting',
'front-import',
'frontimport',
'fhi',
];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about importing the front history from PluralKit.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Front history importing', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'Importing your front history to and from PluralKit is planned in the future, but is currently ' +
'impossible to give any front entries to or take entries from PluralKit until APIv2 for PluralKit is ' +
'finished. This feature also takes a lower priority than features unique to Simply Plural.'
);
return message.channel.send(embed);
}
}
module.exports = new FrontHistoryImporting();

View file

@ -1,184 +1,89 @@
const Discord = require('discord.js');
const Logger = require('@lilywonhalf/pretty-logger');
const Config = require('../../config.json');
const EmojiCharacters = require('../../emoji-characters.json');
const Guild = require('../guild');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission'); const CommandPermission = require('../command-permission');
const CommandCategory = require('../command-category');
const commands = require('../command').commandList;
const messages = require('../messages');
const cachelessRequire = (path) => { const cachelessRequire = (path) => {
if (typeof path === 'string') { if (!typeof path === 'string') {
delete require.cache[require.resolve(path)]; delete require.cache[require.resolve(path)];
} }
return typeof path === 'string' ? require(path) : null; return typeof path === 'string' ? require(path) : null;
}; };
class HelpDialog const cleanString = (str) => str === null || str === undefined ? null : str
{ .replace("_", " ")
/** .split(" ")
* @param {Message} message .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
*/ .join(" ");
constructor(message) {
this.categoriesMapping = new Discord.Collection();
this.categoriesEmbed = new Discord.MessageEmbed();
this.originalMessage = message;
this.categoryCommandMapping = new Discord.Collection();
this.categoryColourMapping = new Discord.Collection();
this.postedMessage = null;
this.usedEmojis = [];
this.stopAddingReactions = false;
this.categoriesEmbed.setColor(APP_MAIN_COLOUR); const mainPage = (id) => {
this.categoriesEmbed.setFooter('Click on one of the reactions below'); const buttons = Object.keys(CommandCategory).map(c => ({
type: 2,
style: 1,
label: cleanString(c),
custom_id: `help-${id}-${c}`,
}))
for (let category of Object.values(CommandCategory)) { return {
this.categoryColourMapping.set(category, APP_MAIN_COLOUR); embeds: [{
} title: "Help command",
color: 0xA95B44,
this.categoryColourMapping.set(CommandCategory.RESOURCE, 'fdfd96'); description:
'Spot stands for **S**imply **P**lural b**ot**. This bot is mainly used to generate changelogs and help ' +
'with the definition of features, so recurring questions can be answered more quickly.\n' +
'\n' +
'Commands are classified by categories because displaying every command in this small box would be ' +
'confusing and would break Discord\'s character limit. Click on a buttom below to show the commands ' +
'available in the corresponding category, or type `.help <category name>`.\n'
}],
components: [{
"type": 1,
"components": buttons,
}]
} }
/** }
* @param {Command} Command
*/
async init(Command) {
const callableCommands = new Discord.Collection();
const commandList = Command.commandList.keyArray();
for (let i = 0; i < commandList.length; i++) { const categoryPage = (cat, id, direct = false) => {
const commandName = commandList[i]; const c = Object.values(CommandCategory).map(x => cleanString(x).toLowerCase());
const command = cachelessRequire(`../${Command.commandList.get(commandName)}`); if (!c.includes(cat.toLowerCase()))
const isAllowed = await command.isAllowedForContext(this.originalMessage); return;
if (isAllowed) { let data = {
callableCommands.set(commandName, command); embeds: [{
} title: `Help command | ${cleanString(cat)}`,
} color: 0xA95B44,
}],
components: [{
"type": 1,
"components": [{
type: 2,
style: 2,
label: "Back",
custom_id: `help-${id}-home`,
}],
}]
};
callableCommands.forEach((command, commandName) => { if (direct) delete data.components;
if (!this.categoryCommandMapping.has(command.category)) {
this.categoryCommandMapping.set(command.category, new Discord.Collection());
}
this.categoryCommandMapping.get(command.category).set(commandName, command); if (cat.toLowerCase() == cleanString(CommandCategory.RESOURCE).toLowerCase())
}); data.embeds[0].fields = messages.getList();
else
data.embeds[0].fields = Array.from(commands.keys()).map(x => {
const cmd = cachelessRequire(commands.get(x).split("command/").join(""));
if (cleanString(cmd.category)?.toLowerCase() != cat.toLowerCase()) return;
return { name: x, value: cmd.description ?? "No description."};
}).filter(x => x);
let i = 1; return data;
const categories = callableCommands.reduce((accumulator, command) => {
if (!this.categoriesMapping.array().includes(command.category)) {
let commandCategory = command.category.replace('_', ' ');
commandCategory = `${commandCategory.slice(0, 1).toUpperCase()}${commandCategory.slice(1)}`;
this.categoriesMapping.set(EmojiCharacters[i], command.category);
this.usedEmojis.push(EmojiCharacters[i]);
accumulator += `${EmojiCharacters[i]} ${commandCategory}\n`;
i++;
}
return accumulator;
}, '');
this.categoriesEmbed.setTitle('Help command');
this.categoriesEmbed.setDescription(
'Spot stands for **S**imply **P**lural b**ot**. This bot is mainly used to generate changelogs and help ' +
'with the definition of features, so recurring questions can be answered more quickly.\n' +
'\n' +
'Commands are classified by categories because displaying every command in this small box would be ' +
'confusing and would break Discord\'s character limit. Click on a reaction to show the commands ' +
'available in the corresponding category.\n' +
'\n' +
categories
);
return this.listCategories();
}
/**
* @param {Collection<Snowflake, MessageReaction>} [collection]
*/
async listCategories(collection) {
this.stopAddingReactions = true;
if (collection !== undefined && collection.size < 1) {
await this.postedMessage.reactions.removeAll().catch(error => Logger.warning(error.message));
return;
}
const member = await Guild.getMemberFromMessage(this.originalMessage);
const filter = (reaction, user) => {
const emoji = reaction.emoji.name;
return this.usedEmojis.includes(emoji) && user.id === member.user.id;
};
if (this.postedMessage === null) {
this.postedMessage = await this.originalMessage.channel.send(this.categoriesEmbed).catch(error => Logger.warning(error.toString()));
} else {
await this.postedMessage.reactions.removeAll().catch(error => Logger.warning(error.message));
await this.postedMessage.edit('', this.categoriesEmbed);
}
// 5 minutes
this.postedMessage.awaitReactions(filter, { time: 300000, max: 1 }).then(this.listCommands.bind(this)).catch(Logger.exception);
this.stopAddingReactions = false;
for (let i = 0; i < this.usedEmojis.length && !this.stopAddingReactions; i++) {
await this.postedMessage.react(this.usedEmojis[i]).catch(error => Logger.warning(error.message));
}
}
/**
* @param {Collection<Snowflake, MessageReaction>} collection
*/
async listCommands(collection) {
this.stopAddingReactions = true;
await this.postedMessage.reactions.removeAll().catch(error => Logger.warning(error.message));
if (collection.size < 1) {
this.postedMessage.edit('Timed out! You may send the command again.');
return;
}
const member = await Guild.getMemberFromMessage(this.originalMessage);
const filter = (reaction, user) => {
const emoji = reaction.emoji.name;
return emoji === '↩️' && user.id === member.user.id;
};
const category = this.categoriesMapping.get(collection.first().emoji.name);
const commandsEmbed = new Discord.MessageEmbed();
const commands = this.categoryCommandMapping.get(category).reduce((accumulator, command, commandName) => {
accumulator += `**${Config.prefix}${commandName}** ${command.description}\n\n`;
return accumulator;
}, '');
commandsEmbed.setTitle('Help command');
commandsEmbed.setDescription(commands);
commandsEmbed.setColor(this.categoryColourMapping.get(category));
commandsEmbed.setFooter('Click on one of the reactions below');
this.postedMessage.edit('', commandsEmbed);
// 5 minutes
this.postedMessage.awaitReactions(filter, { time: 300000, max: 1 }).then(this.listCategories.bind(this)).catch(Logger.exception);
await this.postedMessage.react('↩️').catch(error => Logger.warning(error.message));
}
} }
class Help class Help
{ {
static instance = null;
constructor() { constructor() {
if (Help.instance !== null) {
return Help.instance;
}
this.aliases = ['commands']; this.aliases = ['commands'];
this.category = CommandCategory.INFO; this.category = CommandCategory.INFO;
this.isAllowedForContext = CommandPermission.yes; this.isAllowedForContext = CommandPermission.yes;
@ -190,11 +95,45 @@ class Help
* @param {Array} args * @param {Array} args
* @param {Command} Command * @param {Command} Command
*/ */
async process(message, args, Command) { async process(message, args, command) {
const dialog = new HelpDialog(message); if (!args[0])
await bot.api.channels(message.channel.id).messages.post({ data: mainPage(message.author.id) });
return dialog.init(Command); else
await bot.api.channels(message.channel.id).messages.post({
data:
categoryPage(args.join(" "), message.author.id, true)
?? {
content: "Category not found.",
message_reference: { message_id: message.id, guild_id: message.guild?.id },
allowed_mentions: { parse: [] },
}
})
} }
} }
module.exports = new Help(); module.exports = new Help();
module.exports.interactionHandler = async (event) => {
const user = event.member.user.id;
const custom_id = event.data.custom_id;
let ret;
if (!custom_id.startsWith(`help-${user}`))
ret = {
type: 4,
data: {
flags: 64,
content: "This help command was sent by someone else. Please run `.help` again.",
},
}
else if (custom_id.endsWith('home'))
ret = { type: 7, data: mainPage(user) };
else {
let page = categoryPage(cleanString(custom_id.split(`help-${user}-`).join("")), user);
if (page) ret = { type: 7, data: page };
else ret = { type: 4, data: { flags: 64, content: "Category not found." }}
}
return await bot.api.interactions(event.id, event.token).callback.post({ data: ret })
}

View file

@ -1,43 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class Messaging
{
static instance = null;
constructor() {
if (Messaging.instance !== null) {
return Messaging.instance;
}
this.aliases = [];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about the possibility of having a messaging feature.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Messaging', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'The feature of messaging other systems within the app is out of scope, the app is not meant to be a ' +
'social community app but a tool for you and your friends. Adding messages between systems would need ' +
'us to implement moderation tools, moderation team and the actual feature, which is not the direction ' +
'we are taking the app in right now.\n' +
'\n' +
'Messaging within the system, between headmates, is planned for the future so you can communicate more ' +
'easily within the system.'
);
return message.channel.send(embed);
}
}
module.exports = new Messaging();

View file

@ -1,40 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class Notifications
{
static instance = null;
constructor() {
if (Notifications.instance !== null) {
return Notifications.instance;
}
this.aliases = ['notification'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Explains how your friends can get notifications from your system.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Notifications', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'If your friends are not getting notifications, make sure that you go into the settings of the friend ' +
'by going on their profile and clicking the cog wheel on the right top. Press "They can get ' +
'notifications". As a second step your friend(s) have to opt-in to get notifications from you, they ' +
'have to go to your profile in their friends and click "Get notifications if they change front".'
);
return message.channel.send(embed);
}
}
module.exports = new Notifications();

View file

@ -1,39 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class SeeMembers
{
static instance = null;
constructor() {
if (SeeMembers.instance !== null) {
return SeeMembers.instance;
}
this.aliases = ['see-members', 'seemembers', 'seemember', 'sm'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Explains how to allow your friends to see your members.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('See members', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'If your friends cannot see your members, you have to go into the friend their profile, click on the ' +
'cogwheel on the right top and press "They can see your shared members", this will allow them to see ' +
'your public members'
);
return message.channel.send(embed);
}
}
module.exports = new SeeMembers();

View file

@ -1,73 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class SyncMembersPluralkit
{
static instance = null;
constructor() {
if (SyncMembersPluralkit.instance !== null) {
return SyncMembersPluralkit.instance;
}
this.aliases = [
'sync-member-pluralkit',
'syncmemberpluralkit',
'syncmember-pluralkit',
'sync-memberpluralkit',
'syncmemberspluralkit',
'syncmembers-pluralkit',
'sync-memberspluralkit',
'sync-member-plural-kit',
'syncmemberplural-kit',
'syncmember-plural-kit',
'sync-memberplural-kit',
'syncmembersplural-kit',
'syncmembers-plural-kit',
'sync-membersplural-kit',
'sync-member',
'syncmember',
'sync-members',
'syncmembers',
'sync-pluralkit',
'syncpluralkit',
'sync-plural-kit',
'syncplural-kit',
'smp',
'smpk',
];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about syncing your members to PluralKit.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Sync members to PluralKit', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'If you wish to sync your members to PluralKit, go into the settings page -> Integrations -> PluralKit ' +
'and fill in your PluralKit token, you can get this token by typing pk;token anywhere and PluralKit ' +
'will message you the token in a DM. \n' +
'\n' +
'Once filled out, you can go to actions in the members page and press Sync (rebooting app may be ' +
'required to see this option after adding the token). You will be prompted with the option to sync to ' +
'and from pk. \n' +
'\n' +
'Pay attention that they are linked by the plural kit id found in the individual member settings in ' +
'Simply Plural. If you make a member on Simply Plural and you make the same member on PluralKit you ' +
'will have to go into the individual member settings of Simply Plural and fill in the PluralKit user id ' +
'in the settings. If you don\'t do this you will end up with duplicate members on Plural Kit.'
);
return message.channel.send(embed);
}
}
module.exports = new SyncMembersPluralkit();

View file

@ -1,40 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class SystemRelationships
{
static instance = null;
constructor() {
if (SystemRelationships.instance !== null) {
return SystemRelationships.instance;
}
this.aliases = ['system-relationship', 'systemrelationships', 'systemrelationships', 'sr'];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Explains what "system relationships" are.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('System relationships', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'This is an open-ended field meant to describe what relationships a headmate has. It can be used to ' +
'describe the member\'s relationship to the system as a whole, their inner system relationships such as ' +
'being family, friends, or romantic partners, or it can describe their outer-system relationships with ' +
'people in the outer world, such as family, friends, and romantic partners.'
);
return message.channel.send(embed);
}
}
module.exports = new SystemRelationships();

View file

@ -1,40 +0,0 @@
const { MessageEmbed } = require('discord.js');
const CommandCategory = require('../command-category');
const CommandPermission = require('../command-permission');
class Website
{
static instance = null;
constructor() {
if (Website.instance !== null) {
return Website.instance;
}
this.aliases = [];
this.category = CommandCategory.RESOURCE;
this.isAllowedForContext = CommandPermission.yes;
this.description = 'Talks about the possibility of having a web portal for Simply Plural.';
}
/**
* @param {Message} message
* @param {Array} args
*/
async process(message, args) {
const embed = new MessageEmbed();
embed.setColor(APP_MAIN_COLOUR);
embed.setAuthor('Website', bot.user.displayAvatarURL({ dynamic: true }));
embed.setDescription(
'A web portal for Simply Plural is unlikely to be made at the moment. The framework that Simply Plural ' +
'has been created with has the capability of web development, but it is currently experimental, which ' +
'would make it buggy and unstable to use. This decision may change later in the year when the framework ' +
'becomes more stable and once the app is more complete.'
);
return message.channel.send(embed);
}
}
module.exports = new Website();

54
model/messages.js Normal file
View file

@ -0,0 +1,54 @@
let names = {};
let messages = {};
const genRandomId = () => Math.ceil(Math.random() * 1000);
const load = () => require("../messages").forEach(msg => {
let id = genRandomId();
while (messages[id])
id = genRandomId();
msg.names.forEach(name => names[name] = id);
messages[id] = msg;
});
load();
// interface Message {
// names string[];
// description string;
// title string;
// text string;
// }
const { MessageEmbed } = require("discord.js");
module.exports = {
get names() {
return names;
},
get messages() {
return messages;
},
get: (name) => messages[names[name]],
getList: () => Object.keys(messages).map(msg => ({ name: messages[msg].names[0], value: messages[msg].description })),
getEmbed: (name) => {
let msg = messages[names[name]];
if (!msg) return;
return {
color: APP_MAIN_COLOUR,
author: {
name: msg.title,
iconURL: bot.user.displayAvatarURL({ dynamic: true }),
},
description: msg.text,
}
},
reload: () => {
names = {};
messages = {};
delete require.cache[require.resolve("../messages")];
load();
}
}