From 86764942d9e6a8c72e56db34f7c788507bb67139 Mon Sep 17 00:00:00 2001 From: Ale Date: Sun, 20 Aug 2023 20:44:16 +0200 Subject: [PATCH 01/36] first commit --- .gitignore | 7 +++++++ package.json | 21 +++++++++++++++++++++ src/commands/help.ts | 9 +++++++++ src/commands/help.ts~ | 3 +++ src/index.ts | 20 ++++++++++++++++++++ src/index.ts~ | 18 ++++++++++++++++++ src/repositories/CharacterRepo.ts | 15 +++++++++++++++ src/services/CharacterService.ts | 13 +++++++++++++ src/utils/commandHandler.ts | 23 +++++++++++++++++++++++ src/utils/commandHandler.ts~ | 9 +++++++++ tsconfig.json | 14 ++++++++++++++ 11 files changed, 152 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 src/commands/help.ts create mode 100644 src/commands/help.ts~ create mode 100644 src/index.ts create mode 100644 src/index.ts~ create mode 100644 src/repositories/CharacterRepo.ts create mode 100644 src/services/CharacterService.ts create mode 100644 src/utils/commandHandler.ts create mode 100644 src/utils/commandHandler.ts~ create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39cdef8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules +build +npm-debug.log +.nyc +.env +.DS_Store +config.json \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..615a272 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "cakebot-revolt", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@types/sqlite3": "^3.1.8", + "typescript": "^5.1.3", + "typescript-language-server": "^3.3.2" + }, + "dependencies": { + "revolt.js": "^7.0.0-beta.7", + "shlex": "^2.1.2", + "sqlite3": "^5.1.6" + } +} diff --git a/src/commands/help.ts b/src/commands/help.ts new file mode 100644 index 0000000..05153c5 --- /dev/null +++ b/src/commands/help.ts @@ -0,0 +1,9 @@ +export function returnHelpText() { + return "# Howdy user, welcome to pluralcake\n" + + "pluralcake is a bot that allows you to send messages as your Alters, with a custom profile picture, tag and nickname. \n" + + "It's pretty much a work in progress, and doesn't allow you to edit or delete messages, and to send pictures." + + "The currently available commands are : \n" + + "- list | allows you to see your currently available alters.\n" + + "- create <'name of the alter'> <'your alter s tag'>| Allows you to create your Alters\n" + + "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture" +} diff --git a/src/commands/help.ts~ b/src/commands/help.ts~ new file mode 100644 index 0000000..7ffa94b --- /dev/null +++ b/src/commands/help.ts~ @@ -0,0 +1,3 @@ +export function returnHelpText() { + return "gum" +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..b232baa --- /dev/null +++ b/src/index.ts @@ -0,0 +1,20 @@ +import { Client, Message } from "revolt.js"; +import { commandHandler } from "./utils/commandHandler" +import config from "../config.json" +const client : Client = new Client(); + + +client.on("ready", async () => { + console.info(`Gummed in as ${client.user.username}!`) + client.user.edit({status : {text: config.prefix + "help for the help menu"}}) +}); + +client.on("messageCreate", async (message: Message) => { + if (message.author.bot) {} + else { + if (message.content.startsWith(config.prefix)){commandHandler(message, config.prefix)} + else {} + } +}); + +client.loginBot(config.botKey); diff --git a/src/index.ts~ b/src/index.ts~ new file mode 100644 index 0000000..bf421ed --- /dev/null +++ b/src/index.ts~ @@ -0,0 +1,18 @@ +import { Client, Message } from "revolt.js"; +import { commandHandler } from "./utils/commandHandler" +import config from "../config.json" +const client : Client = new Client(); + + +client.on("ready", async () => + console.info(`Gummed in as ${client.user.username}!`) +); + +client.on("messageCreate", async (message: Message) => { + if (message.author.bot) {} + else { + if (message.content.startsWith(config.prefix)){commandHandler(message, config.prefix)} + } +}); + +client.loginBot(config.botKey); diff --git a/src/repositories/CharacterRepo.ts b/src/repositories/CharacterRepo.ts new file mode 100644 index 0000000..75c9d2f --- /dev/null +++ b/src/repositories/CharacterRepo.ts @@ -0,0 +1,15 @@ +import { Database } from 'sqlite3'; +export class CharacterRepo { + db : Database + constructor() { + this.db = new Database('db.sqlite'); + } + + getAllCharacters(){ + return this.db.get( + 'SELECT * FROM CHARACTERS', + res => console.log(res) + ) + } + +} diff --git a/src/services/CharacterService.ts b/src/services/CharacterService.ts new file mode 100644 index 0000000..5140e20 --- /dev/null +++ b/src/services/CharacterService.ts @@ -0,0 +1,13 @@ +import { CharacterRepo } from "repositories/CharacterRepo"; + +class CharacterService { + repo : CharacterRepo; + + constructor() { + this.repo = new CharacterRepo(); + } + + public getCharacter() : any{ + return this.repo.getAllCharacters(); + } +} \ No newline at end of file diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts new file mode 100644 index 0000000..0d91210 --- /dev/null +++ b/src/utils/commandHandler.ts @@ -0,0 +1,23 @@ +import { Message } from "revolt.js" +import { returnHelpText } from "../commands/help" +import { split } from "shlex" + +export async function commandHandler(message : Message, prefix : String) { + let args : String[] = split(message.content); + args.shift() + const command = args[0] + + switch(command) { + case "help" : { + message.reply(returnHelpText()); + break; + } + case "list" : { + message.reply("not yet implemented") + break; + } + case "create" : { + message.reply("not yet implemented") + } + } +} diff --git a/src/utils/commandHandler.ts~ b/src/utils/commandHandler.ts~ new file mode 100644 index 0000000..fdd5713 --- /dev/null +++ b/src/utils/commandHandler.ts~ @@ -0,0 +1,9 @@ +import { Message } from "revolt.js" + +export function commandHandler(message : Message) { + switch(message.content) { + case "help" : { + } + + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3f3bf8d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "resolveJsonModule" : true, + "target": "es6", + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist", + "baseUrl": "./src" + }, + "lib": ["es2015"] + } + From 5e34da71fbe70cf5f9e8f6b20b8fc79d4145e24a Mon Sep 17 00:00:00 2001 From: ale Date: Sun, 20 Aug 2023 18:51:32 +0000 Subject: [PATCH 02/36] Delete src/index.ts~ --- src/index.ts~ | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/index.ts~ diff --git a/src/index.ts~ b/src/index.ts~ deleted file mode 100644 index bf421ed..0000000 --- a/src/index.ts~ +++ /dev/null @@ -1,18 +0,0 @@ -import { Client, Message } from "revolt.js"; -import { commandHandler } from "./utils/commandHandler" -import config from "../config.json" -const client : Client = new Client(); - - -client.on("ready", async () => - console.info(`Gummed in as ${client.user.username}!`) -); - -client.on("messageCreate", async (message: Message) => { - if (message.author.bot) {} - else { - if (message.content.startsWith(config.prefix)){commandHandler(message, config.prefix)} - } -}); - -client.loginBot(config.botKey); From c92d27779f3ed5b952d2a35adcf8b84e871fab48 Mon Sep 17 00:00:00 2001 From: ale Date: Sun, 20 Aug 2023 18:51:37 +0000 Subject: [PATCH 03/36] Delete src/utils/commandHandler.ts~ --- src/utils/commandHandler.ts~ | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/utils/commandHandler.ts~ diff --git a/src/utils/commandHandler.ts~ b/src/utils/commandHandler.ts~ deleted file mode 100644 index fdd5713..0000000 --- a/src/utils/commandHandler.ts~ +++ /dev/null @@ -1,9 +0,0 @@ -import { Message } from "revolt.js" - -export function commandHandler(message : Message) { - switch(message.content) { - case "help" : { - } - - } -} From 28ea67ea41a22e4ed5cc4e4164d80ebed07a524b Mon Sep 17 00:00:00 2001 From: ale Date: Sun, 20 Aug 2023 18:51:46 +0000 Subject: [PATCH 04/36] Delete src/commands/help.ts~ --- src/commands/help.ts~ | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/commands/help.ts~ diff --git a/src/commands/help.ts~ b/src/commands/help.ts~ deleted file mode 100644 index 7ffa94b..0000000 --- a/src/commands/help.ts~ +++ /dev/null @@ -1,3 +0,0 @@ -export function returnHelpText() { - return "gum" -} From 86e8d2582eb187f9a1c6726acf9dbf901e63342a Mon Sep 17 00:00:00 2001 From: Ale Date: Sat, 2 Sep 2023 23:21:55 +0200 Subject: [PATCH 05/36] feat: Finished rewriting the bot, finally --- .gitignore | 6 ++-- src/commands/avatarAlterChange.ts | 28 ++++++++++++++++ src/commands/createAlter.ts | 54 +++++++++++++++++++++++++++++++ src/commands/deleteAlter.ts | 24 ++++++++++++++ src/commands/listAlters.ts | 16 +++++++++ src/index.ts | 11 +++++-- src/models/alterModel.ts | 8 +++++ src/models/alterModel.ts~ | 7 ++++ src/repositories/AlterRepo.ts | 39 ++++++++++++++++++++++ src/repositories/CharacterRepo.ts | 15 --------- src/services/CharacterService.ts | 13 -------- src/utils/commandHandler.ts | 23 +++++++++++-- src/utils/dbInit.ts | 5 +++ src/utils/nonCommandHandler.ts | 45 ++++++++++++++++++++++++++ src/utils/tableConstructor.ts | 11 +++++++ 15 files changed, 269 insertions(+), 36 deletions(-) create mode 100644 src/commands/avatarAlterChange.ts create mode 100644 src/commands/createAlter.ts create mode 100644 src/commands/deleteAlter.ts create mode 100644 src/commands/listAlters.ts create mode 100644 src/models/alterModel.ts create mode 100644 src/models/alterModel.ts~ create mode 100644 src/repositories/AlterRepo.ts delete mode 100644 src/repositories/CharacterRepo.ts delete mode 100644 src/services/CharacterService.ts create mode 100644 src/utils/dbInit.ts create mode 100644 src/utils/nonCommandHandler.ts create mode 100644 src/utils/tableConstructor.ts diff --git a/.gitignore b/.gitignore index 39cdef8..2999d61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ node_modules -build +dist +package-lock.json npm-debug.log .nyc .env .DS_Store -config.json \ No newline at end of file +config.json +*.db \ No newline at end of file diff --git a/src/commands/avatarAlterChange.ts b/src/commands/avatarAlterChange.ts new file mode 100644 index 0000000..ff262ff --- /dev/null +++ b/src/commands/avatarAlterChange.ts @@ -0,0 +1,28 @@ +import { AlterModel } from "../models/alterModel" +import { AlterRepo } from "../repositories/AlterRepo" + +export async function avatarAlterChange(userId: string, args: string[]){ + const alterRepo = new AlterRepo(); + let userAlters : AlterModel[] = []; + await alterRepo.getAltersByUserId(userId).then( result => userAlters = result ) + + let userAltersNames : string[] = []; + userAlters.forEach(alter => userAltersNames.push(alter.name)); + + if (args.length == 2) { + if (userAltersNames.includes(args[0])){ + userAlters.forEach( alter => { + if (alter.name == args[0]) { + alter.profile_pic_url = args[1]; + alterRepo.editAlter(alter) + } + }) + } + return "The profile picture has been changed" + } + + if (args.length != 2) { + return "Error: Insufficent number of arguments. \nexample: !ck avatar < name > < url >" + } + +} diff --git a/src/commands/createAlter.ts b/src/commands/createAlter.ts new file mode 100644 index 0000000..93e648e --- /dev/null +++ b/src/commands/createAlter.ts @@ -0,0 +1,54 @@ +import { AlterRepo } from "../repositories/AlterRepo"; +import { AlterModel } from "models/alterModel" + +export async function createAlter(userId: string, args: string[]){ + const alterRepo = new AlterRepo(); + + const model: AlterModel = { + owner: userId, + name: args[0], + prefix: args[1], + profile_pic_url: "https://tse3.mm.bing.net/th?id=OIP.yte7rRnbCnWi1giriwTOvwHaHa&pid=15.1" + } + + let userAlters: AlterModel[]; + await alterRepo.getAltersByUserId(userId).then(result => userAlters = result) + + let alterTags : string[] = []; + userAlters.forEach( alter => { + alterTags.push(alter.prefix) + }) + + let alterNames : string[] = []; + userAlters.forEach ( alter => { + alterNames.push(alter.name) + }) + + if (args.length == 2 + && args[1].includes("text") + && !alterTags.includes(args[1]) + && args[1] != "text" + && !alterNames.includes(args[0])) { + + alterRepo.addAlterForUser(model); + return "Alter < " + model.name + " > has been succefully created" + + } + else { + if (args.length != 2){ + return "Error: Insufficent arguments"; + } + if (args[1] === "text"){ + return "Error: Tag may not be only "; + } + if (!args[1].includes("text")) { + return "Error: This command requires a tag that contains in it"; + } + if (alterTags.includes(args[1])) { + return "Error: You already have an Alter with that tag" + } + if (alterNames.includes(args[0])) { + return "Error: You can only have one Alter with that name" + } + } +} diff --git a/src/commands/deleteAlter.ts b/src/commands/deleteAlter.ts new file mode 100644 index 0000000..989e881 --- /dev/null +++ b/src/commands/deleteAlter.ts @@ -0,0 +1,24 @@ +import { AlterRepo } from "../repositories/AlterRepo" +import { AlterModel } from "../models/alterModel" + +export async function deleteAlter(userId: string, args: string[]) { + const alterRepo = new AlterRepo(); + let success: boolean = false; + + if (args.length === 1) { + let alters: AlterModel[]; + await alterRepo.getAltersByUserId(userId).then(result => alters = result ) + alters.forEach(alter => { + if (alter.name == args[0]) { + alterRepo.deleteAlter(alter.id) + success = true; + } + }) + } + if (success) { + return "Alter has been deleted" + } + else { + return "Failed to delete Alter" + } +} diff --git a/src/commands/listAlters.ts b/src/commands/listAlters.ts new file mode 100644 index 0000000..3ad9918 --- /dev/null +++ b/src/commands/listAlters.ts @@ -0,0 +1,16 @@ +import { AlterRepo } from "../repositories/AlterRepo" +import { AlterModel } from "../models/alterModel" +import { tableConstructor } from '../utils/tableConstructor' + +export async function listAlters(userId: string) { + const alterRepo = new AlterRepo(); + let alters: AlterModel[]; + await alterRepo.getAltersByUserId(userId).then(result => { alters = result }) + + if (alters.length > 0 ) { + return tableConstructor(alters) + } + else { + return "No Alters found for this user" + } +} diff --git a/src/index.ts b/src/index.ts index b232baa..77e09ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,24 @@ import { Client, Message } from "revolt.js"; import { commandHandler } from "./utils/commandHandler" +import { nonCommandHandler } from "./utils/nonCommandHandler" import config from "../config.json" const client : Client = new Client(); client.on("ready", async () => { console.info(`Gummed in as ${client.user.username}!`) - client.user.edit({status : {text: config.prefix + "help for the help menu"}}) + client.user.edit({status : {text: config.prefix + " help for the help menu"}}) }); client.on("messageCreate", async (message: Message) => { if (message.author.bot) {} else { - if (message.content.startsWith(config.prefix)){commandHandler(message, config.prefix)} - else {} + if (message.content.startsWith(config.prefix)) { + commandHandler(message, config.prefix); + } + else { + nonCommandHandler(message); + } } }); diff --git a/src/models/alterModel.ts b/src/models/alterModel.ts new file mode 100644 index 0000000..2eb4e19 --- /dev/null +++ b/src/models/alterModel.ts @@ -0,0 +1,8 @@ +export interface AlterModel { + id?: number; + owner: string; + prefix: string; + name: string; + profile_pic_url: string; + color?: string; +} diff --git a/src/models/alterModel.ts~ b/src/models/alterModel.ts~ new file mode 100644 index 0000000..1dacc0d --- /dev/null +++ b/src/models/alterModel.ts~ @@ -0,0 +1,7 @@ +export interface AlterModel { + id?: number; + owner: string; + prefix: string; + name: string; + profile_pic_url: string; +} diff --git a/src/repositories/AlterRepo.ts b/src/repositories/AlterRepo.ts new file mode 100644 index 0000000..4084504 --- /dev/null +++ b/src/repositories/AlterRepo.ts @@ -0,0 +1,39 @@ +import { Database } from 'sqlite3'; +import { AlterModel } from '../models/alterModel' +import config from "../../config.json" + +export class AlterRepo { + db : Database + constructor() { + this.db = new Database(config.databaseName); + this.db.run("CREATE TABLE IF NOT EXISTS alters (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)") + } + + async getAltersByUserId(userId : string) : Promise { + const query : string = 'SELECT * FROM alters WHERE alters.owner = "' + userId + '"' + + let result: AlterModel[] = await new Promise((resolve, reject) => { + this.db.all(query, (err, row: AlterModel[]) => { + if (err) { return reject(err)} + else { return resolve(row) } + }) + }) + + return result + } + + addAlterForUser(alter: AlterModel){ + this.db.run("INSERT INTO alters (owner, prefix, name, profile_pic_url, color) VALUES(?, ?, ?, ?, ?)", + [alter.owner, alter.prefix, alter.name, alter.profile_pic_url]) + } + + editAlter(alter: AlterModel){ + this.db.run("UPDATE alters SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE alters.id ='" + alter.id + "'", + [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color]) + } + + deleteAlter(alterId: number) { + this.db.run("DELETE FROM alters WHERE alters.id='"+ alterId + "'") + } + +} diff --git a/src/repositories/CharacterRepo.ts b/src/repositories/CharacterRepo.ts deleted file mode 100644 index 75c9d2f..0000000 --- a/src/repositories/CharacterRepo.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Database } from 'sqlite3'; -export class CharacterRepo { - db : Database - constructor() { - this.db = new Database('db.sqlite'); - } - - getAllCharacters(){ - return this.db.get( - 'SELECT * FROM CHARACTERS', - res => console.log(res) - ) - } - -} diff --git a/src/services/CharacterService.ts b/src/services/CharacterService.ts deleted file mode 100644 index 5140e20..0000000 --- a/src/services/CharacterService.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CharacterRepo } from "repositories/CharacterRepo"; - -class CharacterService { - repo : CharacterRepo; - - constructor() { - this.repo = new CharacterRepo(); - } - - public getCharacter() : any{ - return this.repo.getAllCharacters(); - } -} \ No newline at end of file diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index 0d91210..d2b414a 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -1,11 +1,16 @@ import { Message } from "revolt.js" import { returnHelpText } from "../commands/help" +import { listAlters } from "../commands/listAlters" +import { createAlter } from "../commands/createAlter" +import { deleteAlter } from "../commands/deleteAlter" +import { avatarAlterChange } from "../commands/avatarAlterChange" import { split } from "shlex" export async function commandHandler(message : Message, prefix : String) { - let args : String[] = split(message.content); + let args : string[] = split(message.content); args.shift() const command = args[0] + args.shift() switch(command) { case "help" : { @@ -13,11 +18,23 @@ export async function commandHandler(message : Message, prefix : String) { break; } case "list" : { - message.reply("not yet implemented") + await message.reply(await listAlters(message.author.id)); break; } case "create" : { - message.reply("not yet implemented") + await message.reply(await createAlter(message.author.id, args)); + break } + case "delete" : { + await message.reply(await deleteAlter(message.author.id, args)) + break + } + case "avatar" : { + await message.reply(await avatarAlterChange(message.author.id, args)); + break + } + case "color" : { + break + } } } diff --git a/src/utils/dbInit.ts b/src/utils/dbInit.ts new file mode 100644 index 0000000..64b3d61 --- /dev/null +++ b/src/utils/dbInit.ts @@ -0,0 +1,5 @@ + + +export function dbInit(){ + +} diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts new file mode 100644 index 0000000..e9b4f5b --- /dev/null +++ b/src/utils/nonCommandHandler.ts @@ -0,0 +1,45 @@ +import { Message } from "revolt.js" +import { AlterRepo } from "../repositories/AlterRepo" +import { AlterModel } from "../models/alterModel" + +export async function nonCommandHandler(message : Message){ + const alterRepo: AlterRepo = new AlterRepo(); + let alters: AlterModel[]; + await alterRepo.getAltersByUserId(message.author.id).then(result => alters = result); + + alters.forEach( async alter => { + const pre_prefix = alter.prefix.split("text"); + if (message.content.startsWith(pre_prefix[0]) && message.content.endsWith(pre_prefix[1])) { + let actualContent: string = message.content; + actualContent = actualContent.slice(pre_prefix[0].length, actualContent.length - pre_prefix[1].length) + + const replyIds: string[] | undefined = message.replyIds; + let replies: any[] = []; + + if (replyIds !== undefined) { + replyIds.forEach( replyId => { + replies.push({ + id: replyId, + mention: false + }) + }) + } + + try{ + await message.channel.sendMessage({ + content: actualContent, + masquerade: { + name: alter.name, + avatar: alter.profile_pic_url, + color: alter.color + }, + replies: replies + }) + await message.delete(); + } + catch(e){ + await message.channel.sendMessage("Error: PluralCake requires at least these permissions: \n- Masquerade permissions. \n- Message editing permissions.") + } + } + }) +} diff --git a/src/utils/tableConstructor.ts b/src/utils/tableConstructor.ts new file mode 100644 index 0000000..416fa47 --- /dev/null +++ b/src/utils/tableConstructor.ts @@ -0,0 +1,11 @@ +import { AlterModel } from '../models/alterModel' +export function tableConstructor(data: AlterModel[]){ + const header = "| Name | tag |\n|----|----|\n" + let body : string = ""; + data.forEach(alter => { + body = body + + "|" + alter.name + "|" + alter.prefix + "|\n" + }) + body = body.slice(0, body.length - 2) + return header + body +} From 6dc0f3ca8d1f93fd872076f54ce1f66c8151e32f Mon Sep 17 00:00:00 2001 From: Ale Date: Mon, 4 Sep 2023 10:41:08 +0200 Subject: [PATCH 06/36] fix: Crash --- src/index.ts | 2 +- src/models/alterModel.ts~ | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 src/models/alterModel.ts~ diff --git a/src/index.ts b/src/index.ts index 77e09ed..f36b246 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { Client, Message } from "revolt.js"; import { commandHandler } from "./utils/commandHandler" import { nonCommandHandler } from "./utils/nonCommandHandler" import config from "../config.json" -const client : Client = new Client(); +const client : Client = new Client({ eagerFetching: false }); client.on("ready", async () => { diff --git a/src/models/alterModel.ts~ b/src/models/alterModel.ts~ deleted file mode 100644 index 1dacc0d..0000000 --- a/src/models/alterModel.ts~ +++ /dev/null @@ -1,7 +0,0 @@ -export interface AlterModel { - id?: number; - owner: string; - prefix: string; - name: string; - profile_pic_url: string; -} From 6574d2af48f7d67798559f006c82860958e0cf9a Mon Sep 17 00:00:00 2001 From: Ale Date: Mon, 4 Sep 2023 10:57:25 +0200 Subject: [PATCH 07/36] fix: Crash p2 --- src/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index f36b246..9153f93 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,8 +11,11 @@ client.on("ready", async () => { }); client.on("messageCreate", async (message: Message) => { - if (message.author.bot) {} - else { + try{if (!message.author) await client.users.fetch(message.authorId)} + catch(e){console.log(e)} + + if (message.author?.bot) {} + else { if (message.content.startsWith(config.prefix)) { commandHandler(message, config.prefix); } From 634b16bd350b6a73552d636ff48830e47978da9d Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:23:53 +0200 Subject: [PATCH 08/36] fix: trying to fix stuff --- src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9153f93..19f5788 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,9 +11,8 @@ client.on("ready", async () => { }); client.on("messageCreate", async (message: Message) => { - try{if (!message.author) await client.users.fetch(message.authorId)} - catch(e){console.log(e)} - + try{if (!message.author)} catch(e) { await client.users.fetch(message.authorId) } + if (message.author?.bot) {} else { if (message.content.startsWith(config.prefix)) { From fcb32abe6b5c434831a092b4c5f659a7377b8cde Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:25:10 +0200 Subject: [PATCH 09/36] fix: trying to fix stuff --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 19f5788..f26cf6f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ client.on("ready", async () => { }); client.on("messageCreate", async (message: Message) => { - try{if (!message.author)} catch(e) { await client.users.fetch(message.authorId) } + try{if (!message.author){}} catch(e) { await client.users.fetch(message.authorId) } if (message.author?.bot) {} else { From 14f8ad4580573dd525b9a8e42cb636feb1e6e5c3 Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:28:54 +0200 Subject: [PATCH 10/36] fix: trying to fix stuff p3 --- src/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index f26cf6f..f603859 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,11 +11,12 @@ client.on("ready", async () => { }); client.on("messageCreate", async (message: Message) => { - try{if (!message.author){}} catch(e) { await client.users.fetch(message.authorId) } - + try{if (!message.author) {await client.users.fetch(message.authorId)} } + catch(e){console.log(e)} + if (message.author?.bot) {} else { - if (message.content.startsWith(config.prefix)) { + if (message?.content.startsWith(config.prefix)) { commandHandler(message, config.prefix); } else { From 943946b7b2ad40bc1d86230062bd2ac96bbc810d Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:40:46 +0200 Subject: [PATCH 11/36] feat: user name --- src/index.ts | 12 ++++++------ src/utils/nonCommandHandler.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index f603859..6e4e509 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,13 +16,13 @@ client.on("messageCreate", async (message: Message) => { if (message.author?.bot) {} else { - if (message?.content.startsWith(config.prefix)) { - commandHandler(message, config.prefix); - } - else { - nonCommandHandler(message); - } + if (message?.content.startsWith(config.prefix)) { + commandHandler(message, config.prefix); } + else { + nonCommandHandler(message); + } + } }); client.loginBot(config.botKey); diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index e9b4f5b..6443639 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -29,7 +29,7 @@ export async function nonCommandHandler(message : Message){ await message.channel.sendMessage({ content: actualContent, masquerade: { - name: alter.name, + name: alter.name + " ( " + message.author.id + " )", avatar: alter.profile_pic_url, color: alter.color }, From 2730c4373ac72db8fb2b0205915e7e8b51bfe9dd Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:44:39 +0200 Subject: [PATCH 12/36] feat: user name something --- src/utils/nonCommandHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index 6443639..9cea311 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -29,7 +29,7 @@ export async function nonCommandHandler(message : Message){ await message.channel.sendMessage({ content: actualContent, masquerade: { - name: alter.name + " ( " + message.author.id + " )", + name: alter.name + " ( " + message.author.member.displayName + " )", avatar: alter.profile_pic_url, color: alter.color }, From 28ed823e2b790a703ad8fe8395d76f78f40e5f32 Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 19:51:19 +0200 Subject: [PATCH 13/36] feat: removed user name something --- src/utils/nonCommandHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index 9cea311..43838fa 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -29,7 +29,7 @@ export async function nonCommandHandler(message : Message){ await message.channel.sendMessage({ content: actualContent, masquerade: { - name: alter.name + " ( " + message.author.member.displayName + " )", + name: alter.name , avatar: alter.profile_pic_url, color: alter.color }, @@ -38,6 +38,7 @@ export async function nonCommandHandler(message : Message){ await message.delete(); } catch(e){ + console.log(e) await message.channel.sendMessage("Error: PluralCake requires at least these permissions: \n- Masquerade permissions. \n- Message editing permissions.") } } From 680eeea7a15e279a544940960aadb8a431e7e76c Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 20:07:46 +0200 Subject: [PATCH 14/36] feat: adding color changing --- src/commands/colorAlterChange.ts | 1 + src/commands/colorAlterChange.ts~ | 1 + src/index.ts | 5 +++-- src/utils/commandHandler.ts | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/commands/colorAlterChange.ts create mode 100644 src/commands/colorAlterChange.ts~ diff --git a/src/commands/colorAlterChange.ts b/src/commands/colorAlterChange.ts new file mode 100644 index 0000000..85b0824 --- /dev/null +++ b/src/commands/colorAlterChange.ts @@ -0,0 +1 @@ +export async function colorAlterChange(userId: string, args: string[]){} diff --git a/src/commands/colorAlterChange.ts~ b/src/commands/colorAlterChange.ts~ new file mode 100644 index 0000000..42fe4ad --- /dev/null +++ b/src/commands/colorAlterChange.ts~ @@ -0,0 +1 @@ +export function colorAlterChange(userId: string, args: string[]){} diff --git a/src/index.ts b/src/index.ts index 6e4e509..dac85a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,10 +13,11 @@ client.on("ready", async () => { client.on("messageCreate", async (message: Message) => { try{if (!message.author) {await client.users.fetch(message.authorId)} } catch(e){console.log(e)} - + + if (message === undefined) {return} if (message.author?.bot) {} else { - if (message?.content.startsWith(config.prefix)) { + if (message.content.startsWith(config.prefix)) { commandHandler(message, config.prefix); } else { diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index d2b414a..b04b6e8 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -4,6 +4,7 @@ import { listAlters } from "../commands/listAlters" import { createAlter } from "../commands/createAlter" import { deleteAlter } from "../commands/deleteAlter" import { avatarAlterChange } from "../commands/avatarAlterChange" +import { colorAlterChange } from "../commands/colorAlterChange" import { split } from "shlex" export async function commandHandler(message : Message, prefix : String) { @@ -34,6 +35,7 @@ export async function commandHandler(message : Message, prefix : String) { break } case "color" : { + await message.reply(await colorAlterChange(message.author.id, args)); break } } From c55fe93901ec58d36882bd40d49ad930b0fd554c Mon Sep 17 00:00:00 2001 From: Ale Date: Tue, 5 Sep 2023 20:34:33 +0200 Subject: [PATCH 15/36] feat: adding color changing rule --- src/commands/colorAlterChange.ts | 15 ++++++++++++++- src/commands/help.ts | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/commands/colorAlterChange.ts b/src/commands/colorAlterChange.ts index 85b0824..a9207c6 100644 --- a/src/commands/colorAlterChange.ts +++ b/src/commands/colorAlterChange.ts @@ -1 +1,14 @@ -export async function colorAlterChange(userId: string, args: string[]){} +import { AlterRepo } from "../repositories/AlterRepo" + +export async function colorAlterChange(userId: string, args: string[]){ + const alterRepo = new AlterRepo(); + + if (args.length == 2){ + const alterName = args[0]; + const alterColor = args[1]; + + + + return "The Alter's colour has been changed" + } +} diff --git a/src/commands/help.ts b/src/commands/help.ts index 05153c5..4314b71 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -5,5 +5,6 @@ export function returnHelpText() { "The currently available commands are : \n" + "- list | allows you to see your currently available alters.\n" + "- create <'name of the alter'> <'your alter s tag'>| Allows you to create your Alters\n" + - "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture" + "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture" + + "- color <'Alter's name'> | Allows you to change the color of your alter ( may be integrated with the website )" } From d6e2d6d7873f5bb685cabd1eb4f99de3d312dc1d Mon Sep 17 00:00:00 2001 From: Ale Date: Thu, 7 Sep 2023 15:18:21 +0200 Subject: [PATCH 16/36] fix: hopefully fixed the crash heeheheheheha --- config.json~ | 5 +++++ src/commands/colorAlterChange.ts | 24 ++++++++++++++++++++---- src/commands/help.ts | 5 +++-- src/index.ts | 3 +++ src/utils/commandHandler.ts | 2 +- 5 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 config.json~ diff --git a/config.json~ b/config.json~ new file mode 100644 index 0000000..ca5a604 --- /dev/null +++ b/config.json~ @@ -0,0 +1,5 @@ +{ + "botKey" : "iK90dt8JNL3JQCKitafcTVH8pWAYCSws-4Wp348tO_7UQ3haT1B0KzfmQcAxxw0d", + "prefix" : "!rck", + "databaseName" : "PluralCakeDatabase.db" +} diff --git a/src/commands/colorAlterChange.ts b/src/commands/colorAlterChange.ts index a9207c6..15bee40 100644 --- a/src/commands/colorAlterChange.ts +++ b/src/commands/colorAlterChange.ts @@ -1,14 +1,30 @@ import { AlterRepo } from "../repositories/AlterRepo" +import { AlterModel } from "../models/alterModel" export async function colorAlterChange(userId: string, args: string[]){ const alterRepo = new AlterRepo(); - - if (args.length == 2){ + const regexHex = /^#[0-9A-F]{6}$/i; + + if (args.length == 2 && regexHex.test(args[1])){ const alterName = args[0]; const alterColor = args[1]; + let alters: AlterModel[]; + await alterRepo.getAltersByUserId(userId).then( result => alters = result ) // fetching alters from user. + if (alters.length == 0) return "This user has no Alters." // checking if returned array is at least not 0, if len 0, then return. + + let alterToEdit: AlterModel; + alters.forEach( alter => { + if (alter.name == alterName) { + alterToEdit = alter; + } + }) + + alterToEdit.color = alterColor; + alterRepo.editAlter(alterToEdit) - - return "The Alter's colour has been changed" + return "The Alter's colour has been changed." } + + return "Error: Insufficent Arguments" } diff --git a/src/commands/help.ts b/src/commands/help.ts index 4314b71..b8a5f89 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -3,8 +3,9 @@ export function returnHelpText() { "pluralcake is a bot that allows you to send messages as your Alters, with a custom profile picture, tag and nickname. \n" + "It's pretty much a work in progress, and doesn't allow you to edit or delete messages, and to send pictures." + "The currently available commands are : \n" + + "### Alters:\n" + "- list | allows you to see your currently available alters.\n" + "- create <'name of the alter'> <'your alter s tag'>| Allows you to create your Alters\n" + - "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture" + - "- color <'Alter's name'> | Allows you to change the color of your alter ( may be integrated with the website )" + "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture\n" + + "- color <'Alter's name'> <'color hex'> | Allows you to change the color of your alter ( may be integrated with the website )" } diff --git a/src/index.ts b/src/index.ts index dac85a9..2509765 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,9 @@ client.on("messageCreate", async (message: Message) => { try{if (!message.author) {await client.users.fetch(message.authorId)} } catch(e){console.log(e)} + try{if (!messafe.content) {await client.messages.fetch(message.id)}} + catch(e){console.log(e)} + if (message === undefined) {return} if (message.author?.bot) {} else { diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index b04b6e8..8533f1a 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -7,7 +7,7 @@ import { avatarAlterChange } from "../commands/avatarAlterChange" import { colorAlterChange } from "../commands/colorAlterChange" import { split } from "shlex" -export async function commandHandler(message : Message, prefix : String) { +export async function commandHandler(message : Message, _prefix : String) { let args : string[] = split(message.content); args.shift() const command = args[0] From 80e5a996d213193b4aaba534e2421ae40bc29dc8 Mon Sep 17 00:00:00 2001 From: ale Date: Thu, 7 Sep 2023 13:19:47 +0000 Subject: [PATCH 17/36] Delete config.json~ --- config.json~ | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 config.json~ diff --git a/config.json~ b/config.json~ deleted file mode 100644 index ca5a604..0000000 --- a/config.json~ +++ /dev/null @@ -1,5 +0,0 @@ -{ - "botKey" : "iK90dt8JNL3JQCKitafcTVH8pWAYCSws-4Wp348tO_7UQ3haT1B0KzfmQcAxxw0d", - "prefix" : "!rck", - "databaseName" : "PluralCakeDatabase.db" -} From ce331b572027058533e72f5d22624d953b851dbf Mon Sep 17 00:00:00 2001 From: ale Date: Thu, 7 Sep 2023 13:20:12 +0000 Subject: [PATCH 18/36] Update src/index.ts --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 2509765..c954bf2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ client.on("messageCreate", async (message: Message) => { try{if (!message.author) {await client.users.fetch(message.authorId)} } catch(e){console.log(e)} - try{if (!messafe.content) {await client.messages.fetch(message.id)}} + try{if (!message.content) {await client.messages.fetch(message.id)}} catch(e){console.log(e)} if (message === undefined) {return} From fa072fd9bf35ff4eda3fe57e7f0cf8e8780165d3 Mon Sep 17 00:00:00 2001 From: Ale Date: Thu, 7 Sep 2023 15:41:29 +0200 Subject: [PATCH 19/36] fix: hopefully fixed the crash heeheheheheha again --- src/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index c954bf2..f3d2bb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,11 +13,8 @@ client.on("ready", async () => { client.on("messageCreate", async (message: Message) => { try{if (!message.author) {await client.users.fetch(message.authorId)} } catch(e){console.log(e)} - - try{if (!message.content) {await client.messages.fetch(message.id)}} - catch(e){console.log(e)} - if (message === undefined) {return} + if (message.content === undefined) {return} if (message.author?.bot) {} else { if (message.content.startsWith(config.prefix)) { From 80b9aab3f76a35c727797f6558d7fe23c08b01fe Mon Sep 17 00:00:00 2001 From: Ale Date: Sat, 9 Dec 2023 22:46:55 +0100 Subject: [PATCH 20/36] FEAT: added tupper migrations from json file --- bun.lockb | Bin 0 -> 57707 bytes package.json | 2 +- src/commands/colorAlterChange.ts~ | 1 - src/commands/createAlter.ts | 12 +++++----- src/commands/help.ts | 6 ++++- src/commands/migrateAlters.ts | 35 ++++++++++++++++++++++++++++++ src/index.ts | 2 +- src/utils/commandHandler.ts | 17 ++++++++++----- 8 files changed, 60 insertions(+), 15 deletions(-) create mode 100755 bun.lockb delete mode 100644 src/commands/colorAlterChange.ts~ create mode 100644 src/commands/migrateAlters.ts diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..34c1ebd37c6d1d560e579109816d1858277b9a4d GIT binary patch literal 57707 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

$J}zzdQ@EKD0})QQSYKn`gf;PeV+~ z0T;=3_wBZ?2AiEyEv?F?_Q)L?ic_41oTy+(oe zgZ$3&sarp|N3U6S>2rac_R7-q0O#p!H={cCcFhnb&HDom%{bj~yl%O>nG1pLM(h69 z7Q>bp=jFnZPCv5cLx z&mPAHobF+~?klY&+7Ao@oRb$iL^kO5MEFgfp=U5sYTI^Da7ac%ZaVn9aGyZBOYe~S z_FH?G@4w$@Ks~H~YUD-Yqql-@uCR6CbdTV5OCAQ~Q50>Im!a`~Jn7Zfl0<15tQTQY z;*jP*HM(srm13;?!CouASFejxtY5^D^u%@cuOAFFrF&@8nthB}_aja>0&nYcCR$;JRD}`r8KpRZka#Jrpik+{hFKT)kA_l8Bpb&Te0uB?xl|xv!7Z;PuzQ_qlvztJ%!QT z9T&JG*wyYmWoe<2dZNu55OTK=O4z|mMYuZ95xl1vcA@i3faDR@S%`eK!odhmJ%l4^5Do44Ta7W9-QI!_=5H(} z3YMsIJ5^fVVpBp>uv|*dtHS#qc|H4d+?zyL&U3vkxhIx;A;ZvzCF=PO>fN2x9GzuD zqH&vIdDJ()EbGyzEA%;i5~q6tuY2xkFIVPDSt>W-9Afm+bIrxutW~dMiEm*mFj=3u zTqCk7B59XNpmuxh2RgSwL2lO{o?#mgW?V}=o9c9XdBu|yoGxkuOT=lO$-?t4N3RIn z_qVB4Uo5;VFH>Q3mvv4px1(SDhc%2ZB9>kceCAwHvVLP2A&v&5tS$FWAf%jLsrhd{5zZbG%Y7UeInER^B$Wy@ldB(IoC} z-jPk)eQk9ncH9ce-ut+MG5`J9Z%eK7&XhcFJ3&w9)n(+ikK(dbq_|&3E8kw6ZaiLB zAT&sYPC3n$Ygj7Avt=l2^#Y#YdzVjql)UGk@*#L&;^Ug4teSf=-xFiX>H^$rMjX;v zoR7o>hHj>3Y#0JUukRL@ z$zd46XlN%fQore*QtwA^&jRW5m$+W*#p~Q(yWv_`(jGsmeH$VIE}!K3+``q+|+5fKy7K)j_nG9JAb{XXTlg{tTQ5)FrvQfhY?SHBFySDIU zs9o&$u=X#Q{ks-YCj$Qq5kTv*arNx)`8@*r-`)rR7hL{n6R00^xexx7JjYDb2KJkh zOzg8ULwVTmOX@=&+SiC=JC!G4!Bb=_ZQOzby0@jhd}*SUgs_IEXZruTn)9_lZ+ zKl3}Gjr@Pjdo<_&|C;x3jQ^AVMBq;Z{zTwU1pY+ePXzu%;7o%>thr6W+ z$=Sox+|g0Q(Z$lihU921V&HCVt;i`Z%IQJ!w|21+;*{hxcO=<5yV$@7Qm&OQ2m zJQ~j!02+5R&S+fGI5GjyxH1FKSi)C_W`27KjRlH5e8q2O>{fv71T+E~0M`LkfNH=s zKn=hi-~h-5TQxj>Z^;j|0FB-~p@!pzj{=0n`C#oHYQNfNcOY#%N5@7@{%T z0oVyJ0HE<=1l$EQ0qz0r1DXL305<^p0J(s302@FiAPa!z7Me?Fo}hVw<^dY_48U1{ zFd!1(0&oR*0uBHI03iTJfF-~buph7o@DR`nXalqWYym0&Rlp{IJU|g32#5e20)zsL z0eb;zfG|Kf;2@w9Ko7VLI1gY4tO2Y8YzK${L;(T-ZvY8k0Wb%c0Sp0l0F4y*2T~pC zB&6TXSu|E?9iw@H#u8~#089WVmQ(;r0P=Sk0QoKk*Z@GjA%B+uP`w2JA^^>w#Q<6W z4S*W35U_}BvDZt<*GQKIfaW2Zk7$gS0~i2k4x;&r<|>-AC?Dma81Mqv0IUFh03QJ5 zp?IwYpn1m$KygH`c>vr1P5>7G#dAFXwJ8KZmD1F#jK4nRJmery3K z1C#)0j1>TK011FN0M(HNNCPAR8v#-P834*db7K<#)x&`11B%yXfC@krfR$ldnvjRR zM&pgv1Qu@;M*{%fN6bGo26_Np02(voBN{Vp0GeAm0JPqA0(JmUeN@i~fW~(Z0QqhQ zK(Vj^SO7KvOaZ7aHV@3wgfi5BYk(EN7H|@90uT*24mbvg z0vrJN0-OMj00#j1mN@MLue|}D02hEWzysh8a09pkya3Dqe}Eq#7!U{u00aRL2VI8% zjshY8M*v}fgMd)LA;4ikI3N;$e24)czhcQ2y~gs8uL*!ez?U@m2U1$etfiITE56ah zO9pQI8~=5G5&QQW|5B(52r*{atfsuPX(bJXsf37_2n-F1G_1Ig^mQRZg5lN{P$C5- zFd@-c!1@Xq+d8q2^J35U8IFVqOo8oC0y8Y+_?D$BSfy4bQ&K2H&JxJ+uyeFVeow3W zCEV*gK~G6xDh_JE@o;k_d0I;l&PLx<^%PEsffCdXOmH+Vuy#WNB!&Czlx1&1iI|9} zi0JGti@aX-_J_!}7_SB>krWX}C7$MJL}0&@J8fg4(i#UP8$nG>?61H2Fr^l_lTCU@ zq>vFo9uWv10m$oQz1DH#<^)>ch|j9oI=Y}qNw6_GKFYF3XA6`_gBmQrACS8kI5Jvy zN5xZEe90bw*NZ4-cAAh!gc7OQ{y4ijIl92q zZ0BgZo17h{2PGS4OR&Gw$ot~&_%V9hekhTE5)?OUCvR)$ER$xx;gXYUUqOkqh=hpL zFJk~4A3KsIT5FHW@pIzx|&U+8R1M>L%TJ0Be2l}&>I2$*rH}M;tlM3m`Jq52x&Ngr= zxASDm5xO<>vZb9|0`raJY-jCG^7LRx9%NqiqTQB~0tRg+?Ep12dpRgyn(B{^x&jBS zV2G%Tvn3i*!kuE3(@DPOXkNqmMbX&{oMphNZyGEK+OO^Qmj^!X=B}==dDW$MHS+~{ zPf=2U&`i>&n%R{@_FNyON_{?pMh;pLk%qGol%UmUq~E^XWW2HWFSQaVL3>E!@qnew zl#gH@z~CU)e&gG(J>a6A_1d;=Lup?)gBP?z9&Irwft@!b=3KC3nD~LWWZ$5tw&q^8 zCV7R zV}Diic*((xxG2juayy{*YY$!l7p;9Vv=kxz(OP3EJPF9V)n?qlmI`_ww9W#9aX;XeNRhJ-K9w$tQkKt5yprLE{7a z!GEglg1Stgk`EU7Hf&|Q>zVuwHQ>mA8pN#xN>D^ExQJbK9JNe?5^}76?Ewu;L*$z= zMQXSD=X5j^(W(dE+@TRPM>PvX^t>+za?bcR)6M}XfqQ*O(+Jh>&Ait)&a?wP`q_-1 z86Sv23vkeUt7>~~ao*$Vkr}m_8ULJIk}1)llb$mvO>PG~@Pwg;!Vs?R4W@jiTyH2T zf~02mcykL2cWbz{OE(W58c$e1^4E+nh8q`ZM>IL6E#R~kFQ`dEM8N|~bNJ8Bn$X6P z-?d94?*(dSR;~s(=$87JmFu07&f&R2X$ucMrXTHGeFBX8jMl%t7dkG~BP?Bx6 zKQL3mBK*yV#7^-^d=k=8=A$RsA4~tOgqi z9dr}*G`{khb}8#3otcuEJ30%w9Ef;0ZP!CgZ}7|)t;{LR`?d`ngb=| z9oECcorE?ZQ`Ll9b)sdOP(q%gzvwBbb(1}?{$3!*CL8>btOg!fSzCD7f?D(;f@Ckt z-Px0a1R7Hhc(23*O3FR%uVnGrIXL6njMpSr)IOa1eT9v)6@?pTN@iv+GfZ8yhbZ>w z2yUzVIymHSK#%REP4O0j0+5hPQglr~RySocpx>#A4=qm78e+s=v zZU;#2)}HR@L`l(N*K?V<=n#}Z)KEh|jlqm>^DLP;q4dFkLg+%6sTiVFf{K%%9r8UG zsr|=&d!`+0XYiTiY#Vkw-k>M^L8h*|`cknWM!eAPFY@nyH;5cyw?G&&Y(av{b<*XW2=Qaw@OsNnkA>TD$LkSumnxm@JFS0Tf{!$x* z60|3l2`|W@e^84*-8xv2+#x)FiyO4_>llcynq9#o{?&o6(x-5Dj9))5)B*?jrcF3@ zEzoPC4}62I3hm1Oxr<>j5P=6k#Ic(U2q7w!Z2hZ0zrLF}nLAhuLzm*ddkspq4EfAN zXJ+4#1vRvOVn5|%RI)8NIHR@^orLD~%!HjbNKWqN@P@+wfoCRoZv4rqlROW8edhbg zsgpbp{tuoyVP*Z)gPDEj*Qd@rh&7sTJC1e~vhUVHPX*{y1Ec+m^C;|M|9OH0&j0K@ z3SR$DPJ;pP<{+9O46ExCSGCA=fY;T@t1WXFiAx zy4T+VHMrq~WUqf7<)ta0H8T@u;`WnOLOzE$!CQl{@I%t9+}kuJo&essPgX9v0 z%y!KKo2crbL{vl)wUbCLS+%^)J&-E_amXbXpahM=xuYZ2yypC9{gC@pK`xPkW9bE{moh08Z^OU@ql9_ed02~yZ`pVnXV%s;uvl+V4!bSn78b^|qu)Rl8 zn#|*!n#_8@foC@48}^r~)w@$Z^y=H7=O5S+VJiIV?^>Im@eK3uR72cg)x-RS_YXW! z`|xfaQ8TbSTD}QNWJJVJ(RZ>3b{>V(U+D`-Fbd?;Ej9b>j?^N>Xt3w$1T`atq5|rw zIKj~iy{|wZq^ys)SIqX*liZFh>^tV}4%Sxiw6kOF8MO=w2PlDfA`gD@v@1J%r}eNS zIiQ0g+cn2gK?61N84300@9$(Sqlg2aU?PSnbIhLBoo^^v74bK%gLcrELOTXff=(z` zcbqJI>*7v=5;zZ|5;G`S1|`uMd)S}lG>Chf4c#h@)bVvr?)AuF0puv+V{vLa~@$}~zjySwEMhF7V3h-KIf#{vkV@-RZ zL=q+s__my9wx?^j7o_WFNcKYsh)KemgMW`GnFAsHdpk3y!I^fjzs@BYzhr3Ex3ho} z@)H>LH?YxNQS_5p7ts4iXh(vGVt+Af!*jTEggz9NkoQsS?`xl$ite~9Sn>ZgcQ&Dx z98~~LB1p2(i5S6!%3DOmV7-@lGn2fLnelC034%Yk5H$3?x9)vC)A#nB?!NQh3xiSo zTLlypBpX3-p=+ZUT}V(@SqQg8w&GIQC^4u%)k3YQs@C`n>f}TR> zy}-zBUtj!TcK2I19~W#)04BV^C$gt6{pseHKk&2L-%~njDRw^SbnbJ%{L5R5U)*|^ z<2A@05HGDF+xd;(e(LqV|MfkRDUodu?o^9)R@L^Q3-|u``Ildl=)=pwShF5|@Ch)< zKVSQ>Rx-Zw+`C_%zVXe!{TdjV8hbj{?MLMkc5eTHH-M4o{fTFO@Z?WE`u6t$LnI@6 zdN$12pZqs77+V+S#x97A{`4cxbNJ5Q7oPvni`TC{)UEU$pU5seQeON0pFjP=uUw2S zcI?d;9WRc4?w-Rcx3k&1pEzl3waSXmHWlH>jh%~q()*xGdN=h{QT*ngkNvp%?zbP~ z_fhub-G$eFbnV{zZ@<*kXcu|aFTT3-)z8d7`PT2S6f&o;A6$9m!IO9X>wks+zF)zs zueU3a{QSkU((_~*ZrMrM7*Z5v(Hsg}>ph<`*Uq%c*G=CtMYdXOvV}En9pr?ORx`0p zwtLkf;rsGOO|z~)wzpT=1&P(_be9D5&3d=27A@{Q)3%Ie<9D0IvxhkAlk#Lwe?JKY zG>g-x<6O(P@dV%sGK8qChKhBnRIUY`u{f0CO z=I1|$Q^zL(7jO`gK~HC!+7cIQ1Lzw4HVR+8`G{+U7F$5z2AijM<>X+gMYS=S3ykb* zHwO5wjc|xF8t0aa^8j-VIGh$(IembT2h$YC4I1-$x3XCwN+mnD%+Mq0n7lUG1k=B1 zY-9!Fq2M3CQfX7|jo^`r1hDd8yhwL^{jL@Ogli~`^GK$y53p{naL&v0L`;gYC+log z=jAFg+0jVQjovUF{?#>4GVJcu&d6uL*(nRm8p&-$(D#GD+;@yfMT(C@ax$|4{d4iD zttbKAHdQZD7Nf0EDV!@;DZP~D2O$Rzqf%%tzA zxLy&B)9LKXbo7r->~aKQI2YkcFg4cbO^jWZH*@@y1+%XWhjyWJ*NnDVm-(tmP;e{s z_+3Z0S(QN+?~q5Z^n<|Cckp1+Ds{%3L3G9^YK&828!!b-K@VpqZTp$te?ah8}_Gj89a&Qv4VQzTyfLK{4oY729Ji&I0PHwCB>wv5gSuk=am= zDoDi+p8Q zc2PEY)|3^rmP9XDPa-|7a)#7mJ4`)=)k*(WhJ}6Ip1d z60H(|V(T4R&n<<->^rErC|8I^U#Ou{SL!^oQFR^Q&@_ewKq|}~G5HR_EP}Bub%3jF z%4SFg9@B#dN!~;*Q$|qqgFw=EdiLJ9zN7NEb8Sactzy`#b7)#H49p?ax#WAugOFLu z6lHiybUGZ~UWQowE5(yKC_4izENYFhLZ&RBGCs6+VAy(hE_YO*?t>_NrQwCn=&&hE z`M%EzCqjekhyZMjWr{u?Pg^0Km8LuT^UN=Ce9SRB36JAm0I1|16)1emP{#0H$RUv) zzm!R&*tVAC9c$$4OoX7wWO=-@-Qm_or36y9H*VA_TgEhDG?F=t-mv3-1^$D&*u-MT zU{sGxVASrZ(B;cb#eewXN0BWGMu8~ksj{a`S8Lr{j(}qP>Rhs{cQXW7@)#;>YVxzi zf*21$Gnn-<<{*wnf@<^zuUJx)h{&|C*$O{9llXjw2j#=|7?Z+r!ltm_Pd9=gAPRiY zW53epTOfle5Oc&p&0j8uzZE=~mb&`wwn7v!Jaj_32!$ohu^!O{UK zvXr$|C#3Uq0Uy3#3nc6o{ommEau4^q2F zKF+G0Cs8s?amngbRLjXtAx#~CG)08uU>qwM^kG-}&=`mAAQ`_>i<|OLdk(b>b>$@q zG8FdsC~J-vW>XcB_4I?l(s%lJ^w>`FSt0pI%8HV5j%mU6V8ObDq0d%CW+vBPfR+ab z2lrkQhjDv73z)XqTj&TKR}ulr*G9xoPpM5Hr~n4N{;Z5qlrIwrL3sj^c3is3Cs19R z@(6tKwNYWt;qs)e=d(Ruyq2W$(jL0P_?i+--VoE*aA&>!l2oz1!^veCMIHK5UYAQ^ zZ@zG2j!7j+_0~`!jjZZeEctOwsLdS<)hQR>N~&km%*}z}(nmhy=ye58_cP)Vg!23J zpp*wp@^(mUk6&K|)QN;xtAaWoRzqc`VD@s8>DXu2t3-@QSKtUp{6IKnPUoOWmK$0zXI z@3nddDFv5UY`Y34SG7`RXjEil5~DY2B9y+!mAfhy&l9>aU~-NAP>wLP;Bp!e@=)cu zni4>N(GHmQCJl@_VCxcs>n?K%m}`mfiq^!z{OvHnd`nGrinqNT0!$2K&4L97<&X&6~2dHZ>ll=pCI33Qjx*@{Y zn{4Vy84WasBSGds^yE%?Y2Ate>)Ij?911XAc###S&qlc*gSe0f2H(=1OGQ{cY7gk> zD6Gz!EhZmhn3Pe+vwQzG6t(nESeMV3NAO+?`V0 z-X28#d$EX0+?g;S_t01#ZgGkXZx0riFJ{=zfB?Bd_BECW_qK81*Mfn+{n}&j_j8tI zd6>XiId#sn`U+}YiAmKSa?db=w6~w*i;Nz#cL_(g98nH&a^gn3$34U)=0AA=C~$iv z5_o?FQ%_wNd;7bY5>-YP7>ojohM@Z#BmSbEH?m4Bf+QRUmar?T_muON-38PCzrX(m D&B)R^ literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 615a272..e44d4eb 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "typescript-language-server": "^3.3.2" }, "dependencies": { - "revolt.js": "^7.0.0-beta.7", + "revolt.js": "^7.0.0-beta.9", "shlex": "^2.1.2", "sqlite3": "^5.1.6" } diff --git a/src/commands/colorAlterChange.ts~ b/src/commands/colorAlterChange.ts~ deleted file mode 100644 index 42fe4ad..0000000 --- a/src/commands/colorAlterChange.ts~ +++ /dev/null @@ -1 +0,0 @@ -export function colorAlterChange(userId: string, args: string[]){} diff --git a/src/commands/createAlter.ts b/src/commands/createAlter.ts index 93e648e..66baf22 100644 --- a/src/commands/createAlter.ts +++ b/src/commands/createAlter.ts @@ -31,24 +31,24 @@ export async function createAlter(userId: string, args: string[]){ && !alterNames.includes(args[0])) { alterRepo.addAlterForUser(model); - return "Alter < " + model.name + " > has been succefully created" + return {message: "Alter < " + model.name + " > has been succefully created", code: 0} } else { if (args.length != 2){ - return "Error: Insufficent arguments"; + return {message: "Error: Insufficent arguments", code: 1}; } if (args[1] === "text"){ - return "Error: Tag may not be only "; + return {message: "Error: Tag may not be only ", code: 2}; } if (!args[1].includes("text")) { - return "Error: This command requires a tag that contains in it"; + return {message: "Error: This command requires a tag that contains in it", code: 3}; } if (alterTags.includes(args[1])) { - return "Error: You already have an Alter with that tag" + return {message: "Error: You already have an Alter with that tag", code: 4} } if (alterNames.includes(args[0])) { - return "Error: You can only have one Alter with that name" + return {message: "Error: You can only have one Alter with that name", code: 5} } } } diff --git a/src/commands/help.ts b/src/commands/help.ts index b8a5f89..a2ef9e3 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -6,6 +6,10 @@ export function returnHelpText() { "### Alters:\n" + "- list | allows you to see your currently available alters.\n" + "- create <'name of the alter'> <'your alter s tag'>| Allows you to create your Alters\n" + + "- delete <'name of the alter'> | Deletes the choosen Alter\n" + + "- name <'name of the alter'> | Changes the choosen Alter's name\n" + "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture\n" + - "- color <'Alter's name'> <'color hex'> | Allows you to change the color of your alter ( may be integrated with the website )" + "- color <'Alter's name'> <'color hex'> | Allows you to change the color of your alter ( may be integrated with the future website )\n"+ + "### Migrations\n"+ + "- pluralkit < Json file attached > | Migrates your alters from pluralkit to pluralcake" } diff --git a/src/commands/migrateAlters.ts b/src/commands/migrateAlters.ts new file mode 100644 index 0000000..f348998 --- /dev/null +++ b/src/commands/migrateAlters.ts @@ -0,0 +1,35 @@ +import { File } from "revolt.js" +import { createAlter } from "./createAlter" + +export default async function migrateAlters(author: string, attachments: File[] | undefined, source: String) { + // source is not utilized for now, it is put as an argument in case the bot evolves further + + let file = attachments[0] + + if (file.contentType === "text/plain") { + + const fileResponse = await fetch(file.url) + const fileResponseBlob = await fileResponse.blob() + const textFromBlob = fileResponseBlob.text() + const jsonFromText = JSON.parse(await textFromBlob) + + if (jsonFromText.tuppers === "undefined"){ + return "wrong json file, be certain that this is a tupperbox migration file" + } + + const tuppers = jsonFromText.tuppers + + tuppers.forEach(async element => { + let name = element.name + let brackets = element.brackets[0] + "text" + element.brackets[1] + const createResult = await createAlter(author, [name, brackets]) + let tupperStruct = {tupper: name, message: createResult} + + console.log(tupperStruct) + }); + return "Migration finished, check your tuppers to confirm" + } + else { + return "This is not a valid json file" + } +} diff --git a/src/index.ts b/src/index.ts index f3d2bb4..8c489fc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ client.on("ready", async () => { }); client.on("messageCreate", async (message: Message) => { - try{if (!message.author) {await client.users.fetch(message.authorId)} } + try{ if (!message.author) { await client.users.fetch(message.authorId) } } catch(e){console.log(e)} if (message.content === undefined) {return} diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index 8533f1a..ed77c86 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -5,6 +5,8 @@ import { createAlter } from "../commands/createAlter" import { deleteAlter } from "../commands/deleteAlter" import { avatarAlterChange } from "../commands/avatarAlterChange" import { colorAlterChange } from "../commands/colorAlterChange" +import migrationCommand from "../commands/migrateAlters" + import { split } from "shlex" export async function commandHandler(message : Message, _prefix : String) { @@ -15,7 +17,7 @@ export async function commandHandler(message : Message, _prefix : String) { switch(command) { case "help" : { - message.reply(returnHelpText()); + await message.reply(returnHelpText()); break; } case "list" : { @@ -23,7 +25,8 @@ export async function commandHandler(message : Message, _prefix : String) { break; } case "create" : { - await message.reply(await createAlter(message.author.id, args)); + const commandResponse = await createAlter(message.author.id, args); + await message.reply (commandResponse.message) break } case "delete" : { @@ -34,9 +37,13 @@ export async function commandHandler(message : Message, _prefix : String) { await message.reply(await avatarAlterChange(message.author.id, args)); break } - case "color" : { - await message.reply(await colorAlterChange(message.author.id, args)); - break + case "color" : { + await message.reply(await colorAlterChange(message.author.id, args)); + break + } + case "tupper" : { + await message.reply(await migrationCommand(message.author.id, message.attachments, "placeholder")) + break } } } From 88034a694061106bbf1607292d65afd9747c99ba Mon Sep 17 00:00:00 2001 From: ale Date: Sat, 9 Dec 2023 21:53:24 +0000 Subject: [PATCH 21/36] Update src/commands/help.ts --- src/commands/help.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/help.ts b/src/commands/help.ts index a2ef9e3..5c90822 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -11,5 +11,5 @@ export function returnHelpText() { "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture\n" + "- color <'Alter's name'> <'color hex'> | Allows you to change the color of your alter ( may be integrated with the future website )\n"+ "### Migrations\n"+ - "- pluralkit < Json file attached > | Migrates your alters from pluralkit to pluralcake" + "- tupper < Json file attached > | Migrates your alters from tupper to pluralcake" } From 209bdeb1b318990fd32187e5523f8fac1bee7136 Mon Sep 17 00:00:00 2001 From: Ale Date: Sat, 9 Dec 2023 23:04:17 +0100 Subject: [PATCH 22/36] FEAT: added tupper migrations avatar migration --- src/commands/migrateAlters.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/commands/migrateAlters.ts b/src/commands/migrateAlters.ts index f348998..c8bee2f 100644 --- a/src/commands/migrateAlters.ts +++ b/src/commands/migrateAlters.ts @@ -1,5 +1,6 @@ import { File } from "revolt.js" import { createAlter } from "./createAlter" +import { avatarAlterChange } from "./avatarAlterChange" export default async function migrateAlters(author: string, attachments: File[] | undefined, source: String) { // source is not utilized for now, it is put as an argument in case the bot evolves further @@ -21,8 +22,12 @@ export default async function migrateAlters(author: string, attachments: File[] tuppers.forEach(async element => { let name = element.name + let avatar = element.avatar_url let brackets = element.brackets[0] + "text" + element.brackets[1] const createResult = await createAlter(author, [name, brackets]) + if ( createResult.code === 0 ) { + await avatarAlterChange(author, [name, avatar]) + } let tupperStruct = {tupper: name, message: createResult} console.log(tupperStruct) From 8a6f2f65624249ddf1951cade7c15fee38d2fb74 Mon Sep 17 00:00:00 2001 From: Ale Date: Mon, 8 Jan 2024 13:43:05 +0100 Subject: [PATCH 23/36] removed any mention of Alter from the user-facing code --- src/commands/avatarAlterChange.ts | 2 +- src/commands/colorAlterChange.ts | 4 ++-- src/commands/createAlter.ts | 6 +++--- src/commands/deleteAlter.ts | 4 ++-- src/commands/help.ts | 16 ++++++++-------- src/commands/listAlters.ts | 2 +- src/commands/migrateAlters.ts | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/commands/avatarAlterChange.ts b/src/commands/avatarAlterChange.ts index ff262ff..873a35f 100644 --- a/src/commands/avatarAlterChange.ts +++ b/src/commands/avatarAlterChange.ts @@ -18,7 +18,7 @@ export async function avatarAlterChange(userId: string, args: string[]){ } }) } - return "The profile picture has been changed" + return "The profile picture for the Member has been changed" } if (args.length != 2) { diff --git a/src/commands/colorAlterChange.ts b/src/commands/colorAlterChange.ts index 15bee40..8b678af 100644 --- a/src/commands/colorAlterChange.ts +++ b/src/commands/colorAlterChange.ts @@ -11,7 +11,7 @@ export async function colorAlterChange(userId: string, args: string[]){ let alters: AlterModel[]; await alterRepo.getAltersByUserId(userId).then( result => alters = result ) // fetching alters from user. - if (alters.length == 0) return "This user has no Alters." // checking if returned array is at least not 0, if len 0, then return. + if (alters.length == 0) return "This user has no Members." // checking if returned array is at least not 0, if len 0, then return. let alterToEdit: AlterModel; alters.forEach( alter => { @@ -23,7 +23,7 @@ export async function colorAlterChange(userId: string, args: string[]){ alterToEdit.color = alterColor; alterRepo.editAlter(alterToEdit) - return "The Alter's colour has been changed." + return "The Member's colour has been changed." } return "Error: Insufficent Arguments" diff --git a/src/commands/createAlter.ts b/src/commands/createAlter.ts index 66baf22..ada39cb 100644 --- a/src/commands/createAlter.ts +++ b/src/commands/createAlter.ts @@ -31,7 +31,7 @@ export async function createAlter(userId: string, args: string[]){ && !alterNames.includes(args[0])) { alterRepo.addAlterForUser(model); - return {message: "Alter < " + model.name + " > has been succefully created", code: 0} + return {message: "Member < " + model.name + " > has been succefully created", code: 0} } else { @@ -45,10 +45,10 @@ export async function createAlter(userId: string, args: string[]){ return {message: "Error: This command requires a tag that contains in it", code: 3}; } if (alterTags.includes(args[1])) { - return {message: "Error: You already have an Alter with that tag", code: 4} + return {message: "Error: You already have a Member with that tag", code: 4} } if (alterNames.includes(args[0])) { - return {message: "Error: You can only have one Alter with that name", code: 5} + return {message: "Error: You can only have one Member with that name", code: 5} } } } diff --git a/src/commands/deleteAlter.ts b/src/commands/deleteAlter.ts index 989e881..d2e99ba 100644 --- a/src/commands/deleteAlter.ts +++ b/src/commands/deleteAlter.ts @@ -16,9 +16,9 @@ export async function deleteAlter(userId: string, args: string[]) { }) } if (success) { - return "Alter has been deleted" + return "Member has been deleted" } else { - return "Failed to delete Alter" + return "Failed to delete Member" } } diff --git a/src/commands/help.ts b/src/commands/help.ts index 5c90822..529cc0e 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,15 +1,15 @@ export function returnHelpText() { return "# Howdy user, welcome to pluralcake\n" + - "pluralcake is a bot that allows you to send messages as your Alters, with a custom profile picture, tag and nickname. \n" + + "pluralcake is a bot that allows you to send messages as your system's Members, with a custom profile picture, tag and nickname. \n" + "It's pretty much a work in progress, and doesn't allow you to edit or delete messages, and to send pictures." + "The currently available commands are : \n" + "### Alters:\n" + - "- list | allows you to see your currently available alters.\n" + - "- create <'name of the alter'> <'your alter s tag'>| Allows you to create your Alters\n" + - "- delete <'name of the alter'> | Deletes the choosen Alter\n" + - "- name <'name of the alter'> | Changes the choosen Alter's name\n" + - "- avatar <'Alter's name'> <'picture url'> | Allows you to edit your alter's profile picture\n" + - "- color <'Alter's name'> <'color hex'> | Allows you to change the color of your alter ( may be integrated with the future website )\n"+ + "- list | allows you to see your currently available Members.\n" + + "- create <'name of the Member'> <'your Member's tag'>| Allows you to add a Member\n" + + "- delete <'name of the Member'> | Deletes the choosen Member\n" + + "- name <'name of the Member'> | Changes the choosen Member's name\n" + + "- avatar <'Member's name'> <'picture url'> | Allows you to edit your Member's profile picture\n" + + "- color <'Member's name'> <'color hex'> | Allows you to change the color of your Member ( may be integrated with the future website )\n"+ "### Migrations\n"+ - "- tupper < Json file attached > | Migrates your alters from tupper to pluralcake" + "- tupper < Json file attached > | Migrates your Member from tupper" } diff --git a/src/commands/listAlters.ts b/src/commands/listAlters.ts index 3ad9918..908e840 100644 --- a/src/commands/listAlters.ts +++ b/src/commands/listAlters.ts @@ -11,6 +11,6 @@ export async function listAlters(userId: string) { return tableConstructor(alters) } else { - return "No Alters found for this user" + return "No Members found for this user" } } diff --git a/src/commands/migrateAlters.ts b/src/commands/migrateAlters.ts index c8bee2f..93a0036 100644 --- a/src/commands/migrateAlters.ts +++ b/src/commands/migrateAlters.ts @@ -32,7 +32,7 @@ export default async function migrateAlters(author: string, attachments: File[] console.log(tupperStruct) }); - return "Migration finished, check your tuppers to confirm" + return "Migration finished, check your Members to confirm" } else { return "This is not a valid json file" From 21927ae359326eb9908a6002f88cb1c8059d918c Mon Sep 17 00:00:00 2001 From: Ale Date: Mon, 8 Jan 2024 22:56:59 +0100 Subject: [PATCH 24/36] removed any mention of Alter from the user-facing code but again --- src/commands/help.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/help.ts b/src/commands/help.ts index 529cc0e..ac725af 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -3,7 +3,7 @@ export function returnHelpText() { "pluralcake is a bot that allows you to send messages as your system's Members, with a custom profile picture, tag and nickname. \n" + "It's pretty much a work in progress, and doesn't allow you to edit or delete messages, and to send pictures." + "The currently available commands are : \n" + - "### Alters:\n" + + "### Members:\n" + "- list | allows you to see your currently available Members.\n" + "- create <'name of the Member'> <'your Member's tag'>| Allows you to add a Member\n" + "- delete <'name of the Member'> | Deletes the choosen Member\n" + From 87e8a4295d30e35b7d03967c8da6fa99f973fad4 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 18:41:08 +0100 Subject: [PATCH 25/36] changed alter to model --- ...arAlterChange.ts => avatarMemberChange.ts} | 15 +++--- ...lorAlterChange.ts => colorMemberChange.ts} | 19 ++++---- .../{createAlter.ts => createMember.ts} | 19 ++++---- src/commands/deleteAlter.ts | 24 ---------- src/commands/deleteMember.ts | 25 ++++++++++ src/commands/listAlters.ts | 16 ------- src/commands/listMember.ts | 19 ++++++++ .../{migrateAlters.ts => migrateMember.ts} | 11 +++-- src/index.ts | 29 ++++++++---- src/models/{alterModel.ts => MemberModel.ts} | 4 +- src/models/User.ts | 7 +++ .../{AlterRepo.ts => MemberRepo.ts} | 24 +++++----- src/utils/checkAutoProxy.ts | 15 ++++++ src/utils/commandHandler.ts | 33 +++++++------ src/utils/nonCommandHandler.ts | 47 ++----------------- src/utils/sendAsMemberHandler.ts | 47 +++++++++++++++++++ 16 files changed, 205 insertions(+), 149 deletions(-) rename src/commands/{avatarAlterChange.ts => avatarMemberChange.ts} (53%) rename src/commands/{colorAlterChange.ts => colorMemberChange.ts} (50%) rename src/commands/{createAlter.ts => createMember.ts} (72%) delete mode 100644 src/commands/deleteAlter.ts create mode 100644 src/commands/deleteMember.ts delete mode 100644 src/commands/listAlters.ts create mode 100644 src/commands/listMember.ts rename src/commands/{migrateAlters.ts => migrateMember.ts} (76%) rename src/models/{alterModel.ts => MemberModel.ts} (68%) create mode 100644 src/models/User.ts rename src/repositories/{AlterRepo.ts => MemberRepo.ts} (62%) create mode 100644 src/utils/checkAutoProxy.ts create mode 100644 src/utils/sendAsMemberHandler.ts diff --git a/src/commands/avatarAlterChange.ts b/src/commands/avatarMemberChange.ts similarity index 53% rename from src/commands/avatarAlterChange.ts rename to src/commands/avatarMemberChange.ts index 873a35f..cd0c649 100644 --- a/src/commands/avatarAlterChange.ts +++ b/src/commands/avatarMemberChange.ts @@ -1,10 +1,11 @@ -import { AlterModel } from "../models/alterModel" -import { AlterRepo } from "../repositories/AlterRepo" +import { Database } from "sqlite3"; +import MemberModel from "../models/MemberModel" +import { MemberRepo } from "../repositories/MemberRepo" -export async function avatarAlterChange(userId: string, args: string[]){ - const alterRepo = new AlterRepo(); - let userAlters : AlterModel[] = []; - await alterRepo.getAltersByUserId(userId).then( result => userAlters = result ) +export async function avatarMemberChange(userId: string, args: string[], database: Database){ + const memberRepo = new MemberRepo(database); + let userAlters : MemberModel[] = []; + await memberRepo.getAltersByUserId(userId).then( result => userAlters = result ) let userAltersNames : string[] = []; userAlters.forEach(alter => userAltersNames.push(alter.name)); @@ -14,7 +15,7 @@ export async function avatarAlterChange(userId: string, args: string[]){ userAlters.forEach( alter => { if (alter.name == args[0]) { alter.profile_pic_url = args[1]; - alterRepo.editAlter(alter) + memberRepo.editAlter(alter) } }) } diff --git a/src/commands/colorAlterChange.ts b/src/commands/colorMemberChange.ts similarity index 50% rename from src/commands/colorAlterChange.ts rename to src/commands/colorMemberChange.ts index 8b678af..c99bd41 100644 --- a/src/commands/colorAlterChange.ts +++ b/src/commands/colorMemberChange.ts @@ -1,19 +1,20 @@ -import { AlterRepo } from "../repositories/AlterRepo" -import { AlterModel } from "../models/alterModel" +import { MemberRepo } from "../repositories/MemberRepo" +import MemberModel from "../models/MemberModel" +import { Database } from "sqlite3"; -export async function colorAlterChange(userId: string, args: string[]){ - const alterRepo = new AlterRepo(); +async function colorMemberChange(userId: string, args: string[], database: Database){ + const memberRepo = new MemberRepo(database); const regexHex = /^#[0-9A-F]{6}$/i; if (args.length == 2 && regexHex.test(args[1])){ const alterName = args[0]; const alterColor = args[1]; - let alters: AlterModel[]; - await alterRepo.getAltersByUserId(userId).then( result => alters = result ) // fetching alters from user. + let alters: MemberModel[]; + await memberRepo.getAltersByUserId(userId).then( result => alters = result ) // fetching alters from user. if (alters.length == 0) return "This user has no Members." // checking if returned array is at least not 0, if len 0, then return. - let alterToEdit: AlterModel; + let alterToEdit: MemberModel; alters.forEach( alter => { if (alter.name == alterName) { alterToEdit = alter; @@ -21,10 +22,12 @@ export async function colorAlterChange(userId: string, args: string[]){ }) alterToEdit.color = alterColor; - alterRepo.editAlter(alterToEdit) + memberRepo.editAlter(alterToEdit) return "The Member's colour has been changed." } return "Error: Insufficent Arguments" } + +export default colorMemberChange diff --git a/src/commands/createAlter.ts b/src/commands/createMember.ts similarity index 72% rename from src/commands/createAlter.ts rename to src/commands/createMember.ts index ada39cb..33111d5 100644 --- a/src/commands/createAlter.ts +++ b/src/commands/createMember.ts @@ -1,18 +1,19 @@ -import { AlterRepo } from "../repositories/AlterRepo"; -import { AlterModel } from "models/alterModel" +import { Database } from "sqlite3"; +import { MemberRepo } from "../repositories/MemberRepo"; +import MemberModel from "models/MemberModel" -export async function createAlter(userId: string, args: string[]){ - const alterRepo = new AlterRepo(); +async function createMember(userId: string, args: string[], database: Database){ + const memberRepo = new MemberRepo(database); - const model: AlterModel = { + const model: MemberModel = { owner: userId, name: args[0], prefix: args[1], profile_pic_url: "https://tse3.mm.bing.net/th?id=OIP.yte7rRnbCnWi1giriwTOvwHaHa&pid=15.1" } - let userAlters: AlterModel[]; - await alterRepo.getAltersByUserId(userId).then(result => userAlters = result) + let userAlters: MemberModel[]; + await memberRepo.getAltersByUserId(userId).then(result => userAlters = result) let alterTags : string[] = []; userAlters.forEach( alter => { @@ -30,7 +31,7 @@ export async function createAlter(userId: string, args: string[]){ && args[1] != "text" && !alterNames.includes(args[0])) { - alterRepo.addAlterForUser(model); + memberRepo.addAlterForUser(model); return {message: "Member < " + model.name + " > has been succefully created", code: 0} } @@ -52,3 +53,5 @@ export async function createAlter(userId: string, args: string[]){ } } } + +export default createMember; diff --git a/src/commands/deleteAlter.ts b/src/commands/deleteAlter.ts deleted file mode 100644 index d2e99ba..0000000 --- a/src/commands/deleteAlter.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AlterRepo } from "../repositories/AlterRepo" -import { AlterModel } from "../models/alterModel" - -export async function deleteAlter(userId: string, args: string[]) { - const alterRepo = new AlterRepo(); - let success: boolean = false; - - if (args.length === 1) { - let alters: AlterModel[]; - await alterRepo.getAltersByUserId(userId).then(result => alters = result ) - alters.forEach(alter => { - if (alter.name == args[0]) { - alterRepo.deleteAlter(alter.id) - success = true; - } - }) - } - if (success) { - return "Member has been deleted" - } - else { - return "Failed to delete Member" - } -} diff --git a/src/commands/deleteMember.ts b/src/commands/deleteMember.ts new file mode 100644 index 0000000..74b5c19 --- /dev/null +++ b/src/commands/deleteMember.ts @@ -0,0 +1,25 @@ +import { MemberRepo } from "../repositories/MemberRepo" +import MemberModel from "../models/MemberModel" +import { Database } from "sqlite3"; + +export async function deleteMember(userId: string, args: string[], database: Database) { + const memberRepo = new MemberRepo(database); + let success: boolean = false; + + if (args.length === 1) { + let alters: MemberModel[]; + await memberRepo.getAltersByUserId(userId).then(result => alters = result ) + alters.forEach(alter => { + if (alter.name == args[0]) { + memberRepo.delete(alter.id) + success = true; + } + }) + } + if (success) { + return "Member has been deleted" + } + else { + return "Failed to delete Member" + } +} diff --git a/src/commands/listAlters.ts b/src/commands/listAlters.ts deleted file mode 100644 index 908e840..0000000 --- a/src/commands/listAlters.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AlterRepo } from "../repositories/AlterRepo" -import { AlterModel } from "../models/alterModel" -import { tableConstructor } from '../utils/tableConstructor' - -export async function listAlters(userId: string) { - const alterRepo = new AlterRepo(); - let alters: AlterModel[]; - await alterRepo.getAltersByUserId(userId).then(result => { alters = result }) - - if (alters.length > 0 ) { - return tableConstructor(alters) - } - else { - return "No Members found for this user" - } -} diff --git a/src/commands/listMember.ts b/src/commands/listMember.ts new file mode 100644 index 0000000..18cf368 --- /dev/null +++ b/src/commands/listMember.ts @@ -0,0 +1,19 @@ +import { MemberRepo } from "../repositories/MemberRepo" +import { tableConstructor } from '../utils/tableConstructor' +import { Database } from "sqlite3"; +import MemberModel from "../models/MemberModel"; + +async function listMember(userId: string, database: Database) { + const memberRepo = new MemberRepo(database); + let alters: MemberModel[]; + await memberRepo.getAltersByUserId(userId).then(result => { alters = result }) + + if (alters.length > 0 ) { + return tableConstructor(alters) + } + else { + return "No Members found for this user" + } +} + +export default listMember diff --git a/src/commands/migrateAlters.ts b/src/commands/migrateMember.ts similarity index 76% rename from src/commands/migrateAlters.ts rename to src/commands/migrateMember.ts index 93a0036..a9982ce 100644 --- a/src/commands/migrateAlters.ts +++ b/src/commands/migrateMember.ts @@ -1,8 +1,9 @@ import { File } from "revolt.js" -import { createAlter } from "./createAlter" -import { avatarAlterChange } from "./avatarAlterChange" +import { Database } from "sqlite3" +import createMember from "./createMember" +import { avatarMemberChange } from "./avatarMemberChange" -export default async function migrateAlters(author: string, attachments: File[] | undefined, source: String) { +export default async function migrateAlters(author: string, attachments: File[] | undefined, source: String, database: Database) { // source is not utilized for now, it is put as an argument in case the bot evolves further let file = attachments[0] @@ -24,9 +25,9 @@ export default async function migrateAlters(author: string, attachments: File[] let name = element.name let avatar = element.avatar_url let brackets = element.brackets[0] + "text" + element.brackets[1] - const createResult = await createAlter(author, [name, brackets]) + const createResult = await createMember(author, [name, brackets], database) if ( createResult.code === 0 ) { - await avatarAlterChange(author, [name, avatar]) + await avatarMemberChange(author, [name, avatar], database) } let tupperStruct = {tupper: name, message: createResult} diff --git a/src/index.ts b/src/index.ts index 8c489fc..6aff86e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,28 +1,37 @@ import { Client, Message } from "revolt.js"; import { commandHandler } from "./utils/commandHandler" import { nonCommandHandler } from "./utils/nonCommandHandler" +import { Database } from "sqlite3"; import config from "../config.json" -const client : Client = new Client({ eagerFetching: false }); +const client : Client = new Client({ eagerFetching: false }); +const db = new Database(config.databaseName); client.on("ready", async () => { - console.info(`Gummed in as ${client.user.username}!`) - client.user.edit({status : {text: config.prefix + " help for the help menu"}}) + console.info(`logged in as ${client.user.username}!`) + client.user.edit( + { + status : { + text: config.prefix + " help for the help menu" + } + } + ) }); + client.on("messageCreate", async (message: Message) => { try{ if (!message.author) { await client.users.fetch(message.authorId) } } catch(e){console.log(e)} if (message.content === undefined) {return} - if (message.author?.bot) {} + if (message.author?.bot) {return} + + // checks if the message's body starts with the prefix + if (message.content.startsWith(config.prefix)) { + commandHandler(message, db, config.prefix); + } else { - if (message.content.startsWith(config.prefix)) { - commandHandler(message, config.prefix); - } - else { - nonCommandHandler(message); - } + nonCommandHandler(message, db); } }); diff --git a/src/models/alterModel.ts b/src/models/MemberModel.ts similarity index 68% rename from src/models/alterModel.ts rename to src/models/MemberModel.ts index 2eb4e19..412c7d4 100644 --- a/src/models/alterModel.ts +++ b/src/models/MemberModel.ts @@ -1,4 +1,4 @@ -export interface AlterModel { +interface MemberModel { id?: number; owner: string; prefix: string; @@ -6,3 +6,5 @@ export interface AlterModel { profile_pic_url: string; color?: string; } + +export default MemberModel; diff --git a/src/models/User.ts b/src/models/User.ts new file mode 100644 index 0000000..8e2d094 --- /dev/null +++ b/src/models/User.ts @@ -0,0 +1,7 @@ +interface UserModel { + id: number, + autoProxy: boolean, + autoProxyMember: number +} + +export default UserModel; diff --git a/src/repositories/AlterRepo.ts b/src/repositories/MemberRepo.ts similarity index 62% rename from src/repositories/AlterRepo.ts rename to src/repositories/MemberRepo.ts index 4084504..69da5b7 100644 --- a/src/repositories/AlterRepo.ts +++ b/src/repositories/MemberRepo.ts @@ -1,19 +1,19 @@ import { Database } from 'sqlite3'; -import { AlterModel } from '../models/alterModel' -import config from "../../config.json" +import MemberModel from '../models/MemberModel'; -export class AlterRepo { +export class MemberRepo { db : Database - constructor() { - this.db = new Database(config.databaseName); - this.db.run("CREATE TABLE IF NOT EXISTS alters (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)") + + constructor(database_instance: Database) { + this.db = database_instance; + this.db.run("CREATE TABLE IF NOT EXISTS alters (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)"); } - async getAltersByUserId(userId : string) : Promise { + async getAltersByUserId(userId : string) : Promise { const query : string = 'SELECT * FROM alters WHERE alters.owner = "' + userId + '"' - let result: AlterModel[] = await new Promise((resolve, reject) => { - this.db.all(query, (err, row: AlterModel[]) => { + let result: MemberModel[] = await new Promise((resolve, reject) => { + this.db.all(query, (err, row: MemberModel[]) => { if (err) { return reject(err)} else { return resolve(row) } }) @@ -22,17 +22,17 @@ export class AlterRepo { return result } - addAlterForUser(alter: AlterModel){ + addAlterForUser(alter: MemberModel){ this.db.run("INSERT INTO alters (owner, prefix, name, profile_pic_url, color) VALUES(?, ?, ?, ?, ?)", [alter.owner, alter.prefix, alter.name, alter.profile_pic_url]) } - editAlter(alter: AlterModel){ + editAlter(alter: MemberModel){ this.db.run("UPDATE alters SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE alters.id ='" + alter.id + "'", [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color]) } - deleteAlter(alterId: number) { + delete(alterId: number) { this.db.run("DELETE FROM alters WHERE alters.id='"+ alterId + "'") } diff --git a/src/utils/checkAutoProxy.ts b/src/utils/checkAutoProxy.ts new file mode 100644 index 0000000..213a7b9 --- /dev/null +++ b/src/utils/checkAutoProxy.ts @@ -0,0 +1,15 @@ +import { MemberRepo } from "repositories/MemberRepo"; +import { Database } from "sqlite3"; + +async function checkAutoProxy +( + userId: number, + database: Database +): Promise +{ + const repo = new MemberRepo(database) + + return true +} + +export default checkAutoProxy; diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index ed77c86..5e00cc1 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -1,15 +1,18 @@ import { Message } from "revolt.js" -import { returnHelpText } from "../commands/help" -import { listAlters } from "../commands/listAlters" -import { createAlter } from "../commands/createAlter" -import { deleteAlter } from "../commands/deleteAlter" -import { avatarAlterChange } from "../commands/avatarAlterChange" -import { colorAlterChange } from "../commands/colorAlterChange" -import migrationCommand from "../commands/migrateAlters" - +import { Database } from "sqlite3" import { split } from "shlex" -export async function commandHandler(message : Message, _prefix : String) { +import { returnHelpText } from "../commands/help" +import listMember from "../commands/listMember" +import createMember from "../commands/createMember" +import { deleteMember } from "../commands/deleteMember" +import { avatarMemberChange } from "../commands/avatarMemberChange" +import colorMemberChange from "../commands/colorMemberChange" +import migrationCommand from "../commands/migrateMember" + + + +export async function commandHandler(message : Message, db: Database, _prefix : String) { let args : string[] = split(message.content); args.shift() const command = args[0] @@ -21,28 +24,28 @@ export async function commandHandler(message : Message, _prefix : String) { break; } case "list" : { - await message.reply(await listAlters(message.author.id)); + await message.reply(await listMember(message.author.id, db)); break; } case "create" : { - const commandResponse = await createAlter(message.author.id, args); + const commandResponse = await createMember(message.author.id, args, db); await message.reply (commandResponse.message) break } case "delete" : { - await message.reply(await deleteAlter(message.author.id, args)) + await message.reply(await deleteMember(message.author.id, args, db)) break } case "avatar" : { - await message.reply(await avatarAlterChange(message.author.id, args)); + await message.reply(await avatarMemberChange(message.author.id, args, db)); break } case "color" : { - await message.reply(await colorAlterChange(message.author.id, args)); + await message.reply(await colorMemberChange(message.author.id, args, db)); break } case "tupper" : { - await message.reply(await migrationCommand(message.author.id, message.attachments, "placeholder")) + await message.reply(await migrationCommand(message.author.id, message.attachments, "placeholder", db)) break } } diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index 43838fa..e606b1b 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -1,46 +1,7 @@ import { Message } from "revolt.js" -import { AlterRepo } from "../repositories/AlterRepo" -import { AlterModel } from "../models/alterModel" +import { Database } from "sqlite3"; +import sendAsMember from "./sendAsMemberHandler"; -export async function nonCommandHandler(message : Message){ - const alterRepo: AlterRepo = new AlterRepo(); - let alters: AlterModel[]; - await alterRepo.getAltersByUserId(message.author.id).then(result => alters = result); - - alters.forEach( async alter => { - const pre_prefix = alter.prefix.split("text"); - if (message.content.startsWith(pre_prefix[0]) && message.content.endsWith(pre_prefix[1])) { - let actualContent: string = message.content; - actualContent = actualContent.slice(pre_prefix[0].length, actualContent.length - pre_prefix[1].length) - - const replyIds: string[] | undefined = message.replyIds; - let replies: any[] = []; - - if (replyIds !== undefined) { - replyIds.forEach( replyId => { - replies.push({ - id: replyId, - mention: false - }) - }) - } - - try{ - await message.channel.sendMessage({ - content: actualContent, - masquerade: { - name: alter.name , - avatar: alter.profile_pic_url, - color: alter.color - }, - replies: replies - }) - await message.delete(); - } - catch(e){ - console.log(e) - await message.channel.sendMessage("Error: PluralCake requires at least these permissions: \n- Masquerade permissions. \n- Message editing permissions.") - } - } - }) +export async function nonCommandHandler(message : Message, database: Database){ + await sendAsMember(message, database); } diff --git a/src/utils/sendAsMemberHandler.ts b/src/utils/sendAsMemberHandler.ts new file mode 100644 index 0000000..75d87be --- /dev/null +++ b/src/utils/sendAsMemberHandler.ts @@ -0,0 +1,47 @@ +import { Message } from "revolt.js" +import { Database } from "sqlite3"; +import { MemberRepo } from "../repositories/MemberRepo" +import MemberModel from "../models/MemberModel" + +export default async function sendAsMember(message: Message, database: Database) { + const alterRepo: MemberRepo = new MemberRepo(database); + let alters: MemberModel[]; + await alterRepo.getAltersByUserId(message.author.id).then(result => alters = result); + + alters.forEach( async alter => { + const pre_prefix = alter.prefix.split("text"); + if (message.content.startsWith(pre_prefix[0]) && message.content.endsWith(pre_prefix[1])) { + let actualContent: string = message.content; + actualContent = actualContent.slice(pre_prefix[0].length, actualContent.length - pre_prefix[1].length) + + const replyIds: string[] | undefined = message.replyIds; + let replies: any[] = []; + + if (replyIds !== undefined) { + replyIds.forEach( replyId => { + replies.push({ + id: replyId, + mention: false + }) + }) + } + + try{ + await message.channel.sendMessage({ + content: actualContent, + masquerade: { + name: alter.name , + avatar: alter.profile_pic_url, + color: alter.color + }, + replies: replies + }) + await message.delete(); + } + catch(e){ + console.log(e) + await message.channel.sendMessage("Error: PluralCake requires at least these permissions: \n- Masquerade permissions. \n- Message editing permissions.") + } + } + }) +} From 327ba2c089daa2692a054a0e5ca69f26122b2424 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 19:57:42 +0100 Subject: [PATCH 26/36] changed alter to model and started implementation of autoproxy --- src/index.ts | 2 ++ src/models/{User.ts => UserModel.ts} | 1 + src/repositories/MemberRepo.ts | 9 ++++----- src/repositories/UserRepo.ts | 14 ++++++++++++++ src/utils/dbInit.ts | 16 ++++++++++++++-- 5 files changed, 35 insertions(+), 7 deletions(-) rename src/models/{User.ts => UserModel.ts} (84%) create mode 100644 src/repositories/UserRepo.ts diff --git a/src/index.ts b/src/index.ts index 6aff86e..8136997 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,9 +3,11 @@ import { commandHandler } from "./utils/commandHandler" import { nonCommandHandler } from "./utils/nonCommandHandler" import { Database } from "sqlite3"; import config from "../config.json" +import dbInit from "utils/dbInit"; const client : Client = new Client({ eagerFetching: false }); const db = new Database(config.databaseName); +dbInit(db); client.on("ready", async () => { console.info(`logged in as ${client.user.username}!`) diff --git a/src/models/User.ts b/src/models/UserModel.ts similarity index 84% rename from src/models/User.ts rename to src/models/UserModel.ts index 8e2d094..a3fb039 100644 --- a/src/models/User.ts +++ b/src/models/UserModel.ts @@ -1,5 +1,6 @@ interface UserModel { id: number, + revolt_id: string, autoProxy: boolean, autoProxyMember: number } diff --git a/src/repositories/MemberRepo.ts b/src/repositories/MemberRepo.ts index 69da5b7..c762279 100644 --- a/src/repositories/MemberRepo.ts +++ b/src/repositories/MemberRepo.ts @@ -6,11 +6,10 @@ export class MemberRepo { constructor(database_instance: Database) { this.db = database_instance; - this.db.run("CREATE TABLE IF NOT EXISTS alters (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)"); } async getAltersByUserId(userId : string) : Promise { - const query : string = 'SELECT * FROM alters WHERE alters.owner = "' + userId + '"' + const query : string = 'SELECT * FROM members WHERE members.owner = "' + userId + '"' let result: MemberModel[] = await new Promise((resolve, reject) => { this.db.all(query, (err, row: MemberModel[]) => { @@ -23,17 +22,17 @@ export class MemberRepo { } addAlterForUser(alter: MemberModel){ - this.db.run("INSERT INTO alters (owner, prefix, name, profile_pic_url, color) VALUES(?, ?, ?, ?, ?)", + this.db.run("INSERT INTO members (owner, prefix, name, profile_pic_url, color) VALUES(?, ?, ?, ?, ?)", [alter.owner, alter.prefix, alter.name, alter.profile_pic_url]) } editAlter(alter: MemberModel){ - this.db.run("UPDATE alters SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE alters.id ='" + alter.id + "'", + this.db.run("UPDATE members SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE members.id ='" + alter.id + "'", [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color]) } delete(alterId: number) { - this.db.run("DELETE FROM alters WHERE alters.id='"+ alterId + "'") + this.db.run("DELETE FROM members WHERE members.id='"+ alterId + "'") } } diff --git a/src/repositories/UserRepo.ts b/src/repositories/UserRepo.ts new file mode 100644 index 0000000..1e856cc --- /dev/null +++ b/src/repositories/UserRepo.ts @@ -0,0 +1,14 @@ +import { Database } from "sqlite3"; + +class UserRepo { + db: Database + + constructor(database: Database) { + this.db = database + } + + getById() {} + new() {} + delete() {} + +} diff --git a/src/utils/dbInit.ts b/src/utils/dbInit.ts index 64b3d61..edd07fb 100644 --- a/src/utils/dbInit.ts +++ b/src/utils/dbInit.ts @@ -1,5 +1,17 @@ +import { Database } from "sqlite3"; +function dbInit(database: Database){ + database.run("CREATE TABLE IF NOT EXISTS members (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)"); -export function dbInit(){ - + database.run(` + CREATE TABLE IF NOT EXISTS users( + id INTEGER PRIMARY KEY AUTOINCREMENT, + revolt_id TEXT NOT NULL, + auto_proxy BOOLEAN NOT NULL, + auto_proxy_member INTEGER, + FOREIGN KEY (auto_proxy_member) + REFERENCES members (id)) + `); } + +export default dbInit From cbcb100525de2c08ef14ac1cd6731f018cc12287 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 20:17:59 +0100 Subject: [PATCH 27/36] readme instructions on how to selfhost --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..d848029 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# MultiPastries +MultiPastries is a pluralkit alternative for the revolt chat platform. +It supports creating members and sending messages as one of the members. + +## How to host the bot yourself. +### requirements. +SQLite on arch. +```bash +sudo pacman -S sqlite +``` +You will need to install the bun runtime from their installation script. +```bash +curl -fsSL https://bun.sh/install | bash +``` From fd3977d224bb4da2c2d1adaab242c39afee2b541 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 20:18:26 +0100 Subject: [PATCH 28/36] small changes to the queries --- src/repositories/MemberRepo.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/repositories/MemberRepo.ts b/src/repositories/MemberRepo.ts index c762279..ff24e03 100644 --- a/src/repositories/MemberRepo.ts +++ b/src/repositories/MemberRepo.ts @@ -27,12 +27,12 @@ export class MemberRepo { } editAlter(alter: MemberModel){ - this.db.run("UPDATE members SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE members.id ='" + alter.id + "'", - [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color]) + this.db.run("UPDATE members SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE members.id=?", + [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color, alter.id]) } delete(alterId: number) { - this.db.run("DELETE FROM members WHERE members.id='"+ alterId + "'") + this.db.run("DELETE FROM members WHERE members.id=?", [alterId]) } } From bd24d7c34b61ed20b05343b87ec5ebf2c167ebcb Mon Sep 17 00:00:00 2001 From: strawberry cake Date: Fri, 15 Mar 2024 19:24:18 +0000 Subject: [PATCH 29/36] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d848029..9f1db77 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# MultiPastries -MultiPastries is a pluralkit alternative for the revolt chat platform. +# PluriPastries +PluriPastries is a pluralkit alternative for the revolt chat platform. It supports creating members and sending messages as one of the members. ## How to host the bot yourself. From 49321cada3759cd098700aaeddfb0777e8df841a Mon Sep 17 00:00:00 2001 From: strawberry cake Date: Fri, 15 Mar 2024 19:40:45 +0000 Subject: [PATCH 30/36] Update package.json --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e44d4eb..9a6d460 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "cakebot-revolt", - "version": "1.0.0", + "name": "pluripastries", + "version": "0.5.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "author": "", - "license": "ISC", + "author": "cake", + "license": "GPLv3", "devDependencies": { "@types/sqlite3": "^3.1.8", "typescript": "^5.1.3", From 0a56096f090a2d4a36c3dc39e0f2571462aef1e7 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 23:20:11 +0100 Subject: [PATCH 31/36] fixed a bug in sendAsMemberHandler.ts and switched to bun's sqlite library --- bun.lockb | Bin 57707 -> 19127 bytes package.json | 5 ++-- src/commands/avatarMemberChange.ts | 2 +- src/commands/colorMemberChange.ts | 2 +- src/commands/createMember.ts | 2 +- src/commands/deleteMember.ts | 2 +- src/commands/listMember.ts | 2 +- src/commands/migrateMember.ts | 2 +- src/index.ts | 2 +- src/repositories/MemberRepo.ts | 29 +++++++++++--------- src/repositories/UserRepo.ts | 42 ++++++++++++++++++++++++++--- src/utils/checkAutoProxy.ts | 17 ++++++------ src/utils/commandHandler.ts | 2 +- src/utils/dbInit.ts | 2 +- src/utils/nonCommandHandler.ts | 4 ++- src/utils/sendAsMemberHandler.ts | 17 +++++++----- tsconfig.json | 3 +++ 17 files changed, 91 insertions(+), 44 deletions(-) diff --git a/bun.lockb b/bun.lockb index 34c1ebd37c6d1d560e579109816d1858277b9a4d..8f3c2ee195845db8337fa09e3e7d8df85c9ac17e 100755 GIT binary patch delta 3734 zcmeHKdr(x@8Nc_k3wswXPtip{1mz{}0t>hxxPn2WEVgb;TpyLlOIYNgq6M@HW7HZ( zr{Xuht&duxO{0}(H5!Z7)`*XS(W>d#=roxkMjKlvjhU$ZeV1J)nd!7M{kw-b{O<3Z z?|$cdoco=#56*e~daJnE6kosK>Ys-9t+wl?FFP=+tS7?r@HXSI-Cu9t<@M~ZKbvN_ z5Su5c&D`RM2pvcsB!mBb1)-_7yt1?&bSm|EL`)urC%roAT;#-auOtY5;N3ufU`D;xtAaW0&fFZ z^YZEvXEBzZryHE_#W=4}R#{WD6qer8QJcop=nwS@hCN*P2&#j@bG-#21b7GtXPR!i z#?QMj5;z>=ZbuOURedd#@iOH=yxKGXWOF{4nKyH6!FBH!QyR8izS-ipX|iunSlUq9 zuA8HC*so8Y|M!dc=nLIf{wqH(yRsqhLDa!ZI~w*?TyxSF@@%ag+Rdc+WJ+%d)I8cM z#fsE3+A7z>>Lh5FC?MD(wTqM&ZIzNGY6etE)Dvx$KS6}2Ktx9^-WEC90~rDnsU^xH zSAk`Nd63=PqCE;WgOs6}@-sY*$GA)ZAr^TGa={uTvin-(U0}JYhCaPTegKvVrcn)u z&{9vVRrS7EA#{EmDk*n#WkR6-ep?x`KEd){#EJDnGygFCtKYk426| z2C`Jv=VOs7W$J;*&oRicf*paGS{Bw2reyPCBmFAR z5EkJHEn^T=7iElb+N2WrhZ`wpJY6Y8`rBLt!nxv6jCZ|Vl2(6fPb$l^Z{5r$&270Sk)q% zm_R4Nj!ac3ywWBb$yo{irYViZC+!)vUdd&@>3^8y+dA)Jfi8EgVcnb?w^rPX_qi-I zfA8r(|MoQ7xqjV{@TM-mv-b|HDS0orXY}sIz^j{PAGE!LJc+_{zvoD^`>W*CY0i`c z+An;(ZOfRxh>Ay__J91w=lAbzc;}PFT}$tnU)W}C8Kv`ke)3Cu$ia*^4mb`)ZfLzQ zZ@(_^t@Vu)&aBiJ?zTRmXVVP%DUW|L=k>1clYyK2Zq%Pl7*_V%Pfs_@F!`NVOr_`c z+}H1p)XEpDif3i+jo#4thl@`}(c_|1&OJ~6xW;b1)SDXjE$fnLNmU*B>*J_fuZdn> z=`3M8D`7W^aua{l%NiD!medprM=*wB$;W|rB5hu>mfxUneyG#_8K;{Wtv+bqrHyf#aESGT%E-l^pRMDuL#XPl-IBxDu%T8HWbPFBr{tA zTg-HBTlS>qF9sVAaRGxhd?Qhto3pv@YRkopWp=pKEJ&f4-BDaJ)nOLpA`8>i@`W=) zEm2%>ag+*tvdCoL8I;3U7Tlcpq*N;*FEA3F?dFm{0-X;G+`9OV#@8aXf<^5>>&Oe6R$hDT#n*nnbPf>{Uc)XyT(1Y@?L3%K>DDO77Z2}Q1_38 z&?t|6_Wh}!4KA8$N*9JvVta~I?nNc-3#DE!y4-G-ZhLL%Fod~(IJ|$SV)clQC0p?h zjA3)|(;>BEp_J=QBRb8}A#dvK$RA|+eNaAWU;)CqDe;K$h_LxaG zA+Je7xk8nlhSBby3UW=>?+5I=PC+2eWFBWq71H_sfp#L3j&x@82Ov;?XOa{x(eN&7 zY&1R?E^2Gj(=LnkzR&wz;t_c)iG*b>Pq&Utrn`F$w7ttuE?Qn~}hO2T2;)U9C~|pOP<(#s>RnbT>_ H-TVInSiKF# literal 57707 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

$J}zzdQ@EKD0})QQSYKn`gf;PeV+~ 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 D&B)R^ diff --git a/package.json b/package.json index e44d4eb..0aa3a17 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,12 @@ "author": "", "license": "ISC", "devDependencies": { - "@types/sqlite3": "^3.1.8", + "bun-types": "^1.0.31", "typescript": "^5.1.3", "typescript-language-server": "^3.3.2" }, "dependencies": { "revolt.js": "^7.0.0-beta.9", - "shlex": "^2.1.2", - "sqlite3": "^5.1.6" + "shlex": "^2.1.2" } } diff --git a/src/commands/avatarMemberChange.ts b/src/commands/avatarMemberChange.ts index cd0c649..f17defb 100644 --- a/src/commands/avatarMemberChange.ts +++ b/src/commands/avatarMemberChange.ts @@ -1,4 +1,4 @@ -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import MemberModel from "../models/MemberModel" import { MemberRepo } from "../repositories/MemberRepo" diff --git a/src/commands/colorMemberChange.ts b/src/commands/colorMemberChange.ts index c99bd41..1f45b1d 100644 --- a/src/commands/colorMemberChange.ts +++ b/src/commands/colorMemberChange.ts @@ -1,6 +1,6 @@ import { MemberRepo } from "../repositories/MemberRepo" import MemberModel from "../models/MemberModel" -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; async function colorMemberChange(userId: string, args: string[], database: Database){ const memberRepo = new MemberRepo(database); diff --git a/src/commands/createMember.ts b/src/commands/createMember.ts index 33111d5..e684bae 100644 --- a/src/commands/createMember.ts +++ b/src/commands/createMember.ts @@ -1,4 +1,4 @@ -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import { MemberRepo } from "../repositories/MemberRepo"; import MemberModel from "models/MemberModel" diff --git a/src/commands/deleteMember.ts b/src/commands/deleteMember.ts index 74b5c19..329a9d1 100644 --- a/src/commands/deleteMember.ts +++ b/src/commands/deleteMember.ts @@ -1,6 +1,6 @@ import { MemberRepo } from "../repositories/MemberRepo" import MemberModel from "../models/MemberModel" -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; export async function deleteMember(userId: string, args: string[], database: Database) { const memberRepo = new MemberRepo(database); diff --git a/src/commands/listMember.ts b/src/commands/listMember.ts index 18cf368..d8e8b38 100644 --- a/src/commands/listMember.ts +++ b/src/commands/listMember.ts @@ -1,6 +1,6 @@ import { MemberRepo } from "../repositories/MemberRepo" import { tableConstructor } from '../utils/tableConstructor' -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import MemberModel from "../models/MemberModel"; async function listMember(userId: string, database: Database) { diff --git a/src/commands/migrateMember.ts b/src/commands/migrateMember.ts index a9982ce..b7e1b6c 100644 --- a/src/commands/migrateMember.ts +++ b/src/commands/migrateMember.ts @@ -1,5 +1,5 @@ import { File } from "revolt.js" -import { Database } from "sqlite3" +import { Database } from "bun:sqlite" import createMember from "./createMember" import { avatarMemberChange } from "./avatarMemberChange" diff --git a/src/index.ts b/src/index.ts index 8136997..caa7c21 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { Client, Message } from "revolt.js"; import { commandHandler } from "./utils/commandHandler" import { nonCommandHandler } from "./utils/nonCommandHandler" -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import config from "../config.json" import dbInit from "utils/dbInit"; diff --git a/src/repositories/MemberRepo.ts b/src/repositories/MemberRepo.ts index ff24e03..7070c7e 100644 --- a/src/repositories/MemberRepo.ts +++ b/src/repositories/MemberRepo.ts @@ -1,4 +1,4 @@ -import { Database } from 'sqlite3'; +import { Database } from 'bun:sqlite'; import MemberModel from '../models/MemberModel'; export class MemberRepo { @@ -9,30 +9,33 @@ export class MemberRepo { } async getAltersByUserId(userId : string) : Promise { - const query : string = 'SELECT * FROM members WHERE members.owner = "' + userId + '"' + const query = this.db.query("SELECT * FROM members WHERE members.owner=?") - let result: MemberModel[] = await new Promise((resolve, reject) => { - this.db.all(query, (err, row: MemberModel[]) => { - if (err) { return reject(err)} - else { return resolve(row) } - }) + let result: MemberModel[] = query.all(userId).map( (row: any) => { + const mapped_row: MemberModel = { + id: row.id, + "name": row.name, + "prefix": row.prefix, + "owner": row.owner, + "profile_pic_url": row.profile_pic_url + } + return mapped_row }) - return result } addAlterForUser(alter: MemberModel){ - this.db.run("INSERT INTO members (owner, prefix, name, profile_pic_url, color) VALUES(?, ?, ?, ?, ?)", - [alter.owner, alter.prefix, alter.name, alter.profile_pic_url]) + this.db.query("INSERT INTO members (owner, prefix, name, profile_pic_url) VALUES(?, ?, ?, ?)") + .run(alter.owner, alter.prefix, alter.name, alter.profile_pic_url) } editAlter(alter: MemberModel){ - this.db.run("UPDATE members SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE members.id=?", - [alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color, alter.id]) + this.db.query("UPDATE members SET owner=?, prefix=?, name=?, profile_pic_url=?, color=? WHERE members.id=?") + .run(alter.owner, alter.prefix, alter.name, alter.profile_pic_url, alter.color, alter.id) } delete(alterId: number) { - this.db.run("DELETE FROM members WHERE members.id=?", [alterId]) + this.db.query("DELETE FROM members WHERE members.id=?").run(alterId) } } diff --git a/src/repositories/UserRepo.ts b/src/repositories/UserRepo.ts index 1e856cc..c25e5a3 100644 --- a/src/repositories/UserRepo.ts +++ b/src/repositories/UserRepo.ts @@ -1,4 +1,5 @@ -import { Database } from "sqlite3"; +import UserModel from "models/UserModel"; +import { Database } from "bun:sqlite"; class UserRepo { db: Database @@ -7,8 +8,41 @@ class UserRepo { this.db = database } - getById() {} - new() {} - delete() {} + getById(id) { + const row = this.db.run(` + SELECT * + FROM users + WHERE users.id = ? + `, [id]) + return row + } + new(model: UserModel) {} + delete(id) {} + + isProxyEnabled(id: number) { + const row: any = this.db.query(` + SELECT auto_proxy + FROM users + WHERE users.id=? + `).get(id) + + let is_enabled: boolean + + is_enabled = row.auto_proxy == "TRUE" ? true : false + return is_enabled + } + + getIdByRevoltId(revolt_id: string){ + const row: any = this.db.query(` + SELECT id + FROM users + WHERE users.revolt_id=? + `).get(revolt_id) + + const id: number = row.id + return id + } } + +export default UserRepo diff --git a/src/utils/checkAutoProxy.ts b/src/utils/checkAutoProxy.ts index 213a7b9..d3c2336 100644 --- a/src/utils/checkAutoProxy.ts +++ b/src/utils/checkAutoProxy.ts @@ -1,15 +1,16 @@ -import { MemberRepo } from "repositories/MemberRepo"; -import { Database } from "sqlite3"; +import UserRepo from "repositories/UserRepo"; +import { Database } from "bun:sqlite"; -async function checkAutoProxy +function checkAutoProxy ( - userId: number, + userId: string, database: Database -): Promise +) { - const repo = new MemberRepo(database) - - return true + const repo = new UserRepo(database) + const user_id = repo.getIdByRevoltId(userId) + const is_enabled = repo.isProxyEnabled(user_id) + return is_enabled } export default checkAutoProxy; diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index 5e00cc1..e03fd7b 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -1,5 +1,5 @@ import { Message } from "revolt.js" -import { Database } from "sqlite3" +import { Database } from "bun:sqlite" import { split } from "shlex" import { returnHelpText } from "../commands/help" diff --git a/src/utils/dbInit.ts b/src/utils/dbInit.ts index edd07fb..23a1c63 100644 --- a/src/utils/dbInit.ts +++ b/src/utils/dbInit.ts @@ -1,4 +1,4 @@ -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; function dbInit(database: Database){ database.run("CREATE TABLE IF NOT EXISTS members (id INTEGER PRIMARY KEY AUTOINCREMENT, owner TEXT, prefix TEXT, name TEXT, profile_pic_url TEXT, color TEXT)"); diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index e606b1b..add7a47 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -1,7 +1,9 @@ import { Message } from "revolt.js" -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import sendAsMember from "./sendAsMemberHandler"; +import checkAutoProxy from "./checkAutoProxy"; export async function nonCommandHandler(message : Message, database: Database){ await sendAsMember(message, database); + checkAutoProxy(message.author.id, database) } diff --git a/src/utils/sendAsMemberHandler.ts b/src/utils/sendAsMemberHandler.ts index 75d87be..0b239c3 100644 --- a/src/utils/sendAsMemberHandler.ts +++ b/src/utils/sendAsMemberHandler.ts @@ -1,16 +1,21 @@ import { Message } from "revolt.js" -import { Database } from "sqlite3"; +import { Database } from "bun:sqlite"; import { MemberRepo } from "../repositories/MemberRepo" import MemberModel from "../models/MemberModel" export default async function sendAsMember(message: Message, database: Database) { - const alterRepo: MemberRepo = new MemberRepo(database); - let alters: MemberModel[]; - await alterRepo.getAltersByUserId(message.author.id).then(result => alters = result); + const memberRepo: MemberRepo = new MemberRepo(database); + let members: MemberModel[]; + await memberRepo.getAltersByUserId(message.author.id).then(result => members = result); + if (members === undefined) {return} - alters.forEach( async alter => { + members.forEach( async alter => { const pre_prefix = alter.prefix.split("text"); - if (message.content.startsWith(pre_prefix[0]) && message.content.endsWith(pre_prefix[1])) { + if ( + message.content.startsWith(pre_prefix[0]) + && message.content.endsWith(pre_prefix[1] + && message.content.length > 1) + ) { let actualContent: string = message.content; actualContent = actualContent.slice(pre_prefix[0].length, actualContent.length - pre_prefix[1].length) diff --git a/tsconfig.json b/tsconfig.json index 3f3bf8d..a650685 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,9 @@ "esModuleInterop": true, "resolveJsonModule" : true, "target": "es6", + "types": [ + "bun-types" + ], "moduleResolution": "node", "sourceMap": true, "outDir": "dist", From ba6bb87b3f3044e3bf06696f0f28a1c374ae74b5 Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 23:33:28 +0100 Subject: [PATCH 32/36] trying to fix bugs in production ongod --- src/utils/sendAsMemberHandler.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/sendAsMemberHandler.ts b/src/utils/sendAsMemberHandler.ts index 0b239c3..ed37d69 100644 --- a/src/utils/sendAsMemberHandler.ts +++ b/src/utils/sendAsMemberHandler.ts @@ -7,7 +7,6 @@ export default async function sendAsMember(message: Message, database: Database) const memberRepo: MemberRepo = new MemberRepo(database); let members: MemberModel[]; await memberRepo.getAltersByUserId(message.author.id).then(result => members = result); - if (members === undefined) {return} members.forEach( async alter => { const pre_prefix = alter.prefix.split("text"); From 0a591323292707944658b0a9c0d46d0aaaec2aad Mon Sep 17 00:00:00 2001 From: Ale Date: Fri, 15 Mar 2024 23:40:10 +0100 Subject: [PATCH 33/36] fixed bug in production --- src/utils/sendAsMemberHandler.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/sendAsMemberHandler.ts b/src/utils/sendAsMemberHandler.ts index ed37d69..09aa3d9 100644 --- a/src/utils/sendAsMemberHandler.ts +++ b/src/utils/sendAsMemberHandler.ts @@ -7,14 +7,14 @@ export default async function sendAsMember(message: Message, database: Database) const memberRepo: MemberRepo = new MemberRepo(database); let members: MemberModel[]; await memberRepo.getAltersByUserId(message.author.id).then(result => members = result); - + members.forEach( async alter => { const pre_prefix = alter.prefix.split("text"); if ( message.content.startsWith(pre_prefix[0]) - && message.content.endsWith(pre_prefix[1] - && message.content.length > 1) - ) { + && message.content.endsWith(pre_prefix[1]) + && message.content.length > 1 + ){ let actualContent: string = message.content; actualContent = actualContent.slice(pre_prefix[0].length, actualContent.length - pre_prefix[1].length) From 962ff117edf0293ede38cac4ef8778c8a1860a6c Mon Sep 17 00:00:00 2001 From: Ale Date: Sun, 17 Mar 2024 17:13:51 +0100 Subject: [PATCH 34/36] added auto proxy --- src/commands/avatarMemberChange.ts | 3 +- src/commands/colorMemberChange.ts | 3 +- src/commands/createMember.ts | 3 +- src/commands/deleteMember.ts | 3 +- src/commands/help.ts | 5 ++- src/commands/listMember.ts | 3 +- src/commands/setAutoProxy.ts | 30 +++++++++++++++ src/commands/toggleAutoProxy.ts | 25 +++++++++++++ src/models/UserModel.ts | 4 +- src/repositories/MemberRepo.ts | 44 ++++++++++++++++++++-- src/repositories/UserRepo.ts | 59 +++++++++++++++++++++++++----- src/utils/checkAutoProxy.ts | 9 +++-- src/utils/commandHandler.ts | 21 +++++++++++ src/utils/nonCommandHandler.ts | 11 +++++- src/utils/sendAsAutoProxyMember.ts | 45 +++++++++++++++++++++++ src/utils/sendAsMemberHandler.ts | 3 +- 16 files changed, 238 insertions(+), 33 deletions(-) create mode 100644 src/commands/setAutoProxy.ts create mode 100644 src/commands/toggleAutoProxy.ts create mode 100644 src/utils/sendAsAutoProxyMember.ts diff --git a/src/commands/avatarMemberChange.ts b/src/commands/avatarMemberChange.ts index f17defb..4200fb5 100644 --- a/src/commands/avatarMemberChange.ts +++ b/src/commands/avatarMemberChange.ts @@ -4,8 +4,7 @@ import { MemberRepo } from "../repositories/MemberRepo" export async function avatarMemberChange(userId: string, args: string[], database: Database){ const memberRepo = new MemberRepo(database); - let userAlters : MemberModel[] = []; - await memberRepo.getAltersByUserId(userId).then( result => userAlters = result ) + const userAlters : MemberModel[] = memberRepo.getAltersByUserId(userId) let userAltersNames : string[] = []; userAlters.forEach(alter => userAltersNames.push(alter.name)); diff --git a/src/commands/colorMemberChange.ts b/src/commands/colorMemberChange.ts index 1f45b1d..f949d16 100644 --- a/src/commands/colorMemberChange.ts +++ b/src/commands/colorMemberChange.ts @@ -10,8 +10,7 @@ async function colorMemberChange(userId: string, args: string[], database: Datab const alterName = args[0]; const alterColor = args[1]; - let alters: MemberModel[]; - await memberRepo.getAltersByUserId(userId).then( result => alters = result ) // fetching alters from user. + const alters: MemberModel[] = memberRepo.getAltersByUserId(userId) // fetching alters from user. if (alters.length == 0) return "This user has no Members." // checking if returned array is at least not 0, if len 0, then return. let alterToEdit: MemberModel; diff --git a/src/commands/createMember.ts b/src/commands/createMember.ts index e684bae..257eabc 100644 --- a/src/commands/createMember.ts +++ b/src/commands/createMember.ts @@ -12,8 +12,7 @@ async function createMember(userId: string, args: string[], database: Database){ profile_pic_url: "https://tse3.mm.bing.net/th?id=OIP.yte7rRnbCnWi1giriwTOvwHaHa&pid=15.1" } - let userAlters: MemberModel[]; - await memberRepo.getAltersByUserId(userId).then(result => userAlters = result) + const userAlters: MemberModel[] = memberRepo.getAltersByUserId(userId) let alterTags : string[] = []; userAlters.forEach( alter => { diff --git a/src/commands/deleteMember.ts b/src/commands/deleteMember.ts index 329a9d1..c12cc68 100644 --- a/src/commands/deleteMember.ts +++ b/src/commands/deleteMember.ts @@ -7,8 +7,7 @@ export async function deleteMember(userId: string, args: string[], database: Dat let success: boolean = false; if (args.length === 1) { - let alters: MemberModel[]; - await memberRepo.getAltersByUserId(userId).then(result => alters = result ) + const alters: MemberModel[] = memberRepo.getAltersByUserId(userId) alters.forEach(alter => { if (alter.name == args[0]) { memberRepo.delete(alter.id) diff --git a/src/commands/help.ts b/src/commands/help.ts index ac725af..456c901 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -11,5 +11,8 @@ export function returnHelpText() { "- avatar <'Member's name'> <'picture url'> | Allows you to edit your Member's profile picture\n" + "- color <'Member's name'> <'color hex'> | Allows you to change the color of your Member ( may be integrated with the future website )\n"+ "### Migrations\n"+ - "- tupper < Json file attached > | Migrates your Member from tupper" + "- tupper < Json file attached > | Migrates your Member from tupper\n" + +"### Auto proxy\n" + +"- setAutoProxy | Sets the member to automatically send messages as\n" + +"- toggleAutoProxy | Enable or disable the autoproxy" } diff --git a/src/commands/listMember.ts b/src/commands/listMember.ts index d8e8b38..757e5fe 100644 --- a/src/commands/listMember.ts +++ b/src/commands/listMember.ts @@ -5,8 +5,7 @@ import MemberModel from "../models/MemberModel"; async function listMember(userId: string, database: Database) { const memberRepo = new MemberRepo(database); - let alters: MemberModel[]; - await memberRepo.getAltersByUserId(userId).then(result => { alters = result }) + const alters: MemberModel[] = memberRepo.getAltersByUserId(userId) if (alters.length > 0 ) { return tableConstructor(alters) diff --git a/src/commands/setAutoProxy.ts b/src/commands/setAutoProxy.ts new file mode 100644 index 0000000..a0a302f --- /dev/null +++ b/src/commands/setAutoProxy.ts @@ -0,0 +1,30 @@ +import Database from "bun:sqlite"; +import { MemberRepo } from "repositories/MemberRepo"; +import UserRepo from "repositories/UserRepo"; +import UserModel from "models/UserModel"; + +function setAutoProxy(author_id: string, args: string[], database: Database) { + + if (args.length != 1) {return 0} + + const memberRepo = new MemberRepo(database); + const userRepo = new UserRepo(database); + + const member = memberRepo.getByName(args[0], author_id); + if (member == null) {return 1} + + if ( + userRepo.getIdByRevoltId(author_id) + ){ + const user_model: UserModel = { + "revolt_id": author_id, + "autoProxy": false + } + userRepo.new(user_model) + } + + const bot_user_id = userRepo.getIdByRevoltId(author_id) + userRepo.setSelectedAutoProxyId(member.id, bot_user_id) +} + +export default setAutoProxy diff --git a/src/commands/toggleAutoProxy.ts b/src/commands/toggleAutoProxy.ts new file mode 100644 index 0000000..fc6ec4e --- /dev/null +++ b/src/commands/toggleAutoProxy.ts @@ -0,0 +1,25 @@ +import Database from "bun:sqlite" +import UserModel from "models/UserModel" +import UserRepo from "repositories/UserRepo" + +function toggleAutoProxy(revolt_id: string, database: Database) { + const userRepo = new UserRepo(database) + + if (userRepo.getById( + userRepo.getIdByRevoltId(revolt_id) + ) == null){ + const model: UserModel = { + "revolt_id": revolt_id, + "autoProxy": false, + } + userRepo.new(model) + } + const user_id = userRepo.getIdByRevoltId(revolt_id) + const is_enabled = userRepo.isProxyEnabled( + userRepo.getIdByRevoltId(revolt_id) + ) + + userRepo.setProxyStatus(user_id, !is_enabled) +} + +export default toggleAutoProxy diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts index a3fb039..94d60be 100644 --- a/src/models/UserModel.ts +++ b/src/models/UserModel.ts @@ -1,8 +1,8 @@ interface UserModel { - id: number, + id?: number, revolt_id: string, autoProxy: boolean, - autoProxyMember: number + autoProxyMember?: number } export default UserModel; diff --git a/src/repositories/MemberRepo.ts b/src/repositories/MemberRepo.ts index 7070c7e..61af4ee 100644 --- a/src/repositories/MemberRepo.ts +++ b/src/repositories/MemberRepo.ts @@ -8,12 +8,51 @@ export class MemberRepo { this.db = database_instance; } - async getAltersByUserId(userId : string) : Promise { + getById(member_id: number): MemberModel { + const row: any = this.db.query("SELECT * FROM members WHERE members.id=?") + .get(member_id) + + const mapped_row: MemberModel = { + "id": row.id, + "name": row.name, + "prefix": row.prefix, + "owner": row.owner, + "profile_pic_url": row.profile_pic_url + } + + return mapped_row + } + + getByName(name: string, user_id: string) { + if (name == null || user_id == null) {return null} + + const query = this.db.query(` + SELECT * + FROM members + WHERE members.name=? + AND members.owner=? + `) + + const row: any = query.get(name, user_id) + if (row == null) {return null} + + const mapped_row: MemberModel = { + "id": row.id, + "name": row.name, + "prefix": row.prefix, + "owner": row.owner, + "profile_pic_url": row.profile_pic_url + } + + return mapped_row + } + + getAltersByUserId(userId : string) : MemberModel[] { const query = this.db.query("SELECT * FROM members WHERE members.owner=?") let result: MemberModel[] = query.all(userId).map( (row: any) => { const mapped_row: MemberModel = { - id: row.id, + "id": row.id, "name": row.name, "prefix": row.prefix, "owner": row.owner, @@ -37,5 +76,4 @@ export class MemberRepo { delete(alterId: number) { this.db.query("DELETE FROM members WHERE members.id=?").run(alterId) } - } diff --git a/src/repositories/UserRepo.ts b/src/repositories/UserRepo.ts index c25e5a3..c79189d 100644 --- a/src/repositories/UserRepo.ts +++ b/src/repositories/UserRepo.ts @@ -9,18 +9,33 @@ class UserRepo { } getById(id) { - const row = this.db.run(` + const row: any = this.db.query(` SELECT * FROM users WHERE users.id = ? - `, [id]) - - return row + `).get(id) + if (row != null){ + return row.id + } + + return null + } + new(model: UserModel) { + this.db.query(` + INSERT INTO users (revolt_id, auto_proxy) values ( ?, ? ) + `) + .run(model.revolt_id, model.autoProxy) + } + delete(id) { + this.db.query(` + DELETE * + FROM users + WHERE users.id=? + `).run(id) } - new(model: UserModel) {} - delete(id) {} isProxyEnabled(id: number) { + if (id == null) { return false } const row: any = this.db.query(` SELECT auto_proxy FROM users @@ -33,15 +48,41 @@ class UserRepo { return is_enabled } - getIdByRevoltId(revolt_id: string){ + setProxyStatus(id: number, status: boolean) { + const string_status = status == true ? "TRUE" : "FALSE" + this.db.query("UPDATE users SET auto_proxy=? WHERE users.id=?").run(string_status, id) + } + + getIdByRevoltId(revolt_id: string): number | null { const row: any = this.db.query(` SELECT id FROM users WHERE users.revolt_id=? `).get(revolt_id) - const id: number = row.id - return id + if (row != null) { + const id: number = row.id + return id + } + return null + } + + setSelectedAutoProxyId(id: number, user_id: number){ + const query = this.db.query(` + UPDATE users + SET auto_proxy_member=? + WHERE users.id=? + `).run(id, user_id) + } + + getSelectedAutoProxyIdByUserId(id: number) { + const row: any = this.db.query(` + SELECT auto_proxy_member + FROM users + WHERE users.id=? + `).get(id) + + return row.auto_proxy_member } } diff --git a/src/utils/checkAutoProxy.ts b/src/utils/checkAutoProxy.ts index d3c2336..416fe0e 100644 --- a/src/utils/checkAutoProxy.ts +++ b/src/utils/checkAutoProxy.ts @@ -5,11 +5,12 @@ function checkAutoProxy ( userId: string, database: Database -) +): boolean { - const repo = new UserRepo(database) - const user_id = repo.getIdByRevoltId(userId) - const is_enabled = repo.isProxyEnabled(user_id) + const repo = new UserRepo(database); + const user_id = repo.getIdByRevoltId(userId); + const is_enabled = repo.isProxyEnabled(user_id); + return is_enabled } diff --git a/src/utils/commandHandler.ts b/src/utils/commandHandler.ts index e03fd7b..6ab57e8 100644 --- a/src/utils/commandHandler.ts +++ b/src/utils/commandHandler.ts @@ -9,6 +9,8 @@ import { deleteMember } from "../commands/deleteMember" import { avatarMemberChange } from "../commands/avatarMemberChange" import colorMemberChange from "../commands/colorMemberChange" import migrationCommand from "../commands/migrateMember" +import toggleAutoProxy from "commands/toggleAutoProxy" +import setAutoProxy from "commands/setAutoProxy" @@ -40,6 +42,25 @@ export async function commandHandler(message : Message, db: Database, _prefix : await message.reply(await avatarMemberChange(message.author.id, args, db)); break } + case "setAutoProxy": { + const status = setAutoProxy(message.author.id, args, db); + switch(status) { + case 0: { + await message.reply("not enough arguments") + break + } + case 1: { + message.reply("no member found with that member name") + break + } + } + break + } + case "toggleAutoProxy": { + toggleAutoProxy(message.author.id, db) + await message.reply("toggled") + break + } case "color" : { await message.reply(await colorMemberChange(message.author.id, args, db)); break diff --git a/src/utils/nonCommandHandler.ts b/src/utils/nonCommandHandler.ts index add7a47..d918f86 100644 --- a/src/utils/nonCommandHandler.ts +++ b/src/utils/nonCommandHandler.ts @@ -2,8 +2,15 @@ import { Message } from "revolt.js" import { Database } from "bun:sqlite"; import sendAsMember from "./sendAsMemberHandler"; import checkAutoProxy from "./checkAutoProxy"; +import sendAsAutoProxyMember from "./sendAsAutoProxyMember"; export async function nonCommandHandler(message : Message, database: Database){ - await sendAsMember(message, database); - checkAutoProxy(message.author.id, database) + const should_auto_proxy = checkAutoProxy(message.author.id, database) + + if (should_auto_proxy) { + await sendAsAutoProxyMember(message.author.id, message, database) + } + else { + await sendAsMember(message, database); + } } diff --git a/src/utils/sendAsAutoProxyMember.ts b/src/utils/sendAsAutoProxyMember.ts new file mode 100644 index 0000000..32008f4 --- /dev/null +++ b/src/utils/sendAsAutoProxyMember.ts @@ -0,0 +1,45 @@ +import Database from "bun:sqlite"; +import { Message } from "revolt.js" +import { MemberRepo } from "repositories/MemberRepo"; +import UserRepo from "repositories/UserRepo"; +import MemberModel from "models/MemberModel"; + +async function sendAsAutoProxyMember(revolt_uid: string, message: Message, database: Database) { + // assumes that every check has been done previously + + const userRepo = new UserRepo(database) + const memberRepo = new MemberRepo(database) + + const user_id = userRepo.getIdByRevoltId(revolt_uid) + const auto_proxy_id = userRepo.getSelectedAutoProxyIdByUserId(user_id) + + const member_to_proxy_as: MemberModel = memberRepo.getById(auto_proxy_id) + const replyIds: string[] | undefined = message.replyIds; + let replies: any[] = []; + + if (replyIds !== undefined) { + replyIds.forEach( replyId => { + replies.push({ + id: replyId, + mention: false + }) + }) + } + + try{ + await message.channel.sendMessage({ + content: message.content, + masquerade: { + name: member_to_proxy_as.name , + }, + replies: replies + }) + await message.delete(); + } + catch(e){ + console.log(e) + await message.channel.sendMessage("Error: PluralCake requires at least these permissions: \n- Masquerade permissions. \n- Message editing permissions.") + } +} + +export default sendAsAutoProxyMember diff --git a/src/utils/sendAsMemberHandler.ts b/src/utils/sendAsMemberHandler.ts index 09aa3d9..1f75840 100644 --- a/src/utils/sendAsMemberHandler.ts +++ b/src/utils/sendAsMemberHandler.ts @@ -5,8 +5,7 @@ import MemberModel from "../models/MemberModel" export default async function sendAsMember(message: Message, database: Database) { const memberRepo: MemberRepo = new MemberRepo(database); - let members: MemberModel[]; - await memberRepo.getAltersByUserId(message.author.id).then(result => members = result); + let members: MemberModel[] = memberRepo.getAltersByUserId(message.author.id); members.forEach( async alter => { const pre_prefix = alter.prefix.split("text"); From 4f4f6235f59a0067d5e61fb0f97c3c14d49e1d79 Mon Sep 17 00:00:00 2001 From: Ale Date: Sun, 17 Mar 2024 17:19:26 +0100 Subject: [PATCH 35/36] auto proxy pfp fix --- src/utils/sendAsAutoProxyMember.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/sendAsAutoProxyMember.ts b/src/utils/sendAsAutoProxyMember.ts index 32008f4..a76572b 100644 --- a/src/utils/sendAsAutoProxyMember.ts +++ b/src/utils/sendAsAutoProxyMember.ts @@ -30,7 +30,8 @@ async function sendAsAutoProxyMember(revolt_uid: string, message: Message, datab await message.channel.sendMessage({ content: message.content, masquerade: { - name: member_to_proxy_as.name , + name: member_to_proxy_as.name, + avatar: member_to_proxy_as.profile_pic_url }, replies: replies }) From 73fdcc95a790b21822c1923576f3d083a2f50982 Mon Sep 17 00:00:00 2001 From: Ale Date: Mon, 15 Jul 2024 22:47:25 +0200 Subject: [PATCH 36/36] feat: skeleton --- .gitignore | 162 ++++++++++++++++++++++ README.md | 1 + pdm.lock | 239 +++++++++++++++++++++++++++++++++ pyproject.toml | 19 +++ src/commandHandler/__init__.py | 19 +++ src/models/alter.py | 2 + src/models/user.py | 2 + src/pluralcakepy/__init__.py | 0 src/pluralcakepy/__main__.py | 28 ++++ src/utils.py | 4 + tests/__init__.py | 0 11 files changed, 476 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pdm.lock create mode 100644 pyproject.toml create mode 100644 src/commandHandler/__init__.py create mode 100644 src/models/alter.py create mode 100644 src/models/user.py create mode 100644 src/pluralcakepy/__init__.py create mode 100644 src/pluralcakepy/__main__.py create mode 100644 src/utils.py create mode 100644 tests/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a8816c --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm-project.org/#use-with-ide +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..811f297 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# pluralcakepy diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..6ae4dbb --- /dev/null +++ b/pdm.lock @@ -0,0 +1,239 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.1" +content_hash = "sha256:5cd19c2d8cd5b70d4f61f66164d3d27b583373b94f43afd456e68d6f9fe70c63" + +[[package]] +name = "aenum" +version = "3.1.15" +summary = "Advanced Enumerations (compatible with Python's stdlib Enum), NamedTuples, and NamedConstants" +groups = ["default"] +files = [ + {file = "aenum-3.1.15-py3-none-any.whl", hash = "sha256:e0dfaeea4c2bd362144b87377e2c61d91958c5ed0b4daf89cb6f45ae23af6288"}, + {file = "aenum-3.1.15.tar.gz", hash = "sha256:8cbd76cd18c4f870ff39b24284d3ea028fbe8731a58df3aa581e434c575b9559"}, +] + +[[package]] +name = "aiohttp" +version = "3.8.6" +requires_python = ">=3.6" +summary = "Async http client/server framework (asyncio)" +groups = ["default"] +dependencies = [ + "aiosignal>=1.1.2", + "async-timeout<5.0,>=4.0.0a3", + "attrs>=17.3.0", + "charset-normalizer<4.0,>=2.0", + "frozenlist>=1.1.1", + "multidict<7.0,>=4.5", + "yarl<2.0,>=1.0", +] +files = [ + {file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"}, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +requires_python = ">=3.7" +summary = "aiosignal: a list of registered asynchronous callbacks" +groups = ["default"] +dependencies = [ + "frozenlist>=1.1.0", +] +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[[package]] +name = "async-timeout" +version = "4.0.3" +requires_python = ">=3.7" +summary = "Timeout context manager for asyncio programs" +groups = ["default"] +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +requires_python = ">=3.7" +summary = "Classes Without Boilerplate" +groups = ["default"] +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["default"] +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "frozenlist" +version = "1.4.1" +requires_python = ">=3.8" +summary = "A list-like structure which implements collections.abc.MutableSequence" +groups = ["default"] +files = [ + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "idna" +version = "3.7" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "multidict" +version = "6.0.5" +requires_python = ">=3.7" +summary = "multidict implementation" +groups = ["default"] +files = [ + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + +[[package]] +name = "peewee" +version = "3.17.6" +summary = "a little orm" +groups = ["default"] +files = [ + {file = "peewee-3.17.6.tar.gz", hash = "sha256:cea5592c6f4da1592b7cff8eaf655be6648a1f5857469e30037bf920c03fb8fb"}, +] + +[[package]] +name = "revolt-py" +version = "0.2.0" +requires_python = ">=3.9" +summary = "Python wrapper for the revolt.chat API" +groups = ["default"] +dependencies = [ + "aenum==3.1.*", + "aiohttp==3.8.*", + "typing-extensions>=4.4.0", + "ulid-py==1.1.*", +] +files = [ + {file = "revolt.py-0.2.0-py3-none-any.whl", hash = "sha256:d40876db30ff23904e3bc46cfda62ddfff8abf4147df41d2811b9a565cefc4ae"}, + {file = "revolt.py-0.2.0.tar.gz", hash = "sha256:06d54d3796df20d7382502c25060fe3eed061f8d200626f3ed171e927ce8b371"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default"] +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "ulid-py" +version = "1.1.0" +summary = "Universally Unique Lexicographically Sortable Identifier" +groups = ["default"] +files = [ + {file = "ulid-py-1.1.0.tar.gz", hash = "sha256:dc6884be91558df077c3011b9fb0c87d1097cb8fc6534b11f310161afd5738f0"}, + {file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"}, +] + +[[package]] +name = "yarl" +version = "1.9.4" +requires_python = ">=3.7" +summary = "Yet another URL library" +groups = ["default"] +dependencies = [ + "idna>=2.0", + "multidict>=4.0", +] +files = [ + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1532824 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "pluralcakepy" +version = "0.1.0" +description = "Default template for PDM package" +authors = [ + {name = "cake", email = "cake@cakey.me"}, +] +dependencies = [ + "revolt-py>=0.2.0", + "aiohttp>=3.8.6", + "peewee>=3.17.6", +] +requires-python = "==3.11.*" +readme = "README.md" +license = {text = "AGPLv3"} + + +[tool.pdm] +distribution = false diff --git a/src/commandHandler/__init__.py b/src/commandHandler/__init__.py new file mode 100644 index 0000000..59302e1 --- /dev/null +++ b/src/commandHandler/__init__.py @@ -0,0 +1,19 @@ +from revolt import Message +from utils import split_args + +def commandHandler(message: Message, debug: bool = False) -> None: + content: str | None = message.content + arguments: list[str] = split_args(content) + prefix = arguments.pop(0) + command: str = arguments.pop(0) + + if debug: + print(f"author id: {message.author.id}\ + \nauthor name: {message.author.nickname}\ + \ncontent: {content}\ + \ncommand: {command}\ + \nargs: {arguments}" + ) + + if message.author.bot or not content: + return diff --git a/src/models/alter.py b/src/models/alter.py new file mode 100644 index 0000000..76f8e25 --- /dev/null +++ b/src/models/alter.py @@ -0,0 +1,2 @@ +class Alter: + ... diff --git a/src/models/user.py b/src/models/user.py new file mode 100644 index 0000000..8e981d1 --- /dev/null +++ b/src/models/user.py @@ -0,0 +1,2 @@ +class User: + ... diff --git a/src/pluralcakepy/__init__.py b/src/pluralcakepy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/pluralcakepy/__main__.py b/src/pluralcakepy/__main__.py new file mode 100644 index 0000000..14554e1 --- /dev/null +++ b/src/pluralcakepy/__main__.py @@ -0,0 +1,28 @@ +import revolt +import asyncio +import os + +from commandHandler import commandHandler + + +class Client(revolt.Client): + async def on_message(self, message: revolt.Message) -> None: + commandHandler(message, debug=os.environ.get("debug")) + + +async def main(): + revolt_token: str | None = os.environ.get("REVOLTTOKEN") + + if not revolt_token: + raise Exception("no REVOLTTOKEN environment variable") + + async with revolt.utils.client_session() as revolt_session: + revolt_client: Client = Client( + session=revolt_session, + token=revolt_token + ) + + await revolt_client.start() + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..cf1321b --- /dev/null +++ b/src/utils.py @@ -0,0 +1,4 @@ +from shlex import split + +def split_args(message: str) -> list[str]: + return split(message) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29