Example #1
0
def get_karma_received_breakdown(uid, raw_events=None):
    if not raw_events:
        raw_events = db.get_karma_received_raw(uid)
    return get_karma_breakdown_from_events(raw_events, "given_by")
Example #2
0
def get_karma_received_dates(uid, raw_events=None):
    if not raw_events:
        raw_events = db.get_karma_received_raw(uid)
    return get_date_range_from_events(raw_events)
Example #3
0
def get_karma_breakdown_user(uid, command_type, guild):
    me = guild.get_member(int(uid))

    given_raw = db.get_karma_given_raw(uid)
    received_raw = db.get_karma_received_raw(uid)

    if not received_raw:
        return None, None

    # Get the breakdown of who + and -d your karma
    given_breakdown = sh.get_karma_given_breakdown(uid, given_raw)
    received_breakdown = sh.get_karma_received_breakdown(uid, received_raw)

    # Order the breakdowns
    given_breakdown_nice = sorted(given_breakdown,
                                  key=lambda user: user["totals"]["positive"],
                                  reverse=True)
    given_breakdown_bulli = sorted(given_breakdown,
                                   key=lambda user: user["totals"]["negative"],
                                   reverse=True)

    received_breakdown_nice = sorted(
        received_breakdown,
        key=lambda user: user["totals"]["positive"],
        reverse=True)
    received_breakdown_bulli = sorted(
        received_breakdown,
        key=lambda user: user["totals"]["negative"],
        reverse=True)

    # Net gained and lost per day, on the days you received karma
    received_dates = sh.get_karma_received_dates(uid, received_raw)

    # Get all the karma to figure out an overall ranking
    karma_list = db.get_all_karma()
    sorted_karma = sorted(karma_list, key=lambda k: k.karma, reverse=True)
    karma_position_list = [
        i for i, v in enumerate(sorted_karma) if v.discord_id == uid
    ]
    karma_position = karma_position_list[0] + 1 if len(
        karma_position_list) > 0 else 0

    # Get for each current karma user how much they've given and taken away
    karma_users_given_totals = [{
        "discord_id":
        karma.discord_id,
        "totals":
        sh.get_karma_given_total(karma.discord_id)
    } for karma in karma_list]
    karma_users_given_totals_nice = sorted(
        karma_users_given_totals,
        key=lambda user: user["totals"]["positive"],
        reverse=True)
    karma_users_given_totals_bulli = sorted(
        karma_users_given_totals,
        key=lambda user: user["totals"]["negative"],
        reverse=True)

    given = next(
        (user
         for user in karma_users_given_totals if user["discord_id"] == uid),
        None)
    given_totals = given["totals"]

    # Get for each current karma user how much they've received and had removed
    karma_users_received_totals = [{
        "discord_id":
        karma.discord_id,
        "totals":
        sh.get_karma_received_total(karma.discord_id)
    } for karma in karma_list]
    karma_users_received_totals_nice = sorted(
        karma_users_received_totals,
        key=lambda user: user["totals"]["positive"],
        reverse=True)
    karma_users_received_totals_bulli = sorted(
        karma_users_received_totals,
        key=lambda user: user["totals"]["negative"],
        reverse=True)

    received = next(
        (user
         for user in karma_users_received_totals if user["discord_id"] == uid),
        None)
    received_totals = received["totals"]

    # Ready to build ...
    output = discord.Embed(title=f'Stats Summary for {me.name}',
                           colour=discord.Colour.purple())

    if (command_type in ['received', 'all']):
        output.add_field(
            name='Karma Collector :crown:',
            value="You've gained **{} karma**, and lost **{} karma**, making for a total of **{} karma**, putting you at overall position **#{}**.".\
                format(received_totals["positive"],
                    received_totals["negative"],
                    received_totals["positive"] - received_totals["negative"],
                    karma_position
                ),
            inline=False
        )

        output.add_field(
            name='Karma Climb :chart_with_upwards_trend: (karma gained rank)',
            value="Position: **#{}**".format(
                karma_users_received_totals_nice.index(received) + 1),
            inline=True)

        output.add_field(
            name='Karma Crash :chart_with_downwards_trend: (karma lost rank)',
            value="Position: **#{}**".format(
                karma_users_received_totals_bulli.index(received) + 1),
            inline=True)

        karma_companions = build_ranking(received_breakdown_nice, "positive",
                                         guild)
        karma_killers = build_ranking(received_breakdown_bulli, "negative",
                                      guild)

        output.add_field(
            name='Karma Companions :heart_eyes: (gave the most karma to you)',
            value=karma_companions,
            inline=True)

        output.add_field(
            name='Karma Killers :skull: (took the most karma from you)',
            value=karma_killers,
            inline=True)

    if (command_type in ['given', 'all']):
        output.add_field(
            name='Karma Circulator :repeat:',
            value="You've given **{} karma**, and taken **{} karma**, making for a total of **{} +/- karma** distributed".\
                format(given_totals["positive"],
                    given_totals["negative"],
                    given_totals["positive"] + given_totals["negative"],
                )
                + " (or **{:.2%}** of total karma transactions)".\
                    format((given_totals["positive"] + given_totals["negative"]) / db.get_all_karma_events_count()),
            inline=False
        )

        output.add_field(
            name='Karma Conferred :ok_woman: (karma given rank)',
            value=
            f'Position: **#{karma_users_given_totals_nice.index(given) + 1}**',
            inline=True)

        output.add_field(
            name='Karma Clobbered :no_good: (karma taken rank)',
            value=
            f'Position: **#{karma_users_given_totals_bulli.index(given) + 1}**',
            inline=True)

        karma_contributions = build_ranking(given_breakdown_nice, "positive",
                                            guild)
        karma_killed = build_ranking(given_breakdown_bulli, "negative", guild)

        output.add_field(
            name='Karma Contributions :gift: (you gave the most karma to)',
            value=karma_contributions,
            inline=True)

        output.add_field(
            name=
            'Karma Killed :regional_indicator_f: (you took the most karma from)',
            value=karma_killed,
            inline=True)

    img_file = None
    if (command_type in ['bff', 'all']):
        # Get BFF
        bff, bff_score, err = calculate_bff(uid, {uid: given_breakdown})
        output.add_field(
            name=':sparkling_heart: Karma BFF :sparkling_heart:',
            value=err if err else
            "Your BFF is **{}**, with a BFF score of **{:.2f}**".format(
                get_username(bff, guild), bff_score),
            inline=False)

    if (command_type in ['graph', 'all']):
        # Graph time
        x_coords, y_coords = zip(*((point["date"], point["diff"]["positive"] -
                                    point["diff"]["negative"])
                                   for point in received_dates))
        max_karma = max(y_coords)
        accumulated = list(accumulate(y_coords))

        buffer = generate_graph([(me, x_coords, accumulated)],
                                f'Karma over time for {me.name}')
        img_file = discord.File(buffer, filename="stats.png")
        output.set_image(url="attachment://stats.png")

        output.add_field(
            name='Karma Chart :bar_chart:',
            value='Below is a graph of your karma over time.' +
            ('' if max_karma <= 0 else
             f' Your max karma earned on a day is **{max_karma}**. Wow!'),
            inline=False)

    return output, img_file
Example #4
0
def get_karma_received_total(uid, raw_events=None):
    if not raw_events:
        raw_events = db.get_karma_received_raw(uid)
    return get_karma_total_from_events(raw_events)
Example #5
0
def get_karma_breakdown_server(command_type, guild):
    # Go and fetch every single person
    karma_list = db.get_all_karma()

    if not karma_list:
        return None, None

    sorted_karma = sorted(karma_list, key=lambda k: k.karma, reverse=True)

    raw = {}
    totals = {}
    breakdowns = {}
    dates = {}

    # For each person in the server, break it down into karma given / received
    for karma in karma_list:
        uid = karma.discord_id
        raw[uid] = {}
        given = db.get_karma_given_raw(uid)
        received = db.get_karma_received_raw(uid)
        raw[uid]["given"] = given,
        raw[uid]["received"] = received

        breakdowns[uid] = {}
        breakdowns[uid]["given"] = sh.get_karma_given_breakdown(uid, given)
        breakdowns[uid]["received"] = sh.get_karma_received_breakdown(
            uid, received)

        dates[uid] = {}
        dates[uid]["given"] = sh.get_karma_given_dates(uid, given)
        dates[uid]["received"] = sh.get_karma_given_dates(uid, received)

    # This code is a copy pasta of part of what is in the user break, so really they should be merged

    # Get for each current karma user how much they've given and taken away
    karma_users_given_totals = [{
        "discord_id":
        karma.discord_id,
        "totals":
        sh.get_karma_given_total(karma.discord_id)
    } for karma in karma_list]
    karma_users_given_totals_nice = sorted(
        karma_users_given_totals,
        key=lambda user: user["totals"]["positive"],
        reverse=True)
    karma_users_given_totals_bulli = sorted(
        karma_users_given_totals,
        key=lambda user: user["totals"]["negative"],
        reverse=True)

    # Get for each current karma user how much they've received and had removed
    karma_users_received_totals = [{
        "discord_id":
        karma.discord_id,
        "totals":
        sh.get_karma_received_total(karma.discord_id)
    } for karma in karma_list]
    karma_users_received_totals_nice = sorted(
        karma_users_received_totals,
        key=lambda user: user["totals"]["positive"],
        reverse=True)
    karma_users_received_totals_bulli = sorted(
        karma_users_received_totals,
        key=lambda user: user["totals"]["negative"],
        reverse=True)

    karma_users_given_top_nice = []
    karma_users_given_top_bulli = []
    # Get the top karma given for each person
    for uid, breakdown in breakdowns.items():
        if breakdown["given"]:
            karma_users_given_top_nice.append(
                (uid,
                 max(breakdown["given"],
                     key=lambda user: user["totals"]["positive"])))
            karma_users_given_top_bulli.append(
                (uid,
                 max(breakdown["given"],
                     key=lambda user: user["totals"]["negative"])))

    karma_users_given_top_nice = sorted(
        karma_users_given_top_nice,
        key=lambda pair: pair[1]["totals"]["positive"],
        reverse=True)
    karma_users_given_top_bulli = sorted(
        karma_users_given_top_bulli,
        key=lambda pair: pair[1]["totals"]["negative"],
        reverse=True)

    # Ready to build ...
    output = discord.Embed(title=f'Stats Summary for {guild.name}',
                           colour=discord.Colour.purple())
    img_file = None

    if (command_type in ['received', 'all']):
        top_score = get_username(sorted_karma[0].discord_id, guild)
        top_karma = sorted_karma[0].karma
        text = f'The current top karma user is **{top_score}**, with **{top_karma}** karma.'
        if len(sorted_karma) > 1:
            second_score = get_username(sorted_karma[1].discord_id, guild)
            second_karma = sorted_karma[1].karma
            diff = top_karma - second_karma
            text += f' **{second_score}** is **{diff}** karma behind them, with **{second_karma}** karma.'

        output.add_field(name='Karma Collector :crown:',
                         value=text,
                         inline=False)

        rec_positive_ranking = build_ranking(karma_users_received_totals_nice,
                                             "positive", guild)
        rec_negative_ranking = build_ranking(karma_users_received_totals_bulli,
                                             "negative", guild)

        output.add_field(
            name=
            'Karma Climb :chart_with_upwards_trend: (most karma gained rank)',
            value=rec_positive_ranking,
            inline=True)

        output.add_field(
            name=
            'Karma Crash :chart_with_downwards_trend: (most karma lost rank)',
            value=rec_negative_ranking,
            inline=True)

        output.add_field(
            name='Karma Companions :heart_eyes: / Karma Killers :skull:',
            value=
            'For information about karma received / removed, please see the mirrored given stats.',
            inline=False)

    if (command_type in ['given', 'all']):

        total_given_positive = 0
        total_given_negative = 0

        for total in karma_users_given_totals:
            total_given_positive += total["totals"]["positive"]
            total_given_negative += total["totals"]["negative"]

        correct_sum = db.get_all_karma_events_count()
        sorted_totals = sorted(karma_users_given_totals,
                               key=lambda user: user["totals"]["positive"] +
                               user["totals"]["negative"],
                               reverse=True)

        top_given_score = get_username(sorted_totals[0]["discord_id"], guild)
        top_given_total = sorted_totals[0]["totals"][
            "positive"] + sorted_totals[0]["totals"]["negative"]

        given_text = "**{}** has been given, and **{}** has been taken, making for a total of **{} +/- karma** distributed.\n".format(
            total_given_positive, total_given_negative, correct_sum)

        given_text += "**{}** has moved the most karma, with **{} +/- karma** (or **{:.2%}** of total karma transactions).".format(
            top_given_score, top_given_total, top_given_total / correct_sum)

        if len(sorted_totals) > 1:
            second_given_score = get_username(sorted_totals[1]["discord_id"],
                                              guild)
            second_given_total = sorted_totals[1]["totals"][
                "positive"] + sorted_totals[1]["totals"]["negative"]
            given_diff = top_given_total - second_given_total
            given_text += "\n**{}** is **{}** karma behind them, with with **{} +/- karma** (or **{:.2%}** of total karma transactions).".format(
                second_given_score, given_diff, second_given_total,
                second_given_total / correct_sum)

        output.add_field(name='Karma Circulator :repeat:',
                         value=given_text,
                         inline=False)

        given_positive_ranking = build_ranking(karma_users_given_totals_nice,
                                               "positive", guild)
        given_negative_ranking = build_ranking(karma_users_given_totals_bulli,
                                               "negative", guild)

        output.add_field(
            name='Karma Conferred :ok_woman: (most karma given rank)',
            value=given_positive_ranking,
            inline=True)

        output.add_field(
            name='Karma Clobbered :no_good: (most karma taken rank)',
            value=given_negative_ranking,
            inline=True)

        karma_contributions = build_relo_ranking(karma_users_given_top_nice,
                                                 "positive", guild)
        karma_killed = build_relo_ranking(karma_users_given_top_bulli,
                                          "negative", guild)

        output.add_field(
            name=
            'Karma Contributions :gift: (people who have given most karma to someone else)',
            value=karma_contributions,
            inline=True)

        output.add_field(
            name=
            'Karma Killed :regional_indicator_f: (people who have taken most karma from someone else)',
            value=karma_killed,
            inline=True)

    if (command_type in ['bff', 'all']):
        # Get all BFFs
        # Not transitive so we have to do it this way
        top_friend = None
        top_friends_friend = None
        top_friend_score = 0
        positive_impact_cache = {}
        given_breakdown_cache = {}
        for uid in breakdowns.keys():
            given_breakdown_cache[uid] = breakdowns[uid]["given"]

        for karma in karma_list:
            name = get_username(karma.discord_id, guild)
            bff, bff_score, err = calculate_bff(karma.discord_id,
                                                given_breakdown_cache,
                                                positive_impact_cache)
            if not err:
                if bff_score > top_friend_score:
                    top_friend = name
                    top_friend_score = bff_score
                    top_friends_friend = get_username(bff, guild)
        if top_friend_score == 0:
            # Wow, nobody has BFFs cause everyone is rude
            value = "Sorry, top BFF can't be calculated as there is no pair that has positively impacted each other."
        else:
            value = "The best BFF pair is **{}** and **{}**, with a whopping score of **{:.2f}**".format(
                top_friend, top_friends_friend, top_friend_score)
        output.add_field(name=':sparkling_heart: Karma BFF :sparkling_heart:',
                         value=value,
                         inline=False)

    if (command_type in ['graph', 'all']):
        graph_points = []
        karma_days = {}

        for karma in karma_list:
            user = guild.get_member(int(karma.discord_id))
            name = get_username(karma.discord_id, guild)
            received_dates = dates[karma.discord_id]["received"]

            if received_dates:
                for day in received_dates:
                    if day["date"] not in karma_days:
                        karma_days[day["date"]] = 0
                    karma_days[day["date"]] += day["diff"]["positive"] + day[
                        "diff"]["negative"]

                x_coords, y_coords = zip(*((point["date"],
                                            point["diff"]["positive"] -
                                            point["diff"]["negative"])
                                           for point in received_dates))
                accumulated = list(accumulate(y_coords))
                graph_points.append((user, x_coords, accumulated))

        max_day = max(karma_days, key=karma_days.get)
        max_amount = karma_days[max_day]

        buffer = generate_graph(graph_points, 'Karma over time for server',
                                True)
        img_file = discord.File(buffer, filename="stats.png")
        output.set_image(url="attachment://stats.png")

        output.add_field(
            name='Karma Chart :bar_chart:',
            value=
            f'Below is a graph of the karma over time for the server. The day with the biggest karma change was **{max_day}** with **{max_amount}** karma +/-',
            inline=False)

    return output, img_file