def notify_new_progress_report_slack(progress_report, updated=False): progress_report = clean_instance(progress_report, ProgressReport) is_pm_report = progress_report.event.type in [PROGRESS_EVENT_PM, PROGRESS_EVENT_INTERNAL] or \ (progress_report.event.type == PROGRESS_EVENT_MILESTONE and progress_report.user.is_project_manager) is_client_report = progress_report.event.type == PROGRESS_EVENT_CLIENT or \ ( progress_report.event.type == PROGRESS_EVENT_MILESTONE and progress_report.user.is_project_owner) is_pm_or_client_report = is_pm_report or is_client_report is_dev_report = not is_pm_or_client_report # All reports go to Tunga #updates Slack slack_msg, attachments = create_progress_report_slack_message( progress_report, updated=updated) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_UPDATES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments }) if is_dev_report: # Re-create report for clients # TODO: Respect client's settings slack_msg, attachments = create_progress_report_slack_message( progress_report, updated=updated, to_client=True) slack_utils.send_project_message(progress_report.event.project, message=slack_msg, attachments=attachments)
def notify_missed_progress_event_slack(progress_event): progress_event = clean_instance(progress_event, ProgressEvent) if progress_event.project.archived or progress_event.status != "missed" or not progress_event.last_reminder_at or progress_event.missed_notification_at: return participants = progress_event.participants if not participants: # No one to report or project is now closed return target_user = None if participants and len(participants) == 1: target_user = participants[0] project_url = '{}/projects/{}'.format(TUNGA_URL, progress_event.project.id) slack_msg = "`Alert (!):` {} {} for \"{}\" | <{}|View on Tunga>".format( target_user and '{} missed a'.format(target_user.short_name) or 'Missed', (progress_event.type == PROGRESS_EVENT_CLIENT and 'progress survey') or (progress_event.type == PROGRESS_EVENT_MILESTONE and 'milestone report') or 'progress report', progress_event.project.title, project_url ) attachments = [ { slack_utils.KEY_TITLE: progress_event.project.title, slack_utils.KEY_TITLE_LINK: project_url, slack_utils.KEY_TEXT: '*Due Date:* {}\n\n{}'.format( progress_event.due_at.strftime("%d %b, %Y"), '\n\n'.join( [ '*Name:* {}\n' '*Email:* {}{}'.format( user.display_name.encode('utf-8'), user.email, not user.is_project_owner and user.profile and user.profile.phone_number and '\n*Phone Number:* {}'.format(user.profile.phone_number) or '') for user in participants ] ) ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA } ] 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_MISSED_UPDATES_CHANNEL } ) # Save notification time progress_event.missed_notification_at = datetime.datetime.now() progress_event.save()
def notify_paid_invoice_slack_admin(invoice): invoice = clean_instance(invoice, Invoice) if invoice.legacy_id or not invoice.paid: # ignore legacy invoices return project_url = '{}/projects/{}/'.format(TUNGA_URL, invoice.project.id) person_url = '{}/network/{}/'.format(TUNGA_URL, invoice.user.username) invoice_url = '{}/api/invoices/{}/download/?format=pdf'.format(TUNGA_URL, invoice.id) slack_msg = ':tada: A {} of *EUR {}* has been {} *<{}|{}>* for <{}|{}> | <{}|Download Invoice>'.format( invoice.type == INVOICE_TYPE_SALE and 'payment' or 'payout', invoice.amount, invoice.type == INVOICE_TYPE_SALE and 'made by' or 'sent to', person_url, invoice.user.display_name.encode('utf-8'), project_url, invoice.full_title, invoice_url ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PAYMENTS_CHANNEL } )
def notify_missed_progress_event_slack(progress_event): progress_event = clean_instance(progress_event, ProgressEvent) if progress_event.project.archived or progress_event.status != "missed" or not progress_event.last_reminder_at or progress_event.missed_notification_at: return participants = progress_event.participants if not participants: # No one to report or project is now closed return target_user = None if participants and len(participants) == 1: target_user = participants[0] project_url = '{}/projects/{}'.format(TUNGA_URL, progress_event.project.id) slack_msg = "`Alert (!):` {} {} for \"{}\" | <{}|View on Tunga>".format( target_user and '{} missed a'.format(target_user.short_name) or 'Missed', (progress_event.type == PROGRESS_EVENT_CLIENT and 'progress survey') or (progress_event.type == PROGRESS_EVENT_MILESTONE and 'milestone report') or 'progress report', progress_event.project.title, project_url ) attachments = [ { slack_utils.KEY_TITLE: progress_event.project.title, slack_utils.KEY_TITLE_LINK: project_url, slack_utils.KEY_TEXT: '*Due Date:* {}\n\n{}'.format( progress_event.due_at.strftime("%d %b, %Y"), '\n\n'.join( [ '*Name:* {}\n' '*Email:* {}{}'.format( user.display_name.encode('utf-8'), user.email, not user.is_project_owner and user.profile and user.profile.phone_number and '\n*Phone Number:* {}'.format(user.profile.phone_number) or '') for user in participants ] ) ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA } ] 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_MISSED_UPDATES_CHANNEL } ) # Save notification time progress_event.missed_notification_at = datetime.datetime.now() progress_event.save()
def notify_new_invite_request_slack(invite_request): invite_request = clean_instance(invite_request, InviteRequest) slack_msg = "<!channel> {} wants to join Tunga".format(invite_request.name) attachments = [{ slack_utils.KEY_TITLE: invite_request.name, slack_utils.KEY_TITLE_LINK: invite_request.cv_url, slack_utils.KEY_TEXT: '*Name:* {}\n*Email:* {}\n*Country*: {}\n<{}|Download CV>'.format( invite_request.name, invite_request.email, invite_request.country.name, invite_request.cv_url), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN, }, { slack_utils.KEY_TITLE: 'Motivation', slack_utils.KEY_TEXT: invite_request.motivation, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE, }] 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_PROFILES_CHANNEL })
def notify_progress_report_client_not_satisfied_slack_admin(instance): instance = clean_instance(instance, ProgressReport) task_url = '{}/work/{}/event/{}'.format(TUNGA_URL, instance.event.task.id, instance.event.id) slack_msg = "`Alert (!):` Client dissatisfied | <{}|View on Tunga>".format(task_url) attachments = [ { slack_utils.KEY_TITLE: instance.event.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'The project owner of \"{}\" {} is unsatisfied with the deliverable.\n ' 'Please contact all stakeholders.'.format( instance.event.task.summary, instance.event.task.is_task and 'task' or 'project' ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA }, create_task_stakeholders_attachment_slack(instance.event.task, show_title=False) ] 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_UPDATES_CHANNEL } )
def notify_progress_report_deadline_missed_slack_admin(instance): instance = clean_instance(instance, ProgressReport) task_url = '{}/work/{}'.format(TUNGA_URL, instance.event.task.id) slack_msg = "`Alert (!):` Follow up on missed deadline for \"{}\" | <{}|View on Tunga>".format( instance.event.task.summary, task_url ) attachments = [ { slack_utils.KEY_TITLE: instance.event.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'A deadline has been missed on the "{}" {}\n' '*Was the client informed before hand?:* {}\n' 'Please contact the stakeholders.'.format( instance.event.task.summary, instance.event.task.is_task and 'task' or 'project', instance.deadline_miss_communicated and 'Yes' or 'No' ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA }, create_task_stakeholders_attachment_slack(instance.event.task, show_title=False) ] 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_UPDATES_CHANNEL } )
def notify_new_progress_report_slack(instance, updated=False): instance = clean_instance(instance, ProgressReport) is_pm_report = instance.event.type in [ PROGRESS_EVENT_TYPE_PM, PROGRESS_EVENT_TYPE_MILESTONE_INTERNAL ] is_client_report = instance.event.type == PROGRESS_EVENT_TYPE_CLIENT is_pm_or_client_report = is_pm_report or is_client_report is_dev_report = not is_pm_or_client_report # if not (slack_utils.is_task_notification_enabled(instance.event.task, slugs.EVENT_PROGRESS)): # return # All reports go to Tunga #updates Slack slack_msg, attachments = create_progress_report_slack_message( instance, updated=updated) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_UPDATES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments }) if is_dev_report: # Re-create report for clients slack_msg, attachments = create_progress_report_slack_message( instance, updated=updated, to_client=True) slack_utils.send_integration_message(instance.event.task, message=slack_msg, attachments=attachments)
def notify_progress_report_stuck_slack_admin(instance): instance = clean_instance(instance, ProgressReport) task_url = '{}/work/{}/event/{}'.format(TUNGA_URL, instance.event.task.id, instance.event.id) slack_msg = "`Alert (!):` The status for the \"{}\" {} has been classified as stuck | <{}|View on Tunga>".format( instance.event.task.summary, instance.event.task.is_task and 'task' or 'project', task_url ) attachments = [ { slack_utils.KEY_TITLE: instance.event.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'Please contact all stakeholders.', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA }, create_task_stakeholders_attachment_slack(instance.event.task, show_title=False) ] 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_UPDATES_CHANNEL } )
def notify_progress_report_wont_meet_deadline_slack_admin(instance): instance = clean_instance(instance, ProgressReport) task_url = '{}/work/{}/event/{}'.format(TUNGA_URL, instance.event.task.id, instance.event.id) slack_msg = "`Alert (!):` {} doesn't expect to meet the deadline | <{}|View on Tunga>".format( instance.event.type in [LEGACY_PROGRESS_EVENT_TYPE_PM, LEGACY_PROGRESS_EVENT_TYPE_MILESTONE_INTERNAL] and 'PM' or 'Developer', task_url ) attachments = [ { slack_utils.KEY_TITLE: instance.event.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'The {} on the \"{}\" {} has indicated that they might not meet the coming deadline.\n' 'Please contact all stakeholders.'.format( instance.event.type in [LEGACY_PROGRESS_EVENT_TYPE_PM, LEGACY_PROGRESS_EVENT_TYPE_MILESTONE_INTERNAL] and 'PM' or 'Developer', instance.event.task.summary, instance.event.task.is_task and 'task' or 'project' ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA }, create_task_stakeholders_attachment_slack(instance.event.task, show_title=False) ] 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_UPDATES_CHANNEL } )
def notify_user_profile_updated_slack(instance, edited=None): instance = clean_instance(instance, UserProfile) if instance.user.type != USER_TYPE_DEVELOPER: return profile_url = '{}/developer/{}'.format(TUNGA_URL, instance.user.username) slack_msg = "{}'s profile has been updated | <{}|Review on Tunga>".format( instance.user.display_name, profile_url) attachments = [{ slack_utils.KEY_TITLE: instance.user.display_name, slack_utils.KEY_TITLE_LINK: profile_url, slack_utils.KEY_TEXT: '*Name:* {}\n' '*Location:* {}\n' '*Skills*: {}\n' '*Verified:* {}'.format(instance.user.display_name, instance.location, str(instance.skills), instance.user.verified and 'True' or 'False'), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: instance.user.verified and SLACK_ATTACHMENT_COLOR_GREEN or SLACK_ATTACHMENT_COLOR_RED }] 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_PROFILES_CHANNEL })
def notify_missed_progress_event_slack(instance): instance = clean_instance(instance, ProgressEvent) is_client_report = instance.type in [LEGACY_PROGRESS_EVENT_TYPE_CLIENT, LEGACY_PROGRESS_EVENT_TYPE_CLIENT_MID_SPRINT] if instance.task.archived or instance.status != "missed" or not instance.last_reminder_at: return participants = instance.participants if not participants or instance.task.closed: # No one to report or task is now closed return target_user = None if participants and len(participants) == 1: target_user = participants[0] task_url = '{}/work/{}'.format(TUNGA_URL, instance.task.id) slack_msg = "`Alert (!):` {} {} for \"{}\" | <{}|View on Tunga>".format( target_user and '{} missed a'.format(target_user.short_name) or 'Missed', is_client_report and 'weekly survey' or 'progress report', instance.task.summary, task_url ) attachments = [ { slack_utils.KEY_TITLE: instance.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: '\n\n'.join( [ '*Due Date:* {}\n\n' '*Name:* {}\n' '*Email:* {}{}'.format( instance.due_at.strftime("%d %b, %Y"), user.display_name.encode('utf-8'), user.email, user.profile and user.profile.phone_number and '\n*Phone Number:* {}'.format( user.profile.phone_number) or '' ) for user in participants ] ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA } ] 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_MISSED_UPDATES_CHANNEL } ) # Save notification time instance.missed_notification_at = datetime.datetime.now() instance.save()
def notify_new_message_slack(instance): instance = clean_instance(instance, Message) if instance.channel.type == CHANNEL_TYPE_SUPPORT and instance.source != APP_INTEGRATION_PROVIDER_SLACK: if instance.user and (instance.user.is_staff or instance.user.is_superuser): # Ignore messages from admins return channel_url = '%s/help/%s/' % (TUNGA_URL, instance.channel_id) message_details = { slack_utils.KEY_AUTHOR_NAME: instance.sender.display_name, slack_utils.KEY_TEXT: instance.text_body, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT, slack_utils.KEY_FOOTER], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA, slack_utils.KEY_FOOTER: 'Type C{} <your reply here>'.format(instance.channel_id), slack_utils.KEY_FOOTER_ICON: TUNGA_ICON_URL_150, } if instance.channel.subject: message_details[slack_utils.KEY_TITLE] = instance.channel.subject message_details[slack_utils.KEY_TITLE_LINK] = channel_url else: inquirer = instance.channel.get_inquirer() if inquirer: try: message_details[slack_utils.KEY_TITLE] = 'Help{}{}'.format( inquirer.name and ': ' or '', inquirer.name or '') if inquirer.email: message_details[ slack_utils.KEY_TEXT] += '\n\nEmail: {}'.format( inquirer.email) message_details[slack_utils.KEY_TITLE_LINK] = channel_url except: pass if instance.user: message_details[slack_utils.KEY_AUTHOR_LINK] = '%s/people/%s/' % ( TUNGA_URL, instance.user.username) try: if instance.sender.avatar_url: message_details[ slack_utils.KEY_AUTHOR_ICON] = instance.sender.avatar_url except: pass slack_msg = { slack_utils.KEY_TEXT: "New message from {} | <{}|View on Tunga>".format( instance.sender.short_name, channel_url), slack_utils.KEY_CHANNEL: SLACK_STAFF_CUSTOMER_CHANNEL, slack_utils.KEY_ATTACHMENTS: [message_details], } slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, slack_msg)
def notify_new_task_invoice_admin_slack(instance): instance = clean_instance(instance, TaskInvoice) task_url = '{}/work/{}/'.format(TUNGA_URL, instance.task.id) owner = instance.task.owner or instance.task.user client_url = '{}/people/{}/'.format(TUNGA_URL, owner.username) invoice_url = '{}/api/task/{}/download/invoice/?format=pdf'.format( TUNGA_URL, instance.task.id) slack_msg = '{} generated an invoice'.format(instance.user.display_name) attachments = [ { slack_utils.KEY_TITLE: instance.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'Client: <{}|{}>\nFee: {}\nPayment Method: {}\n<{}|Download invoice>' .format(client_url, owner.display_name, instance.display_fee().encode('utf-8'), instance.get_payment_method_display(), invoice_url), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE }, ] if not instance.task.payment_approved: if instance.payment_method == TASK_PAYMENT_METHOD_BANK: attachments.append({ slack_utils.KEY_TITLE: 'No payment approval required.', slack_utils.KEY_TEXT: 'Payment will be completed via bank transfer.', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN }) else: task_approval_url = '{}edit/payment-approval/'.format(task_url) attachments.append({ slack_utils.KEY_TITLE: 'Review and approve payment.', slack_utils.KEY_TITLE_LINK: task_approval_url, slack_utils.KEY_TEXT: "The client won't be able to pay until the payment is approved.", slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED }) 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_PAYMENTS_CHANNEL })
def notify_new_project_slack_admin(project): project = clean_instance(project, Project) summary, attachments = create_project_slack_message(project) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: summary, slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments })
def notify_new_project_slack_admin(project): project = clean_instance(project, Project) summary, attachments = create_project_slack_message(project) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: summary, slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments })
def notify_new_task_community_slack(instance): instance = clean_instance(instance, Task) # Notify Devs or PMs via Slack if (not instance.is_developer_ready) or (instance.approved and instance.visibility == VISIBILITY_DEVELOPER): slack_msg = create_task_slack_msg( instance, channel=instance.is_developer_ready and SLACK_DEVELOPER_UPDATES_CHANNEL or SLACK_PMS_UPDATES_CHANNEL ) slack_utils.send_incoming_webhook(SLACK_DEVELOPER_INCOMING_WEBHOOK, slack_msg)
def notify_tunga_new_skill_has_been_added(instance): instance = clean_instance(instance, Skill) slack_msg = "{} has been added as a new skill".format(instance.name, ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS })
def notify_new_message_slack(instance): instance = clean_instance(instance, Message) if instance.channel.type == CHANNEL_TYPE_SUPPORT and instance.source != APP_INTEGRATION_PROVIDER_SLACK: if instance.user and (instance.user.is_staff or instance.user.is_superuser): # Ignore messages from admins return channel_url = '%s/help/%s/' % (TUNGA_URL, instance.channel_id) summary = "New message from %s" % instance.sender.short_name message_details = { slack_utils.KEY_PRETEXT: summary, slack_utils.KEY_AUTHOR_NAME: instance.sender.display_name, slack_utils.KEY_TEXT: '%s\n\n<%s|View on Tunga>' % (instance.text_body, channel_url), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT, slack_utils.KEY_FOOTER], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN, slack_utils.KEY_FOOTER: 'Tunga | Type C%s <your reply here>' % instance.channel_id, slack_utils.KEY_FOOTER_ICON: TUNGA_ICON_URL_150, slack_utils.KEY_FALLBACK: summary, } if instance.channel.subject: message_details[slack_utils.KEY_TITLE] = instance.channel.subject message_details[slack_utils.KEY_TITLE_LINK] = channel_url else: inquirer = instance.channel.get_inquirer() if inquirer: try: message_details[ slack_utils.KEY_TITLE] = 'Help: %s' % inquirer.name message_details[slack_utils.KEY_TITLE_LINK] = channel_url except: pass if instance.user: message_details[slack_utils.KEY_AUTHOR_LINK] = '%s/people/%s/' % ( TUNGA_URL, instance.user.username) try: if instance.sender.avatar_url: message_details[ slack_utils.KEY_AUTHOR_ICON] = instance.sender.avatar_url except: pass slack_msg = { slack_utils.KEY_ATTACHMENTS: [message_details], } slack_utils.send_incoming_webhook(SLACK_CUSTOMER_INCOMING_WEBHOOK, slack_msg)
def notify_new_task_invoice_admin_slack(instance): instance = clean_instance(instance, TaskInvoice) task_url = '{}/work/{}/'.format(TUNGA_URL, instance.task.id) owner = instance.task.owner or instance.task.user client_url = '{}/people/{}/'.format(TUNGA_URL, owner.username) invoice_url = '{}/api/task/{}/download/invoice/?format=pdf'.format(TUNGA_URL, instance.task.id) slack_msg = '{} generated an invoice'.format( instance.user.display_name.encode('utf-8') ) attachments = [ { slack_utils.KEY_TITLE: instance.task.summary, slack_utils.KEY_TITLE_LINK: task_url, slack_utils.KEY_TEXT: 'Client: <{}|{}>\nFee: {}\nPayment Method: {}\n<{}|Download invoice>'.format( client_url, owner.display_name.encode('utf-8'), instance.display_fee().encode('utf-8'), instance.get_payment_method_display(), invoice_url ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE }, ] if not instance.task.payment_approved: task_approval_url = '{}edit/payment-approval/'.format(task_url) if instance.payment_method == PAYMENT_METHOD_BANK: attachments.append({ slack_utils.KEY_TITLE: 'Review and approve payment.', slack_utils.KEY_TITLE_LINK: task_approval_url, slack_utils.KEY_TEXT: "Payment will be completed via bank transfer.\n " "However, developer payments won't be distributed until the payment" " is reviewed and approved.", slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN }) else: attachments.append({ slack_utils.KEY_TITLE: 'Review and approve payment.', slack_utils.KEY_TITLE_LINK: task_approval_url, slack_utils.KEY_TEXT: "The client won't be able to pay until the payment is approved.", slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED }) 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_PAYMENTS_CHANNEL } )
def notify_new_task_invoice_client_email(instance): instance = clean_instance(instance, TaskInvoice) to = [instance.user.email] if instance.task.owner and instance.task.owner.email != instance.user.email: to.append(instance.task.owner.email) if instance.task.user and instance.task.user.email != instance.user.email: to.append(instance.task.user.email) task_url = '{}/task/{}/'.format(TUNGA_URL, instance.task.id) owner = instance.task.owner or instance.task.user merge_vars = [ mandrill_utils.create_merge_var(MANDRILL_VAR_FIRST_NAME, owner.first_name), mandrill_utils.create_merge_var('invoice_title', instance.task.summary), mandrill_utils.create_merge_var( 'can_pay', bool(instance.payment_method != TASK_PAYMENT_METHOD_BANK and not instance.task.payment_approved)), ] rendered_html = process_invoices(instance.task.id, invoice_types=('client', ), user_id=owner.id, is_admin=False) pdf_file = HTML(string=rendered_html, encoding='utf-8').write_pdf() pdf_file_contents = base64.b64encode(pdf_file) attachments = [ dict(content=pdf_file_contents, name='Invoice - {}'.format(instance.task.summary), type='application/pdf') ] mandrill_response = mandrill_utils.send_email('69-invoice', to, merge_vars=merge_vars, attachments=attachments) if mandrill_response: mandrill_utils.log_emails.delay( mandrill_response, to, deal_ids=[instance.task.hubspot_deal_id]) # Notify via Slack of sent email to double check and prevent multiple sends slack_utils.send_incoming_webhook( SLACK_DEBUGGING_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: "Mandrill Email sent to {} for <{}|Invoice: {}>".format( ', '.join(to), task_url, instance.task.summary), slack_utils.KEY_CHANNEL: '#alerts' })
def notify_user_has_been_invited_to_developer_slack(instance): instance = clean_instance(instance, DeveloperInvitation) slack_msg = "{} has been invited to become a Tunga {}".format( instance.first_name, instance.get_type_display().lower()) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS })
def notify_project_slack_dev(project, reminder=False): project = clean_instance(project, Project) if project.stage != PROJECT_STAGE_OPPORTUNITY: # Only notify devs about opportunities return summary, attachments = create_project_slack_message(project, to_developer=True, reminder=reminder) slack_utils.send_incoming_webhook(SLACK_DEVELOPER_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: summary, slack_utils.KEY_CHANNEL: SLACK_DEVELOPER_OPPORTUNITIES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments })
def notify_new_user_signup_on_platform(user): instance = clean_instance(user, get_user_model()) slack_msg = '<{}|{}> has joined Tunga'.format( '{}/network/{}'.format(TUNGA_URL, instance.user.username), instance.user.display_name, ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS })
def notify_project_slack_dev(project, reminder=False): project = clean_instance(project, Project) if project.stage != PROJECT_STAGE_OPPORTUNITY: # Only notify devs about opportunities return summary, attachments = create_project_slack_message(project, to_developer=True, reminder=reminder) slack_utils.send_incoming_webhook(SLACK_DEVELOPER_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: summary, slack_utils.KEY_CHANNEL: SLACK_DEVELOPER_OPPORTUNITIES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments })
def notify_new_message_slack(instance): instance = clean_instance(instance, Message) if instance.channel.type == CHANNEL_TYPE_SUPPORT and instance.source != APP_INTEGRATION_PROVIDER_SLACK: if instance.user and (instance.user.is_staff or instance.user.is_superuser): # Ignore messages from admins return channel_url = '%s/help/%s/' % (TUNGA_URL, instance.channel_id) message_details = { slack_utils.KEY_AUTHOR_NAME: instance.sender.display_name, slack_utils.KEY_TEXT: instance.text_body, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT, slack_utils.KEY_FOOTER], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_TUNGA, slack_utils.KEY_FOOTER: 'Type C{} <your reply here>'.format(instance.channel_id), slack_utils.KEY_FOOTER_ICON: TUNGA_ICON_URL_150, } if instance.channel.subject: message_details[slack_utils.KEY_TITLE] = instance.channel.subject message_details[slack_utils.KEY_TITLE_LINK] = channel_url else: inquirer = instance.channel.get_inquirer() if inquirer: try: message_details[slack_utils.KEY_TITLE] = 'Help{}{}'.format( inquirer.name and ': ' or '', inquirer.name or '' ) if inquirer.email: message_details[slack_utils.KEY_TEXT] += '\n\nEmail: {}'.format(inquirer.email) message_details[slack_utils.KEY_TITLE_LINK] = channel_url except: pass if instance.user: message_details[slack_utils.KEY_AUTHOR_LINK] = '%s/people/%s/' % (TUNGA_URL, instance.user.username) try: if instance.sender.avatar_url: message_details[slack_utils.KEY_AUTHOR_ICON] = instance.sender.avatar_url except: pass slack_msg = { slack_utils.KEY_TEXT: "New message from {} | <{}|View on Tunga>".format( instance.sender.short_name, channel_url ), slack_utils.KEY_CHANNEL: SLACK_STAFF_CUSTOMER_CHANNEL, slack_utils.KEY_ATTACHMENTS: [ message_details ], } slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, slack_msg)
def notify_new_user_signup_on_platform(user): instance = clean_instance(user, get_user_model()) slack_msg = '<{}|{}> has joined Tunga'.format( '{}/network/{}'.format(TUNGA_URL, instance.user.username), instance.user.display_name, ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS } )
def notify_invoice_slack_admin(invoice, updated=False): invoice = clean_instance(invoice, Invoice) if invoice.legacy_id: # ignore legacy invoices return project_url = '{}/projects/{}/'.format(TUNGA_URL, invoice.project.id) payment_url = '{}pay'.format(project_url) person_url = '{}/network/{}/'.format(TUNGA_URL, invoice.user.username) invoice_url = '{}/api/invoices/{}/download/?format=pdf'.format(TUNGA_URL, invoice.id) slack_msg = '{} {} a {} invoice'.format( (updated and invoice.updated_by or invoice.created_by).display_name.encode('utf-8'), updated and 'updated' or 'created', invoice.type == INVOICE_TYPE_SALE and 'client' or 'developer' ) invoice_summary = '{}: <{}|{}>\nProject: <{}|{}>\nTitle: {}\nFee: EUR {}\n<{}|Download invoice>'.format( invoice.type == INVOICE_TYPE_SALE and 'Client' or 'Developer', person_url, invoice.user.display_name.encode('utf-8'), project_url, invoice.project.title, invoice.title, invoice.amount, invoice_url ) attachments = [ { slack_utils.KEY_TITLE: invoice.full_title, slack_utils.KEY_TITLE_LINK: payment_url, slack_utils.KEY_TEXT: invoice_summary, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE }, ] 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_PAYMENTS_CHANNEL } )
def notify_new_contact_request_email(contact_request): contact_request = clean_instance(contact_request, ContactRequest) if contact_request.body: slack_msg = '{} {} is inquiring about {}'.format( contact_request.fullname, contact_request.email, contact_request.body, ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS } ) else: subject = "New {} Request".format(contact_request.item and 'Offer' or 'Contact') msg_suffix = 'wants to know more about Tunga.' if contact_request.item: item_name = contact_request.get_item_display() subject = '%s (%s)' % (subject, item_name) msg_suffix = 'requested for "%s"' % item_name to = TUNGA_CONTACT_REQUEST_EMAIL_RECIPIENTS ctx = { 'email': contact_request.email, 'message': '%s %s ' % ( contact_request.email, msg_suffix ) } slack_msg = "%s %s" % (subject, msg_suffix) if slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS } ): contact_request.email_sent_at = datetime.datetime.utcnow() contact_request.save()
def notify_review_task_admin_slack(instance): instance = clean_instance(instance, Task) task_url = '{}/work/{}/'.format(TUNGA_URL, instance.id) new_user = instance.source == TASK_SOURCE_NEW_USER summary = "Reminder: Review {} {} | <{}|View on Tunga>\nCreated: {}".format( instance.scope == TASK_SCOPE_TASK and 'task' or 'project', new_user and ' (New user)' or '', task_url, instance.created_at.strftime("%d %b, %Y"), instance.approved_at and 'Approved: {}'.format(instance.approved_at.strftime("%d %b, %Y")) or '', ) slack_msg = create_task_slack_msg( instance, summary=summary, channel=SLACK_STAFF_LEADS_CHANNEL, show_contacts=True ) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, slack_msg)
def notify_interest_poll_status_slack(interest_poll): interest_poll = clean_instance(interest_poll, InterestPoll) if interest_poll.project.stage != PROJECT_STAGE_OPPORTUNITY or interest_poll.status != STATUS_INTERESTED: # Notify only accepted opportunities return slack_msg = '<{}|{}> is interested in <{}|{}>'.format( '{}/network/{}'.format(TUNGA_URL, interest_poll.user.username), interest_poll.user.display_name, '{}/projects/{}'.format(TUNGA_URL, interest_poll.project.id), interest_poll.project.title) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL })
def notify_new_task_admin_slack(instance, new_user=False, completed=False, call_scheduled=False): instance = clean_instance(instance, Task) task_url = '{}/work/{}/'.format(TUNGA_URL, instance.id) completed_phrase = '' if call_scheduled: completed_phrase = 'availability window shared' elif completed: completed_phrase = 'details completed' summary = "{} {} {} by {}{} | <{}|View on Tunga>".format( (completed or call_scheduled) and 'New wizard' or 'New', instance.scope == TASK_SCOPE_TASK and 'task' or 'project', completed_phrase or 'created', instance.user.display_name, new_user and ' (New user)' or '', task_url ) slack_msg = create_task_slack_msg(instance, summary=summary, channel=SLACK_STAFF_LEADS_CHANNEL, show_contacts=True, is_admin=True) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, slack_msg)
def notify_new_calendly_event(data): event_details = data.get('event', None) start_time = parse(event_details.get('start_time', None)) invitee_details = data.get('invitee', dict()) invitee_name = invitee_details.get('name') questions_and_answers = data.get('questions_and_answers', []) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL, slack_utils.KEY_TEXT: '*{}* scheduled a call with Calendly'.format(invitee_name), slack_utils.KEY_ATTACHMENTS: [{ slack_utils.KEY_TEXT: '\n'.join([ '*{}:* {}'.format(item[0], item[1]) for item in [['Name', invitee_name], ['Email', invitee_details.get('email')], [ 'Start Time', '{} at {} UTC'.format( start_time.strftime("%a, %d %b, %Y"), start_time.strftime("%I:%M %p")) ]] ]), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN }, { slack_utils.KEY_TEXT: '\n'.join([ '*{}:*\n{}'.format(item.get('question'), item.get('answer')) for item in questions_and_answers ]), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN }] })
def notify_new_task_admin_slack(instance, new_user=False, completed=False, call_scheduled=False): instance = clean_instance(instance, Task) task_url = '{}/work/{}/'.format(TUNGA_URL, instance.id) completed_phrase = '' if call_scheduled: completed_phrase = 'availability window shared' elif completed: completed_phrase = 'details completed' summary = "{} {} {} by {}{} | <{}|View on Tunga>".format( (completed or call_scheduled) and 'New wizard' or 'New', instance.scope == TASK_SCOPE_TASK and 'task' or 'project', completed_phrase or 'created', instance.user.display_name.encode('utf-8'), new_user and ' (New user)' or '', task_url ) slack_msg = create_task_slack_msg(instance, summary=summary, channel=SLACK_STAFF_LEADS_CHANNEL, show_contacts=True, is_admin=True) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, slack_msg)
def remind_no_task_applications_slack(instance, admin=True): instance = clean_instance(instance, Task) if not instance.is_task: return task_url = '{}/work/{}/'.format(TUNGA_URL, instance.id) new_user = instance.source == TASK_SOURCE_NEW_USER summary = "Reminder: No applications yet for {} {} | <{}|View on Tunga>".format( instance.scope == TASK_SCOPE_TASK and 'task' or 'project', new_user and admin and ' (New user)' or '', task_url) slack_msg = create_task_slack_msg( instance, summary=summary, channel=admin and SLACK_STAFF_LEADS_CHANNEL or SLACK_DEVELOPER_UPDATES_CHANNEL, show_contacts=admin) slack_utils.send_incoming_webhook( admin and SLACK_STAFF_INCOMING_WEBHOOK or SLACK_DEVELOPER_INCOMING_WEBHOOK, slack_msg)
def notify_invoice_slack_admin(invoice, updated=False): invoice = clean_instance(invoice, Invoice) if invoice.legacy_id: # ignore legacy invoices return project_url = '{}/projects/{}/'.format(TUNGA_URL, invoice.project.id) payment_url = '{}pay'.format(project_url) person_url = '{}/network/{}/'.format(TUNGA_URL, invoice.user.username) invoice_url = '{}/api/invoices/{}/download/?format=pdf'.format( TUNGA_URL, invoice.id) slack_msg = '{} {} a {}'.format( (updated and invoice.updated_by or invoice.created_by).display_name.encode('utf-8'), updated and 'updated' or 'created', invoice.type == INVOICE_TYPE_SALE and 'client payment' or 'developer payout') invoice_summary = '{}: <{}|{}>\nProject: <{}|{}>\nTitle: {}\nFee: EUR {}\n<{}|Download invoice>'.format( invoice.type == INVOICE_TYPE_SALE and 'Client' or 'Developer', person_url, invoice.user.display_name.encode('utf-8'), project_url, invoice.project.title, invoice.title, invoice.amount, invoice_url) attachments = [ { slack_utils.KEY_TITLE: invoice.full_title, slack_utils.KEY_TITLE_LINK: payment_url, slack_utils.KEY_TEXT: invoice_summary, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE }, ] 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_PAYMENTS_CHANNEL })
def notify_new_calendly_event(data): event_details = data.get('event', None) start_time = parse(event_details.get('start_time', None)) invitee_details = data.get('invitee', dict()) invitee_name = invitee_details.get('name') questions_and_answers = data.get('questions_and_answers', []) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL, slack_utils.KEY_TEXT: '*{}* scheduled a call with Calendly'.format( invitee_name ), slack_utils.KEY_ATTACHMENTS: [ { slack_utils.KEY_TEXT: '\n'.join( ['*{}:* {}'.format(item[0], item[1]) for item in [ ['Name', invitee_name], ['Email', invitee_details.get('email')], ['Start Time', '{} at {} UTC'.format( start_time.strftime("%a, %d %b, %Y"), start_time.strftime("%I:%M %p") )] ]]), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN }, { slack_utils.KEY_TEXT: '\n'.join( ['*{}:*\n{}'.format(item.get('question'), item.get('answer')) for item in questions_and_answers] ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN } ] } )
def notify_interest_poll_status_slack(interest_poll): interest_poll = clean_instance(interest_poll, InterestPoll) if interest_poll.project.stage != PROJECT_STAGE_OPPORTUNITY or interest_poll.status != STATUS_INTERESTED: # Notify only accepted opportunities return slack_msg = '<{}|{}> is interested in <{}|{}>'.format( '{}/network/{}'.format(TUNGA_URL, interest_poll.user.username), interest_poll.user.display_name, '{}/projects/{}'.format(TUNGA_URL, interest_poll.project.id), interest_poll.project.title ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_LEADS_CHANNEL } )
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)
def notify_new_contact_request_email(contact_request): contact_request = clean_instance(contact_request, ContactRequest) if contact_request.body: slack_msg = '{} {} is inquiring about {}'.format( contact_request.fullname, contact_request.email, contact_request.body, ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS }) else: subject = "New {} Request".format(contact_request.item and 'Offer' or 'Contact') msg_suffix = 'wants to know more about Tunga.' if contact_request.item: item_name = contact_request.get_item_display() subject = '%s (%s)' % (subject, item_name) msg_suffix = 'requested for "%s"' % item_name to = TUNGA_CONTACT_REQUEST_EMAIL_RECIPIENTS ctx = { 'email': contact_request.email, 'message': '%s %s ' % (contact_request.email, msg_suffix) } slack_msg = "%s %s" % (subject, msg_suffix) if slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_PLATFORM_ALERTS }): contact_request.email_sent_at = datetime.datetime.utcnow() contact_request.save()
def notify_payment_link_client_email(instance): instance = clean_instance(instance, Task) to = [instance.user.email] if instance.owner and instance.owner.email != instance.user.email: to.append(instance.owner.email) task_url = '{}/task/{}/'.format(TUNGA_URL, instance.id) payment_link = '{}pay/'.format(task_url) owner = instance.owner or instance.user merge_vars = [ mandrill_utils.create_merge_var(MANDRILL_VAR_FIRST_NAME, owner.first_name), mandrill_utils.create_merge_var('payment_title', instance.summary), mandrill_utils.create_merge_var('payment_link', payment_link), ] mandrill_response = mandrill_utils.send_email('70-payment-link-ready', to, merge_vars=merge_vars) if mandrill_response: instance.payment_link_sent = True instance.payment_link_sent_at = datetime.datetime.utcnow() instance.save() mandrill_utils.log_emails.delay(mandrill_response, to, deal_ids=[instance.hubspot_deal_id]) # Notify via Slack of sent email to double check and prevent multiple sends slack_utils.send_incoming_webhook( SLACK_DEBUGGING_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: "Mandrill Email sent to {} for <{}|Payment Link: {}>".format( ', '.join(to), task_url, instance.summary), slack_utils.KEY_CHANNEL: '#alerts' })
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)
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)
def remind_no_task_applications_slack(instance, admin=True): instance = clean_instance(instance, Task) if not instance.is_task: return task_url = '{}/work/{}/'.format(TUNGA_URL, instance.id) new_user = instance.source == TASK_SOURCE_NEW_USER summary = "Reminder: No applications yet for {} {} | <{}|View on Tunga>".format( instance.scope == TASK_SCOPE_TASK and 'task' or 'project', new_user and admin and ' (New user)' or '', task_url ) slack_msg = create_task_slack_msg( instance, summary=summary, channel=admin and SLACK_STAFF_LEADS_CHANNEL or SLACK_DEVELOPER_UPDATES_CHANNEL, show_contacts=admin ) slack_utils.send_incoming_webhook( admin and SLACK_STAFF_INCOMING_WEBHOOK or SLACK_DEVELOPER_INCOMING_WEBHOOK, slack_msg )
def notify_new_progress_report_slack(instance, updated=False): instance = clean_instance(instance, ProgressReport) 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 # if not (slack_utils.is_task_notification_enabled(instance.event.task, slugs.EVENT_PROGRESS)): # return # All reports go to Tunga #updates Slack slack_msg, attachments = create_progress_report_slack_message(instance, updated=updated) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_UPDATES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments }) if is_dev_report: # Re-create report for clients slack_msg, attachments = create_progress_report_slack_message(instance, updated=updated, to_client=True) slack_utils.send_integration_message(instance.event.task, message=slack_msg, attachments=attachments)
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)
def notify_new_progress_report_slack(progress_report, updated=False): progress_report = clean_instance(progress_report, ProgressReport) is_pm_report = progress_report.event.type in [PROGRESS_EVENT_PM, PROGRESS_EVENT_INTERNAL] or \ (progress_report.event.type == PROGRESS_EVENT_MILESTONE and progress_report.user.is_project_manager) is_client_report = progress_report.event.type == PROGRESS_EVENT_CLIENT or \ ( progress_report.event.type == PROGRESS_EVENT_MILESTONE and progress_report.user.is_project_owner) is_pm_or_client_report = is_pm_report or is_client_report is_dev_report = not is_pm_or_client_report # All reports go to Tunga #updates Slack slack_msg, attachments = create_progress_report_slack_message(progress_report, updated=updated) slack_utils.send_incoming_webhook(SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: slack_msg, slack_utils.KEY_CHANNEL: SLACK_STAFF_UPDATES_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments }) if is_dev_report: # Re-create report for clients # TODO: Respect client's settings slack_msg, attachments = create_progress_report_slack_message(progress_report, updated=updated, to_client=True) slack_utils.send_project_message(progress_report.event.project, message=slack_msg, attachments=attachments)
def notify_new_invite_request_slack(invite_request): invite_request = clean_instance(invite_request, InviteRequest) slack_msg = "<!channel> {} wants to join Tunga".format( invite_request.name ) attachments = [ { slack_utils.KEY_TITLE: invite_request.name, slack_utils.KEY_TITLE_LINK: invite_request.cv_url, slack_utils.KEY_TEXT: '*Name:* {}\n*Email:* {}\n*Country*: {}\n<{}|Download CV>'.format( invite_request.name, invite_request.email, invite_request.country.name, invite_request.cv_url ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN, }, { slack_utils.KEY_TITLE: 'Motivation', slack_utils.KEY_TEXT: invite_request.motivation, slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE, } ] 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_PROFILES_CHANNEL } )
def notify_hubspot_deal_changes_slack(deal_id, changes, event_ids=None): deal_url = None final_subscription_type = None deal_details = hubspot_utils.get_deal(deal_id) if deal_details and deal_details.get('properties', None): deal_properties = deal_details['properties'] deal_name = deal_properties.get(hubspot_utils.KEY_DEALNAME, {})['value'] or '' deal_property_changes = [] deal_property_details = hubspot_utils.get_deal_properties() deal_pipelines = hubspot_utils.get_deal_pipelines() for payload in changes: if deal_id != payload.get(hubspot_utils.KEY_OBJECT_ID): # Ignore changes from other deals continue subscription_type = payload.get(hubspot_utils.KEY_SUBSCRIPTION_TYPE) if subscription_type in [ hubspot_utils.KEY_VALUE_DEAL_CREATED, hubspot_utils.KEY_VALUE_DEAL_DELETION, hubspot_utils.KEY_VALUE_DEAL_PROPERTY_CHANGE ]: if subscription_type != hubspot_utils.KEY_VALUE_DEAL_PROPERTY_CHANGE or not final_subscription_type: final_subscription_type = subscription_type if not deal_url: deal_url = 'https://app.hubspot.com/sales/{}/deal/{}/'.format( payload.get(hubspot_utils.KEY_PORTAL_ID), deal_id ) if deal_properties and subscription_type == hubspot_utils.KEY_VALUE_DEAL_PROPERTY_CHANGE: current_deal_property_name = payload.get(hubspot_utils.KEY_PROPERTY_NAME, '') if current_deal_property_name != hubspot_utils.KEY_DEALSTAGE: # Deal stage is already shown current_property_value = payload.get(hubspot_utils.KEY_PROPERTY_VALUE, '') display_property_label, display_property_value = hubspot_utils.clean_property( current_deal_property_name, current_property_value, deal_details, deal_property_details, deal_pipelines ) if current_deal_property_name: deal_property_changes.append( '*{}:* {}'.format( display_property_label, display_property_value ) ) if deal_url and final_subscription_type: current_deal_stage = deal_properties.get(hubspot_utils.KEY_DEALSTAGE, {})['value'] display_deal_stage_label, display_deal_stage_value = hubspot_utils.clean_property( hubspot_utils.KEY_DEALSTAGE, current_deal_stage, deal_details, deal_property_details, deal_pipelines ) slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_CHANNEL: SLACK_STAFF_HUBSPOT_CHANNEL, slack_utils.KEY_TEXT: '{} in HubSpot | <{}|View details>'.format( final_subscription_type == hubspot_utils.KEY_VALUE_DEAL_CREATED and 'New deal created' or ( 'Deal {}'.format(final_subscription_type == hubspot_utils.KEY_VALUE_DEAL_DELETION and 'deleted' or 'updated') ), deal_url ), slack_utils.KEY_ATTACHMENTS: [ { slack_utils.KEY_TITLE: deal_name, slack_utils.KEY_TITLE_LINK: deal_url, slack_utils.KEY_TEXT: '*Deal Stage:* {}{}'.format( display_deal_stage_value or 'Unknown', deal_property_changes and '\n\n{}'.format('\n'.join(deal_property_changes)) or '' ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_GREEN } ] } ) if event_ids: ExternalEvent.objects.filter(id__in=event_ids).update(notification_sent_at=datetime.datetime.utcnow())
def send_survey_summary_report_slack(event, client_report, pm_report, dev_report): event = clean_instance(event, ProgressEvent) client_report = clean_instance(client_report, ProgressReport) pm_report = clean_instance(pm_report, ProgressReport) dev_report = clean_instance(dev_report, ProgressReport) attachments = list() if not client_report: attachments.append({ slack_utils.KEY_TEXT: '`Client survey was not filled`', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED, }) if event.task.pm and not pm_report: attachments.append({ slack_utils.KEY_TEXT: '`PM Report was not filled`', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED, }) if event.task.active_participants and not dev_report: attachments.append({ slack_utils.KEY_TEXT: '`No Developer report was filled`', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED, }) if client_report or pm_report or dev_report: if client_report: summary_report = list() summary_report.append(dict( title='Was the last deadline met?:', client=client_report and (client_report.last_deadline_met and 'Yes' or 'No') or None, pm=pm_report and (pm_report.last_deadline_met and 'Yes' or 'No') or None, dev=dev_report and (dev_report.last_deadline_met and 'Yes' or 'No') or None, color=client_report.last_deadline_met and SLACK_ATTACHMENT_COLOR_GREEN or SLACK_ATTACHMENT_COLOR_RED )) if not client_report.last_deadline_met: summary_report.append(dict( title='Was the client informed about missing the deadline?:', client=(client_report.deadline_miss_communicated and 'Yes' or 'No') or None, pm=pm_report and (pm_report.deadline_miss_communicated and 'Yes' or 'No') or None, dev=dev_report and (dev_report.deadline_miss_communicated and 'Yes' or 'No') or None, color=client_report.deadline_miss_communicated and SLACK_ATTACHMENT_COLOR_GREEN or SLACK_ATTACHMENT_COLOR_RED )) if client_report.deliverable_satisfaction is not None: summary_report.append(dict( title='Are you satisfied with the deliverable?:', client=(client_report.deliverable_satisfaction and 'Yes' or 'No') or None, pm=None, dev=None, color=client_report.deliverable_satisfaction and SLACK_ATTACHMENT_COLOR_GREEN or SLACK_ATTACHMENT_COLOR_RED )) if client_report.rate_deliverables is not None: summary_report.append(dict( title='Deliverable rating:', client=client_report.rate_deliverables or None, pm=pm_report and pm_report.rate_deliverables or None, dev=dev_report and dev_report.rate_deliverables or None, color=(client_report.rate_deliverables > 3 and SLACK_ATTACHMENT_COLOR_GREEN) or ( client_report.rate_deliverables < 3 and SLACK_ATTACHMENT_COLOR_RED or SLACK_ATTACHMENT_COLOR_NEUTRAL) )) if pm_report or dev_report: summary_report.append(dict( title='Status:', client=None, pm=pm_report and pm_report.get_status_display() or None, dev=dev_report and dev_report.get_status_display() or None, color=SLACK_ATTACHMENT_COLOR_RED )) if (pm_report and pm_report.stuck_reason) or (dev_report and dev_report.stuck_reason): summary_report.append(dict( title='Stuck reason:', client=None, pm=pm_report and pm_report.get_stuck_reason_display() or None, dev=dev_report and dev_report.get_stuck_reason_display() or None, color=SLACK_ATTACHMENT_COLOR_BLUE )) for item in summary_report: client = item.get('client', None) pm = item.get('pm', None) dev = item.get('dev', None) attachments.append({ slack_utils.KEY_TITLE: item['title'], slack_utils.KEY_TEXT: '{} {} {}'.format( client and 'Client: {}'.format(client) or '', pm and '{}PM: {}{}'.format( client_report and '*|* ' or '', pm, dev_report and ' *|*' or '' ) or '{}'.format(dev_report and '*|*' or ''), dev and 'Dev: {}'.format(dev) or ''), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: item.get('color', SLACK_ATTACHMENT_COLOR_NEUTRAL) }) else: attachments.append({ slack_utils.KEY_TEXT: '`Insufficent data for creating a summary report`', slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_RED, }) attachments.append({ slack_utils.KEY_TITLE: 'Reports:', slack_utils.KEY_TEXT: '{}{}{}'.format( client_report and '<{}|Client Survey>'.format( '{}/work/{}/event/{}'.format(TUNGA_URL, event.task.id, client_report.event.id)) or '', pm_report and '{}<{}|PM Report>{}'.format(client_report and '\n' or '', '{}/work/{}/event/{}'.format(TUNGA_URL, event.task.id, pm_report.event.id), dev_report and '\n' or '') or '{}'.format( dev_report and '\n' or ''), dev_report and '<{}|Developer Report>'.format( '{}/work/{}/event/{}'.format(TUNGA_URL, event.task.id, dev_report.event.id)) or '', ), slack_utils.KEY_MRKDWN_IN: [slack_utils.KEY_TEXT], slack_utils.KEY_COLOR: SLACK_ATTACHMENT_COLOR_BLUE, }) owner = event.task.owner or event.task.user slack_utils.send_incoming_webhook( SLACK_STAFF_INCOMING_WEBHOOK, { slack_utils.KEY_TEXT: "*Summary Report:* <{}|{}>\nProject Owner: <{}|{}>{}".format( '{}/work/{}'.format(TUNGA_URL, event.task.id), event.task.summary, '{}/people/{}'.format(TUNGA_URL, owner.username), owner.display_name.encode('utf-8'), event.task.pm and '\nPM: <{}|{}>'.format('{}/people/{}'.format( TUNGA_URL, event.task.pm.username), event.task.pm.display_name.encode('utf-8') ) or '' ), slack_utils.KEY_CHANNEL: SLACK_STAFF_PROJECT_EXECUTION_CHANNEL, slack_utils.KEY_ATTACHMENTS: attachments } )