blob: 81d15033ffeb0d8c7b90aec0eb4c0aca8dacd8cb [file] [log] [blame]
pineafane23c4ec2022-07-27 21:56:27 +01001import { LoadingEmbed } from './../utils/defaultEmbeds.js';
pineafan73a7c4a2022-07-24 10:38:04 +01002import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
pineafane23c4ec2022-07-27 21:56:27 +01003import { SelectMenuOption, SlashCommandBuilder } from "@discordjs/builders";
pineafan4f164f32022-02-26 22:07:12 +00004import { WrappedCheck } from "jshaiku";
pineafan73a7c4a2022-07-24 10:38:04 +01005import { testLink, testMalware, testNSFW } from "../reflex/scanners.js";
6import EmojiEmbed from "../utils/generateEmojiEmbed.js";
pineafane23c4ec2022-07-27 21:56:27 +01007import getEmojiByName from "../utils/getEmojiByName.js";
8import createPageIndicator from "../utils/createPageIndicator.js";
9import client from "../utils/client.js";
10import confirmationMessage from "../utils/confirmationMessage.js";
pineafan4f164f32022-02-26 22:07:12 +000011
12const command = new SlashCommandBuilder()
13 .setName("privacy")
pineafan73a7c4a2022-07-24 10:38:04 +010014 .setDescription("Information and options for you and your server's settings")
pineafan4f164f32022-02-26 22:07:12 +000015
pineafane23c4ec2022-07-27 21:56:27 +010016class Embed {
17 embed: Discord.MessageEmbed;
18 title: string;
19 description: string = "";
20 pageId: number = 0;
21 components?: MessageActionRow[] = [];
22 setEmbed(embed: Discord.MessageEmbed) { this.embed = embed; return this; }
23 setTitle(title: string) { this.title = title; return this; }
24 setDescription(description: string) { this.description = description; return this; }
25 setPageId(pageId: number) { this.pageId = pageId; return this; }
26 setComponents(components: MessageActionRow[]) { this.components = components; return this; }
27}
28
pineafan4edb7762022-06-26 19:21:04 +010029const callback = async (interaction: CommandInteraction): Promise<any> => {
pineafane23c4ec2022-07-27 21:56:27 +010030 let pages = [
31 new Embed()
32 .setEmbed(new EmojiEmbed()
33 .setTitle("Nucleus Privacy")
34 .setDescription(
35 "Nucleus is a bot that naturally needs to store data about servers.\n" +
36 "We are entirely [open source](https://github.com/ClicksMinutePer/Nucleus), so you can check exactly what we store, and how it works.\n\n" +
37 "If you are a server administrator, you can view the options page in the dropdown under this message.\n\n" +
38 "Any questions about Nucleus, how it works and data stored can be asked in [our server](https://discord.gg/bPaNnxe)."
39 )
40 .setEmoji("NUCLEUS.LOGO")
41 .setStatus("Danger")
42 ).setTitle("Welcome").setDescription("General privacy information").setPageId(0),
43 new Embed()
44 .setEmbed(new EmojiEmbed()
45 .setTitle("Scanners")
46 .setDescription(
47 "Nucleus uses [unscan](https://unscan.co) to scan links, images and files for malware and other threats.\n" +
48 "This service's [privacy policy](https://unscan.co/policies) is public, and they \"do not store or sell your data.\""
49 )
50 .setEmoji("NUCLEUS.LOGO")
51 .setStatus("Danger")
52 ).setTitle("Scanners").setDescription("About Unscan").setPageId(1),
53 new Embed()
54 .setEmbed(new EmojiEmbed()
55 .setTitle("Link scanning and Transcripts")
56 .setDescription(
57 "**Facebook** - Facebook trackers include data such as your date of birth, and guess your age if not entered, your preferences, who you interact with and more.\n" +
58 "**AMP** - AMP is a technology that allows websites to be served by Google. This means Google can store and track data, and are pushing this to as many pages as possible.\n\n" +
59 "Transcripts allow you to store all messages sent in a channel. This could be an issue in some cases, as they are hosted on [Pastebin](https://pastebin.com), so a leaked link could show all messages sent in the channel.\n"
60 )
61 .setEmoji("NUCLEUS.LOGO")
62 .setStatus("Danger")
63 ).setTitle("Link scanning and Transcripts").setDescription("Regarding Facebook and AMP filter types, and ticket transcripts").setPageId(2)
64 ].concat((interaction.member as Discord.GuildMember).permissions.has("ADMINISTRATOR") ? [new Embed()
65 .setEmbed(new EmojiEmbed()
66 .setTitle("Options")
67 .setDescription(
68 "Below are buttons for controlling this servers privacy settings"
69 )
70 .setEmoji("NUCLEUS.LOGO")
71 .setStatus("Danger")
72 ).setTitle("Options").setDescription("Options").setPageId(3).setComponents([new MessageActionRow().addComponents([
73 new MessageButton().setLabel("Clear all data").setCustomId("clear-all-data").setStyle("DANGER")
74 ])])
75 ] : []);
76 let m;
77 m = await interaction.reply({embeds: LoadingEmbed, fetchReply: true, ephemeral: true});
78 let page = 0;
79
80 let selectPaneOpen = false;
81 let nextFooter = null;
82
83 while (true) {
84 let selectPane = []
85
86 if (selectPaneOpen) {
87 let options = [];
88 pages.forEach(embed => {
89 options.push(new SelectMenuOption({
90 label: embed.title,
91 value: embed.pageId.toString(),
92 description: embed.description || "",
93 }))
94 })
95 selectPane = [new MessageActionRow().addComponents([
96 new Discord.MessageSelectMenu()
97 .addOptions(options)
98 .setCustomId("page")
99 .setMaxValues(1)
100 .setPlaceholder("Choose a page...")
101 ])]
102 }
103 let components = selectPane.concat([new MessageActionRow().addComponents([
104 new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(page === 0),
105 new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(false),
106 new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(page === pages.length - 1)
107 ])])
108 let em = new Discord.MessageEmbed(pages[page].embed)
109 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
110 em.setFooter({text: nextFooter ?? ""})
111 await interaction.editReply({
112 embeds: [em],
113 components: components.concat(pages[page].components)
114 });
115 let i
116 try {
117 i = await m.awaitMessageComponent({time: 300000});
118 } catch(e) { break }
119 nextFooter = null
120 i.deferUpdate()
121 if (i.component.customId === "left") {
122 if (page > 0) page--;
123 selectPaneOpen = false;
124 } else if (i.component.customId === "right") {
125 if (page < pages.length - 1) page++;
126 selectPaneOpen = false;
127 } else if (i.component.customId === "select") {
128 selectPaneOpen = !selectPaneOpen;
129 } else if (i.component.customId === "page") {
130 page = parseInt(i.values[0]);
131 selectPaneOpen = false;
132 } else if (i.component.customId === "clear-all-data") {
133 let confirmation = await new confirmationMessage(interaction)
134 .setEmoji("CONTROL.BLOCKCROSS")
135 .setTitle("Clear All Data")
136 .setDescription(
137 `Are you sure you want to delete all data on this server? This includes your settings and all punishment histories.\n\n` +
138 "**This cannot be undone.**"
139 )
140 .setColor("Danger")
141 .send(true)
142 if (confirmation.cancelled) { break; }
143 if (confirmation.success) {
144 client.database.guilds.delete(interaction.guild.id);
145 client.database.history.delete(interaction.guild.id);
146 nextFooter = "All data cleared";
147 continue;
148 } else {
149 nextFooter = "No changes were made";
150 continue;
151 }
152 } else {
153 let em = new Discord.MessageEmbed(pages[page].embed)
154 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page))
155 em.setFooter({text: "Message closed"});
156 interaction.editReply({embeds: [em], components: []});
157 return
158 }
pineafan73a7c4a2022-07-24 10:38:04 +0100159 }
pineafane23c4ec2022-07-27 21:56:27 +0100160 let em = new Discord.MessageEmbed(pages[page].embed)
161 em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page))
162 em.setFooter({text: "Message timed out"});
163 await interaction.editReply({
164 embeds: [em],
165 components: []
166 });
pineafan4f164f32022-02-26 22:07:12 +0000167}
168
169const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
170 return true;
171}
172
173export { command };
174export { callback };
175export { check };