예제 #1
0
def handle_binify(command: Command):
    """
    `!binify (binary | ascii)` - Converts a binary string to an ascii string
    or vice versa
    """
    if not command.has_arg():
        response = "Please include string to convert."
    elif set(command.arg).issubset(["0", "1"]) and len(command.arg) > 2:
        if len(command.arg) % 8 != 0:
            response = "Binary string contains partial byte."
        else:
            response = ""
            for i in range(0, len(command.arg), 8):
                n = int(command.arg[i:i + 8], 2)
                if n >= 128:
                    response = "Character out of ascii range (0-127)"
                    break
                response += chr(n)
    else:
        response = ""
        for c in command.arg.replace("&",
                                     "&").replace("<",
                                                  "<").replace("&gt;", ">"):
            n = ord(c)
            if n >= 128:
                response = "Character out of ascii range (0-127)"
                break
            response += f"{n:08b}"

    command.reply_with(bot, response)
예제 #2
0
def handle_mock(command: Command):
    """
    `!mock ([TEXT] | [NUM POSTS])` - Mocks the message from the specified number of
    messages back. If no number is specified, mocks the most recent message.
    """
    num_posts_back = None
    # Add 1 here to account for the calling user's message,
    # which we don't want to mock by default.
    if not command.has_arg():
        num_posts_back = 1
    elif is_number(command.arg):
        num_posts_back = int(command.arg) + 1

    if num_posts_back is None:
        response = mock_message(command.arg)
    elif num_posts_back > MAX_NUM_POSTS_BACK:
        response = f'Cannot recall messages that far back, try under {MAX_NUM_POSTS_BACK}.'
    elif num_posts_back < 0:
        response = 'Cannot mock into the future (yet)!'
    else:
        message_to_mock = get_nth_most_recent_message(command.channel_id,
                                                      num_posts_back)
        if message_to_mock is None:
            response = 'Something went wrong (likely insufficient conversation history).'
        else:
            response = mock_message(message_to_mock)

    command.reply_with(bot, response)
예제 #3
0
파일: cat.py 프로젝트: lsenjov/uqcsbot
def handle_cat(command: Command):
    """
    `!cat` - Displays the moss cat. Brings torture to CSSE2310 students.
    """
    cat = "\n".join(
        ("```", "         __..--''``\\--....___   _..,_            ",
         "     _.-'    .-/\";  `        ``<._  ``-+'~=.     ",
         " _.-' _..--.'_    \\                    `(^) )    ",
         "((..-'    (< _     ;_..__               ; `'   fL",
         "           `-._,_)'      ``--...____..-'         ```"))
    command.reply_with(bot, cat)
예제 #4
0
def handle_uptime(command: Command):
    """
    `!uptime` - displays the current uptime for UQCSBot
    """
    t = datetime.now() - bot.start_time
    message = (
        "The bot has been online for" +
        f" {precisedelta(t, format='%.0f'):s}" +
        (f" (`{round(t.total_seconds()):d}` seconds)"
         if t.total_seconds() >= 60 else "") +
        f", since {bot.start_time.strftime('%H:%M:%S on %b %d'):s}"
        # adds ordinal suffix
        +
        f"{(lambda n: 'tsnrhtdd'[(n//10%10!=1)*(n%10<4)*n%10::4])(bot.start_time.day):s}."
    )
    command.reply_with(bot, message)
예제 #5
0
def handle_umart(command: Command):
    """
    `!umart <QUERY>` - Returns 5 top results for products from umart matching the search query.
    """
    # Makes sure the query is not empty
    if not command.has_arg():
        bot.post_message(command.channel_id, NO_QUERY_MESSAGE)
        return
    search_query = command.arg.strip()
    # Detects if user is being smart
    if "SOMETHING NOT AS SPECIFIC" in search_query:
        bot.post_message(command.channel_id, "Not literally...")
        return
    search_results = get_umart_results(search_query)
    if search_results is None:
        bot.post_message(command.channel_id, ERROR_MESSAGE)
        return
    if len(search_results) == 0:
        bot.post_message(command.channel_id, NO_RESULTS_MESSAGE)
        return
    message = "```"
    for result in search_results:
        message += f"Name: <{UMART_PRODUCT_URL}{result['link']}|{result['name']}>\n"
        message += f"Price: {result['price']}\n"
    message += "```"
    bot.post_message(command.channel_id, message)
예제 #6
0
파일: bgg.py 프로젝트: gaenrique/uqcsbot
def handle_bgg(command: Command):
    """
    `!bgg board_game` - Gets the details of `board_game` from Board Game Geek
    """

    if not command.has_arg():
        raise UsageSyntaxException()
    argument = command.arg

    identity = get_bgg_id(argument)
    if identity is None:
        bot.post_message(command.channel_id,
                         "Could not find board game with that name.")
        return

    parameters = get_board_game_parameters(identity)
    if parameters is None:
        bot.post_message(command.channel_id, "Something has gone wrong.")
        return

    message = format_board_game_parameters(parameters)
    bot.post_message(command.channel_id,
                     message,
                     unfurl_links=False,
                     unfurl_media=False)
예제 #7
0
async def handle_acronym(command: Command):
    if not command.has_arg():
        return

    words = command.arg.split(" ")

    # Requested by @wbo, do not remove unless you get his express permission
    if len(words) == 1:
        word = words[0]
        if word.lower() in [":horse:", "horse"]:
            bot.post_message(command.channel, ">:taco:")
            return
        if word.lower() in [":rachel:", "rachel"]:
            bot.post_message(command.channel, ">:older_woman:")
            return

    acronym_futures = [get_acronyms(word) for word in words[:ACRONYM_LIMIT]]
    response = ""
    for word, acronyms in await asyncio.gather(*acronym_futures):
        if acronyms:
            acronym = acronyms[0]
            response += f">{word.upper()}: {acronym}\r\n"
        else:
            response += f"{word.upper()}: No acronyms found!\r\n"

    if len(words) > ACRONYM_LIMIT:
        response += f">I am limited to {ACRONYM_LIMIT} acronyms at once"

    bot.post_message(command.channel, response)
예제 #8
0
def define(command: Command):
    '''
    `!define <TEXT>` - Gets the dictionary definition of TEXT
    '''
    query = command.arg
    # Fun Fact: Empty searches return the definition of adagio (a piece of music to be played or
    # sung slowly)
    if not command.has_arg():
        bot.post_message(command.channel_id, "Please specify a word")
        return

    http_response = requests.get(API_URL, params={'headword': query})

    # Check if the response is OK
    if http_response.status_code != requests.codes.ok:
        bot.post_message(command.channel_id, "Problem fetching definition")
        return

    json_data = json.loads(http_response.content)
    results = json_data.get('results', [])
    if len(results) == 0:
        message = "No Results"
    else:
        # This gets the first definition of the first result.
        senses = results[0].get('senses', [{}])[0]
        # Sometimes there are "subsenses" for whatever reason and sometimes there aren't.
        # No explanation provided. This gets the first subsense if there are, otherwise,
        # just uses senses.
        message = senses.get('subsenses',
                             [senses])[0].get('definition',
                                              "Definition not available")

    bot.post_message(command.channel_id, f">>>{message}")
예제 #9
0
def handle_repo(command: Command):
    """
    `!repo` - Returns the url for the uqcsbot Github repository and other club repos
    """

    # Setup for message passing
    channel = bot.channels.get(command.channel_id)
    # Read the commands provided
    arguments = command.arg.split() if command.has_arg() else []

    # All repos
    if len(arguments) > 0 and arguments[0] in ["--list", "-l", "list", "full", "all"]:
        return bot.post_message(channel,
                                "_Useful :uqcs: Github repositories_:\n"
                                + format_repo_message(list(REPOS.keys())))

    # List of specific repos
    if len(arguments) > 0:
        return bot.post_message(channel,
                                "_Requested :uqcs: Github repositories_:\n"
                                + format_repo_message(arguments))

    # Default option: just uqcsbot link
    return bot.post_message(channel,
                            "_Have you considered contributing to the bot?_\n" +
                            format_repo_message(["uqcsbot"]) +
                            "\n _For more repositories, try_ `!repo list`")
예제 #10
0
def handle_dominos(command: Command):
    """
    `!dominos [--num] N [--expiry] <KEYWORDS>`
    Returns a list of dominos coupons (default: 5 | max: 10)
    """
    command_args = command.arg.split() if command.has_arg() else []

    parser = argparse.ArgumentParser()

    def usage_error(*args, **kwargs):
        raise UsageSyntaxException()

    parser.error = usage_error  # type: ignore
    parser.add_argument('-n', '--num', default=5, type=int)
    parser.add_argument('-e', '--expiry', action='store_true')
    parser.add_argument('keywords', nargs='*')

    args = parser.parse_args(command_args)
    coupons_amount = min(args.num, MAX_COUPONS)
    coupons = get_coupons(coupons_amount, args.expiry, args.keywords)

    message = ""
    for coupon in coupons:
        message += f"Code: *{coupon.code}* - {coupon.description}\n"
    bot.post_message(command.channel_id, message)
예제 #11
0
def handle_meme(command: Command):
    """
    `!meme <names | (<MEME NAME> "<TOP TEXT>" "<BOTTOM TEXT>")>`
    Generates a meme of the given format with the provided top and
    bottom text. For a full list of formats, try `!meme names`.
    """
    channel = command.channel_id

    if not command.has_arg():
        raise UsageSyntaxException()

    name = command.arg.split()[0].lower()
    if name == "names":
        send_meme_names(command)
        return
    elif name not in MEME_NAMES.keys():
        bot.post_message(channel, "The meme name is invalid. "
                         "Try `!meme names` to get a list of all valid names")
        return

    args = get_meme_arguments(command.arg)
    if len(args) != 2:
        raise UsageSyntaxException()

    # Make an attachment linking to image
    top, bottom = args
    image_url = API_URL + f"{quote(name)}/{quote(top)}/{quote(bottom)}.jpg"
    attachments = [{"text": "", "image_url": image_url}]
    bot.post_message(channel, "", attachments=attachments)
예제 #12
0
async def voteythumbs(evt: dict):
    if "!voteythumbs" not in evt.get("text", ""):
        return
    evt["text"] = strip(evt["text"])
    cmd = Command.from_message(bot, evt)
    if cmd is None:
        return
    if not cmd.has_arg() and "!voteythumbs" in evt["text"]:
        await bot.run_async(bot.post_message, cmd.channel,
                            "Invalid voteythumbs command")
    if not cmd.has_arg():
        bot.logger.error("Invalid voteythumbs command")
        return
    cmd.arg = strip(cmd.arg)

    result = await bot.run_async(bot.post_message, cmd.channel,
                                 f"Starting vote: {cmd.arg}")
    add_reaction = partial(
        bot.run_async,
        bot.api.reactions.add,
        channel=cmd.channel.id,
        timestamp=result['ts'],
    )
    for emoji in ["thumbsup", "thumbsdown", "eyes"]:
        res = await add_reaction(name=emoji)
        if not res.get('ok'):
            bot.logger.error(f"Voteythumbs error adding \"{emoji}\": {res}")
            return
예제 #13
0
def handle_calendar(command: Command):
    '''
    `!calendar <COURSE CODE 1> [COURSE CODE 2] ...` - Returns a compiled
    calendar containing all the assessment for a given list of course codes.
    '''
    channel = bot.channels.get(command.channel_id)
    course_names = command.arg.split() if command.has_arg() else [channel.name]

    if len(course_names) > COURSE_LIMIT:
        bot.post_message(channel,
                         f'Cannot process more than {COURSE_LIMIT} courses.')
        return

    try:
        assessment = get_course_assessment(course_names)
    except HttpException as e:
        bot.logger.error(e.message)
        bot.post_message(channel, f'An error occurred, please try again.')
        return
    except (CourseNotFoundException, ProfileNotFoundException) as e:
        bot.post_message(channel, e.message)
        return

    user_direct_channel = bot.channels.get(command.user_id)
    bot.api.files.upload(
        title='Importable calendar containing your assessment!',
        channels=user_direct_channel.id,
        filetype='text/calendar',
        filename='assessment.ics',
        file=get_calendar(assessment))
예제 #14
0
def handle_latex_cmd(command: Command):
    """
    `!latex CONTENT` - Renders `CONTENT` to LaTeX and sends it to Slack.
    `$$ CONTENT $$` also works.
    """
    if not command.has_arg():
        bot.post_message(command.channel_id, "No data provided")
    handle_latex_internal(command.channel_id, command.arg.strip())
예제 #15
0
파일: latex.py 프로젝트: rachcatch/uqcsbot
def handle_latex_command(command: Command):
    """
    `!latex CONTENT` - Renders `CONTENT` to LaTeX and sends it to Slack.
    `$$ CONTENT $$` also works.
    """
    if not command.has_arg():
        raise UsageSyntaxException()
    handle_latex_internal(command.channel_id, command.arg.strip())
예제 #16
0
def handle_urban(command: Command) -> None:
    """
    `!urban <PHRASE>` - Looks a phrase up on Urban Dictionary.
    """
    # Check for search phase
    if not command.has_arg():
        raise UsageSyntaxException()

    search_term = command.arg

    # Attempt to get definitions from the Urban Dictionary API.
    http_response = requests.get(URBAN_API_ENDPOINT,
                                 params={'term': search_term})
    if http_response.status_code != 200:
        bot.post_message(
            command.channel_id,
            'There was an error accessing the Urban Dictionary API.')
        return
    results = http_response.json()

    # Filter for exact matches
    filtered_definitions = filter(
        lambda def_: def_['word'].casefold() == search_term.casefold(),
        results['list'])

    # Sort definitions by their number of thumbs ups.
    sorted_definitions = sorted(filtered_definitions,
                                key=lambda def_: def_['thumbs_up'],
                                reverse=True)

    # If search phrase is not found, notify user.
    if len(sorted_definitions) == 0:
        bot.post_message(command.channel_id,
                         f'> No results found for {search_term}. ¯\\_(ツ)_/¯')
        return

    best_definition = sorted_definitions[0]
    best_definition_text = re.sub(
        r'[\[\]]', '',
        best_definition["definition"])  # Remove Urban Dictionary [links]

    example_text = re.sub(r'[\[\]]', '', best_definition.get(
        'example', ''))  # Remove Urban Dictionary [links]
    # Break example into individual lines and wrap each in it's own block quote.
    example_lines = example_text.split('\r\n')
    formatted_example = '\n'.join(f'> {line}' for line in example_lines)

    # Format message and send response to user in channel query was sent from.
    message = f'*{search_term.title()}*\n' \
              f'{best_definition_text.capitalize()}\n' \
              f'{formatted_example}'
    # Only link back to Urban Dictionary if there are more definitions.
    if len(sorted_definitions) > 1:
        endpoint_url = http_response.url.replace(URBAN_API_ENDPOINT,
                                                 URBAN_USER_ENDPOINT)
        message += f'\n_ more definitions at {endpoint_url} _'

    bot.post_message(command.channel_id, message)
예제 #17
0
def handle_pastexams(command: Command):
    '''
    `!pastexams [COURSE CODE]` - Retrieves past exams for a given course code.
    If unspecified, will attempt to find the ECP for the channel the command was
    called from.
    '''
    channel = bot.channels.get(command.channel_id)
    course_code = command.arg if command.has_arg() else channel.name
    bot.post_message(channel, get_past_exams(course_code))
예제 #18
0
def handle_crates(command: Command):
    """
    `!crates [-h] [[name] | {search,categories,users}]`
            - Get information about crates from crates.io
    """
    args = parse_arguments(command.arg if command.has_arg() else '')

    # Executes the function that was stored by the arg parser depending on which sub-command was used
    args.execute_action(command.channel_id, args)  # type: ignore
예제 #19
0
파일: help.py 프로젝트: kprohith/uqcsbot
def handle_help(command: Command):
    """
    `!help [COMMAND]` - Display the helper docstring for the given command.
    If unspecified, will return the helper docstrings for all commands.
    """

    # get helper docs
    helper_docs = get_helper_docs(command.arg)
    if len(helper_docs) == 0:
        message = 'Could not find any helper docstrings.'
    else:
        message = '>>>' + '\n'.join(helper_docs)

    # post helper docs
    if command.arg:
        command.reply_with(bot, message)
    else:
        bot.post_message(command.user_id, message, as_user=True)
예제 #20
0
def handle_leet(command: Command) -> None:
    """
    `!leet [`easy` | `medium` | `hard`] - Retrieves a set of questions from online coding
    websites, and posts in channel with a random question from this set. If a difficulty
    is provided as an argument, the random question will be restricted to this level of
    challenge. Else, a random difficulty is generated to choose.
    """
    was_random = True  # Used for output later

    if command.has_arg():
        if (command.arg not in {"easy", "medium", "hard"}):
            bot.post_message(command.channel_id,
                             "Usage: !leet [`easy` | `medium` | `hard`]")
            return
        else:
            difficulty = command.arg.lower()
            was_random = False
    else:
        difficulty = random.choice(
            LC_DIFFICULTY_MAP)  # No difficulty specified, randomly generate

    # List to store questions collected
    questions: List[Tuple[str, str]] = []

    # Go fetch questions from APIs
    collect_questions(questions, difficulty)
    selected_question = select_question(questions)  # Get a random question

    # If we didn't find any questions for this difficulty, try again, probably timeout on all 3
    if (selected_question is None):
        bot.post_message(
            command.channel_id,
            "Hmm, the internet pipes are blocked. Try that one again.")
        return

    # Leetcode difficulty colors
    color = COLORS[difficulty]

    if (was_random):
        title_text = f"Random {difficulty} question generated!"
    else:
        # Style this a bit nicer
        difficulty = difficulty.title()
        title_text = f"{difficulty} question generated!"

    difficulty = difficulty.title(
    )  # If we haven't already (i.e. random question)

    msg_text = f"Here's a new question for you! <{selected_question[1]}|{selected_question[0]}>"

    bot.post_message(command.channel_id,
                     text=title_text,
                     attachments=[
                         Attachment(SectionBlock(msg_text),
                                    color=color)._resolve()
                     ])
예제 #21
0
def advent(command: Command) -> None:
    """
    !advent - Prints the Advent of Code private leaderboard for UQCS
    """

    channel = bot.channels.get(command.channel_id, use_cache=False)

    def reply(message):
        bot.post_message(channel, message, thread_ts=command.thread_ts)

    try:
        args = parse_arguments(
            command.arg.split() if command.has_arg() else [])
    except UsageSyntaxException as error:
        reply(str(error))
        return

    try:
        leaderboard = get_leaderboard(args.year, args.code)
    except ValueError:
        reply(
            "Error fetching leaderboard data. Check the leaderboard code, year, and day."
        )
        raise

    try:
        members = [
            Member.from_member_data(data, args.year, args.day)
            for data in leaderboard["members"].values()
        ]
    except Exception:
        reply("Error parsing leaderboard data.")
        raise

    # whether to show only one day
    is_day = bool(args.day)
    # whether to use global points
    is_global = args.global_

    # header message
    message = f":star: *Advent of Code Leaderboard {args.code}* :trophy:"
    if is_day:
        message += f"\n:calendar: *Day {args.day}* (sorted by {SORT_LABELS[args.sort]})"
    elif is_global:
        message += "\n:earth_asia: *Global Leaderboard Points*"

    # reply with leaderboard as a file attachment because it gets quite large.
    bot.api.files.upload(
        initial_comment=message,
        content=format_advent_leaderboard(members, is_day, is_global,
                                          args.sort),
        title=f"advent_{args.code}_{args.year}_{args.day}.txt",
        filetype="text",
        channels=channel.id,
        thread_ts=command.thread_ts)
예제 #22
0
파일: zalgo.py 프로젝트: kprohith/uqcsbot
def handle_zalgo(command: Command):
    """
    `!zalgo TEXT` - Adds Zalgo characters to the given text.
    """
    text = command.arg if command.has_arg() else "Cthulhu fhtagn!"
    response = ""
    for c in text:
        response += c
        for i in range(randrange(7)//3):
            response += choice(HORROR)
    bot.post_message(command.channel_id, response)
예제 #23
0
def handle_cards(command: Command):
    """
    `!cards [number] [joker]` - Deals one or more cards
    """

    # easter egg - prepare four 500 hands, and the kitty
    if command.arg == "500":
        deck = (list(range(0, 0 + 10)) + list(range(13, 13 + 11)) +
                list(range(26, 26 + 10)) + list(range(39, 39 + 11)) + [-1])
        shuffle(deck)
        hands = [deck[0:10], deck[10:20], deck[20:30], deck[30:40], deck[40:]]
        for i in range(5):
            h = [emojify(j) for j in sorted(hands[i])]
            response = [
                ":regional-indicator-n: ", ":regional-indicator-e: ",
                ":regional-indicator-s: ", ":regional-indicator-w: ", ":cat: "
            ][i] + "".join(h)
            bot.post_message(command.channel_id, response)
        return

    deck = list(range(52))

    # add joker
    if command.has_arg() and command.arg.split(" ")[-1][0].lower() == "j":
        deck.append(-1)

    # set number to deal
    if command.has_arg() and command.arg.split(" ")[0].isnumeric():
        cards = min(max(int(command.arg.split(" ")[0]), 1), len(deck))
    else:
        cards = 1

    shuffle(deck)
    deck = deck[:cards]
    deck.sort()

    response = ""
    for i in deck:
        response += emojify(i)

    bot.post_message(command.channel_id, response)
예제 #24
0
def handle_whatsdue(command: Command):
    """
    `!whatsdue [-f] [--full] [COURSE CODE 1] [COURSE CODE 2] ...` - Returns all
    the assessment for a given list of course codes that are scheduled to occur
    after today. If unspecified, will attempt to return the assessment for the
    channel that the command was called from. If -f/--full is provided, will
    return the full assessment list without filtering by cutoff dates.
    """
    channel = bot.channels.get(command.channel_id)
    command_args = command.arg.split() if command.has_arg() else []

    is_full_output = False
    if '--full' in command_args:
        command_args.remove('--full')
        is_full_output = True
    if '-f' in command_args:
        command_args.remove('-f')
        is_full_output = True

    # If we have any command args left, they're course names. If we don't,
    # attempt to instead use the channel name as the course name.
    course_names = command_args if len(command_args) > 0 else [channel.name]

    if len(course_names) > COURSE_LIMIT:
        bot.post_message(channel,
                         f'Cannot process more than {COURSE_LIMIT} courses.')
        return

    # If full output is not specified, set the cutoff to today's date.
    cutoff = None if is_full_output else datetime.today()
    try:
        asses_page = get_course_assessment_page(course_names)
        assessment = get_course_assessment(course_names, cutoff, asses_page)
    except HttpException as e:
        bot.logger.error(e.message)
        bot.post_message(channel, f'An error occurred, please try again.')
        return
    except (CourseNotFoundException, ProfileNotFoundException) as e:
        bot.post_message(channel, e.message)
        return

    message = (
        '_*WARNING:* Assessment information may vary/change/be entirely' +
        ' different! Use at your own discretion_\n>>>')
    message += '\n'.join(map(get_formatted_assessment_item, assessment))
    if not is_full_output:
        message += (
            '\n_Note: This may not be the full assessment list. Use -f' +
            '/--full to print out the full list._')
    message += f'\nLink to assessment page <{asses_page}|here>'
    bot.post_message(channel, message)
예제 #25
0
파일: events.py 프로젝트: rachcatch/uqcsbot
 def from_command(cls, command: Command):
     if not command.has_arg():
         return cls(weeks=2)
     else:
         match = re.match(FILTER_REGEX, command.arg)
         if not match:
             return cls(is_valid=False)
         filter_str = match.group(0)
         if filter_str in ['full', 'all']:
             return cls(full=True)
         elif 'week' in filter_str:
             return cls(weeks=int(filter_str.split()[0]))
         else:
             return cls(cap=int(filter_str))
예제 #26
0
def handle_coin(command: Command):
    """
    `!coin [number]` - Flips 1 or more coins.
    """
    if command.has_arg() and command.arg.isnumeric():
        flips = min(max(int(command.arg), 1), 500)
    else:
        flips = 1

    response = []
    emoji = (':heads:', ':tails:')
    for i in range(flips):
        response.append(choice(emoji))

    bot.post_message(command.channel_id, "".join(response))
예제 #27
0
def handle_parking(command: Command) -> None:
    """
    `!parking [all]` - Displays how many car parks are available at UQ St. Lucia
    By default, only dispalys casual parking availability
    """

    if command.has_arg() and command.arg.lower() == "all":
        permit = True
    else:
        permit = False

    # read parking data
    code, data = get_pf_parking_data()
    if code != 200:
        bot.post_message(command.channel_id, "Could Not Retrieve Parking Data")
        return

    response = ["*Available Parks at UQ St. Lucia*"]
    names = {"P1": "P1 - Warehouse (14P Daily)", "P2": "P2 - Space Bank (14P Daily)",
             "P3": "P3 - Multi-Level West (Staff)", "P4": "P4 - Multi-Level East (Staff)",
             "P6": "P6 - Hartley Teakle (14P Hourly)", "P7": "P7 - DustBowl (14P Daily)",
             "P7 UC": "P7 - Keith Street (14P Daily Capped)",
             "P8 L1": "P8 - Athletics Basement (14P Daily)",
             "P8 L2": "P8 - Athletics Roof (14P Daily)", "P9": "P9 - Boatshed (14P Daily)",
             "P10": "P10 - UQ Centre & Playing Fields (14P Daily/14P Daily Capped)",
             "P11 L1": "P11 - Conifer Knoll Lower (Staff)",
             "P11 L2": "P11 - Conifer Knoll Upper (Staff)",
             "P11 L3": "P11 - Conifer Knoll Roof (14P Daily Restricted)"}

    def category(fill):
        if fill.upper() == "FULL":
            return "No"
        if fill.upper() == "NEARLY FULL":
            return "Few"
        return fill

    # find parks
    table = Soup(data, "html.parser").find("table", attrs={"id": "parkingAvailability"})
    rows = table.find_all("tr")[1:]
    # split and join for single space whitespace
    areas = [[" ".join(i.get_text().split()) for i in j.find_all("td")] for j in rows]

    for area in areas:
        if area[2]:
            response.append(f"{category(area[2])} Carparks Available in {names[area[0]]}")
        elif permit and area[1]:
            response.append(f"{category(area[1])} Carparks Available in {names[area[0]]}")
    bot.post_message(command.channel_id, "\n".join(response))
예제 #28
0
def handle_dice(command: Command):
    """
    `!dice [number]` - Rolls 1 or more six sided dice (d6).
    """
    if command.has_arg() and command.arg.isnumeric():
        rolls = min(max(int(command.arg), 1), 360)
    else:
        rolls = 1

    response = []
    emoji = (':dice-one:', ':dice-two:', ':dice-three:', ':dice-four:',
             ':dice-five:', ':dice-six:')
    for i in range(rolls):
        response.append(choice(emoji))

    bot.post_message(command.channel_id, "".join(response))
예제 #29
0
def handle_http(command: Command):
    '''
    `!http <CODE>` - Returns a HTTP cat.
    '''
    if not command.has_arg():
        raise UsageSyntaxException()

    try:
        http_code = int(command.arg.strip())
    except ValueError as e:
        raise UsageSyntaxException()

    if http_code not in AVAILABLE_CODES:
        bot.post_message(command.channel_id, f'HTTP cat {http_code} is not available')
        return

    bot.post_message(command.channel_id, f'https://http.cat/{http_code}')
예제 #30
0
def handle_urban(command: Command) -> None:
    """
    `!urban <PHRASE>` - Looks a phrase up on Urban Dictionary.
    """
    # Check for search phase
    if not command.has_arg():
        bot.post_message(command.channel_id,
                         '> Usage: `!urban <SEARCH_PHRASE>`')
        return
    search_term = command.arg

    # Attempt to get definitions from the Urban Dictionary API.
    http_response = requests.get(URBAN_API_ENDPOINT,
                                 params={'term': search_term})
    if http_response.status_code != 200:
        bot.post_message(command.channel_id,
                         'There was an error accessing the Urban Dictionary.')
        return
    results = http_response.json()

    # If search phrase is not found, notify user.
    if results['result_type'] != 'exact':
        bot.post_message(command.channel_id,
                         f'> No results found for {search_term}. ¯\\_(ツ)_/¯')
        return

    # Get best definition (by most 'thumbs up') and construct response.
    sorted_defs = sorted(results['list'],
                         key=lambda def_: def_['thumbs_up'],
                         reverse=True)
    best_def = sorted_defs[0]
    # Break example into individual lines and wrap each in it's own block quote.
    example = best_def.get('example', '').split('\r\n')
    formatted_example = '\n'.join(f'> {line}' for line in example)

    # Format message and send response to user in channel query was sent from.
    message = f'*{search_term.title()}*\n' \
              f'{best_def["definition"].capitalize()}\n' \
              f'{formatted_example}'
    # Only link back to Urban Dictionary if there are more definitions.
    if len(sorted_defs) > 1:
        endpoint_url = http_response.url.replace(URBAN_API_ENDPOINT,
                                                 URBAN_USER_ENDPOINT)
        message += f'\n_ more definitions at {endpoint_url} _'

    bot.post_message(command.channel_id, message)