com.kantenkugel.discordbot.modules.AutoRespond.java Source code

Java tutorial

Introduction

Here is the source code for com.kantenkugel.discordbot.modules.AutoRespond.java

Source

/*
 * Copyright 2016 Michael Ritter (Kantenkugel)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kantenkugel.discordbot.modules;

import com.kantenkugel.discordbot.Statics;
import com.kantenkugel.discordbot.commands.Command;
import com.kantenkugel.discordbot.commands.CommandWrapper;
import com.kantenkugel.discordbot.config.ServerConfig;
import com.kantenkugel.discordbot.listener.MessageEvent;
import com.kantenkugel.discordbot.util.MessageUtil;
import net.dv8tion.jda.JDA;
import net.dv8tion.jda.entities.TextChannel;
import net.dv8tion.jda.utils.SimpleLog;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AutoRespond extends Module {
    private static final Pattern addPattern = Pattern.compile("^(\\w+)\\s\\[([^\\]]+)\\]\\s(.+)$");
    private final Map<String, Pair<Set<String>, String>> responses = new HashMap<>(); //name ->
    private final Set<String> channels = new HashSet<>();
    private ServerConfig servercfg;

    private static final SimpleLog respondLog = SimpleLog.getLog("Responder");

    @Override
    public String getName() {
        return "responder";
    }

    @Override
    public boolean availableInPms() {
        return false;
    }

    @Override
    public void init(JDA jda, ServerConfig cfg) {
        this.servercfg = cfg;
    }

    @Override
    public void configure(String cfgString, MessageEvent event, ServerConfig cfg) {
        MessageUtil.reply(event, cfg, intConfig(cfgString, cfg, event));
    }

    @Override
    public Map<String, Command> getCommands() {
        HashMap<String, Command> commands = new HashMap<>();
        commands.put("responder", new CommandWrapper("Used to configure the responder module.", (e, cfg) -> {
            String[] args = MessageUtil.getArgs(e, cfg, 2);
            MessageUtil.reply(e, cfg, intConfig(args.length == 1 ? null : args[1], cfg, e));
        }).acceptPrivate(false).acceptPriv(Command.Priv.MOD));
        return commands;
    }

    @Override
    public JSONObject toJson() {
        JSONArray r = new JSONArray();
        responses.entrySet().forEach(e -> {
            JSONArray keys = new JSONArray();
            e.getValue().getKey().forEach(keys::put);
            r.put(new JSONObject().put("name", e.getKey()).put("keys", keys).put("response",
                    e.getValue().getValue()));
        });
        JSONArray channels = new JSONArray();
        this.channels.forEach(channels::put);
        return new JSONObject().put("channels", channels).put("responses", r);
    }

    @Override
    public void fromJson(JSONObject cfg) {
        if (!cfg.has("channels")) {
            cfg.put("channels", new JSONArray());
        }
        if (!cfg.has("responses")) {
            cfg.put("responses", new JSONArray());
        }
        channels.clear();
        JSONArray arr = cfg.getJSONArray("channels");
        for (int i = 0; i < arr.length(); i++) {
            channels.add(arr.getString(i));
        }
        responses.clear();
        arr = cfg.getJSONArray("responses");
        for (int i = 0; i < arr.length(); i++) {
            JSONObject obj = arr.getJSONObject(i);
            Set<String> keys = new HashSet<>();
            JSONArray keyarr = obj.getJSONArray("keys");
            for (int j = 0; j < keyarr.length(); j++) {
                keys.add(keyarr.getString(j));
            }
            responses.put(obj.getString("name"), new ImmutablePair<>(keys, obj.getString("response")));
        }
    }

    @Override
    public boolean handle(MessageEvent event, ServerConfig cfg) {
        if (event.isEdit() || event.getAuthor() == event.getJDA().getSelfInfo()
                || (!channels.isEmpty() && !channels.contains(event.getTextChannel().getId()))
                || event.getContent().startsWith(servercfg.getPrefix())) {
            return false;
        }
        String content = event.getContent().toLowerCase();
        Optional<String> response = responses.values().parallelStream()
                .filter(r -> r.getLeft().parallelStream().allMatch(k -> {
                    int i = content.indexOf(k);
                    return i >= 0 //exists
                            && (i == 0 || content.charAt(i - 1) == ' ') //at beginning or after space
                            && (i + k.length() == content.length() //et end or no alphanumeric
                                    || !Character.isLetterOrDigit(content.charAt(i + k.length())));
                })).map(Pair::getRight).findAny();
        if (response.isPresent()) {
            respondLog.info(String.format("[%s][%s] %s: %s\n\t->%s", event.getGuild().getName(),
                    event.getTextChannel().getName(), event.getAuthor().getUsername(), event.getContent(),
                    response.get()));
            MessageUtil.replySync(event, cfg, response.get());
        }
        return false;
    }

    private String intConfig(String cfgString, ServerConfig cfg, MessageEvent event) {
        if (cfgString == null) {
            return getUsage();
        }
        String[] split = cfgString.split("\\s+", 2);
        if (split.length < 2) {
            return getUsage();
        }
        switch (split[0].toLowerCase()) {
        case "add":
            Matcher matcher = addPattern.matcher(split[1]);
            if (matcher.matches() && matcher.group(2).trim().length() > 0) {
                Set<String> keys = new HashSet<>();
                Collections.addAll(keys, matcher.group(2).toLowerCase().split("\\s+"));
                responses.put(matcher.group(1).toLowerCase(), new ImmutablePair<>(keys, matcher.group(3)));
                cfg.save();
                return "Response " + matcher.group(1).toLowerCase() + " added.";
            }
            break;
        case "remove":
        case "del":
            if (responses.containsKey(split[1].toLowerCase())) {
                responses.remove(split[1].toLowerCase());
                cfg.save();
                return "Response " + split[1].toLowerCase() + " removed.";
            } else {
                return "Response " + split[1].toLowerCase() + " not found!";
            }
        case "channels":
            String[] split2 = split[1].split("\\s+", 2);
            if (split2.length == 2) {
                switch (split2[0].toLowerCase()) {
                case "add":
                    if (event.getMessage().getMentionedChannels().size() > 0) {
                        event.getMessage().getMentionedChannels().forEach(c -> channels.add(c.getId()));
                        cfg.save();
                        return "Channel(s) added.";
                    }
                    Optional<TextChannel> any = event.getGuild().getTextChannels().parallelStream()
                            .filter(tc -> tc.getName().equals(split2[1])).findAny();
                    if (any.isPresent()) {
                        channels.add(any.get().getId());
                        cfg.save();
                        return "Channel " + split2[1] + " added.";
                    } else {
                        return "Channel " + split2[1] + " not found!";
                    }
                case "del":
                case "remove":
                    if (event.getMessage().getMentionedChannels().size() > 0) {
                        event.getMessage().getMentionedChannels().forEach(c -> channels.remove(c.getId()));
                        cfg.save();
                        return "Channel(s) removed.";
                    }
                    Optional<TextChannel> any2 = event.getGuild().getTextChannels().parallelStream()
                            .filter(tc -> tc.getName().equals(split2[1])).findAny();
                    if (any2.isPresent()) {
                        if (channels.contains(any2.get().getId())) {
                            channels.remove(any2.get().getId());
                            cfg.save();
                            return "Channel " + split2[1] + " removed.";
                        } else {
                            return "Channel " + split2[1] + " was not added!";
                        }
                    } else {
                        return "Channel " + split2[1] + " not found!";
                    }
                }
            }
            break;
        }
        return getUsage();
    }

    private String getUsage() {
        return "**Usage:**\n`add NAME [WORD WORD ...] RESPONSE` (include brackets)\n**Or:**\n`remove NAME`\n**Or:**\n`channels add/remove CHANNEL [CHANNEL ...]`\n\n"
                + "Registered: " + (responses.isEmpty() ? "None!" : StringUtils.join(responses.keySet(), ", "))
                + "\nChannels: "
                + (channels.isEmpty() ? "All"
                        : channels.stream()
                                .map(id -> Statics.jdaInstance.getTextChannelById(id) == null ? null
                                        : Statics.jdaInstance.getTextChannelById(id).getName())
                                .filter(s -> s != null).reduce((s1, s2) -> s1 + ", " + s2).get());
    }

}