3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

Add name history plugin

This commit is contained in:
Dragory 2019-01-06 15:27:51 +02:00
parent 50c6233190
commit 681517341e
7 changed files with 245 additions and 6 deletions

View file

@ -0,0 +1,64 @@
import { BaseRepository } from "./BaseRepository";
import { getRepository, Repository } from "typeorm";
import { NameHistoryEntry } from "./entities/NameHistoryEntry";
const MAX_ENTRIES_PER_USER = 10;
export class GuildNameHistory extends BaseRepository {
private nameHistory: Repository<NameHistoryEntry>;
constructor(guildId) {
super(guildId);
this.nameHistory = getRepository(NameHistoryEntry);
}
async getByUserId(userId): Promise<NameHistoryEntry[]> {
return this.nameHistory.find({
where: {
guild_id: this.guildId,
user_id: userId
},
order: {
id: "DESC"
},
take: MAX_ENTRIES_PER_USER
});
}
getLastEntryByType(userId, type): Promise<NameHistoryEntry> {
return this.nameHistory.findOne({
where: {
guild_id: this.guildId,
user_id: userId,
type
},
order: {
id: "DESC"
}
});
}
async addEntry(userId, type, value) {
await this.nameHistory.insert({
guild_id: this.guildId,
user_id: userId,
type,
value
});
// Cleanup (leave only the last MAX_ENTRIES_PER_USER entries)
const lastEntries = await this.getByUserId(userId);
if (lastEntries.length > MAX_ENTRIES_PER_USER) {
const earliestEntry = lastEntries[lastEntries.length - 1];
if (!earliestEntry) return;
this.nameHistory
.createQueryBuilder()
.where("guild_id = :guildId", { guildId: this.guildId })
.andWhere("user_id = :userId", { userId })
.andWhere("id < :id", { id: earliestEntry.id })
.delete()
.execute();
}
}
}

View file

@ -0,0 +1,4 @@
export enum NameHistoryEntryTypes {
Username = 1,
Nickname
}

View file

@ -0,0 +1,18 @@
import { Entity, Column, PrimaryColumn } from "typeorm";
@Entity("name_history")
export class NameHistoryEntry {
@Column()
@PrimaryColumn()
id: string;
@Column() guild_id: string;
@Column() user_id: string;
@Column() type: number;
@Column() value: string;
@Column() timestamp: string;
}

View file

@ -61,6 +61,7 @@ import { CasesPlugin } from "./plugins/Cases";
import { MutesPlugin } from "./plugins/Mutes";
import { SlowmodePlugin } from "./plugins/Slowmode";
import { StarboardPlugin } from "./plugins/Starboard";
import { NameHistoryPlugin } from "./plugins/NameHistory";
// Run latest database migrations
logger.info("Running database migrations");
@ -72,12 +73,13 @@ connect().then(async conn => {
});
client.setMaxListeners(100);
const basePlugins = ["message_saver", "cases", "mutes"];
const basePlugins = ["message_saver", "name_history", "cases", "mutes"];
const bot = new Knub(client, {
plugins: [
// Base plugins (always enabled)
MessageSaverPlugin,
NameHistoryPlugin,
CasesPlugin,
MutesPlugin,
@ -95,10 +97,7 @@ connect().then(async conn => {
StarboardPlugin
],
globalPlugins: [
BotControlPlugin,
LogServerPlugin
],
globalPlugins: [BotControlPlugin, LogServerPlugin],
options: {
getEnabledPlugins(guildId, guildConfig): string[] {

View file

@ -0,0 +1,62 @@
import { MigrationInterface, QueryRunner, Table } from "typeorm";
export class CreateNameHistoryTable1546778415930 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.createTable(
new Table({
name: "name_history",
columns: [
{
name: "id",
type: "int",
unsigned: true,
isGenerated: true,
generationStrategy: "increment",
isPrimary: true
},
{
name: "guild_id",
type: "bigint",
unsigned: true
},
{
name: "user_id",
type: "bigint",
unsigned: true
},
{
name: "type",
type: "tinyint",
unsigned: true
},
{
name: "value",
type: "varchar",
length: "128",
isNullable: true
},
{
name: "timestamp",
type: "datetime",
default: "CURRENT_TIMESTAMP"
}
],
indices: [
{
columnNames: ["guild_id", "user_id"]
},
{
columnNames: ["type"]
},
{
columnNames: ["timestamp"]
}
]
})
);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable("name_history");
}
}

View file

@ -0,0 +1,85 @@
import { Plugin, decorators as d } from "knub";
import { GuildNameHistory } from "../data/GuildNameHistory";
import { Member, Message, Relationship, User } from "eris";
import { NameHistoryEntryTypes } from "../data/NameHistoryEntryTypes";
import { createChunkedMessage, errorMessage, trimLines } from "../utils";
export class NameHistoryPlugin extends Plugin {
public static pluginName = "name_history";
protected nameHistory: GuildNameHistory;
getDefaultOptions() {
return {
permissions: {
view: false
},
overrides: [
{
level: ">=50",
permissions: {
view: true
}
}
]
};
}
onLoad() {
this.nameHistory = GuildNameHistory.getInstance(this.guildId);
}
@d.command("names", "<userId:userId>")
@d.permission("view")
async namesCmd(msg: Message, args: { userId: string }) {
const names = await this.nameHistory.getByUserId(args.userId);
if (!names) {
msg.channel.createMessage(errorMessage("No name history found for that user!"));
return;
}
const rows = names.map(entry => {
const type = entry.type === NameHistoryEntryTypes.Username ? "Username" : "Nickname";
const value = entry.value || "<none>";
return `\`[${entry.timestamp}]\` ${type} **${value}**`;
});
const user = this.bot.users.get(args.userId);
const currentUsername = user ? `${user.username}#${user.discriminator}` : args.userId;
const message = trimLines(`
Name history for **${currentUsername}**:
${rows.join("\n")}
`);
createChunkedMessage(msg.channel, message);
}
@d.event("userUpdate")
async onUserUpdate(user: User, oldUser: { username: string; discriminator: string; avatar: string }) {
console.log("onUserUpdate", user.username, oldUser.username);
if (user.username !== oldUser.username || user.discriminator !== oldUser.discriminator) {
const newUsername = `${user.username}#${user.discriminator}`;
await this.nameHistory.addEntry(user.id, NameHistoryEntryTypes.Username, newUsername);
}
}
@d.event("presenceUpdate")
async onPresenceUpdate(other: Member | Relationship) {
const user = other.user;
const username = `${user.username}#${user.discriminator}`;
const lastEntry = await this.nameHistory.getLastEntryByType(user.id, NameHistoryEntryTypes.Username);
if (!lastEntry || lastEntry.value !== username) {
await this.nameHistory.addEntry(user.id, NameHistoryEntryTypes.Username, username);
}
}
@d.event("guildMemberUpdate")
async onGuildMemberUpdate(_, member: Member, oldMember: { nick: string; roles: string[] }) {
if (member.nick !== oldMember.nick) {
await this.nameHistory.addEntry(member.id, NameHistoryEntryTypes.Nickname, member.nick);
}
}
}

View file

@ -1,5 +1,5 @@
import at = require("lodash.at");
import { Guild, GuildAuditLogEntry } from "eris";
import { Guild, GuildAuditLogEntry, TextableChannel } from "eris";
import url from "url";
import tlds from "tlds";
import emojiRegex from "emoji-regex";
@ -276,6 +276,13 @@ export function chunkMessageLines(str: string): string[] {
});
}
export async function createChunkedMessage(channel: TextableChannel, messageText: string) {
const chunks = chunkMessageLines(messageText);
for (const chunk of chunks) {
await channel.createMessage(chunk);
}
}
export function noop() {
// IT'S LITERALLY NOTHING
}