Exemplo n.º 1
0
async def late_callback(event: slack_util.Event, match: Match) -> None:
    verb = slack_util.VerboseWrapper(event)

    # Find out who we are trying to sign off is
    signee_name = match.group(1)
    signee = await verb(scroll_util.find_by_name(signee_name, MIN_RATIO))

    # Score by name similarity. Don't care if signed off or not
    def scorer(assign: house_management.JobAssignment):
        if assign.assignee is not None:
            r = fuzz.ratio(signee.name, assign.assignee.name)
            if r > MIN_RATIO:
                return r

    # Just set the assigner
    async def modifier(context: _ModJobContext):
        context.assign.late = not context.assign.late

        # Say we did it
        client.get_slack().reply(
            event, "Toggled lateness of {}.\n"
            "Now marked as late: {}".format(context.assign.job.pretty_fmt(),
                                            context.assign.late))

    # Fire it off
    await _mod_jobs(event, scorer, modifier)
Exemplo n.º 2
0
async def undo_callback(event: slack_util.Event, match: Match) -> None:
    verb = slack_util.VerboseWrapper(event)

    # Find out who we are trying to sign off is
    signee_name = match.group(1)
    signee = await verb(scroll_util.find_by_name(signee_name, MIN_RATIO))

    # Score by name similarity, only accepting jobs that are signed off
    def scorer(assign: house_management.JobAssignment):
        if assign.assignee is not None:
            r = fuzz.ratio(signee.name, assign.assignee.name)
            if assign.signer is not None and r > MIN_RATIO:
                return r

    # Set the assigner to be None, and notify
    async def modifier(context: _ModJobContext):
        context.assign.signer = None

        # Say we did it wooo!
        client.get_slack().reply(
            event,
            "Undid signoff of {} for {}".format(context.assign.assignee.name,
                                                context.assign.job.name))
        await alert_user(
            context.assign.assignee, "{} undid your signoff off for {}.\n"
            "Must have been a mistake".format(context.assign.signer.name,
                                              context.assign.job.pretty_fmt()))

    # Fire it off
    await _mod_jobs(event, scorer, modifier)
Exemplo n.º 3
0
async def count_work_callback(event: slack_util.Event, match: Match) -> None:
    # If no user, continue
    if event.user is None:
        return

    # If bot, continue
    if event.bot is not None:
        return

    # Make an error wrapper
    verb = slack_util.VerboseWrapper(event)

    # Tidy the text
    text = event.message.text.strip().lower()

    # Couple things to work through.
    # One: Who sent the message?
    who_wrote = await verb(event.user.as_user().get_brother())
    who_wrote_label = "{} [{}]".format(who_wrote.name, who_wrote.scroll)

    # Two: What work did they do?
    new_work = {}
    for job in counted_data:
        pattern = lookup_format.format(job)
        match = re.search(pattern, text)
        if match:
            new_work[job] = int(match.group(1))

    # Three: check if we found anything
    if len(new_work) == 0:
        if re.search(r'\s\d\s', text) is not None:
            client.get_slack().reply(
                event,
                "If you were trying to record work, it was not recognized.\n"
                "Use words {} or work will not be recorded".format(
                    counted_data))
        return

    # Four: Knowing they did something, record to total work
    contribution_count = sum(new_work.values())
    new_total = await verb(
        record_towel_contribution(who_wrote, contribution_count))

    # Five, congratulate them on their work!
    congrats = textwrap.dedent("""{} recorded work:
    {}
    Net increase in points: {}
    Total points since last reset: {}""".format(who_wrote_label,
                                                fmt_work_dict(new_work),
                                                contribution_count, new_total))
    client.get_slack().reply(event, congrats)
Exemplo n.º 4
0
async def start_callback(event: slack_util.Event, match: Match) -> None:
    verb = slack_util.VerboseWrapper(event)

    laundry = LaundryRoom()

    machine = match.group(1).strip()
    scroll = match.group(2).strip()
    timeRemaining = match.group(3).strip()

    brother = await verb(scroll_util.find_by_scroll(scroll))
    info = [brother, int(scroll), datetime.datetime.now(), int(timeRemaining)]

    #This cluster is for figuring out which machine they actually want to start
    if machine[0].lower() == "w":
        if machine[1] == "1":
            laundry.start_machine(4, info)
        elif machine[1] == "2":
            laundry.start_machine(5, info)
        else:
            raise Exception("No other washers exist")
    elif machine[0].lower() == "d":
        if machine[1] == "1":
            laundry.start_machine(1, info)
        elif machine[1] == "2":
            laundry.start_machine(2, info)
        elif machine[1] == "3":
            laundry.start_machine(3, info)
        else:
            raise Exception("No other dryers exist")
    else:
        raise Exception("Only washers and dryers exist")

    result = "{} started by {} for {} minutes".format(machine, brother,
                                                      timeRemaining)
    client.get_slack().reply(event, result)
    await asyncio.sleep(timeRemaining * 60)
    msg = "Your laundry is done in machine {}".format(machine)
    #Not sure if this way of getting the user will work
    client.get_slack().send_message(msg, event.user)
Exemplo n.º 5
0
async def reassign_callback(event: slack_util.Event, match: Match) -> None:
    verb = slack_util.VerboseWrapper(event)

    # Find out our two targets
    from_name = match.group(1).strip()
    to_name = match.group(2).strip()

    # Get them as brothers
    from_bro = await verb(scroll_util.find_by_name(from_name, MIN_RATIO))
    to_bro = await verb(scroll_util.find_by_name(to_name, MIN_RATIO))

    # Score by name similarity to the first brother. Don't care if signed off or not,
    # as we want to be able to transfer even after signoffs (why not, amirite?)
    def scorer(assign: house_management.JobAssignment):
        if assign.assignee is not None:
            r = fuzz.ratio(from_bro.name, assign.assignee.name)
            if r > MIN_RATIO:
                return r

    # Change the assignee
    async def modifier(context: _ModJobContext):
        context.assign.assignee = to_bro

        # Say we did it
        reassign_msg = "Job {} reassigned from {} to {}".format(
            context.assign.job.pretty_fmt(), from_bro, to_bro)
        client.get_slack().reply(event, reassign_msg)

        # Tell the people
        reassign_msg = "Job {} reassigned from {} to {}".format(
            context.assign.job.pretty_fmt(), from_bro, to_bro)
        await alert_user(from_bro, reassign_msg)
        await alert_user(to_bro, reassign_msg)

    # Fire it off
    await _mod_jobs(event, scorer, modifier)
Exemplo n.º 6
0
async def _mod_jobs(event: slack_util.Event,
                    relevance_scorer: Callable[
                        [house_management.JobAssignment], Optional[float]],
                    modifier: Callable[[_ModJobContext], Coroutine[Any, Any,
                                                                   None]],
                    no_job_msg: str = None) -> None:
    """
    Stub function that handles various tasks relating to modifying jobs
    :param relevance_scorer: Function scores job assignments on relevance. Determines which gets modified
    :param modifier: Callback function to modify a job. Only called on a successful operation, and only on one job
    """
    # Make an error wrapper
    verb = slack_util.VerboseWrapper(event)

    # Who invoked this command?
    signer = await verb(event.user.as_user().get_brother())

    # Get all of the assignments
    assigns = await verb(house_management.import_assignments())

    # Find closest assignment to what we're after. This just wraps relevance_scorer to handle nones.
    def none_scorer(
            a: Optional[house_management.JobAssignment]) -> Optional[float]:
        if a is None:
            return None
        else:
            return relevance_scorer(a)

    closest_assigns = tiemax(assigns, key=none_scorer)

    # This is what we do on success. It will or won't be called immediately based on what's in closest_assigns
    async def success_callback(
            targ_assign: house_management.JobAssignment) -> None:
        # First get the most up to date version of the jobs
        fresh_assigns = await verb(house_management.import_assignments())

        # Find the one that matches what we had before
        fresh_targ_assign = fresh_assigns[fresh_assigns.index(targ_assign)]

        # Create the context
        context = _ModJobContext(signer, fresh_targ_assign)

        # Modify it
        await modifier(context)

        # Re-upload
        await house_management.export_assignments(fresh_assigns)

        # Also import and update points
        headers, points = await house_management.import_points()
        house_management.apply_house_points(points, fresh_assigns)
        house_management.export_points(headers, points)

    # If there aren't any jobs, say so
    if len(closest_assigns) == 0:
        if no_job_msg is None:
            no_job_msg = "Unable to find any jobs to apply this command to. Try again with better spelling or whatever."
        client.get_slack().reply(event, no_job_msg)

    # If theres only one job, sign it off
    elif len(closest_assigns) == 1:
        await success_callback(closest_assigns[0])

    # If theres multiple jobs, we need to get a follow up!
    else:
        # Say we need more info
        job_list = "\n".join("{}: {}".format(i, a.job.pretty_fmt())
                             for i, a in enumerate(closest_assigns))
        client.get_slack().reply(
            event, "Multiple relevant job listings found.\n"
            "Please enter the number corresponding to the job "
            "you wish to modify:\n{}".format(job_list))

        # Establish a follow up command pattern
        pattern = r"\d+"

        # Make the follow up callback
        async def foc(_event: slack_util.Event, _match: Match) -> None:
            # Get the number out
            index = int(_match.group(0))

            # Check that its valid
            if 0 <= index < len(closest_assigns):
                # We now know what we're trying to sign off!
                await success_callback(closest_assigns[index])
            else:
                # They gave a bad index, or we were unable to find the assignment again.
                client.get_slack().reply(
                    _event, "Invalid job index / job unable to be found.")

        # Make a listener hook
        new_hook = hooks.ReplyWaiter(foc, pattern, event.message.ts, 120)

        # Register it
        client.get_slack().add_hook(new_hook)