From 2bfbf3c661b6c8a56253cfaf86c9bc82934c89a6 Mon Sep 17 00:00:00 2001
From: Tagadda <36127788+Tagadda@users.noreply.github.com>
Date: Sat, 9 Jun 2018 12:29:07 +0200
Subject: [PATCH] Implements commands

---
 CommandBase.js          |  7 ++++++
 README.md               |  8 +++----
 bot.js                  | 20 +++++++++++++---
 commands/BlockDomain.js | 18 ++++++++++++++
 commands/MuteUser.js    | 18 ++++++++++++++
 commands/Unfollow.js    | 18 ++++++++++++++
 index.js                | 53 ++++++++++++++++++++++++++++++++++++++---
 package.json            |  1 +
 8 files changed, 133 insertions(+), 10 deletions(-)
 create mode 100644 CommandBase.js
 create mode 100644 commands/BlockDomain.js
 create mode 100644 commands/MuteUser.js
 create mode 100644 commands/Unfollow.js

diff --git a/CommandBase.js b/CommandBase.js
new file mode 100644
index 0000000..2222d78
--- /dev/null
+++ b/CommandBase.js
@@ -0,0 +1,7 @@
+class CommandBase {
+    constructor(client) {
+        this.client = client;
+    }
+}
+
+module.exports = CommandBase;
\ No newline at end of file
diff --git a/README.md b/README.md
index d8a9df9..5e94206 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,13 @@ This bot listens on the Federated Timeline and follows everyone.
 This bot respect the #nobot tag.
 
 If you don't want to be followed by the bot anymore, 
-just DM "unfollow" to the bot, and it'll never follow you again. [WIP]
+just DM "unfollow" to the bot, and it'll never follow you again.
 
 |Command|What is does|
 |---|---|
-|unfollow|[WIP] The bot will unfollow and mure you so it'll never follow you again.|
-|blockuser <user@domain.tld>|[WIP] The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.|
-|blockdomain <domain.tld>|[WIP] The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.|
+|unfollow|The bot will unfollow and mure you so it'll never follow you again.|
+|blockuser <user@domain.tld>|The bot will mute the targeted user. If followed, it'll unfollow they too. Admin only.|
+|blockdomain <domain.tld>|The bot will mute the targeted domain. If users from this domain are followed, it'll unfollow them. Admin only.|
 
 ## Running the bot
 
diff --git a/bot.js b/bot.js
index 63dab79..753137b 100644
--- a/bot.js
+++ b/bot.js
@@ -1,9 +1,6 @@
 const EventEmitter = require('events');
 const MastodonAPI = require('mastodon-api');
 
-// Todo: Implements mute_user and block_domain
-// Todo: Implements unfollow
-
 class Bot extends EventEmitter {
     /**
      * Constructor
@@ -110,6 +107,15 @@ class Bot extends EventEmitter {
     follow(id) {
         this.M.post('accounts/' + id + '/follow');
     }
+
+    /**
+     * Unfollow a user
+     * @param {int} id
+     */
+    unfollow(id) {
+        this.M.post('accounts/' + id + '/unfollow');
+    }
+
     /**
      * Mute an user
      * @param {int} id
@@ -118,5 +124,13 @@ class Bot extends EventEmitter {
         this.M.post('accounts/' + id + '/mute');
     }
 
+    /**
+     * Block a domain
+     * @param {string} domain
+     */
+    block_domain(domain) {
+        this.M.post('domain_blocks', { domain });
+    }
 }
+
 module.exports = Bot;
\ No newline at end of file
diff --git a/commands/BlockDomain.js b/commands/BlockDomain.js
new file mode 100644
index 0000000..1a9753e
--- /dev/null
+++ b/commands/BlockDomain.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class BlockDomain extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'blockdomain';
+        this.admin_only = true;
+        this.required_args = 1;
+    }
+
+    execute(msg, args) {
+        this.client.block_domain(args[0]);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = BlockDomain;
\ No newline at end of file
diff --git a/commands/MuteUser.js b/commands/MuteUser.js
new file mode 100644
index 0000000..116465b
--- /dev/null
+++ b/commands/MuteUser.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class MuteUser extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'muteuser';
+        this.admin_only = true;
+        this.required_args = 1;
+    }
+
+    execute(msg, args) {
+        this.client.mute_user(args[0]);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = MuteUser;
\ No newline at end of file
diff --git a/commands/Unfollow.js b/commands/Unfollow.js
new file mode 100644
index 0000000..9505c02
--- /dev/null
+++ b/commands/Unfollow.js
@@ -0,0 +1,18 @@
+const CommandBase = require('../CommandBase');
+
+class Unfollow extends CommandBase {
+    constructor(client) {
+        super(client);
+        this.name = 'unfollow';
+    }
+
+    execute(msg) {
+        this.client.unfollow(msg.account.id);
+
+        this.client.mute_user(msg.account.id);
+
+        this.client.fav(msg.status.id);
+    }
+}
+
+module.exports = Unfollow;
\ No newline at end of file
diff --git a/index.js b/index.js
index 7e3c39a..fadc7a8 100644
--- a/index.js
+++ b/index.js
@@ -1,10 +1,23 @@
 const Bot = require("./bot");
 const striptags = require('striptags');
+const fs = require('fs');
+const Dict = require('collections/dict');
 const config = require('./config.json');
 
+// Hardcode admins since Mastodon API doesn't provide such thing...
+const admins = ['tagadmin', 'Dhveszak', 'Incandescente'];
+
 const client = new Bot(config, [{api_point: "public", events: ["update"]},
                                 {api_point: "user", events: ["notification"]}]);
 
+const commands = new Dict();
+const commandFiles = fs.readdirSync(__dirname + "/commands/");
+for (const file of commandFiles) {
+    const commandClass = require(__dirname + "/commands/" + file);
+    const command = new commandClass(client);
+    commands.set(command.name, command)
+}
+
 // Following list
 const following = [];
 
@@ -16,6 +29,7 @@ client.start().then(() => {
     });
 });
 
+// When a toot arrives in Federated Timeline
 client.on('update', (msg) => {
     const acct = msg.account.acct;
     const id = parseInt(msg.account.id);
@@ -45,10 +59,43 @@ client.on('update', (msg) => {
     console.log("NOW FOLLOWS: " + acct);
 });
 
+// When a toto arrives in notifications (mentions)
 client.on("notification", (msg) => {
     if (msg.type !== "mention") return;
 
-    // Todo: Implement unfollow command
-    // Todo: Implement blockuser command
-    // Todo: Implement blockdomain command
+    if (!admins.some((e) => { return e === msg.account.acct;})) return;
+
+    const status = striptags(msg.status.content);
+
+    if (!status.startsWith(client.me.acct)) return;
+
+    const args = stripped.slice(client.me.acct + 1).trim().split(/ +/);
+    const commandName = args.shift().toLowerCase();
+
+    //Check if command exists
+    if (!this.commands.has(commandName)) {
+        return;
+    }
+    const command = this.commands.get(commandName);
+
+    //Check if command is disabled
+    if (command.disabled === true) return;
+
+    //Check if command is AdminOnly
+    if(command.admin_only === true && !admins.some((e) => { return e === msg.account.acct;})) return;
+
+    //Check args length
+    if (command.required_args > args) {
+        return;
+    }
+
+    console.log(`CMD: ${commandName} from ${msg.account.acct}`);
+
+    //Execute the command
+    try {
+        command.execute(msg, args);
+    }
+    catch (error) {
+        console.error(error);
+    }
 });
\ No newline at end of file
diff --git a/package.json b/package.json
index 8f668da..cd1f73e 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
   "name": "federationbot",
   "version": "0.0.1",
   "dependencies": {
+    "collections": "^5.1.2",
     "mastodon-api": "^1.3.0",
     "striptags": "^3.1.1"
   }
-- 
GitLab