Skip to content

Commit

Permalink
Merge branch 'firebase-store'
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickMatthiesen committed Sep 12, 2023
2 parents 602da50 + 8430ea1 commit a1c4c3f
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 210 deletions.
4 changes: 2 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
"es6": true
},
"parserOptions": {
"ecmaVersion": 2021
"ecmaVersion": "latest"
},
"rules": {
"semi": ["error", "always"],
"max-nested-callbacks": ["error", { "max": 4 }],
"max-statements-per-line": ["error", { "max": 2 }],
"@typescript-eslint/no-inferrable-types": "off"
"@typescript-eslint/no-inferrable-types": "warn"
}
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Go to a link bellow and pick the server you want to add the bot to.

1. Make a channel named `blacklist`.
2. (optional) set a prefix with command `/blacklist set-prefix`
1. Don't recommend doing it later, as support hasn't been added so the blacklist is updated.
1. A prefix is a string that will be added to the start of the header of the message.
2. Don't recommend doing it later, as support hasn't been added so the blacklist is updated.
3. Init the list with `/blacklist inti`.
1. if the chat has an old blacklist, then use the option `has-old-list` set to `true`.
2. If the list should be initialized with additions, then use the option `has-old` set to `true`. Messages in the channel should be in the format `add <name>` to be added on initialization.
Expand Down
4 changes: 2 additions & 2 deletions guilds/793169144757223474/Blacklist.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@
"K",
[
"**--K--**",
"kaasismelk",
"kapitan_pipik",
"KennyandDevon",
"KILL_REBEL",
"KingOfChaos9202",
"ksallis",
"KSWHITESHEEP21",
"kw0512762",
"kzed2003",
"kaasismelk"
"kzed2003"
]
],
[
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
81 changes: 81 additions & 0 deletions src/Firebase/firebase-blacklist-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { BlacklistStore } from '../interfaces/blacklist-store.js';
import { getStorage, Storage } from "firebase-admin/storage";
import { Message } from 'discord.js';

export class FirebaseBlacklistStore implements BlacklistStore {
private folderPath: string;
private store: Storage;

constructor(guildId: string) {
this.folderPath = `guilds/${guildId}`;

this.store = getStorage();
}

async load(): Promise<{ blacklist: Map<string, string[]>; messages: Map<string, Message<boolean>>; }> {
return {
'blacklist': await this.loadBlacklist(),
'messages': await this.loadMessages()
};
}

async loadBlacklist(): Promise<Map<string, string[]>> {
const [contents] = await this.store.bucket().file(`${this.folderPath}/Blacklist.json`).download();
const fileContent = contents.toString();
return new Map(JSON.parse(fileContent));
}

async loadMessages(): Promise<Map<string, Message>> {
const [contents] = await this.store.bucket().file(`${this.folderPath}/messages.json`).download();
const fileContent = contents.toString();
return new Map(JSON.parse(fileContent));
}

async loadConfig(): Promise<Map<string, string>> {
const [contents] = await this.store.bucket().file(`${this.folderPath}/config.json`).download();
const fileContent = contents.toString();
return new Map(JSON.parse(fileContent));
}

async loadByName(name: string): Promise<string | null> {
const [contents] = await this.store.bucket().file(`${this.folderPath}/${name}.json`).download();
return contents.toString();
}

async save(blacklist: Map<string, string[]>, messages: Map<string, Message>) {
await this.saveBlacklist(blacklist);
await this.saveMessages(messages);
}

async saveBlacklist(blacklist: Map<string, string[]>): Promise<void> {
const file = this.store.bucket().file(`${this.folderPath}/Blacklist.json`);
await file.save(JSON.stringify([...blacklist], null, 4), {
gzip: true,
contentType: 'application/json'
});
}

async saveMessages(messages: Map<string, Message<boolean>>) {
const file = this.store.bucket().file(`${this.folderPath}/messages.json`);
await file.save(JSON.stringify([...messages], null, 4), {
gzip: true,
contentType: 'application/json'
});
}

async saveConfig(config: Map<string, string>) {
const file = this.store.bucket().file(`${this.folderPath}/config.json`);
await file.save(JSON.stringify([...config], null, 4), {
gzip: true,
contentType: 'application/json'
});
}

async saveByName(name: string, data: string | Buffer) {
const file = this.store.bucket().file(`${this.folderPath}/${name}.json`);
await file.save(data, {
gzip: true,
contentType: 'application/json'
});
}
}
33 changes: 33 additions & 0 deletions src/Firebase/localStoreToFirebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getStorage } from "firebase-admin/storage";
import { initializeApp } from "firebase-admin/app";
import { readdir } from "node:fs/promises";


// Initialize Firebase
const app = initializeApp();

const storage = getStorage(app);

const dir = await readdir('./guilds/');

for (const subDir of dir) {
console.log(subDir);
const files = await readdir(`./guilds/${subDir}`);
for (const file of files) {
console.log(file);
const responce = await storage.bucket().upload(`guilds/${subDir}/${file}`, {
destination: `guilds/${subDir}/${file}`,
gzip: true,
});
console.log(responce[0].publicUrl());
console.log(responce);
console.log();
}
}

// const file = storage.bucket().file(`guilds/899233872447946804/Blacklist.json`);

// file.download().then((data) => {
// console.log(data[0].toString());
// // console.log(JSON.parse(data.toString()));
// });
97 changes: 60 additions & 37 deletions src/commands/addToList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { ApplicationCommandOptionType, CommandInteraction, Message, TextBasedCha
import { Discord, Slash, SlashGroup, SlashOption } from 'discordx';
import { Blacklist } from '../objects/Blacklist.js';
import { setGuildBlPrefix } from '../objects/GuildDataHandler.js';
import { LocalBlacklistStore } from '../objects/local-blacklist-store.js';
import { FirebaseBlacklistStore } from '../Firebase/firebase-blacklist-store.js';
import { BlacklistStore } from '../interfaces/blacklist-store.js';



Expand All @@ -14,7 +17,7 @@ abstract class BlacklistButler {
@SlashOption({ name: 'name', description: 'name of person', required: false, type: ApplicationCommandOptionType.String })
name: string,
@SlashOption({ name: 'old', description: 'delete all messages and resend the blacklist to chat', required: false, type: ApplicationCommandOptionType.Boolean }) // depricate this
hasOldMessages: boolean = false,
hasOldMessages = false,
// @SlashChoice('One', 'one')
// @SlashOption('amount', { description: 'add all or just one' })
// amount: string,
Expand All @@ -25,13 +28,15 @@ abstract class BlacklistButler {
await interaction.reply({ content: 'please add a name or ask me to add old messages starting with "add "', ephemeral: true });
return;
}
await interaction.deferReply({ ephemeral: true });

const blacklist = new Blacklist(interaction.channel);
blacklist.loadFromFile();
const store = await getStore(interaction.guildId!);
const blacklist = new Blacklist(interaction.channel, store);
await blacklist.init();

if (blacklist.isEmpty()) {
console.log('blacklist is empty');
await interaction.reply({ content: 'something went wrong getting the blacklist', ephemeral: true });
await interaction.editReply({ content: 'something went wrong getting the blacklist' });
return;
}

Expand All @@ -42,7 +47,7 @@ abstract class BlacklistButler {

if (name && !hasOldMessages) {
if (!await blacklist.addOne(name)) {
await interaction.reply({ content: 'something went wrong adding the name', ephemeral: true });
await interaction.editReply({ content: 'something went wrong adding the name' });
return;
}
} else blacklist.add(name);
Expand All @@ -53,79 +58,87 @@ abstract class BlacklistButler {

await blacklist.cleanChat();

await interaction.reply({ content: `${name ? 'added ' + name : ''}${hasOldMessages ? ' and added extra from chat' : ''}`, ephemeral: true });
blacklist.saveBlacklistToFile();
await interaction.editReply({ content: `${name ? 'added ' + name : ''}${hasOldMessages ? ' and added extra from chat' : ''}` });
blacklist.saveBlacklist();
}

@Slash({ name: 'remove', description: 'Removes the user from the blacklist' })
@Slash({ name: 'remove', description: 'Removes a user from the blacklist' })
async remove(
@SlashOption({ name: 'name', description: 'name to remove', type: ApplicationCommandOptionType.String })
name: string,
interaction: CommandInteraction): Promise<void> {
if (!interaction.channel || !await isBlacklistChannel(interaction)) return;

const blacklist = new Blacklist(interaction.channel);
blacklist.loadFromFile();
blacklist.removeOne(name);
await interaction.deferReply({ ephemeral: true });

await interaction.reply({ content: 'name has been removed', ephemeral: true });
const store = await getStore(interaction.guildId!);
const blacklist = new Blacklist(interaction.channel, store);
await blacklist.init();

await blacklist.removeOne(name);

await interaction.editReply({ content: 'name has been removed' });
}

@Slash({ name: 'init', description: 'Adds the users to the blacklist' })
async init(
@SlashOption({ name: 'from-old-list', description: 'use this option if you have an old list to init from', required: false, type: ApplicationCommandOptionType.String })
fromOldList: boolean = false,
fromOldList = false,
@SlashOption({ name: 'has-old', description: '(require "from-old-list = true") if messages like "add `name`" should be added to the list', required: false, type: ApplicationCommandOptionType.String })
hasOldAdds: boolean = false,
hasOldAdds = false,
interaction: CommandInteraction): Promise<void> {
if (!interaction.channel || !await isBlacklistChannel(interaction)) return;

const blacklist = new Blacklist(interaction.channel);
await interaction.deferReply({ ephemeral: true });

const store = await getStore(interaction.guildId!);
const blacklist = new Blacklist(interaction.channel, store);

if (fromOldList) {
if (hasOldAdds) await addAllMessages(interaction.channel, blacklist);
else await addOldMessages(interaction.channel, blacklist);
await interaction.reply({ content: 'stored your list' + (hasOldAdds ? ' and added extras' : '') + ' to the database', ephemeral: true });
await interaction.editReply({ content: 'stored your list' + (hasOldAdds ? ' and added extras' : '') + ' to the database' });

} else {
blacklist.initEmpty();
await interaction.reply({ content: 'I inited the list for you, now just print it :)', ephemeral: true });
await interaction.editReply({ content: 'I inited the list for you, now just print it :)' });
}

blacklist.saveBlacklistToFile();
blacklist.saveBlacklist();

}


@Slash({ name: 'print', description: 'Prints the blacklist to the channel' })
async print(
@SlashOption({ name: 'clean', description: 'delete all other messages before printing the list', required: false, type: ApplicationCommandOptionType.String })
clean: boolean = false,
clean = false,
interaction: CommandInteraction): Promise<void> {
if (!interaction.channel || !await isBlacklistChannel(interaction)) return;

const blacklist = new Blacklist(interaction.channel);
await interaction.deferReply({ ephemeral: true });

const store = await getStore(interaction.guildId!);
const blacklist = new Blacklist(interaction.channel, store);
try {
blacklist.loadFromFile();
console.log("read from file");
blacklist.init();
console.log("read from store");
} catch (error) {
console.log('fuck this');
await interaction.reply({ content: 'something went wrong getting the blacklist', ephemeral: true });
await interaction.editReply({ content: 'something went wrong getting the blacklist' });
return;
}
if (blacklist.isEmpty()) blacklist.initEmpty();


await interaction.deferReply({ ephemeral: true }); //needed as writeing takes a long time

// make an empty blacklist
if (blacklist.isEmpty()) blacklist.initEmpty();

if (clean) await deleteOld(interaction.channel, blacklist.getPrefix());

await blacklist.writeToChat();

await interaction.editReply({ content: 'printet list' });

blacklist.saveMessageIdsToFile();
blacklist.saveMessages();
}

//if you really dont have a life, then make it so it removes all the category headers and add on the new ones
Expand All @@ -138,20 +151,24 @@ abstract class BlacklistButler {
interaction: CommandInteraction): Promise<void> {
if (!interaction.guildId) return;

if (setGuildBlPrefix(interaction.guildId, prefix))
await interaction.reply({ content: 'The headers will now look like ' + prefix + 'A' + prefix.split('').reverse().join(''), ephemeral: true });
else await interaction.reply({ content: 'something went wrong setting the prefix', ephemeral: true });
await interaction.deferReply({ ephemeral: true });

const store = await getStore(interaction.guildId!);

if (await setGuildBlPrefix(interaction.guildId, prefix, store))
await interaction.editReply({ content: 'The headers will now look like ' + prefix + 'A' + prefix.split('').reverse().join('') });
else await interaction.editReply({ content: 'something went wrong setting the prefix' });
}
}

async function isBlacklistChannel(interaction: CommandInteraction) {
if ((interaction.channel as TextChannel).name !== 'blacklist') {
console.log('channel was not a blacklist');
await interaction.reply({ content: 'channel is not a blacklist', ephemeral: true });
return false;
if ((interaction.channel as TextChannel).name == 'blacklist') {
return true;
}

return true;

console.log('channel was not a blacklist');
await interaction.reply({ content: 'channel is not a blacklist', ephemeral: true });
return false;
}

async function addAllMessages(channel: TextBasedChannel, blacklist: Blacklist) {
Expand Down Expand Up @@ -216,3 +233,9 @@ async function addSingles(msg: Message, blacklist: Blacklist) {
}
}

async function getStore(guildId: string): Promise<BlacklistStore> {
if (process.env.STORE_TYPE == 'firebase')
return new FirebaseBlacklistStore(guildId);

return new LocalBlacklistStore(guildId);
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "reflect-metadata";
import { Interaction, Message, IntentsBitField } from "discord.js";
import { Client } from "discordx";
import { dirname, importx } from "@discordx/importer";
import { initializeApp } from "firebase-admin/app";

// set client token
const token = process.env.DISCORD_TOKEN ?? '';
Expand Down Expand Up @@ -55,6 +56,8 @@ client.on('messageCreate', async (message: Message) => {
async function run() {
await importx(dirname(import.meta.url) + "/{events,commands}/**/*.{ts,js}");
await client.login(token); // provide your bot token
if (process.env.STORE_TYPE == 'firebase')
initializeApp();
}

await run();
Expand Down
16 changes: 16 additions & 0 deletions src/interfaces/blacklist-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Message } from "discord.js";

export interface BlacklistStore {
load: () => Promise<{ blacklist: Map<string, string[]>; messages: Map<string, Message<boolean>>; }>;
loadBlacklist: () => Promise<Map<string, string[]>>;
loadMessages: () => Promise<Map<string, Message>>;
loadConfig: () => Promise<Map<string, string>>;
loadByName: (name: string) => Promise<string | null>;


save: (blacklist: Map<string, string[]>, idMap: Map<string, Message>) => Promise<void>;
saveBlacklist: (Blacklist: Map<string, string[]>) => Promise<void>;
saveMessages: (idMap: Map<string, Message>) => Promise<void>;
saveConfig: (config: Map<string, string>) => Promise<void>;
saveByName: (name: string, file: string | Buffer) => Promise<void>;
}
Loading

0 comments on commit a1c4c3f

Please sign in to comment.