diff --git a/src/data/GuildStarboardReactions.ts b/src/data/GuildStarboardReactions.ts new file mode 100644 index 00000000..8b837e12 --- /dev/null +++ b/src/data/GuildStarboardReactions.ts @@ -0,0 +1,43 @@ +import { BaseGuildRepository } from "./BaseGuildRepository"; +import { Repository, getRepository } from "typeorm"; +import { StarboardReaction } from "./entities/StarboardReaction"; + +export class GuildStarboardReactions extends BaseGuildRepository { + private allStarboardReactions: Repository; + + constructor(guildId) { + super(guildId); + this.allStarboardReactions = getRepository(StarboardReaction); + } + + async getAllReactionsForMessageId(messageId: string) { + return this.allStarboardReactions + .createQueryBuilder() + .where("guild_id = :gid", { gid: this.guildId }) + .andWhere("message_id = :msgid", { msgid: messageId }) + .getMany(); + } + + async createStarboardReaction(messageId: string, reactorId: string) { + await this.allStarboardReactions.insert({ + message_id: messageId, + reactor_id: reactorId, + guild_id: this.guildId, + }); + } + + async deleteAllStarboardReactionsForMessageId(messageId: string) { + await this.allStarboardReactions.delete({ + guild_id: this.guildId, + message_id: messageId, + }); + } + + async deleteStarboardMessage(messageId: string, reactorId: string) { + await this.allStarboardReactions.delete({ + guild_id: this.guildId, + reactor_id: reactorId, + message_id: messageId, + }); + } +} diff --git a/src/data/entities/StarboardReaction.ts b/src/data/entities/StarboardReaction.ts new file mode 100644 index 00000000..020b3a03 --- /dev/null +++ b/src/data/entities/StarboardReaction.ts @@ -0,0 +1,22 @@ +import { Entity, Column, PrimaryColumn, JoinColumn, OneToOne } from "typeorm"; +import { SavedMessage } from "./SavedMessage"; + +@Entity("starboard_reactions") +export class StarboardReaction { + @Column() + @PrimaryColumn() + id: string; + + @Column() + guild_id: string; + + @Column() + message_id: string; + + @Column() + reactor_id: string; + + @OneToOne(type => SavedMessage) + @JoinColumn({ name: "message_id" }) + message: SavedMessage; +} diff --git a/src/migrations/1571055675462-CreateStarboardReactionsTable.ts b/src/migrations/1571055675462-CreateStarboardReactionsTable.ts new file mode 100644 index 00000000..bbe35aa3 --- /dev/null +++ b/src/migrations/1571055675462-CreateStarboardReactionsTable.ts @@ -0,0 +1,44 @@ +import { MigrationInterface, QueryRunner, Table } from "typeorm"; + +export class CreateStarboardReactionsTable1571055675462 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: "starboard_reactions", + columns: [ + { + name: "id", + type: "int", + isGenerated: true, + generationStrategy: "increment", + isPrimary: true, + }, + { + name: "guild_id", + type: "bigint", + unsigned: true, + }, + { + name: "message_id", + type: "bigint", + unsigned: true, + }, + { + name: "reactor_id", + type: "bigint", + unsigned: true, + }, + ], + indices: [ + { + columnNames: ["reactor_id", "message_id"], + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("starboard_reactions", true, false, true); + } +} diff --git a/src/plugins/Starboard.ts b/src/plugins/Starboard.ts index 8181becd..70fe9270 100644 --- a/src/plugins/Starboard.ts +++ b/src/plugins/Starboard.ts @@ -16,6 +16,7 @@ const StarboardOpts = t.type({ positive_emojis: tNullable(t.array(t.string)), positive_required: tNullable(t.number), allow_multistar: tNullable(t.boolean), + allowed_roles: tNullable(t.array(t.string)), enabled: tNullable(t.boolean), }); type TStarboardOpts = t.TypeOf; @@ -31,6 +32,7 @@ const defaultStarboardOpts: Partial = { positive_emojis: ["⭐"], positive_required: 5, allow_multistar: false, + allowed_roles: [], enabled: true, }; @@ -122,6 +124,7 @@ export class StarboardPlugin extends ZeppelinPlugin { if (cfg.enabled == null) cfg.enabled = defaultStarboardOpts.enabled; if (cfg.positive_emojis == null) cfg.positive_emojis = defaultStarboardOpts.positive_emojis; if (cfg.positive_required == null) cfg.positive_required = defaultStarboardOpts.positive_required; + if (cfg.allowed_roles == null) cfg.allowed_roles = defaultStarboardOpts.allowed_roles; }); return configs; @@ -136,6 +139,7 @@ export class StarboardPlugin extends ZeppelinPlugin { if (cfg.enabled == null) cfg.enabled = defaultStarboardOpts.enabled; if (cfg.positive_emojis == null) cfg.positive_emojis = defaultStarboardOpts.positive_emojis; if (cfg.positive_required == null) cfg.positive_required = defaultStarboardOpts.positive_required; + if (cfg.allowed_roles == null) cfg.allowed_roles = defaultStarboardOpts.allowed_roles; }); return configs; @@ -184,7 +188,7 @@ export class StarboardPlugin extends ZeppelinPlugin { ); if (starboardMessages.length > 0) continue; - const reactionsCount = await this.countReactions(msg, starboard.positive_emojis, starboard.allow_multistar); + const reactionsCount = await this.countReactions(msg, starboard); if (reactionsCount >= starboard.positive_required) { await this.saveMessageToStarboard(msg, starboard.starboard_channel_id); } @@ -194,11 +198,12 @@ export class StarboardPlugin extends ZeppelinPlugin { /** * Tallys the reaction count of ALL reactions in the array */ - async countReactions(msg: Message, counted: string[], countDouble: boolean) { + async countReactions(msg: Message, starboard: any) { let totalCount = []; - for (const emoji of counted) { - totalCount = await this.countReactionsForEmoji(msg, emoji, totalCount, countDouble); + for (const emoji of starboard.positive_emojis) { + totalCount = await this.countReactionsForEmoji(msg, emoji, totalCount, starboard); + if (totalCount >= starboard.positive_required) return totalCount; // Exit if we already have enough reactions } return totalCount.length; @@ -207,8 +212,8 @@ export class StarboardPlugin extends ZeppelinPlugin { /** * Counts the emoji specific reactions in the message, ignoring the message author and the bot */ - async countReactionsForEmoji(msg: Message, reaction, usersAlreadyCounted: string[], countDouble: boolean) { - countDouble = countDouble || false; + async countReactionsForEmoji(msg: Message, reaction, usersAlreadyCounted: string[], starboard: any) { + const countDouble = starboard.allow_multistar || false; // Ignore self-stars, bot-stars and multi-stars const reactors = await msg.getReaction(reaction); @@ -216,6 +221,11 @@ export class StarboardPlugin extends ZeppelinPlugin { if (user.id === msg.author.id) continue; if (user.id === this.bot.user.id) continue; if (!countDouble && usersAlreadyCounted.includes(user.id)) continue; + + const mem = await this.getMember(user.id); + const foundRole = mem.roles.some(role => starboard.allowed_roles.includes(role)); + if (!foundRole && starboard.allowed_roles.length > 0) continue; + usersAlreadyCounted.push(user.id); }