Skip to content

Commit 456f10c

Browse files
committed
Add option for ping roles
1 parent 6a66500 commit 456f10c

File tree

5 files changed

+70
-27
lines changed

5 files changed

+70
-27
lines changed

src/HuTaoClient.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ export default class HuTaoClient extends Discord.Client {
5959
stickers: filterAll,
6060
users: filterAll
6161
},
62+
allowedMentions: {
63+
parse: [],
64+
repliedUser: false,
65+
roles: [],
66+
users: []
67+
},
6268
presence: {
6369
status: "online",
6470
activities: [{

src/commands/news/follow.ts

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { CommandInteraction, Message } from "discord.js"
1+
import { APIInteractionDataResolvedGuildMember } from "discord-api-types/v10"
2+
import { CommandInteraction, Message, MessageMentions } from "discord.js"
23

34
import config from "../../data/config.json"
45
import client from "../../main"
@@ -38,7 +39,7 @@ export default class Follow extends Command {
3839
super({
3940
name,
4041
category: "News",
41-
usage: `follow <list|add|remove> <${Object.keys(descriptions).join("|")}>\` or just \`follow list`,
42+
usage: `follow <list|add|remove> <${Object.keys(descriptions).join("|")}> [pingRole, in the case of add]\` or just \`follow list`,
4243
help: `Follow certain events in a channel
4344
4445
**Possible events**:
@@ -77,6 +78,10 @@ Example of adding news: \`${config.prefix}follow add news\``,
7778
value: d
7879
}
7980
})
81+
}, {
82+
name: "pingrole",
83+
description: "Role to ping",
84+
type: "MENTIONABLE"
8085
}]
8186
}, {
8287
name: "remove",
@@ -115,7 +120,7 @@ Example of adding news: \`${config.prefix}follow add news\``,
115120
if (sub == "list") {
116121
return this.runList(source, options.getString("category") as (FollowCategory | null))
117122
} else if (sub == "add") {
118-
return this.runFollow(source, options.getString("category", true) as FollowCategory)
123+
return this.runFollow(source, options.getString("category", true) as FollowCategory, options.getMentionable("pingrole", false))
119124
} else if (sub == "remove") {
120125
return this.runUnfollow(source, options.getString("category", true) as FollowCategory)
121126
}
@@ -132,6 +137,7 @@ Example of adding news: \`${config.prefix}follow add news\``,
132137
const sub = args[0]?.toLowerCase() ?? "help"
133138
args.shift()
134139
const otherArgs = args[0]?.toLowerCase()
140+
args.shift()
135141

136142
const category: FollowCategory | undefined = otherArgs ? Object.keys(descriptions).find(r => r.toLowerCase() == otherArgs) as (FollowCategory | undefined) : undefined
137143
if (!category)
@@ -145,7 +151,7 @@ Example of adding news: \`${config.prefix}follow add news\``,
145151
if (["list", "l"].includes(sub)) {
146152
return this.runList(source, category)
147153
} else if (["add", "a", "follow", "enable", "on"].includes(sub)) {
148-
return this.runFollow(source, category)
154+
return this.runFollow(source, category, args[0])
149155
} else if (["remove", "delete", "d", "r", "disable", "off", "unfollow"].includes(sub)) {
150156
return this.runUnfollow(source, category)
151157
} else {
@@ -162,14 +168,15 @@ Example of adding news: \`${config.prefix}follow add news\``,
162168
if (!category) {
163169
const following = followManager.following(source.guild)
164170

165-
const channels: {category: string, channelname: string}[] = []
171+
const channels: {category: string, channelname: string, pingRole: string}[] = []
166172
for (const follow of following)
167173
try {
168174
const channel = await client.channels.fetch(follow.channelID)
169175
if (isNewsable(channel))
170176
channels.push({
171177
channelname: channel.name,
172-
category: follow.category
178+
category: follow.category,
179+
pingRole: follow.pingRole
173180
})
174181
} catch (error) {
175182
followManager.dropChannel(follow.channelID)
@@ -178,9 +185,9 @@ Example of adding news: \`${config.prefix}follow add news\``,
178185

179186
return sendMessage(source, `Following per event: \`\`\`
180187
${createTable(
181-
["Event", "|", "Channel"],
188+
["Event", "|", "Channel", "|", "Ping role ID"],
182189
channels.map(
183-
k => [k.category, "|", k.channelname]
190+
k => [k.category, "|", k.channelname, "|", k.pingRole]
184191
))}\`\`\``, undefined, true)
185192
}
186193

@@ -209,15 +216,33 @@ ${createTable(
209216

210217
return sendMessage(source, `Unfollowed ${category} in <#${channel.id}>`, undefined, true)
211218
}
212-
async runFollow(source: CommandSource, category: FollowCategory): Promise<SendMessage | undefined> {
219+
async runFollow(source: CommandSource, category: FollowCategory, pingRole: string | { id: string } | APIInteractionDataResolvedGuildMember | null): Promise<SendMessage | undefined> {
213220
const channel = await source.channel?.fetch()
214221
if (!channel || !isNewsable(channel) || source.guild == null)
215222
return sendMessage(source, "Unable to follow in this channel", undefined, true)
216223

224+
let pingedRole = ""
225+
if (typeof pingRole == "string") {
226+
if (pingRole.match(/^\d+$/))
227+
pingedRole = pingRole
228+
else {
229+
const response = MessageMentions.ROLES_PATTERN.exec(pingRole)
230+
if (response == null)
231+
return sendMessage(source, "Unable to extract ping role from message", undefined, true)
232+
pingedRole = response[1]
233+
}
234+
} else if ((pingRole as {id: string})?.id) {
235+
const role = await source.guild.roles.fetch((pingRole as {id: string}).id)
236+
if (!role)
237+
return sendMessage(source, "Unable to extract ping role from command", undefined, true)
238+
pingedRole = role.id
239+
} else if (pingRole)
240+
return sendMessage(source, "Unable to extract ping role from command", undefined, true)
241+
217242
const { followManager } = client
218243

219-
followManager.addFollow(source.guild, channel, category, getUserID(source))
244+
followManager.addFollow(source.guild, channel, category, getUserID(source), pingedRole)
220245

221-
return sendMessage(source, `Now following ${category} in <#${channel.id}>`, undefined, true)
246+
return sendMessage(source, `Now following ${category} in <#${channel.id}> (Ping role: ${pingedRole == "" ? "none" : `<@&${pingedRole}> - make sure the bot can ping this role - this might require the @everyone permission!`})`, undefined, true)
222247
}
223248
}

src/utils/FollowManager.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,39 @@ export default class FollowManager {
1919
process.on("SIGINT", () => process.exit(128 + 2))
2020
process.on("SIGTERM", () => process.exit(128 + 15))
2121

22-
this.sql.exec("CREATE TABLE IF NOT EXISTS follows (guildID TEXT, channelID TEXT, category TEXT, addedOn BIGINT, addedBy TEXT, PRIMARY KEY (channelID, category))")
22+
this.sql.exec("CREATE TABLE IF NOT EXISTS follows (guildID TEXT, channelID TEXT, category TEXT, addedOn BIGINT, addedBy TEXT, pingRole TEXT DEFAULT '', PRIMARY KEY (channelID, category))")
2323
this.sql.exec("CREATE INDEX IF NOT EXISTS follows_category ON follows (category)")
2424
this.sql.exec("CREATE INDEX IF NOT EXISTS follows_channelID ON follows (channelID)")
2525
this.sql.exec("CREATE INDEX IF NOT EXISTS follows_guildID ON follows (guildID)")
26+
try {
27+
this.sql.exec("ALTER TABLE follows ADD COLUMN pingRole TEXT DEFAULT ''")
28+
Logger.debug("Table migrated for ping roles")
29+
} catch (error) {
30+
void 0
31+
}
2632

27-
this.addFollowStatement = this.sql.prepare("INSERT OR REPLACE INTO follows VALUES (@guildID, @channelID, @category, @addedOn, @addedBy)")
33+
this.addFollowStatement = this.sql.prepare("INSERT OR REPLACE INTO follows VALUES (@guildID, @channelID, @category, @addedOn, @addedBy, @pingRole)")
2834

2935
this.getFollowsStatement = this.sql.prepare("SELECT * FROM follows WHERE category = @category AND channelID = @channelID")
3036
this.getFollowsInChannelStatement = this.sql.prepare("SELECT * FROM follows WHERE channelID = @channelID")
31-
this.followingStatement = this.sql.prepare("SELECT category, channelID FROM follows WHERE guildID = @guildID GROUP BY category, channelID")
32-
this.getFollowersStatement = this.sql.prepare("SELECT channelID FROM follows WHERE category = @category")
33-
this.followsStatement = this.sql.prepare("SELECT channelID FROM follows WHERE category = @category AND channelID = @channelID")
37+
this.followingStatement = this.sql.prepare("SELECT category, channelID, pingRole FROM follows WHERE guildID = @guildID GROUP BY category, channelID")
38+
this.getFollowersStatement = this.sql.prepare("SELECT channelID, pingRole FROM follows WHERE category = @category")
39+
this.followsStatement = this.sql.prepare("SELECT channelID, pingRole FROM follows WHERE category = @category AND channelID = @channelID")
3440

3541
this.unfollowsStatement = this.sql.prepare("DELETE FROM follows WHERE category = @category AND channelID = @channelID")
3642
this.dropChannelStatement = this.sql.prepare("DELETE FROM follows WHERE channelID = @channelID")
3743
this.dropGuildStatement = this.sql.prepare("DELETE FROM follows WHERE guildID = @guildID")
3844
}
3945

4046
private addFollowStatement: SQLite.Statement
41-
addFollow(guild: Guild, channel: Channel, category: FollowCategory, addedBy: string): void {
42-
Logger.info(`Following in ${category} for ${addedBy} in ${channel.id} in ${guild.name} (${guild.id})`)
47+
addFollow(guild: Guild, channel: Channel, category: FollowCategory, addedBy: string, pingRole: string): void {
48+
Logger.info(`Following in ${category} for ${addedBy} in ${channel.id} in ${guild.name} (${guild.id}) - PingRole: ${pingRole}`)
4349
this.addFollowStatement.run({
4450
guildID: guild.id,
4551
channelID: channel.id,
4652
category,
4753
addedOn: new Date().getTime(),
54+
pingRole,
4855
addedBy
4956
})
5057
}
@@ -62,7 +69,7 @@ export default class FollowManager {
6269
}
6370

6471
private getFollowersStatement: SQLite.Statement
65-
getFollowers(category: string): { channelID: Snowflake }[] {
72+
getFollowers(category: string): { channelID: Snowflake, pingRole: Snowflake }[] {
6673
return this.getFollowersStatement.all({
6774
category
6875
})
@@ -103,15 +110,15 @@ export default class FollowManager {
103110
}
104111

105112
private followingStatement: SQLite.Statement
106-
following(guild: Guild): { category: FollowCategory, channelID: Snowflake }[] {
113+
following(guild: Guild): { category: FollowCategory, channelID: Snowflake, pingRole: Snowflake }[] {
107114
return this.followingStatement.all({
108115
guildID: guild.id
109116
})
110117
}
111118

112119
async send(category: FollowCategory, content?: string, embed?: MessageEmbed): Promise<(Message | Message[])[]> {
113-
let channels = this.getFollowers(category).map(k => k.channelID)
114-
channels = channels.filter((val, ind) => channels.indexOf(val) === ind)
120+
let channels = this.getFollowers(category)
121+
channels = channels.filter((val, ind) => channels.findIndex(v => v.channelID == val.channelID) === ind)
115122

116123
Logger.info(`Sending ${category} to ${channels.length} channels: ${content}`)
117124
const messages = (await sendToChannels(channels, content, embed)).filter((x): x is PromiseFulfilledResult<Message | Message[]> => x.status == "fulfilled").map(x => x.value).flat()

src/utils/Types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface Follower {
3232
category: FollowCategory
3333
addedOn: number
3434
addedBy: string
35+
pingRole: string
3536
}
3637

3738
// Reminder stuff

src/utils/Utils.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,21 @@ const Logger = log4js.getLogger("Utils")
1313
* @param embed Possible embed/attachment to send
1414
* @returns All the messages send
1515
*/
16-
export async function sendToChannels(channels: Snowflake[] | undefined, content?: string, embed?: MessageEmbed): Promise<PromiseSettledResult<Message | Message[]>[]> {
16+
export async function sendToChannels(channels: {channelID: Snowflake, pingRole?: string}[] | undefined, content?: string, embed?: MessageEmbed): Promise<PromiseSettledResult<Message | Message[]>[]> {
1717
const messages = []
1818
if (!channels) return Promise.all([])
1919

2020
for (const channel of channels) {
2121
try {
22-
const chanObj = await client.channels.fetch(channel)
22+
const chanObj = await client.channels.fetch(channel.channelID)
2323
if (!(chanObj && chanObj.isText()))
2424
continue
25-
if (embed && content && content.length > 0)
26-
messages.push(chanObj.send({ content, embeds: [embed] }))
25+
if (embed && ((content && content.length > 0) || (channel.pingRole && channel.pingRole.length > 0)))
26+
messages.push(chanObj.send({
27+
content: `${channel.pingRole && channel.pingRole != "" ? `<@&${channel.pingRole}> ` : ""}${content ?? ""}`.trim(),
28+
embeds: [embed],
29+
allowedMentions: { roles: channel.pingRole ? [channel.pingRole] : [] }
30+
}))
2731
else if (embed)
2832
messages.push(chanObj.send({ embeds: [embed] }))
2933
else if (content)
@@ -44,7 +48,7 @@ export async function sendToChannels(channels: Snowflake[] | undefined, content?
4448
*/
4549
export async function sendError(content: string, embed?: MessageEmbed): Promise<Message[]> {
4650
Logger.error(content)
47-
return (await sendToChannels(config.errorLog as Snowflake[], content, embed)).filter((x): x is PromiseFulfilledResult<Message | Message[]> => x.status == "fulfilled").map(x => x.value).flat()
51+
return (await sendToChannels((config.errorLog as Snowflake[]).map(x => ({ channelID: x })), content, embed)).filter((x): x is PromiseFulfilledResult<Message | Message[]> => x.status == "fulfilled").map(x => x.value).flat()
4852
}
4953

5054
export const PAD_START = 0

0 commit comments

Comments
 (0)