예제 #1
0
def notify_new_task_application_slack(instance):
    instance = clean_instance(instance, Application)

    if not slack_utils.is_task_notification_enabled(instance.task,
                                                    slugs.EVENT_APPLICATION):
        return

    application_url = '%s/work/%s/applications/' % (TUNGA_URL,
                                                    instance.task_id)
    slack_msg = "New application from %s" % instance.user.short_name
    attachments = [{
        slack_utils.KEY_TITLE:
        instance.task.summary,
        slack_utils.KEY_TITLE_LINK:
        application_url,
        slack_utils.KEY_TEXT:
        '%s%s%s%s\n\n<%s|View details on Tunga>' %
        (truncatewords(convert_to_text(instance.pitch),
                       100), instance.hours_needed
         and '\n*Workload:* {} hrs'.format(instance.hours_needed)
         or '', instance.deliver_at and '\n*Delivery Date:* {}'.format(
             instance.deliver_at.strftime("%d %b, %Y at %H:%M GMT"))
         or '', instance.remarks and '\n*Remarks:* {}'.format(
             truncatewords(convert_to_text(instance.remarks), 100))
         or '', application_url),
        slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
        slack_utils.KEY_COLOR:
        SLACK_ATTACHMENT_COLOR_TUNGA
    }]
    slack_utils.send_integration_message(instance.task,
                                         message=slack_msg,
                                         attachments=attachments)
예제 #2
0
def render_mail(subject,
                template_prefix,
                to_emails,
                context,
                bcc=None,
                cc=None,
                **kwargs):
    """
    :param subject:
    :param template_prefix: path to template for email with extension (e.g hello if template name is hello.html)
    :param to_emails:
    :param context: variables to be passed into template
    :param bcc:
    :param cc:
    :param kwargs:
    :return:
    """
    from_email = DEFAULT_FROM_EMAIL
    if not re.match(r'^\[\s*Tunga', subject):
        subject = '{} {}'.format(EMAIL_SUBJECT_PREFIX, subject)

    bodies = {}
    for ext in ['html', 'txt']:
        try:
            template_name = '{0}.{1}'.format(template_prefix, ext)
            bodies[ext] = render_to_string(template_name, context).strip()
        except TemplateDoesNotExist:
            if ext == 'txt':
                if 'html' in bodies:
                    # Compose text body from html
                    bodies[ext] = convert_to_text(bodies['html'])
                else:
                    # We need at least one body
                    raise

    if bodies:
        msg = EmailMultiAlternatives(subject,
                                     bodies['txt'],
                                     from_email,
                                     to_emails,
                                     bcc=bcc,
                                     cc=cc)
        if 'html' in bodies:
            try:
                html_body = render_to_string(
                    'tunga/email/base.html',
                    dict(email_content=bodies['html'])).strip()
            except TemplateDoesNotExist:
                html_body = bodies['html']
            msg.attach_alternative(premailer.transform(html_body), 'text/html')
    else:
        raise TemplateDoesNotExist
    return msg
예제 #3
0
def notify_task_application_response_slack(instance, admin=True):
    instance = clean_instance(instance, Application)

    application_url = '%s/work/%s/applications/' % (TUNGA_URL,
                                                    instance.task_id)
    task_url = '%s/work/%s/' % (TUNGA_URL, instance.task.id)
    slack_msg = "Task Application {} | <{}|View on Tunga>".format(
        instance.status == STATUS_ACCEPTED and 'accepted' or 'rejected',
        task_url)

    attachments = [{
        slack_utils.KEY_TITLE:
        instance.task.summary,
        slack_utils.KEY_TITLE_LINK:
        application_url,
        slack_utils.KEY_TEXT:
        '%s%s%s%s\n\n<%s|View on Tunga>' %
        (truncatewords(convert_to_text(instance.pitch),
                       100), instance.hours_needed
         and '\n*Workload:* {} hrs'.format(instance.hours_needed)
         or '', instance.deliver_at and '\n*Delivery Date:* {}'.format(
             instance.deliver_at.strftime("%d %b, %Y"))
         or '', instance.remarks and '\n*Remarks:* {}'.format(
             truncatewords(convert_to_text(instance.remarks), 100))
         or '', application_url),
        slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
        slack_utils.KEY_COLOR:
        SLACK_ATTACHMENT_COLOR_TUNGA
    }]
    if admin:
        slack_utils.send_incoming_webhook(
            SLACK_STAFF_INCOMING_WEBHOOK, {
                slack_utils.KEY_TEXT: slack_msg,
                slack_utils.KEY_ATTACHMENTS: attachments,
                slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL
            })
    else:
        slack_utils.send_integration_message(instance.task,
                                             message=slack_msg,
                                             attachments=attachments)
예제 #4
0
파일: slack.py 프로젝트: tunga-io/tunga-api
def notify_task_application_response_slack(instance, admin=True):
    instance = clean_instance(instance, Application)

    application_url = '%s/work/%s/applications/' % (TUNGA_URL, instance.task_id)
    task_url = '%s/work/%s/' % (TUNGA_URL, instance.task.id)
    slack_msg = "Task Application {} | <{}|View on Tunga>".format(
        instance.status == STATUS_ACCEPTED and 'accepted' or 'rejected',
        task_url
    )

    attachments = [
        {
            slack_utils.KEY_TITLE: instance.task.summary,
            slack_utils.KEY_TITLE_LINK: application_url,
            slack_utils.KEY_TEXT: '%s%s%s%s\n\n<%s|View on Tunga>' %
                                  (truncatewords(convert_to_text(instance.pitch), 100),
                                   instance.hours_needed and '\n*Workload:* {} hrs'.format(instance.hours_needed) or '',
                                   instance.deliver_at and '\n*Delivery Date:* {}'.format(
                                       instance.deliver_at.strftime("%d %b, %Y")
                                   ) or '',
                                   instance.remarks and '\n*Remarks:* {}'.format(
                                       truncatewords(convert_to_text(instance.remarks), 100)
                                   ) or '',
                                   application_url),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA
        }
    ]
    if admin:
        slack_utils.send_incoming_webhook(
            SLACK_STAFF_INCOMING_WEBHOOK,
            {
                slack_utils.KEY_TEXT: slack_msg,
                slack_utils.KEY_ATTACHMENTS: attachments,
                slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL
            }
        )
    else:
        slack_utils.send_integration_message(instance.task, message=slack_msg, attachments=attachments)
예제 #5
0
파일: slack.py 프로젝트: tunga-io/tunga-api
def notify_new_task_application_slack(instance, admin=True):
    instance = clean_instance(instance, Application)

    if not slack_utils.is_task_notification_enabled(instance.task, slugs.EVENT_APPLICATION):
        return

    application_url = '%s/work/%s/applications/' % (TUNGA_URL, instance.task_id)
    slack_msg = "New application from %s" % instance.user.short_name
    attachments = [
        {
            slack_utils.KEY_TITLE: instance.task.summary,
            slack_utils.KEY_TITLE_LINK: application_url,
            slack_utils.KEY_TEXT: '%s%s%s%s\n\n<%s|View on Tunga>' %
                                  (truncatewords(convert_to_text(instance.pitch), 100),
                                   instance.hours_needed and '\n*Workload:* {} hrs'.format(instance.hours_needed) or '',
                                   instance.deliver_at and '\n*Delivery Date:* {}'.format(
                                       instance.deliver_at.strftime("%d %b, %Y")
                                   ) or '',
                                   instance.remarks and '\n*Remarks:* {}'.format(
                                       truncatewords(convert_to_text(instance.remarks), 100)
                                   ) or '',
                                   application_url),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA
        }
    ]
    if admin:
        slack_utils.send_incoming_webhook(
            SLACK_STAFF_INCOMING_WEBHOOK,
            {
                slack_utils.KEY_TEXT: slack_msg,
                slack_utils.KEY_ATTACHMENTS: attachments,
                slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL
            }
        )
    else:
        slack_utils.send_integration_message(instance.task, message=slack_msg, attachments=attachments)
예제 #6
0
def log_emails(responses, to, subject=None, cc=None, bcc=None, deal_ids=None):
    mandrill_client = get_client()

    print('logging responses: ', responses)

    if responses:
        for response in responses:
            content_id = response.get('_id')
            print('mandrill response', content_id, response)

            if response.get('status') == 'sent':
                tries = 0
                while True:
                    try:
                        sent_details = mandrill_client.messages.content(
                            content_id)
                    except mandrill.UnknownMessageError:
                        sent_details = None

                    print('sent_details', sent_details)
                    if sent_details:
                        email_html = sent_details.get('html', '')
                        email_text = sent_details.get('text', '')

                        create_hubspot_engagement(
                            from_email=sent_details.get(
                                'from_email', DEFAULT_FROM_EMAIL),
                            to_emails=isinstance(to, (str, unicode)) and [to]
                            or to,
                            subject=sent_details.get('subject', subject),
                            body=email_text or convert_to_text(email_html),
                            **dict(cc=cc,
                                   bcc=bcc,
                                   html=email_html,
                                   deal_ids=deal_ids))
                        break
                    else:
                        # Hacks to wait to Mandrill indicates the message so it can be logged in hubspot
                        tries += 1
                        if tries >= 60:
                            # Give up after for 15 minutes
                            break
                        else:
                            # Wait for 15 seconds
                            sleep(15)
예제 #7
0
def render_mail(subject, template_prefix, to_emails, context, bcc=None, cc=None, **kwargs):
    """
    :param subject:
    :param template_prefix: path to template for email with extension (e.g hello if template name is hello.html)
    :param to_emails:
    :param context: variables to be passed into template
    :param bcc:
    :param cc:
    :param kwargs:
    :return:
    """
    from_email = DEFAULT_FROM_EMAIL
    if not re.match(r'^\[\s*Tunga', subject):
        subject = '{} {}'.format(EMAIL_SUBJECT_PREFIX, subject)

    bodies = {}
    for ext in ['html', 'txt']:
        try:
            template_name = '{0}.{1}'.format(template_prefix, ext)
            bodies[ext] = render_to_string(template_name,
                                           context).strip()
        except TemplateDoesNotExist:
            if ext == 'txt':
                if 'html' in bodies:
                    # Compose text body from html
                    bodies[ext] = convert_to_text(bodies['html'])
                else:
                    # We need at least one body
                    raise

    if bodies:
        msg = EmailMultiAlternatives(subject, bodies['txt'], from_email, to_emails, bcc=bcc, cc=cc)
        if 'html' in bodies:
            try:
                html_body = render_to_string(
                    'tunga/email/base.html', dict(email_content=bodies['html'])
                ).strip()
            except TemplateDoesNotExist:
                html_body = bodies['html']
            msg.attach_alternative(premailer.transform(html_body), 'text/html')
    else:
        raise TemplateDoesNotExist
    return msg
예제 #8
0
def log_emails(responses, to, subject=None, cc=None, bcc=None, deal_ids=None):
    mandrill_client = get_client()
    if responses:
        for response in responses:
            content_id = response.get('_id')
            print('mandrill response', content_id, response)

            if response.get('status') == 'sent':
                tries = 0
                while True:
                    try:
                        sent_details = mandrill_client.messages.content(content_id)
                    except mandrill.UnknownMessageError:
                        sent_details = None

                    print('sent_details', sent_details)
                    if sent_details:
                        email_html = sent_details.get('html', '')
                        email_text = sent_details.get('text', '')

                        create_hubspot_engagement(
                            from_email=sent_details.get('from_email', DEFAULT_FROM_EMAIL),
                            to_emails=isinstance(to, (str, unicode)) and [to] or to,
                            subject=sent_details.get('subject', subject),
                            body=email_text or convert_to_text(email_html),
                            **dict(cc=cc, bcc=bcc, html=email_html, deal_ids=deal_ids)
                        )
                        break
                    else:
                        # Hacks to wait to Mandrill indicates the message so it can be logged in hubspot
                        tries += 1
                        if tries >= 60:
                            # Give up after for 15 minutes
                            break
                        else:
                            # Wait for 15 seconds
                            sleep(15)
예제 #9
0
 def text_body(self):
     return convert_to_text(convert_slack_to_html(self.body))
예제 #10
0
def create_progress_report_slack_message(instance, updated=False, to_client=False):
    is_pm_report = instance.event.type in [LEGACY_PROGRESS_EVENT_TYPE_PM, LEGACY_PROGRESS_EVENT_TYPE_MILESTONE_INTERNAL]
    is_client_report = instance.event.type in [LEGACY_PROGRESS_EVENT_TYPE_CLIENT, LEGACY_PROGRESS_EVENT_TYPE_CLIENT_MID_SPRINT]
    is_pm_or_client_report = is_pm_report or is_client_report
    is_dev_report = not is_pm_or_client_report

    report_url = '%s/work/%s/event/%s/' % (TUNGA_URL, instance.event.task_id, instance.event_id)
    slack_msg = "{} {} a {} | {}".format(
        instance.user.display_name.encode('utf-8'),
        updated and 'updated' or 'submitted',
        is_client_report and "Weekly Survey" or "Progress Report",
        '<{}|View on Tunga>'.format(report_url)
    )

    slack_text_suffix = ''
    if not is_client_report:
        slack_text_suffix += '*Status:* {}\n*Percentage completed:* {}{}'.format(
            instance.get_status_display(), instance.percentage, '%')
    if not to_client:
        if instance.last_deadline_met is not None:
            slack_text_suffix += '\n*Was the last deadline met?:* {}'.format(
                instance.last_deadline_met and 'Yes' or 'No'
            )
        if instance.next_deadline:
            slack_text_suffix += '\n*Next deadline:* {}'.format(instance.next_deadline.strftime("%d %b, %Y"))
    if is_client_report:
        if instance.deliverable_satisfaction is not None:
            slack_text_suffix += '\n*Are you satisfied with the deliverables?:* {}'.format(
                instance.deliverable_satisfaction and 'Yes' or 'No'
            )
    if is_dev_report:
        if instance.stuck_reason:
            slack_text_suffix += '\n*Reason for being stuck:*\n {}'.format(
                convert_to_text(instance.get_stuck_reason_display())
            )
    attachments = [
        {
            slack_utils.KEY_TITLE: instance.event.task.summary,
            slack_utils.KEY_TITLE_LINK: report_url,
            slack_utils.KEY_TEXT: slack_text_suffix,
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE
        }
    ]

    if not to_client:
        if instance.deadline_miss_communicated is not None:
            attachments.append({
                slack_utils.KEY_TITLE: '{} promptly about not making the deadline?'.format(
                    is_client_report and 'Did the project manager/ developer(s) inform you' or 'Did you inform the client'),
                slack_utils.KEY_TEXT: '{}'.format(instance.deadline_miss_communicated and 'Yes' or 'No'),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
            })

    if instance.deadline_report:
        attachments.append({
            slack_utils.KEY_TITLE: 'Report about the last deadline:',
            slack_utils.KEY_TEXT: convert_to_text(instance.deadline_report),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
        })

    if is_client_report:
        if instance.rate_deliverables:
            attachments.append({
                slack_utils.KEY_TITLE: 'How would you rate the deliverables on a scale from 1 to 5?',
                slack_utils.KEY_TEXT: '{}/5'.format(instance.rate_deliverables),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE
            })
        if instance.pm_communication:
            attachments.append({
                slack_utils.KEY_TITLE: 'Is the communication between you and the project manager/developer(s) going well?',
                slack_utils.KEY_TEXT: '{}'.format(instance.pm_communication and 'Yes' or 'No'),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
            })
    else:
        # Status
        if instance.stuck_details:
            attachments.append({
                slack_utils.KEY_TITLE: 'Explain Further why you are stuck/what should be done:',
                slack_utils.KEY_TEXT: convert_to_text(instance.stuck_details),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
            })

        if instance.started_at and not to_client:
            attachments.append({
                slack_utils.KEY_TITLE: 'When did you start this sprint/task/project?',
                slack_utils.KEY_TEXT: instance.started_at.strftime("%d %b, %Y"),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE
            })

        # Last
        if instance.accomplished:
            attachments.append({
                slack_utils.KEY_TITLE: 'What has been accomplished since last update?',
                slack_utils.KEY_TEXT: convert_to_text(instance.accomplished),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
            })
        if instance.rate_deliverables and not to_client:
            attachments.append({
                slack_utils.KEY_TITLE: 'Rate Deliverables:',
                slack_utils.KEY_TEXT: '{}/5'.format(instance.rate_deliverables),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
            })

        # Current
        if instance.todo:
            attachments.append({
                slack_utils.KEY_TITLE: is_dev_report and 'What do you intend to achieve/complete today?' or 'What are the next next steps?',
                slack_utils.KEY_TEXT: convert_to_text(instance.todo),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
            })

        if not to_client:
            # Next
            if instance.next_deadline:
                attachments.append({
                    slack_utils.KEY_TITLE: 'When is the next deadline?',
                    slack_utils.KEY_TEXT: instance.next_deadline.strftime("%d %b, %Y"),
                    slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                    slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
                })

            # Keep information about failures to meet deadlines internal
            if instance.next_deadline_meet is not None:
                attachments.append({
                    slack_utils.KEY_TITLE: 'Do you anticipate to meet this deadline?',
                    slack_utils.KEY_TEXT: '{}'.format(instance.next_deadline_meet and 'Yes' or 'No'),
                    slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                    slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
                })
            if instance.next_deadline_fail_reason:
                attachments.append({
                    slack_utils.KEY_TITLE: 'Why will you not be able to make the next deadline?',
                    slack_utils.KEY_TEXT: convert_to_text(instance.next_deadline_fail_reason),
                    slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                    slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
                })
        if instance.obstacles:
            attachments.append({
                slack_utils.KEY_TITLE: 'What obstacles are impeding your progress?',
                slack_utils.KEY_TEXT: convert_to_text(instance.obstacles),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED
            })
        if instance.obstacles_prevention:
            attachments.append({
                slack_utils.KEY_TITLE: 'What could have been done to prevent this from happening?',
                slack_utils.KEY_TEXT: convert_to_text(instance.obstacles_prevention),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN
            })

    if is_pm_report:
        if instance.team_appraisal:
            attachments.append({
                slack_utils.KEY_TITLE: 'Team appraisal:',
                slack_utils.KEY_TEXT: convert_to_text(instance.team_appraisal),
                slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
                slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_NEUTRAL
            })

    if instance.remarks:
        attachments.append({
            slack_utils.KEY_TITLE: 'Other remarks or questions',
            slack_utils.KEY_TEXT: convert_to_text(instance.remarks),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_NEUTRAL
        })

    return slack_msg, attachments
예제 #11
0
 def text_body(self):
     return convert_to_text(convert_slack_to_html(self.body))
예제 #12
0
 def text_body(self):
     return convert_to_text(self.body)
예제 #13
0
    def handle(self, *args, **options):
        """
        Fix payment rates based on task status
        """
        # command to run: python manage.py tunga_refactor_html_fields_to_text

        # Fix profiles
        profiles = UserProfile.objects.filter(Q(bio__isnull=False) & ~Q(bio=''))
        for item in profiles:
            item.bio = convert_to_text(item.bio)
            item.save()
        print('profiles', len(profiles))

        # Fix messages
        messages = Message.objects.filter(Q(body__isnull=False) & ~Q(body=''))
        for item in messages:
            item.body = convert_to_text(item.body)
            item.save()
        print('messages', len(messages))

        # Fix comments
        comments = Comment.objects.filter(Q(body__isnull=False) & ~Q(body=''))
        for item in comments:
            item.body = convert_to_text(item.body)
            item.save()
        print('comments', len(comments))

        # Fix tasks
        tasks = Task.objects.all()
        for item in tasks:
            item.description = convert_to_text(item.description)
            item.remarks = convert_to_text(item.remarks)
            item.stack_description = convert_to_text(item.stack_description)
            item.deliverables = convert_to_text(item.deliverables)
            item.save()
        print('tasks', len(tasks))

        # Fix applications
        applications = Application.objects.all()
        for item in applications:
            item.pitch = convert_to_text(item.pitch)
            item.remarks = convert_to_text(item.remarks)
            item.save()
        print('applications', len(applications))

        # Fix progress events
        progress_events = ProgressEvent.objects.all()
        for item in progress_events:
            item.description = convert_to_text(item.description)
            item.save()
        print('progress events', len(progress_events))

        # Fix progress events
        progress_reports = ProgressReport.objects.all()
        for item in progress_reports:
            item.accomplished = convert_to_text(item.accomplished)
            item.todo = convert_to_text(item.todo)
            item.obstacles = convert_to_text(item.obstacles)
            item.remarks = convert_to_text(item.remarks)
            item.save()
        print('progress reports', len(progress_reports))

        # Fix work
        work = Work.objects.all()
        for item in work:
            item.details = convert_to_text(item.details)
            item.save()
        print('work', len(work))

        # Fix education
        education = Education.objects.all()
        for item in education:
            item.details = convert_to_text(item.details)
            item.save()
        print('education', len(education))
예제 #14
0
def notify_new_progress_report_slack(instance):
    instance = clean_instance(instance, ProgressReport)

    if not slack_utils.is_task_notification_enabled(instance.event.task,
                                                    slugs.EVENT_PROGRESS):
        return

    report_url = '%s/work/%s/event/%s/' % (TUNGA_URL, instance.event.task_id,
                                           instance.event_id)
    slack_msg = "%s submitted a Progress Report | %s" % (
        instance.user.display_name,
        '<{}|View details on Tunga>'.format(report_url))
    attachments = [{
        slack_utils.KEY_TITLE:
        instance.event.task.summary,
        slack_utils.KEY_TITLE_LINK:
        report_url,
        slack_utils.KEY_TEXT:
        '*Status:* %s'
        '\n*Percentage completed:* %s%s' %
        (instance.get_status_display(), instance.percentage, '%'),
        slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
        slack_utils.KEY_COLOR:
        SLACK_ATTACHMENT_COLOR_BLUE
    }]
    if instance.accomplished:
        attachments.append({
            slack_utils.KEY_TITLE:
            'What has been accomplished since last update?',
            slack_utils.KEY_TEXT:
            convert_to_text(instance.accomplished),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR:
            SLACK_ATTACHMENT_COLOR_GREEN
        })
    if instance.next_steps:
        attachments.append({
            slack_utils.KEY_TITLE:
            'What are the next next steps?',
            slack_utils.KEY_TEXT:
            convert_to_text(instance.next_steps),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR:
            SLACK_ATTACHMENT_COLOR_BLUE
        })
    if instance.obstacles:
        attachments.append({
            slack_utils.KEY_TITLE:
            'What obstacles are impeding your progress?',
            slack_utils.KEY_TEXT:
            convert_to_text(instance.obstacles),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR:
            SLACK_ATTACHMENT_COLOR_RED
        })
    if instance.remarks:
        attachments.append({
            slack_utils.KEY_TITLE:
            'Other remarks or questions',
            slack_utils.KEY_TEXT:
            convert_to_text(instance.remarks),
            slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT],
            slack_utils.KEY_COLOR:
            SLACK_ATTACHMENT_COLOR_NEUTRAL
        })
    slack_utils.send_integration_message(instance.event.task,
                                         message=slack_msg,
                                         attachments=attachments)