Exemplo n.º 1
0
async def redo(
    ctx: commands.Context,
    raffle_type: str = "normal",
    num_winners: int = 1,
) -> None:
    """
    Picks new winner(s) from a past raffle.
    Make sure to reply to the original raffle message when invoking this command.
    """
    original_raffle = ctx.message.reference
    if original_raffle is None:
        raise Exception(
            "You must invoke this by replying to the original raffle message."
        )

    original_raffle_id = original_raffle.message_id
    if original_raffle_id is None:
        raise Exception("Could not find the referenced raffle.")

    num_winners = int(num_winners)
    if num_winners < 1:
        raise Exception("The number of winners must be at least 1.")

    raffle_message = await ctx.fetch_message(original_raffle_id)
    if raffle_message is None:
        raise Exception("Oops! That raffle does not exist anymore.")

    # We need to reset the past winners if we're re-doing a raffle draw
    # otherwise it'd be unfairly counted against them
    DB.get().clear_wins(ctx.guild.id, raffle_message.id)

    await _end_raffle_impl(ctx, raffle_message.id, raffle_type, num_winners)
Exemplo n.º 2
0
 async def approve_post(self, post_id, is_report=False):
     submission = await self.reddit.submission(id=post_id)
     await submission.mod.approve()
     if is_report:
         DB.get().mark_report_resolved(post_id)
     else:
         DB.get().mark_post_resolved(post_id)
Exemplo n.º 3
0
class Main:
    def __init__(self):
        GPIO.setmode(GPIO.BCM)
        self.config = parse_config()
        self.db = DB(self.config['influxdb'])
        self.sensors = []

    def start(self):
        self.sensors = self.find_temperature_sensors(self.config['sensors'])
        print('Found {} sensors'.format(len(self.sensors)))
        while True:
            start = time.time()
            self._measure_temperatures()
            duration = (time.time() - start)
            time.sleep(max(10 - duration, 0))

    def _measure_temperatures(self):
        for sensor in self.sensors:
            temperature = sensor.get_temperature()
            print('Saving {:.2f} C for {}'.format(temperature, sensor.name))
            self.db.insert_temperature(sensor, temperature)

    @staticmethod
    def find_temperature_sensors(config):
        return list(
            map(lambda path: Sensor(path, config),
                glob.glob('/sys/bus/w1/devices/28*/w1_slave')))
Exemplo n.º 4
0
def register():
    db = DB()
    print(request.data)
    print(request.data.decode())
    data = json.loads(request.data.decode())
    print(data)
    if not db.isExist(data['username']):
        username = data['username']
        salt = os.urandom(16)
        password = encrypt(data['password'], salt)
        email = data['email']
        print('DEBUG: Ready to create doc')
        if db.newDoc(
                dict(_id=username,
                     salt=base64.b64encode(salt).decode(),
                     password=base64.b64encode(password).decode(),
                     email=email)):
            response = make_response("OK")
            return response
            # return 'OK'
        else:
            response = make_response("An Error occured on the server")
            return response
            # return 'An Error occured on the server'
    else:
        response = make_response("Username Exists")
        return response
Exemplo n.º 5
0
async def start(ctx: commands.Context):
    """Creates a brand new raffle"""
    if DB.get().has_ongoing_raffle(ctx.guild.id):
        raise Exception("There is already an ongoing raffle!")

    raffle_message = await ctx.send(
        "Raffle time! React to this message to enter. The winner(s) will be randomly chosen."
    )

    DB.get().create_raffle(ctx.guild.id, raffle_message.id)
Exemplo n.º 6
0
 async def remove_post(self, post_id, reasons=None, is_report=False):
     submission = await self.reddit.submission(id=post_id)
     await submission.mod.remove()
     if reasons is not None:
         reply = await submission.reply(reasons)
         await reply.mod.distinguish()
         await submission.mod.lock()
     if is_report:
         DB.get().mark_report_resolved(post_id)
     else:
         DB.get().mark_post_resolved(post_id)
Exemplo n.º 7
0
    async def purge_resolved_posts(self):
        unresolved_posts = DB.get().get_unresolved_posts()

        current_unmoderated_ids = []
        async for post in self.subreddit.mod.unmoderated():
            current_unmoderated_ids.append(post.id)

        resolved_posts = []
        for post in unresolved_posts:
            if post[0] not in current_unmoderated_ids:
                resolved_posts.append(post[0])

        messages_to_delete = []
        for post_id in resolved_posts:
            DB.get().mark_post_resolved(post_id)
            messages_to_delete.append(
                self.delete_message(self.posts_channel, post_id))
        await asyncio.gather(*messages_to_delete)
Exemplo n.º 8
0
    def generate_payload(self, upload_method, file, group_name, query):

        # Excel Handler
        if upload_method == 'excel':
            # create a Pandas Dataframe to store Excel Data
            df = pd.read_excel(file)

            row_count = len(df)

            if row_count > 10:
                payload = list()
                # generate payload

                for row in df.itertuples():
                    payload_tuple = (row._1 + ' ' + row._2, row.Email,
                                     group_name)
                    payload.append(payload_tuple)

                # self.create_users_with_thread(payload)

        # JSON Handler
        elif upload_method == 'json':
            with open(file) as json_file:
                data = json.load(json_file)

                row_count = len(data)

                if row_count > 10:
                    payload = list()
                    for current_user in data:
                        payload_tuple = (current_user['first_name'] + ' ' +
                                         current_user['last_name'],
                                         current_user['email'], group_name)
                        payload.append(payload_tuple)

                        # self.create_users_with_thread(payload)

        # PostgreSQL Handler
        elif upload_method == 'db':

            db = DB()

            with db.conn.cursor() as cursor:
                cursor.execute(query)
                records = cursor.fetchall()

                num_rows = cursor.rowcount

                if num_rows > 10:
                    payload = list()
                    for row in records:
                        payload_tuple = (row[1] + row[2], row[3], group_name)
                        payload.append(payload_tuple)

                        # self.create_users_with_thread(payload)

        return payload
Exemplo n.º 9
0
    async def purge_resolved_reports(self):
        unresolved_reports = DB.get().get_unresolved_reports()

        current_report_ids = []
        async for submission in self.subreddit.mod.modqueue():
            current_report_ids.append(submission.id)

        resolved_reports = []
        for report in unresolved_reports:
            if report[0] not in current_report_ids:
                resolved_reports.append(report[0])

        messages_to_delete = []
        for report_id in resolved_reports:
            DB.get().mark_report_resolved(report_id)
            messages_to_delete.append(
                self.delete_message(self.reports_channel, report_id))
        await asyncio.gather(*messages_to_delete)
Exemplo n.º 10
0
async def end(
    ctx: commands.Context,
    raffle_type: str = "normal",
    num_winners: int = 1,
) -> None:
    """Closes an existing raffle and pick the winner(s)"""
    if not DB.get().has_ongoing_raffle(ctx.guild.id):
        raise Exception("There is no ongoing raffle! You need to start a new one.")

    num_winners = int(num_winners)
    if num_winners < 1:
        raise Exception("The number of winners must be at least 1.")

    raffle_message_id = DB.get().get_raffle_message_id(ctx.guild.id)
    if raffle_message_id is None:
        raise Exception("Oops! That raffle does not exist anymore.")

    await _end_raffle_impl(ctx, raffle_message_id, raffle_type, num_winners)
    DB.get().close_raffle(ctx.guild.id)
Exemplo n.º 11
0
def login():
    print(request.data)
    print(request.data.decode())
    data = json.loads(request.data.decode())
    db = DB()
    if not db.isExist(data['username']):
        response = make_response("No such username")
        return response
    res = db.findDoc(data['username'])
    print(base64.b64decode(res['salt'].encode()))
    print(base64.b64decode(res['password'].encode()))
    tmp = encrypt(data['password'], base64.b64decode(res['salt'].encode()))
    if base64.b64encode(tmp).decode() == res['password']:
        session['login'] = True
        response = make_response("OK")
        return response
    else:
        response = make_response("Password Wrong")
        return response
Exemplo n.º 12
0
    async def on_ready(self):
        server = self.bot.get_guild(int(self.config["Discord"]["ServerID"]))
        channel = utils.get(
            server.channels, name=self.config["Discord"]["ReportsChannel"]
        )
        subreddit = await self.reddit.praw().subreddit(
            self.config["Reddit"]["Subreddit"]
        )

        while not self.bot.is_closed():
            async for submission in subreddit.mod.modqueue():
                if not DB.get().is_report_added(submission.id):
                    if isinstance(submission, Comment):
                        em = self.create_comment_em(submission)
                    else:
                        em = self.create_post_em(submission, reports=True)
                    await channel.send(embed=em)
                    DB.get().add_report(submission.id)
                elif DB.get().report_was_resolved(submission.id):
                    if isinstance(submission, Comment):
                        em = self.create_comment_em(submission)
                    else:
                        em = self.create_post_em(submission, reports=True)
                    await channel.send(embed=em)
                    DB.get().unresolve_report(submission.id)
            await asyncio.sleep(10)
Exemplo n.º 13
0
    async def remove(self, ctx, post_id_list, *reasons):
        post_ids = post_id_list.split(",")
        if len(post_ids) == 0:
            raise ValueError("No posts were given")

        if len(reasons) < 2:
            reasons = []
        else:
            if reasons[0] != "reasons":
                raise ValueError('Invalid command format. Expected "reasons".')
            reasons = reasons[1:]

        if len(reasons) == 0:
            for post_id in post_ids:
                is_report = False
                if DB.get().is_post_resolved(post_id):
                    is_report = True
                await self.reddit.remove_post(post_id, is_report=is_report)
            await ctx.message.delete()
            return

        if len(post_ids) > 1:
            raise ValueError(
                "Reasons are not supported when removing multiple posts")

        post_id = post_ids[0]
        reason_body = self.parse_reasons(reasons)
        submission = await self.reddit.praw().submission(id=post_id)
        header = self.reasons.get_header(submission.author, "post")
        footer = self.reasons.get_footer()
        reason_text = "{}{}{}".format(header, reason_body, footer)

        is_report = False
        if DB.get().is_post_resolved(post_id):
            is_report = True
        await asyncio.gather(
            self.reddit.remove_post(post_id, reason_text, is_report=is_report),
            ctx.message.delete(),
            self.delete_message(ctx.channel, post_id),
        )
Exemplo n.º 14
0
 async def approve(self, ctx, post_id_list):
     post_ids = post_id_list.split(",")
     if len(post_ids) == 0:
         raise ValueError("No posts were given")
     for post_id in post_ids:
         is_report = False
         if DB.get().is_post_resolved(post_id):
             is_report = True
         await self.reddit.approve_post(post_id, is_report=is_report)
     await asyncio.gather(
         ctx.message.delete(),
         self.delete_message(ctx.channel, post_id),
     )
Exemplo n.º 15
0
 async def remove_comment(self, comment_id):
     comment = await self.reddit.comment(id=comment_id)
     await comment.mod.remove()
     DB.get().mark_report_resolved(comment_id)
Exemplo n.º 16
0
def _choose_winners_weighted(
    guild_id: int, entrants: list[discord.Member], num_winners: int
) -> list[discord.Member]:
    """
    Purpose of this algorithm is to choose winners in a way that actually lowers
    their chances the more raffles they've won in the past.
    Conceptually, can think of it as giving out more raffle "tickets" to those that have not won as often.

    Each raffle win lowers your relative odds of winning by 25%.
    So someone who has won once is 0.75x as likely to win as someone who has never won.
    Someone who's won twice is 0.5625x (0.75^2) as likely as someone who has never won.
    And so on.

    Here's how it works.

    We start by fetching the past wins of everyone in the guild.
    Then, of the current raffle entrants, we start with the person who's won the most times.
    Going from that win count -> 0 we figure out the ticket distribution factor for each bucket of win counts.
    Then we figure out how many tickets they should get for each bucket based on that distribution factor.
    That then gives us the relative probability array that gets fed into random.choice

    Here's an example.

    Say we have the following entrants:
    8 people who've won 0 times
    5 people who have won 1 time
    2 people who have won 2 times
    1 person who has won 4 times

    Highest win count is 4 wins so we start there.
    That bucket awards 1 ticket and then we calculate the fewer-win bucket tickets:
    4 wins -> 1 ticket
    3 wins -> 4/3 (~1.3) tickets
    2 wins -> 16/9 (~1.8) tickets
    1 win -> 64/27 (~2.4) tickets
    0 wins -> 256/81 (~3.16) tickets

    This way: 4 wins gets 0.75x as many tickets as 3 wins,
    3 wins gets 0.75x as many tickets as 2 wins, and so on.

    Total tickets given out is the sum of each bucket's tickets the number of entrants:
    8 entrants * 256/81 tickets
    + 5 * 64/27
    + 2 * 16/9
    + 0 * 4/3
    + 1 * 1
    = ~41.7 tickets

    Now, the p-list values should all sum up to 1. So we treat those tickets as
    portions of a "single ticket" and give out those portions.
    We do that by taking the reciprocal, so 1/41.7 = 0.0239857862

    0.0239857862 now is the chance of winning if you were given one "ticket".
    Then we divvy out those tickets according to the number awarded per win bucket.

    So then we end with:
    8 people get 256/81 * 0.0239857862 = 0.07580692922 "tickets"
    5 people get 64/27 * 0.0239857862 = 0.05685519692 tickets
    2 people get 16/9 * 0.0239857862 = 0.04264139769 tickets
    1 person gets 1 * 0.0239857862 = 0.0239857862 tickets

    As a check, if we add all those up, it should equal 1.
    0.07580692922 * 8 + 0.05685519692 * 5 + 0.04264139769 * 2 + 0.0239857862 = 0.9999999999

    So then for our p-list, our resultant structure is:
    [0.07580692922, 0.07580692922, 0.07580692922, ..., 0.04264139769, 0.04264139769, 0.0239857862]

    And we sort the corresponding entrants list by their win counts ascending so the two lists line up.
    [0-wins entrant, 0-wins entrant, 0-wins entrant, ..., 2-wins entrant, 2-wins entrant, 4-wins entrant]

    Then we let numpy.random.choice work its magic.
    """
    if len(entrants) < num_winners:
        raise Exception("There are not enough entrants for that many winners.")

    # Just to add even more randomness
    random.shuffle(entrants)
    random.shuffle(entrants)
    random.shuffle(entrants)

    past_winner_win_counts = DB.get().win_counts(guild_id)
    entrants = sorted(
        entrants, key=lambda entrant: past_winner_win_counts.get(entrant.id, 0)
    )

    total_win_counts = {}
    for entrant in entrants:
        entrant_past_wins = past_winner_win_counts.get(entrant.id, 0)
        if entrant_past_wins not in total_win_counts:
            total_win_counts[entrant_past_wins] = 1
        else:
            total_win_counts[entrant_past_wins] += 1

    tickets_per_win_bucket = {}
    highest_entrant_wins = max(total_win_counts.keys())
    for i in range(highest_entrant_wins, -1, -1):
        tickets_per_win_bucket[i] = (4 / 3) ** (highest_entrant_wins - i)

    total_tickets = 0
    for win, tickets in tickets_per_win_bucket.items():
        total_tickets += total_win_counts.get(win, 0) * tickets

    value_of_one_ticket = 1 / total_tickets
    for win, multiplier in tickets_per_win_bucket.copy().items():
        tickets_per_win_bucket[win] = multiplier * value_of_one_ticket

    p_list = []
    for win, tickets in reversed(tickets_per_win_bucket.items()):
        for i in range(0, total_win_counts.get(win, 0)):
            p_list.append(tickets)

    return numpy.random.choice(entrants, num_winners, replace=False, p=p_list)
Exemplo n.º 17
0
async def _end_raffle_impl(
    ctx: commands.Context,
    raffle_message_id: int,
    raffle_type: str,
    num_winners: int,
) -> None:
    raffle_message = await ctx.fetch_message(raffle_message_id)
    if raffle_message is None:
        raise Exception("Oops! That raffle does not exist anymore.")

    # We annotate the raffle_type param above as `str` for a more-clear error message
    # This way it says it doesn't recognize the raffle type rather than fail param type conversion
    raffle_type = RaffleType(raffle_type)

    if raffle_type == RaffleType.Normal:
        recent_raffle_winner_ids = DB.get().recent_winner_ids(ctx.guild.id)
        past_week_winner_ids = DB.get().past_week_winner_ids(ctx.guild.id)
        ineligible_winner_ids = recent_raffle_winner_ids.union(past_week_winner_ids)
    elif raffle_type == RaffleType.Anyone:
        ineligible_winner_ids = set()
    elif raffle_type == RaffleType.New:
        ineligible_winner_ids = DB.get().all_winner_ids(ctx.guild.id)
    else:
        raise Exception("Unimplemented raffle type")

    entrants = set()
    for reaction in raffle_message.reactions:
        users = await reaction.users().flatten()
        for user in users:
            if user.id not in ineligible_winner_ids:
                entrants.add(user)

    # Certain servers may only want you to be eligible for a raffle if you have
    # given role(s). These are checked as ORs meaning if you have at least one
    # of the configured roles you are eligible to win.
    eligible_role_ids = DB.get().eligible_role_ids(ctx.guild.id)
    if len(eligible_role_ids) > 0:
        for entrant in entrants.copy():
            if eligible_role_ids.intersection(_get_role_ids(entrant)) == set():
                entrants.remove(entrant)

    if len(entrants) == 0:
        await ctx.send("No one eligible entered the raffle so there is no winner.")
        return

    if raffle_type == RaffleType.Normal:
        winners = _choose_winners_weighted(ctx.guild.id, list(entrants), num_winners)
    else:
        winners = _choose_winners_unweighted(list(entrants), num_winners)

    if raffle_type != RaffleType.Anyone:
        DB.get().record_win(ctx.guild.id, raffle_message_id, *winners)

    if len(winners) == 1:
        await ctx.send("{} has won the raffle!".format(winners[0].mention))
    else:
        await ctx.send(
            "Raffle winners are: {}!".format(
                ", ".join(map(lambda winner: winner.mention, winners))
            )
        )
Exemplo n.º 18
0
    def create_users(self, upload_method, file, group_name, query):
        """
        Create users at scale

        :param upload_method:
        :param file:
        :param group_name:
        :return: a dictionary containing on how many users were created and how many failed to be created
        """

        success_count = 0
        fail_count = 0

        group_id = self.get_group_id(group_name)

        # If the group doesn't exist, create it.
        if not group_id:
            user_input = input(
                "The group %s doesn't exist. Would you like to create it (yes/no)? "
                % group_name)

            if user_input == "yes":
                group_response = self.create_groups(logger, group_name)

                msg = "Group '%s' successfully created" % group_name
                logger.info(msg)

            elif user_input == "no":

                msg = "No users were added because user opted to not create a new group"
                logger.warning(msg)

                return {
                    'success_count': success_count,
                    'fail_count': fail_count
                }

        # Excel Handler
        if upload_method == 'excel':
            # create a Pandas Dataframe to store Excel Data
            df = pd.read_excel(file)

            row_count = len(df)

            user_input = input(
                "You are about to create %s new user accounts. Are you sure you'd like to continue? (yes/no): "
                % row_count)
            if user_input == "yes":

                if row_count > 10:
                    payload = list()
                    # generate payload

                    for row in df.itertuples():
                        payload_tuple = (row._1 + ' ' + row._2, row.Email,
                                         group_name)
                        payload.append(payload_tuple)

                    self.create_users_with_thread(payload)

                else:
                    # Todo: is there a better way to iterate through DataFrame rows?
                    for row in df.itertuples():
                        create_user_response = self.create_user(
                            row._1 + row._2, row.Email, group_name)

                        if create_user_response:
                            success_count += 1
                        else:
                            fail_count += 1
            else:
                logger.info("User chose not to create accounts")

        # JSON Handler
        elif upload_method == 'json':
            with open(file) as json_file:
                data = json.load(json_file)

                row_count = len(data)

                user_input = input(
                    "You are about to create %s new user accounts. Are you sure you'd like to continue? (yes/no): "
                    % row_count)
                if user_input == "yes":

                    if row_count > 10:
                        payload = list()
                        for current_user in data:
                            payload_tuple = (current_user['first_name'] + ' ' +
                                             current_user['last_name'],
                                             current_user['email'], group_name)
                            payload.append(payload_tuple)

                            self.create_users_with_thread(payload)

                    else:
                        for current_user in data:
                            create_user_response = self.create_user(
                                (current_user['first_name'] + ' ' +
                                 current_user['last_name'],
                                 current_user['email'], group_name))

                            if create_user_response:
                                success_count += 1
                            else:
                                fail_count += 1

                else:
                    logger.info("User chose not to create accounts")

        # PostgreSQL Handler
        elif upload_method == 'db':

            db = DB()

            with db.conn.cursor() as cursor:
                cursor.execute(query)
                records = cursor.fetchall()

                num_rows = cursor.rowcount

                user_input = input(
                    "You are about to create %s new user accounts. Are you sure you'd like to continue? (yes/no): "
                    % num_rows)
                if user_input == "yes":

                    if num_rows > 10:
                        payload = list()
                        for row in records:
                            payload_tuple = (row[1] + row[2], row[3],
                                             group_name)
                            payload.append(payload_tuple)

                            self.create_users_with_thread(payload)

                    else:
                        for row in records:
                            login = row[3]
                            create_user_response = self.create_user(
                                row[1] + row[2], login, group_name)

                            if create_user_response:
                                success_count += 1
                            else:
                                fail_count += 1
                else:
                    logger.info("User chose not to create accounts")

        return {'success_count': success_count, 'fail_count': fail_count}
Exemplo n.º 19
0
 def __init__(self):
     GPIO.setmode(GPIO.BCM)
     self.config = parse_config()
     self.db = DB(self.config['influxdb'])
     self.sensors = []