Forge-Media/teamspeak-bot

View on GitHub
plugins/registerLOL.js

Summary

Maintainability
D
1 day
Test Coverage
/**
 * Plugin used to register your League account in order receive your League Rank as an icon
 * @example !registerLOL
 * @module Plugin-registerLOL
 */

const async = require("async");

exports.help = [
    ["!registerLOL <summoner name> <region e.g. EUW> <type e.g. Solo or Flex>", "Register your League account to receive your LOL Rank as an icon"],
    ["!deregisterLOL", "Deregister your League account and remove your rank icon"],
    ["!statusLOL", "Check your registration status and LOL rank status"],
];

/**
 * Plugin configuration settings, please change to match your server
 * CHANGE THESE SETTINGS!
 *
 * @version 1.0
 * @property {array} owners - The IDs of ServerGroups which can use this plugin
 * @property {array} rank_group_ids - The IDs of the ServerGroups which the bot will assign corresponing with the (n) LOL ranks
 * @property {number} update_rank_interval - How often to automatically update ranks in millseconds (2 hours - 7200000ms)
 * @memberof Plugin-registerLOL
 */
const config = {
    owners: [40],
    regionList: ["BR1", "EUN1", "EUW1", "JP1", "KR", "LA1", "LA2", "NA1", "OC1", "RU", "TR1"],
    rank_group_ids: [204, 203, 202, 201, 200, 199, 198, 197, 196],
    ranks: ["IRON", "BRONZE", "SILVER", "GOLD", "PLATINUM", "DIAMOND", "MASTER", "GRANDMASTER", "CHALLENGER"],
    update_rank_interval: 7200000,
};

/**
 * This function is called whenever Jarvis recieves a private message
 * Will ask target-user(s) if they want to register their steam ID
 * @version 1.0
 * @memberof Plugin-registerLOL
 * @param    {String} msg - Message string sent to Jarvis
 * @param    {String} jarvis - Middleware Function: Provides access to certain Jarvis functions.
 */
exports.onMessage = async (msg, jarvis) => {
    const items = msg.split(" <");
    const command = items.shift();
    const invoker = jarvis.invoker;

    // Register new user
    if (command.toLowerCase() === "!registerlol") {
        // Check user has permissions to use plugin
        if (!config.owners.some((r) => jarvis.groups.indexOf(r) >= 0)) {
            invoker.message(`${jarvis.error_message.forbidden}\n Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] please [b]Verify[/b] to use this command!`);
            return;
        }

        // Check user entered valid parameters
        if (items === undefined || items.length === 0) {
            invoker.message("[b]No summoner name entered![/b] - Type '!registerLOL <summoner name> <region e.g. EUW> <type e.g. Solo/Flex>'");
            return;
        }

        // Construct query parameters array
        // Params[0] = Summoner Name | Params[1] = Region | Params[2] = Ranked Type
        const params = items.map((p) => {
            return p.substring(0, p.length - 1);
        });

        // VALID RANKED QUEUE TYPE CHECK
        if (params[2].toUpperCase() !== "FLEX" && params[2].toUpperCase() !== "SOLO") {
            invoker.message("[b]Invalid type entered![/b] - Valid types: Solo or Flex");
            return;
        }

        // VALID REGION CHECK
        if (params[1] !== undefined && params[1].length >= 2 && params[1].length <= 3) {
            // Check for edge case server names
            if (params[1].toUpperCase() !== "KR" && params[1].toUpperCase() !== "RU") {
                // Add stupid server name (id) to region, i.e: EUW1 or NA1
                params[1] = params[1] + "1";
            }
            // Check server name exists
            if (!config.regionList.includes(params[1].toUpperCase())) {
                invoker.message("[b]Invalid region entered![/b] - Valid regions: BR, EUN, EUW, JP, KR, LA, LA, NA, OC, RU, TR");
                return;
            }
        } else {
            invoker.message("[b]Invalid region entered![/b] - Valid regions: BR, EUN, EUW, JP, KR, LA, LA, NA, OC, RU, TR");
            return;
        }

        // VALID SUMMONER NAME CHECK
        if (params[0] === undefined || params[0].length <= 2 || params[0].length >= 17) {
            invoker.message("[b]Invalid summoner name entered![/b] - Type '!registerLOL <summoner name> <region e.g. EUW> <type e.g. Solo/Flex>'");
            return;
        }

        try {
            // Check the summoner exists
            let summoner = await jarvis.riot.getSummoner(null, params[0], params[1]);
            if (!summoner) {
                invoker.message(`[b]Summoner name does exist on the ${params[1]} server![/b]`);
                return;
            }

            let clientScheme = {
                id: summoner.id,
                data: {
                    riot_account_id: summoner.accountId,
                    summoner_name: summoner.name,
                    summoner_region: params[1],
                    ranked_type: params[2].toUpperCase(),
                    ts_nickname: invoker.nickname,
                    ts_uid: invoker.uniqueIdentifier,
                },
            };

            // Check user is not already registered
            if (await jarvis.riot.isRegisteredByUid(invoker.uniqueIdentifier)) {
                console.info(`${invoker.nickname} is already registered! by UID`);
                invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like you're already registered!`);
                return; // Is regsitered already
            } else if (await jarvis.riot.isRegisteredBySummonerName(summoner.name)) {
                console.info(`${invoker.nickname} is already registered! by Name`);
                invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like [color=#0069ff][b]${summoner.name}[/b][/color] is already registered!`);
                return; // Summoner name already registered
            }
            // Check user was registered sucesfully
            let register = await jarvis.riot.registerUser(clientScheme);
            if (register) {
                invoker.message(`Sorry something went wront, please try again later!`);
                throw new Error(register);
            }

            // Get summoner leagues object
            let summonerLeagues = await jarvis.riot.getSummonerLeagues(summoner.id, params[1]);

            // Check for unranked summoner
            if (summonerLeagues.length === 0) {
                invoker.message(
                    `Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like you're unranked in: [b]${clientScheme.data.ranked_type}[/b], we'll monitor your rank and add it when you rank up!`
                );
                return;
            }
            // Get summoner tier for respective queue type
            let summonerTier = getSummonerTier(summonerLeagues, clientScheme.data.ranked_type);

            if (!summonerTier) {
                invoker.message(
                    `Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like you're unranked in: [b]${clientScheme.data.ranked_type}[/b], we'll monitor your rank and add it when you rank up!`
                );
            } else {
                invoker.message(
                    `Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] we've added your [color=#0069ff][b]${summonerTier.tier}[/b][/color] in [color=#0069ff][b]${clientScheme.data.ranked_type}[/b][/color] rank!`
                );

                // 0 = Iron | 1 = Bronze | 2 = Silver | 3 = Gold | 4 = Platinum | 5 = Master | 6 = Grandmaster | 6 = Challenger
                invoker.addGroups(config.rank_group_ids[config.ranks.indexOf(summonerTier.tier.toUpperCase())]);
            }
        } catch (e) {
            console.error(`CATCHED: ${e.message}`);
        }
    } else if (command.toLowerCase() === "!deregisterlol") {
        // Check user has permissions to use plugin
        if (!config.owners.some((r) => jarvis.groups.indexOf(r) >= 0)) {
            invoker.message(`${jarvis.error_message.forbidden}\n Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] please [b]Verify[/b] to use this command!`);
            return;
        }

        // Check the deregistering user is registered, and retrieve their Summoner ID from the firestore database
        try {
            let summoner = await jarvis.riot.getRegisterdUserByUid(invoker.uniqueIdentifier);
            if (!summoner) {
                invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like you're not currently registered!`);
                return;
            }
            // Deregistering user, using their Summoner ID
            let deregister = await jarvis.riot.deregisterUser(summoner.id);
            if (deregister) {
                invoker.message(`Sorry something went wront, please try again later!`);
                throw new Error(deregister);
            }

            console.log(`${invoker.nickname} removed from database`);
            invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] your League ID: [color=#0069ff][b]${summoner.id}[/b][/color] has been deregistered!`);

            // Remove users Teamspeak server group
            const existingRank = config.rank_group_ids.filter((element) => invoker.servergroups.includes(element));
            if (existingRank.length > 0) {
                invoker.delGroups(existingRank);
            }
        } catch (e) {
            console.error(`CATCHED: ${e.message}`);
        }
    } else if (command.toLowerCase() === "!statuslol") {
        // Check user has permissions to use plugin
        if (!config.owners.some((r) => jarvis.groups.indexOf(r) >= 0)) {
            invoker.message(`${jarvis.error_message.forbidden}\n Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] please [b]Verify[/b] to use this command!`);
            return;
        }
        try {
            // Get the user's Summoner ID by their Teamspeak UID
            let summoner = await jarvis.riot.getRegisterdUserByUid(invoker.uniqueIdentifier);
            if (!summoner) {
                invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] looks like you're not currently registered!`);
                return;
            }

            invoker.message(`Hi, [color=#0069ff][b]${invoker.nickname}[/b][/color] you're registered with League ID: [color=#0069ff][b]${summoner.id}[/b][/color]. Updating your rank...`);

            // Get the user's Summoner Leagues object from the Riot-API
            let summonerLeagues = await jarvis.riot.getSummonerLeagues(summoner.id, summoner.data().summoner_region);

            // -1 = Unraked | 0 = Iron | 1 = Bronze | 2 = Silver | 3 = Gold | 4 = Platinum | 5 = Master | 6 = Grandmaster | 6 = Challenger
            let newRankIndex = getSummonerTierIndex(summonerLeagues, summoner.data().ranked_type);

            updateUsersTeamspeakGroups(invoker, newRankIndex, true);
        } catch (e) {
            console.error(`CATCHED: ${e.message}`);
        }
    }
};

/**
 * Updates the invoker's Teamspeak LoL Server Groups
 *
 * @version 1.0
 *
 * @memberof Plugin-registerLOL
 * @param    {Object} invoker - Teamspeak user who made request
 * @param    {Number} newRankIndex - Invoker's updated LOL rank (-1 = Unranked)
 * @param    {Boolean} notify - Flag weather to notify the invoker of their status
 */
function updateUsersTeamspeakGroups(invoker, newRankIndex, notify) {
    // Make sure existing rank is instantiated as an array, to avoid undefined when no existing server group is found!
    let existingTier = [];
    try {
        // Get all the user's existing LOL Teamseak Server Group IDs (Could be multiple, but should not be)
        existingTier = config.rank_group_ids.filter((element) => invoker.servergroups.includes(element));

        // User was unranked and remains unranked
        if (existingTier.length === 0 && newRankIndex === -1) {
            if (notify) {
                invoker.message(`You're still [color=#0069ff][b]Unranked[/b][/color]!`);
            }
            return;
        }

        // Check user is still ranked
        if (newRankIndex >= 0) {
            // Convert the updated LOL tier to corresponding Teamseak Server Group ID
            const rankSgid = config.rank_group_ids[newRankIndex];
            // Check user has gained/lost a rank by checking if existing Teamspeak server groups contains the updated rank

            if (!existingTier.includes(rankSgid)) {
                // If user has an existing rank, remove all old ranks
                if (existingTier.length > 0) {
                    invoker.delGroups(existingTier);
                }

                // Add new League Tier
                invoker.addGroups(rankSgid);
                invoker.message(`Your updated LoL rank is: [color=#0069ff][b]${config.ranks[newRankIndex]}[/b][/color], any previouse LoL ranks have been removed!`);

                // Debugging
                console.log(Date(), "=>", invoker.nickname, "=>", "rank changed to", "=>", config.ranks[newRankIndex]);
            } else {
                if (notify) {
                    invoker.message(`No rank update required!`);
                }
            }
            // User has become unranked, remove existing Teamseak Server Group ID
        } else if (newRankIndex === -1) {
            // Remove old rank
            invoker.delGroups(existingTier);
            invoker.message(`You've become [color=#0069ff][b]Unranked[/b][/color], any previouse LoL ranks have been removed!`);
        }
    } catch (e) {
        console.error(`CATCHED: ${e.message}`);
    }
}

/**
 * Converts a summoners rank to an index
 * -1 = Unraked | 0 = Iron | 1 = Bronze | 2 = Silver | 3 = Gold | 4 = Platinum | 5 = Master | 6 = Grandmaster | 6 = Challenger
 *
 * @version 1.0
 *
 * @memberof Plugin-registerLOL
 * @param    {Object} summonerLeagues - A summoners league object
 * @returns {Number} - Converted summoner rank to index value
 */
function getSummonerTierIndex(summonerLeagues, type) {
    // Get the user's current LOL rank from the Riot API
    let summonerTier = getSummonerTier(summonerLeagues, type);
    // -1 = Unraked | 0 = Iron | 1 = Bronze | 2 = Silver | 3 = Gold | 4 = Platinum | 5 = Master | 6 = Grandmaster | 6 = Challenger
    if (!summonerTier) {
        return -1;
    } else {
        return config.ranks.indexOf(summonerTier.tier.toUpperCase());
    }
}

/**
 * Returns the summoners tier for their respective queue
 *
 * @version 1.0
 *
 * @memberof Plugin-registerLOL
 * @param    {Array} leagues - Invoker's updated LOL rank (0 = Unranked)
 * @param    {String} type - Summoner's selected queue type
 * @returns {Promise.<data>} - data contains the formated summoner league object for their respective queue (returns Null for unranked)
 */
function getSummonerTier(leagues, type) {
    let summonerTier = null;

    if (leagues && leagues.length >= 1) {
        // Check summoner has rank in selected rank type
        leagues.forEach((league) => {
            if (league.queueType.includes(type)) {
                summonerTier = {
                    tier: league.tier,
                    rank: league.rank,
                };
            }
        });
        return summonerTier;
    } else {
        return summonerTier;
    }
}

/**
 * Updates the all registered users's LoL rank
 *
 * @version 1.0
 *
 * @memberof Plugin-registerLOL
 * @param    {object} jarvis - Middleware Function: Provides access to certain Jarvis functions.
 */
async function updateAllUsers(jarvis) {
    try {
        // Get all registered members in the League Firebase database
        const members = await jarvis.riot.getAllRegisterdUsers();

        if (!members) {
            return;
        }

        // Iterate through all registered members
        for (const member of members) {
            try {
                const client = await jarvis.ts.getClientByUID(member.data().ts_uid);

                // Client may be offline, therefore only process online clients
                // TODO: Find way to process offline users
                if (client) {
                    const summonerLeagues = await jarvis.riot.getSummonerLeagues(member.id, member.data().summoner_region);

                    // -1 = Unraked | 0 = Iron | 1 = Bronze | 2 = Silver | 3 = Gold | 4 = Platinum | 5 = Master | 6 = Grandmaster | 6 = Challenger
                    const newRankIndex = getSummonerTierIndex(summonerLeagues, member.data().ranked_type);
                    updateUsersTeamspeakGroups(client, newRankIndex, false);
                }
            } catch (e) {
                console.error(`CATCHED: ${e.message}`);
            }
        }
    } catch (e) {
        console.error(`CATCHED: ${e.message}`);
    }
}

/**
 * Active Worker: Which iterates through all registered users and updates their Teamspeak CSGO Server Group Rank
 *
 * @version 1.0
 * @memberof Plugin-registerLOL
 * @param    {object} jarvis - Middleware Function: Provides access to certain Jarvis functions.
 *
 */
exports.run = (helpers, jarvis) => {
    async.forever((next) => {
        setTimeout(() => {
            updateAllUsers(jarvis);
            next();
        }, config.update_rank_interval);
    });
};