blob: d24110bd69bd1848019c2a14dcc56022ddfc111a [file] [log] [blame]
pineafan4edb7762022-06-26 19:21:04 +01001import Discord, { CommandInteraction, GuildMember, MessageActionRow, MessageButton, MessageSelectMenu } from "discord.js";
pineafan4f164f32022-02-26 22:07:12 +00002import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
3import { WrappedCheck } from "jshaiku";
pineafan4edb7762022-06-26 19:21:04 +01004import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
5import getEmojiByName from "../../utils/getEmojiByName.js";
6import addPlural from "../../utils/plurals.js";
7import client from "../../utils/client.js";
pineafan4f164f32022-02-26 22:07:12 +00008
9const command = (builder: SlashCommandSubcommandBuilder) =>
10 builder
11 .setName("all")
12 .setDescription("Gives or removes a role from everyone")
13
pineafan4edb7762022-06-26 19:21:04 +010014class Filter {
15 name: string;
16 data: object;
17 checkFunction: (member) => boolean;
18 inverted: boolean = false;
19 constructor(name: (data) => string | string, data: object, check: (member) => boolean) {
20 if (typeof name === "function") { this.name = name(data);
21 } else { this.name = name; }
22 this.data = data;
23 this.checkFunction = check;
24 }
25 flip() { this.inverted = true; return this; }
26 check(member) {
27 if (this.inverted) return !this.checkFunction(member)
28 else return this.checkFunction(member)
29 }
pineafan4f164f32022-02-26 22:07:12 +000030}
31
pineafan4edb7762022-06-26 19:21:04 +010032const filterList = {
33 member: {
34 render: "Member",
35 has: {
36 render: "has",
37 role: (role) => ( new Filter((data) => `Member has role <@&${data.role}>`, {role: role, type: Discord.Role, render: "role"}, (member) => { return member.roles.cache.has(role)}))
38 },
39 joined: {
40 render: "joined",
41 before: (date) => ( new Filter((data) => `Joined server before <t:${Math.round(date.getTime() / 1000)}:F>`, {date: date, type: Date, render: "before"}, (member) => {
42 return member.joinedTimestamp < date.getTime()
43 })),
44 after: (date) => ( new Filter((data) => `Joined server after <t:${Math.round(date.getTime() / 1000)}:F>`, {date: date, type: Date, render: "after"}, (member) => {
45 return member.joinedTimestamp > date.getTime()
46 }).flip())
47 },
48 nickname: {
49 render: "Nickname",
50 set: () => ( new Filter((data) => `Member has a nickname set"`, {render: "set"}, (member) => { return member.nickname !== null})),
51 include: (name) => ( new Filter((data) => `Nickname includes "${name}"`, {nickname: name, type: String, render: "includes"}, (member) => {
52 return member.displayName.includes(name)})),
53 startsWith: (name) => ( new Filter((data) => `Nickname starts with "${name}"`, {nickname: name, type: String, render: "starts with"}, (member) => {
54 return member.displayName.startsWith(name)})),
55 endsWith: (name) => ( new Filter((data) => `Nickname ends with "${name}"`, {nickname: name, type: String, render: "ends with"}, (member) => {
56 return member.displayName.endsWith(name)}))
57 }
58 },
59 account: {
60 render: "Account",
61 created: {
62 render: "created",
63 before: (date) => ( new Filter((data) => `Account created before <t:${Math.round(date.getTime() / 1000)}:D>`, {date: date, type: Date, render: "before"}, (member) => {
64 return member.user.createdTimestamp < date.getTime()
65 })),
66 after: (date) => ( new Filter((data) => `Account created after <t:${Math.round(date.getTime() / 1000)}:D>`, {date: date, type: Date, render: "after"}, (member) => {
67 return member.user.createdTimestamp < date.getTime()
68 }).flip())
69 },
70 is: {
71 render: "is",
72 human: () => ( new Filter((data) => `Member is a human`, {human: true, render: "human"}, (member) => { return !member.bot })),
73 },
74 username: {
75 render: "Username",
76 include: (name) => ( new Filter((data) => `Nickname includes "${name}"`, {nickname: name, type: String, render: "includes"}, (member) => {
77 return member.user.name.includes(name)})),
78 startsWith: (name) => ( new Filter((data) => `Nickname starts with "${name}"`, {nickname: name, type: String, render: "starts with"}, (member) => {
79 return member.user.name.startsWith(name)})),
80 endsWith: (name) => ( new Filter((data) => `Nickname ends with "${name}"`, {nickname: name, type: String, render: "ends with"}, (member) => {
81 return member.user.name.endsWith(name)}))
82 }
83 }
84}
85
86const callback = async (interaction: CommandInteraction) => {
87 await interaction.reply({embeds: [new EmojiEmbed()
88 .setTitle("Role all")
89 .setDescription("Loading...")
90 .setStatus("Danger")
91 .setEmoji("NUCLEUS.LOADING")
92 ], ephemeral: true, fetchReply: true})
93 let filters: Filter[] = [
94 filterList.member.has.role("959901346000154674"),
95 filterList.member.nickname.startsWith("Pinea"),
96 filterList.member.joined.before(new Date(2022, 1)).flip()
97 ]
98 let all = true;
99 while (true) {
100 let count = 0;
101 let affected = []
102 let members = interaction.guild.members.cache
103 if (all) {
104 members.forEach(member => {
105 let applies = true;
106 filters.forEach(filter => { if (!filter.check(member)) { applies = false } })
107 if (applies) { affected.push(member) }
108 })
109 } else {
110 members.forEach(member => {
111 let applies = false;
112 filters.forEach(filter => { if (filter.check(member)) { applies = true } })
113 if (applies) { affected.push(member) }
114 })
115 }
116 await interaction.editReply({embeds: [new EmojiEmbed()
117 .setTitle("Role all")
118 .setDescription((all ? "All of the following must be true:" : "Any of the following must be true") + "\n" +
119 filters.map((f) => {
120 count ++;
121 return (count == 1 ? getEmojiByName("ICONS.FILTER") : (all ? "**and** " : "**or** ")) +
122 (f.inverted ? "**not** " : "") + `${f.name}`
123 }).join("\n") + "\n\n" + `This will affect ${addPlural(affected.length.toString(), "member")}`)
124 .setEmoji("GUILD.ROLES.CREATE")
125 .setStatus("Success")
126 ], components: [
127 new MessageActionRow().addComponents([new MessageSelectMenu().setOptions(filters.map((f, index) => ({
128 label: (f.inverted ? "(Not) " : "") + f.name,
129 value: index.toString()
130 }))).setMinValues(1).setMaxValues(filters.length).setCustomId("select").setPlaceholder("Remove a filter")]),
131 new MessageActionRow().addComponents([
132 new MessageButton()
133 .setLabel("Apply")
134 .setStyle("PRIMARY")
135 .setCustomId("apply")
136 .setEmoji(client.emojis.cache.get(getEmojiByName("CONTROL.TICK", "id")))
137 .setDisabled(affected.length === 0),
138 new MessageButton()
139 .setLabel("Add filter")
140 .setStyle("PRIMARY")
141 .setCustomId("add")
142 .setEmoji(client.emojis.cache.get(getEmojiByName("ICONS.FILTER", "id")))
143 .setDisabled(filters.length >= 25)
144 ])
145 ]})
146 break
147 }
148}
149
150const check = async (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
151 let member = (interaction.member as GuildMember)
152 let me = (interaction.guild.me as GuildMember)
153 if (!me.permissions.has("MANAGE_ROLES")) throw "I do not have the Manage roles permission";
154 // Allow the owner to role anyone
155 if (member.id == interaction.guild.ownerId) return true
156 // Check if the user has manage_roles permission
157 if (! member.permissions.has("MANAGE_ROLES")) throw "You do not have the Manage roles permission";
158 // Allow role
pineafan4f164f32022-02-26 22:07:12 +0000159 return true;
160}
161
162export { command };
163export { callback };
164export { check };