tekulvw/Squid-Plugins

View on GitHub
karma/karma.py

Summary

Maintainability
A
25 mins
Test Coverage
import discord
from discord.ext import commands
from cogs.utils.dataIO import fileIO
from cogs.utils.chat_formatting import box
from cogs.utils import checks
from __main__ import send_cmd_help
import logging
import os
try:
    import tabulate
except:
    tabulate = None


log = logging.getLogger("red.karma")


class Karma:
    """Keep track of user scores through @mention ++/--

    Example: ++ @\u200BWill (or @\u200BWill ++)"""

    def __init__(self, bot):
        self.bot = bot
        self.scores = fileIO("data/karma/scores.json", "load")
        self.settings = fileIO("data/karma/settings.json", 'load')

    def _process_scores(self, member, score_to_add):
        member_id = member.id
        if member_id in self.scores:
            if "score" in self.scores.get(member_id, {}):
                self.scores[member_id]["score"] += score_to_add
            else:
                self.scores[member_id]["score"] = score_to_add
        else:
            self.scores[member_id] = {}
            self.scores[member_id]["score"] = score_to_add

    def _add_reason(self, member_id, reason):
        if reason.lstrip() == "":
            return
        if member_id in self.scores:
            if "reasons" in self.scores.get(member_id, {}):
                old_reasons = self.scores[member_id].get("reasons", [])
                new_reasons = [reason] + old_reasons[:4]
                self.scores[member_id]["reasons"] = new_reasons
            else:
                self.scores[member_id]["reasons"] = [reason]
        else:
            self.scores[member_id] = {}
            self.scores[member_id]["reasons"] = [reason]

    def _fmt_reasons(self, reasons):
        if len(reasons) == 0:
            return None
        ret = "```Latest Reasons:\n"
        for num, reason in enumerate(reasons):
            ret += "\t" + str(num + 1) + ") " + str(reason) + "\n"
        return ret + "```"

    @commands.command(pass_context=True)
    async def karma(self, ctx):
        """Checks a user's karma, requires @ mention

           Example: !karma @Red"""
        if len(ctx.message.mentions) != 1:
            await send_cmd_help(ctx)
            return
        member = ctx.message.mentions[0]
        if self.scores.get(member.id, 0) != 0:
            member_dict = self.scores[member.id]
            await self.bot.say(member.name + " has " +
                               str(member_dict["score"]) + " points!")
            reasons = self._fmt_reasons(member_dict.get("reasons", []))
            if reasons:
                await self.bot.send_message(ctx.message.author, reasons)
        else:
            await self.bot.say(member.name + " has no karma!")

    @commands.command(pass_context=True)
    async def karmaboard(self, ctx):
        """Karma leaderboard"""
        server = ctx.message.server
        member_ids = [m.id for m in server.members]
        karma_server_members = [key for key in self.scores.keys()
                                if key in member_ids]
        log.debug("Karma server members:\n\t{}".format(
            karma_server_members))
        names = list(map(lambda mid: discord.utils.get(server.members, id=mid),
                         karma_server_members))
        log.debug("Names:\n\t{}".format(names))
        scores = list(map(lambda mid: self.scores[mid]["score"],
                          karma_server_members))
        log.debug("Scores:\n\t{}".format(scores))
        headers = ["User", "Karma"]
        body = sorted(zip(names, scores), key=lambda tup: tup[1],
                      reverse=True)[:10]
        table = tabulate.tabulate(body, headers, tablefmt="psql")
        await self.bot.say(box(table))

    @commands.group(pass_context=True)
    @checks.mod_or_permissions(manage_messages=True)
    async def karmaset(self, ctx):
        """Manage karma settings"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            return

    @karmaset.command(pass_context=True, name="respond")
    async def _karmaset_respond(self, ctx):
        """Toggles if bot will respond when points get added/removed"""
        if self.settings['RESPOND_ON_POINT']:
            await self.bot.say("Responses disabled.")
        else:
            await self.bot.say('Responses enabled.')
        self.settings['RESPOND_ON_POINT'] = \
            not self.settings['RESPOND_ON_POINT']
        fileIO('data/karma/settings.json', 'save', self.settings)

    async def check_for_score(self, message):
        user = message.author
        content = message.content
        mentions = message.mentions
        if message.author.id == self.bot.user.id:
            return
        splitted = content.split(" ")
        if len(splitted) > 1:
            if "++" == splitted[0] or "--" == splitted[0]:
                first_word = "".join(splitted[:2])
            elif "++" == splitted[1] or "--" == splitted[1]:
                first_word = "".join(splitted[:2])
            else:
                first_word = splitted[0]
        else:
            first_word = splitted[0]
        reason = content[len(first_word) + 1:]
        for member in mentions:
            if member.id in first_word.lower():
                if "++" in first_word.lower() or "--" in first_word.lower():
                    if member == user:
                        await self.bot.send_message(message.channel,
                                                    "You can't modify your own"
                                                    " rep, jackass.")
                        return
                if "++" in first_word.lower():
                    self._process_scores(member, 1)
                    self._add_reason(member.id, reason)
                elif "--" in first_word.lower():
                    self._process_scores(member, -1)
                    self._add_reason(member.id, reason)
                else:
                    return

                if self.settings['RESPOND_ON_POINT']:
                    msg = "{} now has {} points.".format(
                        member.name, self.scores[member.id]["score"])
                    await self.bot.send_message(message.channel, msg)
                fileIO("data/karma/scores.json", "save", self.scores)
                return


def check_folder():
    if not os.path.exists("data/karma"):
        print("Creating data/karma folder...")
        os.makedirs("data/karma")


def check_file():
    scores = {}
    settings = {"RESPOND_ON_POINT": True}

    f = "data/karma/scores.json"
    if not fileIO(f, "check"):
        print("Creating default karma's scores.json...")
        fileIO(f, "save", scores)

    f = "data/karma/settings.json"
    if not fileIO(f, "check"):
        print("Creating default karma's scores.json...")
        fileIO(f, "save", settings)


def setup(bot):
    if tabulate is None:
        raise RuntimeError("Run `pip install tabulate` to use Karma.")
    check_folder()
    check_file()
    n = Karma(bot)
    bot.add_listener(n.check_for_score, "on_message")
    bot.add_cog(n)