cf.adriantodt.David.modules.db.GuildModule.java Source code

Java tutorial

Introduction

Here is the source code for cf.adriantodt.David.modules.db.GuildModule.java

Source

/*
 * This class was created by <AdrianTodt>. It's distributed as
 * part of the DavidBot. Get the Source Code in github:
 * https://github.com/adriantodt/David
 *
 * DavidBot is Open Source and distributed under the
 * GNU Lesser General Public License v2.1:
 * https://github.com/adriantodt/David/blob/master/LICENSE
 *
 * File Created @ [11/11/16 08:15]
 */

package cf.adriantodt.David.modules.db;

import cf.adriantodt.David.loader.Module;
import cf.adriantodt.David.loader.Module.JDAInstance;
import cf.adriantodt.David.loader.Module.OnEnabled;
import cf.adriantodt.David.loader.Module.SubscribeJDA;
import cf.adriantodt.David.modules.cmds.manager.PermissionsModule;
import cf.adriantodt.utils.TaskManager;
import cf.adriantodt.utils.data.Commitable;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.rethinkdb.RethinkDB;
import com.rethinkdb.model.MapObject;
import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.events.guild.GuildJoinEvent;
import net.dv8tion.jda.core.events.guild.GuildLeaveEvent;
import net.dv8tion.jda.core.events.guild.update.GuildUpdateNameEvent;
import net.dv8tion.jda.core.hooks.SubscribeEvent;

import java.util.*;
import java.util.function.Function;

import static cf.adriantodt.David.loader.Module.Type.STATIC;

@Module(name = "db.guild", type = STATIC)
@SubscribeJDA
public class GuildModule {
    public static final String[] DEFAULT_PREFIXES = { "&", "!" };
    public static Data GLOBAL;
    private static List<Data> all = new ArrayList<>();
    private static Map<Guild, Data> guildMap = new HashMap<Guild, Data>() {
        @Override
        public Data put(Guild key, Data value) {
            if (key == null)
                return null;
            return super.put(key, value);
        }

        @Override
        public void putAll(Map<? extends Guild, ? extends Data> m) {
            m.remove(null);
            super.putAll(m);
        }

        @Override
        public Data putIfAbsent(Guild key, Data value) {
            if (key == null)
                return null;
            return super.putIfAbsent(key, value);
        }
    };
    private static Map<Data, Integer> timeoutUntilDbRemoval = new HashMap<>();

    @OnEnabled
    private static void load() {
        //FakeGuilds Impl
        GLOBAL = new Data();
        GLOBAL.id = "-1";
        GLOBAL.name = "GLOBAL";

        TaskManager.startAsyncTask("GuildTimeoutCleanup", () -> {
            timeoutUntilDbRemoval.replaceAll((guild, integer) -> Math.min(integer - 1, 0));
            timeoutUntilDbRemoval.entrySet().stream().filter(entry -> entry.getValue() == 0).map(Map.Entry::getKey)
                    .forEach(data -> {
                        DBModule.onDB(r -> r.table("commands").filter(r.row("gid").eq(data.id)).delete()).noReply();
                        DBModule.onDB(r -> r.table("guilds").get(data.id).delete()).noReply();
                        timeoutUntilDbRemoval.remove(data);
                    });
        }, 60);
    }

    public static List<Data> all() {
        return Collections.unmodifiableList(all);
    }

    private static Data unpack(JsonElement element) {
        JsonObject object = element.getAsJsonObject();
        Data data = all.stream().filter(dataPredicate -> object.get("id").getAsString().equals(dataPredicate.id))
                .findFirst().orElseGet(Data::new);
        data.id = object.get("id").getAsString();
        data.name = object.get("name").getAsString();
        data.cmdPrefixes.clear();
        object.get("cmdPrefixes").getAsJsonArray()
                .forEach(jsonElement -> data.cmdPrefixes.add(jsonElement.getAsString()));
        data.lang = object.get("lang").getAsString();
        data.flags.clear();
        object.get("flags").getAsJsonObject().entrySet()
                .forEach(entry -> data.flags.put(entry.getKey(), entry.getValue().getAsBoolean()));
        object.get("userPerms").getAsJsonObject().entrySet()
                .forEach(entry -> data.userPerms.put(entry.getKey(), entry.getValue().getAsLong()));
        return data;
    }

    @SubscribeEvent
    private static void newGuild(GuildJoinEvent e) {
        Data data = fromDiscord(e.getGuild());
        if (timeoutUntilDbRemoval.containsKey(data))
            timeoutUntilDbRemoval.remove(data);
    }

    @SubscribeEvent
    private static void byeGuild(GuildLeaveEvent e) {
        timeoutUntilDbRemoval.put(fromDiscord(e.getGuild()), 5);
    }

    @SubscribeEvent
    private static void renamedGuild(GuildUpdateNameEvent e) {
        fromDiscord(e.getGuild()).setName(toGuildName(e.getGuild().getName()));
    }

    public static Data fromDiscord(Guild guild) {
        if (guild == null)
            return GLOBAL;
        if (guildMap.containsKey(guild)) {
            return guildMap.get(guild);
        } else {
            return getOrGen(Optional.of(guild), Optional.empty(), Optional.empty());
        }
    }

    private static Data getOrGen(Optional<Guild> guildOptional, Optional<String> optionalId,
            Optional<String> optionalName) {
        RuntimeException ex = new IllegalStateException("Id and/or Name can't be Optional if Guild isn't returned");
        String id = optionalId.orElseGet(() -> guildOptional.orElseThrow(() -> ex).getId());
        String name = optionalName.orElseGet(() -> guildOptional.orElseThrow(() -> ex).getName());

        Data data;

        JsonElement object = DBModule.onDB(r -> r.db("bot").table("guilds").get(id)).run().simpleExpected();
        if (object.isJsonNull()) {
            data = new Data();

            data.id = id;
            data.name = toGuildName(name);

            MapObject m = new MapObject().with("id", data.id).with("name", data.name)
                    .with("cmdPrefixes", data.cmdPrefixes).with("lang", data.lang).with("userPerms", data.userPerms)
                    .with("flags", data.flags);

            DBModule.onDB(r -> r.table("guilds").insert(m)).noReply();
        } else {
            data = unpack(object);
        }
        Data finalData = data;
        guildOptional.ifPresent(guild -> guildMap.put(guild, finalData));
        UserCommandsModule.loadAllFrom(data);
        return data;
    }

    public static Data fromName(String name) {
        for (Data g : all) {
            if (g.name.equals(name))
                return g;
        }
        return null;
    }

    private static String toGuildName(String name) {
        name = name.replace(" ", "_").replace(":", "");
        if (fromName(name) == null)
            return name;
        for (int i = 2; i < 1000; i++) {
            if (fromName(name + i) == null)
                return name + i;
        }
        throw new RuntimeException("What. the. fuck.");
    }

    public static String toString(Data data, JDA jda, String language) {
        Guild guild = data.getGuild(jda);
        return I18nModule.getLocalized("guild.guild", language) + ": " + data.name
                + (data.getFlag("vip") ? " [VIP]" : "")
                + (guild != null && !data.name.equals(guild.getName()) ? " (" + guild.getName() + ")" : "")
                + "\n - " + I18nModule.getLocalized("guild.admin", language) + ": "
                + (guild == null ? jda.getUserById(DBModule.getConfig().get("ownerID").getAsString()).getName()
                        : guild.getOwner().getUser().getName())
                + "\n - " + I18nModule.getLocalized("guild.cmds", language) + ": "
                + UserCommandsModule.allFrom(data).size() + "\n - "
                + I18nModule.getLocalized("guild.channels", language) + ": "
                + (guild == null ? (jda.getTextChannels().size() + jda.getPrivateChannels().size())
                        : guild.getTextChannels().size())
                + "\n - " + I18nModule.getLocalized("guild.users", language) + ": "
                + (guild == null ? jda.getUsers().size() : guild.getMembers().size()) + "\n - "
                + I18nModule.getLocalized("guild.id", language) + ": " + data.id;
    }

    public static class Data {
        private Map<String, Long> userPerms = new HashMap<>();
        private Map<String, Boolean> flags = new HashMap<>();
        private String id = "-1", name = "", lang = "en_US";
        private List<String> cmdPrefixes = new ArrayList<>(Arrays.asList(DEFAULT_PREFIXES));

        private Data() {
            flags.put("cleanup", true);
            flags.put("vip", true);
            userPerms.put("default", PermissionsModule.BASE_USER);
            all.add(this);
        }

        private static void pushUpdate(Data data, Function<RethinkDB, MapObject> changes) {
            DBModule.onDB(r -> r.table("guilds").get(data.id).update(arg -> changes.apply(r))).noReply();
        }

        public List<String> getCmdPrefixes() {
            return Collections.unmodifiableList(cmdPrefixes);
        }

        public Commitable<List<String>> modifyCmdPrefixes() {
            int oldHash = Arrays.hashCode(cmdPrefixes.toArray());
            return Commitable.bake(new ArrayList<>(cmdPrefixes), list -> {
                if (Arrays.hashCode(list.toArray()) != oldHash) {
                    pushUpdate(this, r -> r.hashMap("cmdPrefixes", list));
                    cmdPrefixes.clear();
                    cmdPrefixes.addAll(list);
                }
            });
        }

        public long getUserPerms(String s) {
            return getUserPerms(s, 0L);
        }

        public long getUserPerms(String s, long orDefault) {
            return userPerms.getOrDefault(s, orDefault);
        }

        public void setUserPerms(String s, long userPerms) {
            this.userPerms.put(s, userPerms);
            pushUpdate(this, r -> r.hashMap("userPerms", this.userPerms));
        }

        public boolean getFlag(String s) {
            return flags.getOrDefault(s, false);
        }

        public void setFlag(String s, Boolean flag) {
            this.flags.put(s, flag);
            pushUpdate(this, r -> r.hashMap("flags", flags));
        }

        public boolean toggleFlag(String s) {
            boolean f = !getFlag(s);
            setFlag(s, f);
            return f;
        }

        public Guild getGuild(JDA jda) {
            return jda.getGuildById(id);
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
            pushUpdate(this, r -> r.hashMap("name", name));
        }

        public String getLang() {
            return lang;
        }

        public void setLang(String lang) {
            this.lang = lang;
            pushUpdate(this, r -> r.hashMap("lang", lang));
        }
    }
}