Ejemplo n.º 1
0
def message_project_team(request):
    """
    Endpoint for sending arbitrary message to a project team.
    Payload example:
    {'message': 'Chat message', 'project_id': 'some-id-123'}
    """
    data = load_encoded_json(request.body)
    try:
        message = data['message']
        project_id = data['project_id']
        project = Project.objects.get(id=project_id)
    except KeyError:
        text = ('An object with `message` and `project_id` attributes'
                ' should be supplied')
        raise BadRequest(text)
    except Project.DoesNotExist:
        raise BadRequest('No project for given id')
    if project.slack_group_id:
        message_experts_slack_group(project.slack_group_id, message)
    else:
        error_message = (
            "The following project doesn't have slack_group_id: {}"
        ).format(project)
        raise BadRequest(error_message)
    return {'success': True}
Ejemplo n.º 2
0
def _send_request_inquiries(staffbot, request, worker_batch_size,
                            worker_certifications):
    inquiries_sent = 0
    required_role = get_role_from_counter(request.required_role_counter)
    contacted_workers = set()
    for certification in worker_certifications:
        worker = certification.worker
        if worker.id in contacted_workers:
            continue
        contacted_workers.add(worker.id)
        if _is_worker_assignable(worker, request.task, required_role):
            staffbot.send_task_to_worker(worker, request)
            inquiries_sent += 1
        if inquiries_sent >= worker_batch_size:
            break

    # check whether all inquiries have been sent out.
    if inquiries_sent < worker_batch_size:
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('All staffing requests for task {} have been sent!'.format(
                request.task)))
        request.status = StaffBotRequest.Status.DONE_SENDING_INQUIRIES.value
    request.last_inquiry_sent = timezone.now()
    request.save()
Ejemplo n.º 3
0
 def perform_update(self, serializer):
     todo = serializer.save()
     sender = Worker.objects.get(
         user=self.request.user).formatted_slack_username()
     message = '{} has marked `{}` as `{}`.'.format(
         sender, todo.description,
         'complete' if todo.completed else 'incomplete')
     message_experts_slack_group(todo.task.project.slack_group_id, message)
Ejemplo n.º 4
0
def notify_single_todo_update(user, old_todo, todo):
    # To avoid Slack noise, only send updates for changed TODOs with
    # depth 0 (no parent) or 1 (no grandparent).
    sender = _get_sender(user)
    message = get_update_message(old_todo, todo, sender)
    if message and \
            (not (todo.parent_todo and todo.parent_todo.parent_todo)):
        message_experts_slack_group(todo.project.slack_group_id, message)
Ejemplo n.º 5
0
 def perform_create(self, serializer):
     todo = serializer.save()
     sender = Worker.objects.get(
         user=self.request.user).formatted_slack_username()
     recipients = ' & '.join(assignment.worker.formatted_slack_username()
                             for assignment in todo.task.assignments.all()
                             if assignment and assignment.worker)
     message = '{} has created a new todo `{}` for {}.'.format(
         sender, todo.description,
         recipients if recipients else '`{}`'.format(todo.task.step.slug))
     message_experts_slack_group(todo.task.project.slack_group_id, message)
Ejemplo n.º 6
0
def check_responses_complete(request):
    # check all responses have been complete
    responses = StaffingResponse.objects.filter(
        request_inquiry__request=request)
    request_inquiries = StaffingRequestInquiry.objects.filter(request=request)
    if (responses.count() == request_inquiries.count()
            and not responses.filter(is_winner=True).exists()):
        # notify that all workers have rejected a task
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('No worker has accepted to work on task {}'.format(request.task)))
Ejemplo n.º 7
0
def check_responses_complete(request):
    # check all responses have been complete
    responses = StaffingResponse.objects.filter(request__request=request)
    request_inquiries = StaffingRequestInquiry.objects.filter(
        request=request)
    if (responses.count() == request_inquiries.count() and
            not responses.filter(is_winner=True).exists()):
        # notify that all workers have rejected a task
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('No worker has accepted to work on task {}'
             .format(request.task)))
Ejemplo n.º 8
0
def notify_todo_created(todo, user):
    sender = _get_sender(user)
    tasks = (task for task in todo.project.tasks.all()
             if task.step.slug == todo.step.slug)
    recipients = ' & '.join(assignment.worker.formatted_slack_username()
                            for task in tasks
                            for assignment in task.assignments.all()
                            if assignment and assignment.worker)
    if sender:
        message = '{} has created a new todo `{}` for {}.'.format(
            sender, todo.title,
            recipients if recipients else '`{}`'.format(todo.step.slug))
    else:
        message = 'A new todo `{}` was created for {}.'.format(
            todo.title,
            recipients if recipients else '`{}`'.format(todo.step.slug))
    message_experts_slack_group(todo.project.slack_group_id, message)
Ejemplo n.º 9
0
def _handle(project, sanity_check, handler):
    handler_type = handler.get('type')
    handler_message = handler.get('message')
    handler_steps = handler.get('steps')
    if (handler_type != 'slack_project_channel' or
            not handler_message or not handler_steps):
        raise SanityBotError('Invalid handler: {}'.format(handler))
    tasks = (
        task for task in project.tasks.all()
        if task.step.slug in handler_steps)
    usernames = {
        assignment.worker.formatted_slack_username()
        for task in tasks
        for assignment in task.assignments.all()
        if assignment and assignment.worker
    }
    message = '{}: {}'.format(' '.join(usernames), handler_message)
    message_experts_slack_group(
        project.slack_group_id, message)
Ejemplo n.º 10
0
    def staff(self, task_id,
              request_cause=StaffBotRequest.RequestCause.USER.value):
        """
        This function handles staffing a request for the given task_id.
        """
        command = 'staff {}'.format(task_id)
        try:
            task = Task.objects.get(id=task_id)
            required_role_counter = role_counter_required_for_new_task(task)
            error_msg = None
            assert_new_task_status_valid(task.status)
        except TaskStatusError:
            error_msg = self.staffing_is_not_allowed.format(task_id)
        except Task.DoesNotExist:
            error_msg = self.task_does_not_exist_error.format(task_id)
        except TaskAssignmentError as error:
            error_msg = self.task_assignment_error.format(task_id, error)

        if error_msg is not None:
            logger.exception(error_msg)
            return format_slack_message(
                command,
                attachments=[{
                    'color': 'danger',
                    'title': 'Error',
                    'text': error_msg
                }])

        StaffBotRequest.objects.create(
            task=task,
            required_role_counter=required_role_counter,
            request_cause=request_cause)

        slack_message = self.staffing_success.format(task_id)
        message_experts_slack_group(task.project.slack_group_id, slack_message)
        return format_slack_message(
            command,
            attachments=[{
                'color': 'good',
                'title': 'Success',
                'text': slack_message
            }])
Ejemplo n.º 11
0
    def staff(self, task_id,
              request_cause=StaffBotRequest.RequestCause.USER.value):
        """
        This function handles staffing a request for the given task_id.
        """
        command = 'staff {}'.format(task_id)
        try:
            task = Task.objects.get(id=task_id)
            required_role_counter = role_counter_required_for_new_task(task)
            error_msg = None
            assert_new_task_status_valid(task.status)
        except TaskStatusError:
            error_msg = self.staffing_is_not_allowed.format(task_id)
        except Task.DoesNotExist:
            error_msg = self.task_does_not_exist_error.format(task_id)
        except TaskAssignmentError as error:
            error_msg = self.task_assignment_error.format(task_id, error)

        if error_msg is not None:
            logger.exception(error_msg)
            return format_slack_message(
                command,
                attachments=[{
                    'color': 'danger',
                    'title': 'Error',
                    'text': error_msg
                }])

        StaffBotRequest.objects.create(
            task=task,
            required_role_counter=required_role_counter,
            request_cause=request_cause)

        slack_message = self.staffing_success.format(task_id)
        message_experts_slack_group(task.project.slack_group_id, slack_message)
        return format_slack_message(
            command,
            attachments=[{
                'color': 'good',
                'title': 'Success',
                'text': slack_message
            }])
Ejemplo n.º 12
0
def send_request_inquiries(staffbot, request, worker_batch_size):
    # Get Workers that haven't already received an inquiry.
    workers_with_inquiries = (StaffingRequestInquiry.objects.filter(
        request=request).distinct().values_list(
            'communication_preference__worker__id', flat=True))
    # Sort Workers by their staffing priority first, and then randomly
    # within competing staffing priorities.
    workers = (Worker.objects.exclude(id__in=workers_with_inquiries).order_by(
        '-staffing_priority', '?'))
    required_role = get_role_from_counter(request.required_role_counter)
    inquiries_sent = 0

    for worker in workers:
        try:
            check_worker_allowed_new_assignment(worker)
            if (is_worker_certified_for_task(worker,
                                             request.task,
                                             required_role,
                                             require_staffbot_enabled=True)
                    and not request.task.is_worker_assigned(worker)):
                staffbot.send_task_to_worker(worker, request)
                inquiries_sent += 1
            if inquiries_sent >= worker_batch_size:
                break

        except TaskStatusError:
            pass
        except TaskAssignmentError:
            pass

    # check whether all inquiries have been sent out.
    if inquiries_sent < worker_batch_size:
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('All staffing requests for task {} have been sent!'.format(
                request.task)))
        request.status = StaffBotRequest.Status.COMPLETE.value
    request.last_inquiry_sent = timezone.now()
    request.save()
Ejemplo n.º 13
0
def send_request_inquiries(staffbot, request, worker_batch_size):
    # Get Workers that haven't already received an inquiry.
    workers_with_inquiries = (StaffingRequestInquiry.objects.filter(
        request=request).distinct().values_list(
            'communication_preference__worker__id', flat=True))
    # Sort Workers by their staffing priority first, and then randomly
    # within competing staffing priorities.
    workers = (Worker.objects
               .exclude(id__in=workers_with_inquiries)
               .order_by('-staffing_priority', '?'))
    required_role = get_role_from_counter(request.required_role_counter)
    inquiries_sent = 0

    for worker in workers:
        try:
            check_worker_allowed_new_assignment(worker)
            if (is_worker_certified_for_task(worker, request.task,
                                             required_role,
                                             require_staffbot_enabled=True) and
                    not request.task.is_worker_assigned(worker)):
                staffbot.send_task_to_worker(worker, request)
                inquiries_sent += 1
            if inquiries_sent >= worker_batch_size:
                break

        except TaskStatusError:
            pass
        except TaskAssignmentError:
            pass

    # check whether all inquiries have been sent out.
    if inquiries_sent < worker_batch_size:
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('All staffing requests for task {} have been sent!'
             .format(request.task)))
        request.status = StaffBotRequest.Status.COMPLETE.value
    request.last_inquiry_sent = timezone.now()
    request.save()
Ejemplo n.º 14
0
def _send_request_inquiries(staffbot, request, worker_batch_size,
                            worker_certifications):
    inquiries_sent = 0
    required_role = get_role_from_counter(request.required_role_counter)
    contacted_workers = set()

    for certification in worker_certifications:
        try:
            worker = certification.worker
            if worker.id in contacted_workers:
                continue

            contacted_workers.add(worker.id)
            check_worker_allowed_new_assignment(worker)
            if (is_worker_certified_for_task(worker,
                                             request.task,
                                             required_role,
                                             require_staffbot_enabled=True)
                    and not request.task.is_worker_assigned(worker)):
                staffbot.send_task_to_worker(worker, request)
                inquiries_sent += 1
            if inquiries_sent >= worker_batch_size:
                break

        except TaskStatusError:
            pass
        except TaskAssignmentError:
            pass

    # check whether all inquiries have been sent out.
    if inquiries_sent < worker_batch_size:
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('All staffing requests for task {} have been sent!'.format(
                request.task)))
        request.status = StaffBotRequest.Status.DONE_SENDING_INQUIRIES.value
    request.last_inquiry_sent = timezone.now()
    request.save()
Ejemplo n.º 15
0
def check_responses_complete(request):
    inquiries = (StaffingRequestInquiry.objects.filter(
        request=request)).distinct()
    num_inquired_workers = len(
        set(
            inquiries.values_list('communication_preference__worker__id',
                                  flat=True)))
    responded_inquiries = inquiries.filter(responses__isnull=False).distinct()
    num_responded_workers = len(
        set(
            responded_inquiries.values_list(
                'communication_preference__worker__id', flat=True)))

    responses = StaffingResponse.objects.filter(
        request_inquiry__request=request)
    if (num_responded_workers >= num_inquired_workers
            and not responses.filter(is_winner=True).exists()):
        request.status = StaffBotRequest.Status.CLOSED.value
        request.save()

        # notify that all workers have rejected a task
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('No worker has accepted to work on task {}'.format(request.task)))
Ejemplo n.º 16
0
def send_request_inquiries(staffbot, request, worker_batch_size):

    # get names of workers that that already received inquiry
    worker_usernames = (StaffingRequestInquiry.objects.filter(
        request=request).values_list(
            'communication_preference__worker__user__username', flat=True))
    workers = (Worker.objects
               .exclude(user__username__in=worker_usernames)
               .order_by('?'))
    required_role = get_role_from_counter(request.required_role_counter)
    inquiries_sent = 0

    for worker in workers:
        try:
            check_worker_allowed_new_assignment(worker)
            if (is_worker_certified_for_task(worker, request.task,
                                             required_role) and
                    not request.task.is_worker_assigned(worker)):
                staffbot.send_task_to_worker(worker, request)
                inquiries_sent += 1
            if inquiries_sent >= worker_batch_size:
                break

        except TaskStatusError:
            pass
        except TaskAssignmentError:
            pass

    # check whether all inquiries have been sent out.
    if inquiries_sent < worker_batch_size:
        message_experts_slack_group(
            request.task.project.slack_group_id,
            ('All staffing requests for task {} have been sent!'
             .format(request.task)))
        request.status = StaffBotRequest.Status.COMPLETE.value
        request.save()
Ejemplo n.º 17
0
    def perform_update(self, serializer):
        old_todo = self.get_object()
        todo = serializer.save()
        sender = Worker.objects.get(
            user=self.request.user).formatted_slack_username()

        if old_todo.completed != todo.completed:
            todo_change = 'complete' if todo.completed else 'incomplete'
        elif old_todo.skipped_datetime != todo.skipped_datetime:
            todo_change = 'not relevant' \
                if todo.skipped_datetime else 'relevant'
        else:
            # When activity_log is updated, `todo_change = None`
            # to avoid triggering any slack messages
            todo_change = None

        # To avoid Slack noise, only send updates for changed TODOs with
        # depth 0 (no parent) or 1 (no grantparent).
        if todo_change and \
                (not (todo.parent_todo and todo.parent_todo.parent_todo)):
            message = '{} has marked `{}` as `{}`.'.format(
                sender, todo.description, todo_change)
            message_experts_slack_group(todo.task.project.slack_group_id,
                                        message)
Ejemplo n.º 18
0
    def restaff(self, task_id, username,
                request_cause=StaffBotRequest.RequestCause.USER.value):
        """
        This function handles restaffing a request for the given task_id.
        The current user for the given username is removed, and a new user
        is found.
        """
        command = 'restaff {} {}'.format(task_id, username)
        try:
            error_msg = None

            worker = Worker.objects.filter(
                Q(user__username=username) | Q(slack_username=username))

            if worker.exists():
                worker = worker.first()
            else:
                error_msg = self.worker_does_not_exist.format(username)
                return format_slack_message(
                    command,
                    attachments=[{
                        'color': 'danger',
                        'title': 'Error',
                        'text': error_msg
                    }])
            task = Task.objects.get(id=task_id)
            task_assignment = TaskAssignment.objects.get(worker=worker,
                                                         task=task)
            required_role_counter = task_assignment.assignment_counter

        except Task.DoesNotExist:
            error_msg = self.task_does_not_exist_error.format(task_id)
        except TaskAssignment.DoesNotExist:
            error_msg = (self.task_assignment_does_not_exist_error
                         .format(username, task_id))
        except TaskAssignmentError as error:
            error_msg = self.task_assignment_error.format(task_id, error)

        if error_msg is not None:
            logger.exception(error_msg)
            return format_slack_message(
                command,
                attachments=[{
                    'color': 'danger',
                    'title': 'Error',
                    'text': error_msg
                }])

        StaffBotRequest.objects.create(
            task=task,
            required_role_counter=required_role_counter,
            request_cause=request_cause)
        slack_message = self.restaffing_success.format(task_id)

        message_experts_slack_group(task.project.slack_group_id, slack_message)
        return format_slack_message(
            command,
            attachments=[{
                'color': 'good',
                'title': 'Success',
                'text': slack_message
            }])
Ejemplo n.º 19
0
    def restaff(self, task_id, username,
                request_cause=StaffBotRequest.RequestCause.USER.value):
        """
        This function handles restaffing a request for the given task_id.
        The current user for the given username is removed, and a new user
        is found.
        """
        command = 'restaff {} {}'.format(task_id, username)
        try:
            error_msg = None

            worker = Worker.objects.filter(
                Q(user__username=username) | Q(slack_username=username))

            if worker.exists():
                worker = worker.first()
            else:
                error_msg = self.worker_does_not_exist.format(username)
                return format_slack_message(
                    command,
                    attachments=[{
                        'color': 'danger',
                        'title': 'Error',
                        'text': error_msg
                    }])
            task = Task.objects.get(id=task_id)
            task_assignment = TaskAssignment.objects.get(worker=worker,
                                                         task=task)
            required_role_counter = task_assignment.assignment_counter

        except Task.DoesNotExist:
            error_msg = self.task_does_not_exist_error.format(task_id)
        except TaskAssignment.DoesNotExist:
            error_msg = (self.task_assignment_does_not_exist_error
                         .format(username, task_id))
        except TaskAssignmentError as error:
            error_msg = self.task_assignment_error.format(task_id, error)

        if error_msg is not None:
            logger.exception(error_msg)
            return format_slack_message(
                command,
                attachments=[{
                    'color': 'danger',
                    'title': 'Error',
                    'text': error_msg
                }])

        StaffBotRequest.objects.create(
            task=task,
            required_role_counter=required_role_counter,
            request_cause=request_cause)
        slack_message = self.restaffing_success.format(task_id)

        message_experts_slack_group(task.project.slack_group_id, slack_message)
        return format_slack_message(
            command,
            attachments=[{
                'color': 'good',
                'title': 'Success',
                'text': slack_message
            }])