示例#1
0
def handle_reply(evt: dict):
    """
    Handles a message event. Whenever a message is a reply to one of !wolframs conversational
    results this handles getting the next response and updating the old stored information.
    """
    # If the message isn't from a thread or is from a bot ignore it (avoid those infinite loops)
    if 'thread_ts' not in evt or evt.get('subtype') == 'bot_message':
        return

    channel = evt['channel']
    thread_ts = evt['thread_ts']  # This refers to time the original message
    thread_parent = bot.api.conversations.history(channel=channel,
                                                  limit=1,
                                                  inclusive=True,
                                                  latest=thread_ts)

    if not thread_parent['ok']:
        # The most likely reason for this error is auth issues or possibly rate limiting
        bot.logger.error(
            f'Error with wolfram script thread history: {thread_parent}')
        return

    # Limit=1 was used so the first (and only) message is what we want
    parent_message = thread_parent['messages'][0]
    # If the threads parent wasn't by a bot ignore it
    if parent_message.get('subtype') != 'bot_message':
        return

    # Finally, we have to check that this is a Wolfram replyable message
    # It is rare we would reach this point and not pass as who
    # replies to a bot in a thread for another reason?
    parent_attachment = parent_message['attachments'][
        0]  # Only one attachment to get
    parent_fallback = parent_attachment['fallback']
    if 'WolframCanReply' not in parent_fallback:
        return

    # Now we can grab the conversation_id from the message
    # and get the new question (s only sometimes appears).
    # Recall the format of the fallback "identifier hostname s_output conversationID"
    _, reply_host, s_output, conversation_id = parent_fallback.split(' ')
    new_question = evt[
        'text']  # This is the value of the message that triggered the response
    s_output = '' if s_output is None else s_output

    # Ask Wolfram for the new answer grab the new stuff and post the reply.
    reply, conversation_id, reply_host, s_output = conversation_request(
        new_question, reply_host, conversation_id, s_output)

    bot.post_message(channel, reply, thread_ts=thread_ts)

    # If getting a the conversation request results in an error then conversation_id will be None
    if conversation_id is not None:
        # Update the old fallback to reflect the new state of the conversation
        parent_attachment[
            'fallback'] = f'WolframCanReply {reply_host} {s_output} {conversation_id}'

        bot.api.chat.update(channel=channel,
                            attachments=[parent_attachment],
                            ts=thread_ts)
示例#2
0
def handle_conduct(command: Command):
    """
    `!conduct` - Returns the url for the uqcs code of conduct.
    """
    bot.post_message(
        command.channel_id, "UQ Computing Society Code of Conduct\n"
        "https://github.com/UQComputingSociety/code-of-conduct")
示例#3
0
def job_response(evt: dict):
    """
    Messages users that have posted in #jobs-bulletin to remind them of the rules.

    @no_help
    """
    chan = bot.channels.get(evt.get("channel"))

    if chan.name != "jobs-bulletin":
        return

    if evt.get("subtype") in ["channel_join", "channel_leave"]:
        return

    jobs_bulletin = chan
    jobs_discussion = bot.channels.get("jobs-discussion")
    user = bot.users.get(evt.get("user"))

    if user is None or user.is_bot:
        return

    bot.post_message(jobs_bulletin, f"{user.display_name} has posted a new job in <#{jobs_bulletin.id}>! "
                                    f":tada: \nPlease ask any questions in <#{jobs_discussion.id}> or in a private "
                                    f"message to <@{user.user_id}>")

    bot.post_message(user.user_id, f"Hey {user.display_name}, you've just posted in <#{jobs_bulletin.id}>! "
                                   f"Just a quick reminder of the conditions surrounding the use of this channel:\n" +
                                   f"\n".join(WELCOME_MESSAGES[1:]) +
                                   f"\n *Broken one of these rules?*\n It's not too late! Please go back ASAP and edit"
                                   f" your message in <#{jobs_bulletin.id}> so it complies (or ask a committee member"
                                   f" to delete it). Thanks!")
示例#4
0
def emoji_log(evt: dict):
    """
    Notes when emojis are added or deleted.

    @no_help
    """
    emoji_request = bot.channels.get("emoji-request")
    subtype = evt.get("subtype")

    if subtype == 'add':
        name = evt["name"]
        value = evt["value"]

        if value.startswith('alias:'):
            _, alias = value.split('alias:')

            bot.post_message(
                emoji_request,
                f'Emoji alias added: `:{name}:` :arrow_right: `:{alias}:` (:{name}:)'
            )

        else:
            message = bot.post_message(emoji_request,
                                       f'Emoji added: :{name}: (`:{name}:`)')
            bot.api.reactions.add(channel=message["channel"],
                                  timestamp=message["ts"],
                                  name=name)

    elif subtype == 'remove':
        names = evt.get("names")
        removed = ', '.join(f'`:{name}:`' for name in names)
        plural = 's' if len(names) > 1 else ''

        bot.post_message(emoji_request, f'Emoji{plural} removed: {removed}')
示例#5
0
def handle_radar(command: Command):
    '''
    `!radar` - Returns the latest BOM radar image for Brisbane.
    '''
    time_in_s = int(time())
    radar_url = f'https://bom.lambda.tools/?location=brisbane&timestamp={time_in_s}'
    bot.post_message(command.channel_id, radar_url)
示例#6
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)
示例#7
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)
示例#8
0
文件: mock.py 项目: rachcatch/uqcsbot
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)

    bot.post_message(command.channel_id, response)
示例#9
0
def handle_pokemash(command: Command):
    """
    `!pokemash pokemon pokemon` - Returns the pokemash of the two Pokemon.
    Can use Pokemon names or Pokedex numbers (first gen only)
    """
    cmd = command.arg.lower()
    # checks for exactly two pokemon
    # mr. mime is the only pokemon with a space in it's name
    if not cmd or (cmd.count(" ") - cmd.count("mr. mime")) != 1:
        bot.post_message(command.channel_id, "Incorrect Number of Pokemon")
        return

    # two pokemon split
    arg_left, arg_right = match(r"(mr\. mime|\S+) (mr\. mime|\S+)",
                                cmd).group(1, 2)

    num_left = lookup(command, arg_left)
    num_right = lookup(command, arg_right)
    if num_left is None or num_right is None:
        return

    bot.post_message(
        command.channel_id, f"_{PREFIX[num_left]+SUFFIX[num_right]}_\n"
        f"https://images.alexonsager.net/pokemon/fused/" +
        f"{num_right}/{num_right}.{num_left}.png")
示例#10
0
def daily_weather() -> None:
    """
    Posts today's Brisbane weather at 6:00am every day
    """

    (state, location, future) = ("QLD", "Brisbane", 0)

    root = get_xml(state)
    if root is None:
        return

    node, find_response = find_location(root, location, future)
    if node is None:
        return

    # get responses
    response = []
    brisbane_detailed, brisbane_fire, brisbane_uv = response_brisbane_detailed()
    response.append(response_header(node, location))
    response.append(response_overall(node))
    response.append(brisbane_detailed)
    response.append(response_temperature(node))
    response.append(brisbane_fire)
    response.append(brisbane_uv)
    # post
    general = bot.channels.get("general")
    bot.post_message(general.id, "\n".join([r for r in response if r]))
示例#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
def daily_history() -> None:
    """
    Selets a random pin that was posted on this date some years ago,
    and reposts it in the same channel
    """
    anniversary = []
    today = datetime.now(utc).astimezone(timezone('Australia/Brisbane')).date()

    # for every channel
    for channel in bot.api.conversations.list(types="public_channel")['channels']:
        # skip archived channels
        if channel['is_archived']:
            continue

        for pin in bot.api.pins.list(channel=channel['id'])['items']:
            # messily get the date the pin was originally posted
            pin_date = (datetime.fromtimestamp(int(float(pin['message']['ts'])), tz=utc)
                        .astimezone(timezone('Australia/Brisbane')).date())
            # if same date as today
            if pin_date.month == today.month and pin_date.day == today.day:
                # add pin to possibilities
                anniversary.append(Pin(channel=channel['name'], years=today.year-pin_date.year,
                                       user=pin['message']['user'], text=pin['message']['text']))

    # if no pins were posted on this date, do nothing
    if not anniversary:
        return

    # randomly select a pin, and post it in the original channel
    selected = choice(anniversary)
    bot.post_message(selected.origin(), selected.message())
示例#13
0
def get_user(channel: Channel, username: str) -> Optional[UserResult]:
    """
    Gets a UserResult by querying the crates.io api for the given username.
    None on error.
    """
    url = f'{BASE_URL}/users/{username}'
    response = requests.get(url)

    if response.status_code != requests.codes.ok:
        bot.post_message(channel, 'There was a problem getting the user')
        return None

    raw_user = json.loads(response.content).get('user')

    if raw_user is None or 'errors' in raw_user:
        bot.post_message(channel, f'User "{username}" not found')
        return None

    user_id = raw_user.get('id', -1)
    login = raw_user.get('login', username)
    name = raw_user.get('name', username)
    avatar = raw_user.get(
        'avatar', 'https://imgur.com/gwtcGmr')  # Blank avatar as a default
    url = raw_user.get('url', '')

    return UserResult(user_id, login, name, avatar, url)
示例#14
0
def daily_trivia():
    """Adds a job that displays a random question to the specified channel at lunch time"""
    channel = bot.channels.get(CRON_CHANNEL).id

    # Get arguments and update the seconds
    args = parse_arguments(channel, CRON_ARGUMENTS)
    args.seconds = CRON_SECONDS

    # Get and post the actual question
    handle_question(channel, args)

    # Format a nice message to tell when the answer will be
    hours = CRON_SECONDS // 3600
    minutes = (CRON_SECONDS - (hours * 3600)) // 60
    if minutes > 55:
        hours += 1
        minutes = 0

    time_until_answer = 'Answer in '
    if hours > 0:
        time_until_answer += f'{hours} hours'
    if minutes > 0:
        time_until_answer += f' and {minutes} minutes' if hours > 0 else f'{minutes} minutes'

    bot.post_message(channel, time_until_answer)
示例#15
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():
        raise UsageSyntaxException()

    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}")
示例#16
0
def display_all_categories(channel: Channel, args: CategorySearch):
    """
    Displays just the names of all the categories in one big list
    """
    categories, total = get_category_page(channel, args.sort, 1)
    if categories is None:
        return  # Error occurred

    # Get all of the categories by incrementing page number
    page = 2
    while len(categories) < total:
        next_cats, _ = get_category_page(channel, args.sort, page)
        if next_cats is None or not next_cats:
            break

        categories.extend(next_cats)
        page += 1

    # Begin formatting the message
    category_string = '\n'.join(categories)
    blocks = [
        create_slack_section_block(
            TextBlock(f'*Displaying {total} categories:*')),
        create_slack_section_block(TextBlock(f'```{category_string}```')),
    ]

    bot.post_message(channel, '', blocks=blocks)
示例#17
0
def new_xkcd() -> None:
    """
    Posts new xkcd comic when they are released every Monday, Wednesday
    & Friday at 4AM UTC or 2PM Brisbane time.

    @no_help
    """
    link = get_latest()

    day = datetime.datetime.today().weekday()
    if (day == 0):  #Monday
        message = "It's Monday, 4 days till Friday; here's the "
    elif (day == 2):  #Wednesday
        message = "Half way through the week, time for the "
    elif (day == 4):  #Friday
        message = ":musical_note: It's Friday, Friday\nGotta get down on Friday\nEverybody's lookin' forward to the "
    else:
        message = "@pah It is day " + str(
            day) + ", please fix me... Here's the "
    message = message + "latest xkcd comic "

    general = bot.channels.get("general")
    bot.post_message(general.id,
                     message + link,
                     unfurl_links=True,
                     unfurl_media=True)
示例#18
0
def job_response(evt: dict):
    """
    Messages users that have posted in #jobs-bulletin to remind them of the rules.

    @no_help
    """
    channel = bot.channels.get(evt.get("channel"))

    if channel.name != "jobs-bulletin":
        return

    if evt.get("subtype") in ["channel_join", "channel_leave"]:
        return

    jobs_bulletin = channel

    user = bot.users.get(evt.get("user"))

    if user is None or user.is_bot:
        return

    channel_message = (f"{user.name} has posted a new job in #jobs-bulletin! :tada: \n"
                       f"Please ask any questions in #jobs-discussion"
                       + f" or in a private message to <@{user.user_id}>")
    bot.post_message(jobs_bulletin, insert_channel_links(channel_message))

    user_message = (f"Hey {user.name}, you've just posted in #jobs-bulletin! \n"
                    f"Just a quick reminder of the conditions"
                    + f" surrounding the use of this channel:\n" +
                    f"\n".join(WELCOME_MESSAGES[1:] + [""]) +
                    f"*Broken one of these rules?*\n"
                    f"It's not too late! Please go back ASAP and"
                    + f" edit your message in #jobs-bulletin so it complies (or ask a committee"
                    + f" member to delete it). Thanks!")
    bot.post_message(user.user_id, insert_channel_links(user_message))
示例#19
0
def handle_weather(command: Command) -> None:
    """
    `!weather [[state] location] [day]` - Returns the weather forecast for a location
    `day` is how many days into the future the forecast is for (0 is today and default)
    `location` defaults to Brisbane, and `state` defaults to QLD
    """

    (state, location, future) = process_arguments(command.arg)

    root = get_xml(state)
    if root is None:
        failure_respone = bot.post_message(command.channel_id, "Could Not Retrieve BOM Data")
        bot.api.reactions.add(channel=failure_respone["channel"],
                              timestamp=failure_respone["ts"], name="disapproval")
        return

    node, find_response = find_location(root, location, future)
    if node is None:
        bot.post_message(command.channel_id, find_response)
        return

    # get responses
    response = []
    response.append(response_header(node, location))
    response.append(response_overall(node))
    response.append(response_temperature(node))
    response.append(response_precipitation(node))
    # post
    bot.post_message(command.channel_id, "\n".join([r for r in response if r]))
示例#20
0
def handle_dog(command: Command):
    """
    `!dog` - Like !cat, but for dog people.
    """
    dog = "\n".join(
        ("```", "                          _         ",
         "                       ,:'/   _..._ ", "                      // ( `"
         "-.._.'", "                      \\| /    O\\___",
         "                      |    O       4",
         "                      |            /",
         "                      \\_       .--' ",
         "                      (_'---'`)     ",
         "                      / `'---`()    ",
         "                    ,'        |     ",
         "    ,            .'`          |     ",
         "    )\\       _.-'             ;     ",
         "   / |    .'`   _            /      ",
         " /` /   .'       '.        , |      ",
         "/  /   /           \\   ;   | |      ",
         "|  \\  |            |  .|   | |      ",
         " \\  `\"|           /.-' |   | |      ",
         "  '-..-\\       _.;.._  |   |.;-.    ",
         "        \\    <`.._  )) |  .;-. ))   ",
         "        (__.  `  ))-'  \\_    ))'    ",
         "            `'--\"`  jgs  `\"\"\"`      ```"))

    bot.post_message(command.channel_id, dog)
示例#21
0
def handle_exact_crate_route(channel: Channel, args: ExactCrate):
    """Handles what happens when a single crate is being searched for by exact name"""
    crate = get_crate_name_result(channel, args.name)
    if crate is None:
        return

    bot.post_message(channel, '', blocks=get_crate_blocks(crate))
示例#22
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`")
示例#23
0
def handle_caesar(message: dict):
    '''
    `!caesar[N] <TEXT>` - Performs caesar shift with a left shift of N on given
    text. If unspecified, will shift by 47.
    '''
    text = message.get("text")
    if message.get("subtype") == "bot_message" or text is None:
        return
    m = CAESAR_REGEX.match(text)
    if not m:
        return
    n, msg = m.groups()
    shift = 47 if n == "" else int(n)
    result = ""
    for c in msg:
        # 32 (SPACE) to 126 (~)
        # Get ascii code - 32. This makes SPACE the equivalent of 0
        # + n. Add caesar shift
        # mod 94 (from 126-32=94). This prevents overflow
        # + 32. Changes back (so SPACE is back to 32 instead of 0)
        char_code = ord(c) - 32 + shift
        char_code = ((char_code % 94) + 94) % 94
        char_code += 32
        result += chr(char_code)
    bot.post_message(message['channel'], result)
示例#24
0
def get_category_page(channel: Channel, sort: str,
                      page: int) -> Tuple[Optional[List[str]], int]:
    """
    Returns all the names of all categories from a page of the response
    :param channel: The channel to post any errors to
    :param sort: The order to sort by. One of "crates" or "alpha"
    :param page: The page number to get the categories from
    :return: A tuple containing a list of category names (or None on error)
        and the total number of categories
    """
    # Get the categories
    url = BASE_URL + '/categories'
    response = requests.get(url, {'sort': sort, 'page': page})  # type: ignore

    if response.status_code != requests.codes.ok:
        bot.post_message(channel,
                         'There was a problem getting the list of categories')
        return None, 0

    # Convert the json response
    response_data = json.loads(response.content)

    raw_categories = response_data.get('categories')
    total = response_data.get('meta', {}).get('total', 0)

    # Get the category names
    categories = [
        cat.get('name') if 'name' in cat else cat.get('id', '')
        for cat in raw_categories
    ]

    return categories, total
示例#25
0
def send_meme_names(command: Command):
    """
    Sends the full list of meme names to the users channel to avoid channel spam
    """
    user_channel = bot.channels.get(command.user_id)
    names_text = "\n".join((f"{full_name}: {name}" for (name, full_name) in MEME_NAMES.items()))
    attachments = [{'text': names_text, 'title': "Meme Names:"}]
    bot.post_message(user_channel, "", attachments=attachments)
示例#26
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())
示例#27
0
def yelling(event: dict):
    """
    Responds to people talking quietly in #yelling
    """

    # ensure in #yelling channel
    channel = event.get("channel")
    if not in_yelling(channel):
        return

    # ensure message proper
    if "subtype" in event and event.get("subtype") != "thread_broadcast":
        return

    # ensure user proper
    user = bot.users.get(event.get("user"))
    if not is_human(user):
        return

    # ignore emoji
    text = sub(r":[\w\-\+\_']+:",
               lambda m: m.group(0).upper(),
               event['text'],
               flags=UNICODE)
    text = text.replace("&gt;", ">").replace("&lt;", "<").replace("&amp;", "&")
    # randomly select a response
    response = choice(
        [
            "WHAT’S THAT‽", "SPEAK UP!", "STOP WHISPERING!",
            "I CAN’T HEAR YOU!", "I THOUGHT I HEARD SOMETHING!",
            "I CAN’T UNDERSTAND YOU WHEN YOU MUMBLE!",
            "YOU’RE GONNA NEED TO BE LOUDER!", "WHY ARE YOU SO QUIET‽",
            "QUIET PEOPLE SHOULD BE DRAGGED OUT INTO THE STREET AND SHOT!",
            "PLEASE USE YOUR OUTSIDE VOICE!",
            "IT’S ON THE LEFT OF THE “A” KEY!",
            "FORMER PRESIDENT THEODORE ROOSEVELT’S FOREIGN POLICY IS A SHAM!",
            "#YELLING IS FOR EXTERNAL SCREAMING!" +
            " (FOR INTERNAL SCREAMING, VISIT #CRIPPLINGDEPRESSION!)",
            ":disapproval:", ":oldmanyellsatcloud:",
            f"DID YOU SAY \n>>>{mutate_minuscule(text)}".upper(),
            f"WHAT IS THE MEANING OF THIS ARCANE SYMBOL “{random_minuscule(text)}”‽"
            + " I RECOGNISE IT NOT!"
        ]
        # the following is a reference to both "The Wicker Man" and "Nethack"
        + (['OH, NO! NOT THE `a`S! NOT THE `a`S! AAAAAHHHHH!'] if 'a' in
           text else []))

    # check if minuscule in message, and if so, post response
    if any(c.islower() for c in text):
        if event.get("subtype") == "thread_broadcast":
            bot.post_message(channel,
                             response,
                             reply_broadcast=True,
                             thread_ts=event.get("thread_ts"))
        else:
            bot.post_message(channel,
                             response,
                             thread_ts=event.get("thread_ts"))
示例#28
0
def handle_cat(command: Command):
    cat = "```\n" + \
          "         __..--''``\\--....___   _..,_\n" + \
          "     _.-'    .-/\";  `        ``<._  ``-+'~=.\n" + \
          " _.-' _..--.'_    \\                    `(^) )\n" + \
          "((..-'    (< _     ;_..__               ; `'   fL\n" + \
          "           `-._,_)'      ``--...____..-'\n```"

    bot.post_message(command.channel, cat)
示例#29
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))
示例#30
0
def channel_log(evt: dict):
    """
    Notes when channels are created in #uqcs-meta

    @no_help
    """
    bot.post_message(
        bot.channels.get("uqcs-meta"), 'New Channel Created: ' +
        f'<#{evt.get("channel").get("id")}|{evt.get("channel").get("name")}>')