def send_submission_slack(submission_pk: str): submission = Submission.objects.get(pk=submission_pk) text = get_text(submission) logging.info("Notifying Slack of Submission<%s>", submission_pk) send_slack_message(settings.SLACK_MESSAGE.CLIENT_INTAKE, text) # Mark request as sent Submission.objects.filter(pk=submission.pk).update(is_alert_sent=True)
def test_send_issue_slack(slug): """ Ensure send_issue_slack call Slack without anything exploding https://github.com/getsentry/responses """ # Set up API response. responses.add(method=responses.POST, url="https://example.com", status=200, json={}) # Not used # Prepare database channel = SlackChannel.objects.last() assert channel.webhook_url == "https://example.com" msg = SlackMessage.objects.select_related("channel").get(slug=slug) assert msg.channel == channel user_1 = SlackUser.objects.create(name="Alice", slack_id="1234") user_2 = SlackUser.objects.create(name="Bob", slack_id="5678") msg.users.add(user_1) msg.users.add(user_2) msg.save() # Send the message text = "This is a cool Slack message!" send_slack_message(msg.slug, text) # Check it worked! assert len(responses.calls) == 1 body_text = responses.calls[0].request.body.decode("utf-8") body_json = json.loads(body_text) assert body_json["text"] == ("Hi <@1234> and <@5678>.\n\n" "This is a cool Slack message!\n\n" ":heart: Client Bot :robot_face:")
def send_issue_slack(issue_pk: str): issue = Issue.objects.select_related("client").get(pk=issue_pk) text = get_text(issue) logging.info("Notifying Slack of Issue<%s>", issue_pk) send_slack_message(settings.SLACK_MESSAGE.CLIENT_INTAKE, text) # Mark request as sent Issue.objects.filter(pk=issue.pk).update(is_alert_sent=True)
def send_submission_failure_slack(sub_pk: str): logger.info("Sending failure Slack message for Submission[%s]", sub_pk) msg = ( "*Submission failed to process*\n" f"A new client intake submission ({sub_pk}) has failed to process.\n" f"The tech team needs to fix this manually\n" ) send_slack_message(settings.SLACK_MESSAGE.CLIENT_INTAKE, msg)
def send_webflow_contact_slack(webflow_contact_pk: str): webflow_contact = WebflowContact.objects.get(pk=webflow_contact_pk) text = get_text(webflow_contact) logging.info("Notifying Slack of WebflowContact<%s>", webflow_contact_pk) send_slack_message(settings.SLACK_MESSAGE.LANDING_FORM, text) # Mark request as sent WebflowContact.objects.filter(pk=webflow_contact.pk).update( is_alert_sent=True)
def send_weekly_report_slack(): """ Tell #general about our metrics. """ quarterly_text = get_report_text(90) annual_text = get_report_text(365) text = ( "*Monthly Metrics Report*\n" "This is an automated monthly report on some of our key metrics.\n\n" f"\tIn the last 90 days we saw:\n\n{quarterly_text}\n\n" f"\tIn the last 365 days we saw:\n\n{annual_text}\n\n" f"See more details at our submissions/outcomes <{PUBLIC_REPORTING_URL}|dashboard>." ) send_slack_message(settings.SLACK_MESSAGE.WEEKLY_REPORT, text)
def send_email_alert_slack(email_pk: str): """ Notify alerts channel of new unhandled email. """ logging.info("Sending alert for Email<%s>", email_pk) email = Email.objects.get(pk=email_pk) issue = email.issue assert issue, f"Email<{email_pk}> does not have an associated Issue" paralegal = issue.paralegal alert_sent = False case_email_url = settings.CLERK_BASE_URL + reverse( "case-email-list", args=(str(issue.pk),) ) case_url = settings.CLERK_BASE_URL + reverse( "case-detail-view", args=(str(issue.pk),) ) msg = ( "*New Email Notification*\n" f"A new email has been received for case <{case_url}|{issue.fileref}> .\n" f"You can view this case's emails here: <{case_email_url}|here>.\n" ) if paralegal and issue.is_open: # Send alert directly to paralegal for open issues. alert_email = settings.SLACK_EMAIL_ALERT_OVERRIDE or paralegal.email logging.info("Looking up %s in Slack", alert_email) slack_user = get_slack_user_by_email(alert_email) if slack_user: logging.info("Notifying %s of Email<%s> via Slack", alert_email, email_pk) send_slack_direct_message(msg, slack_user["id"]) alert_sent = True if not alert_sent: # In all other cases send to alerts channel. logging.info( "Could not find someone to DM in Slack, sending generic alert for Email<%s>", email_pk, ) send_slack_message(settings.SLACK_MESSAGE.CLIENT_INTAKE, msg) Email.objects.filter(pk=email_pk).update(is_alert_sent=True) logging.info("Alert sent sucessfully for Email<%s>", email_pk)
def _send_issue_actionstep(issue_pk: str): """ Send a issue to Actionstep. """ if not settings.ACTIONSTEP_WEB_URI: logger.info("Skipping sending Issue<%s]> to Actionstep: not set up.", issue_pk) return issue = Issue.objects.get(pk=issue_pk) logger.info("Sending Issue<%s]> to Actionstep", issue.id) api = ActionstepAPI() # Fetch new action owner. owner_email = settings.ACTIONSTEP_SETUP_OWNER owner_data = api.participants.get_by_email(owner_email) logger.info("Assigning Issue<%s]> to owner %s", issue_pk, owner_data["email"]) answers = issue.answers client = issue.client # Ensure participant is in the system. logger.info("Try to create participant %s, %s.", client.get_full_name(), client.email) participant_data, created = api.participants.get_or_create( client.first_name, client.last_name, client.email, client.phone_number) if created: logger.info("Created participant %s, %s.", client.get_full_name(), client.email) else: logger.info("Participant %s, %s already exists.", client.get_full_name(), client.email) # Check if this issue already has an action action_id = None issue_filenotes = api.filenotes.list_by_text_match(issue.pk) if issue_filenotes: action_id = max([int(fn["links"]["action"]) for fn in issue_filenotes]) else: action_id = None if action_id: # An matter has already been created for this issue logger.info("Found existing matter %s for %s", action_id, issue.pk) action_data = api.actions.get(action_id) fileref_name = action_data["reference"] logger.info("Existing matter has fileref %s", fileref_name) else: # We need to create a new matter file_ref_prefix = PREFIX_LOOKUP[issue.topic] fileref_name = api.actions.get_next_ref(file_ref_prefix) logger.info("Creating new matter %s for %s", fileref_name, client.get_full_name()) action_type_name = ACTION_TYPE_LOOKUP[issue.topic] action_type_data = api.actions.action_types.get_for_name( action_type_name) action_type_id = action_type_data["id"] action_data = api.actions.create( issue_id=issue.pk, action_type_id=action_type_id, action_name=client.get_full_name(), file_reference=fileref_name, participant_id=owner_data["id"], ) Issue.objects.filter(pk=issue_pk).update(fileref=fileref_name) action_id = action_data["id"] client_id = participant_data["id"] api.participants.set_action_participant(action_id, client_id, Participant.CLIENT) # Upload files. Note that multiple uploads will create copies. logger.info("Generating PDF for Issue<%s>", issue.id) pdf_bytes = create_pdf(issue) pdf_filename = f"client-intake-{issue_pk}.pdf" logger.info("Uploading PDF for Issue<%s>", issue.id) file_data = api.files.upload(pdf_filename, pdf_bytes) file_id = file_data["id"] folder_name = "Client" logger.info("Attaching PDF for Issue<%s>", issue.id) api.files.attach(pdf_filename, file_id, action_id, folder_name) logger.info("Setting up training materials for Actionstep action %s", action_id) topic_docs = ActionDocument.objects.filter(topic=issue.topic) for doc in topic_docs: name = doc.get_filename() logger.info("Attaching doc %s to Actionstep action %s", name, action_id) api.files.attach(name, doc.actionstep_id, action_id, doc.folder) logger.info("Marking Actionstep integration complete for Issue<%s>", issue.id) Issue.objects.filter(pk=issue.pk).update(is_case_sent=True) # Try send a Slack message logging.info("Notifying Slack of Actionstep integration for Issue<%s>", issue_pk) action_url = urljoin( settings.ACTIONSTEP_WEB_URI, f"/mym/asfw/workflow/action/overview/action_id/{action_id}", ) topic_title = issue.topic.title() text = f"{topic_title} issue has been uploaded to Actionstep as <{action_url}|{fileref_name}> ({issue.pk})" send_slack_message(settings.SLACK_MESSAGE.ACTIONSTEP_CREATE, text)
def _send_submission_actionstep(submission_pk: str): """ Send a submission to Actionstep. FIXME: add tests FIXME: Make it harder to sync the same data twice. """ submission = Submission.objects.get(pk=submission_pk) logger.info("Sending Submission<%s]> to Actionstep", submission.id) api = ActionstepAPI() # Fetch new action owner. owner_email = settings.ACTIONSTEP_SETUP_OWNERS[submission.topic] owner_data = api.participants.get_by_email(owner_email) logger.info("Assigning Submission<%s]> to owner %s", submission_pk, owner_data["email"]) # Pull client data out of the Submission answers JSON. # FIXME: This is pretty bad in that we depend on an schemaless JSON object that is set by the frontend. answers = {a["name"]: a["answer"] for a in submission.answers} client_name = answers["CLIENT_NAME"] client_phone = answers["CLIENT_PHONE"] client_email = answers["CLIENT_EMAIL"] client_firstname = client_name.split(" ")[0] client_lastname = client_name.split(" ")[-1] # Ensure participant is in the system. logger.info("Try to create participant %s, %s.", client_name, client_email) participant_data, created = api.participants.get_or_create( client_firstname, client_lastname, client_email, client_phone) if created: logger.info("Created participant %s, %s.", client_name, client_email) else: logger.info("Participant %s, %s already exists.", client_name, client_email) # Check if this submission already has an action action_id = None submission_filenotes = api.filenotes.get_by_text_match(submission.pk) # This can be a list or a dict >.< if type(submission_filenotes) is list: action_id = max( [int(fn["links"]["action"]) for fn in submission_filenotes]) elif type(submission_filenotes) is dict: action_id = int(submission_filenotes["links"]["action"]) if action_id: # An matter has already been created for this submission logger.info("Found existing matter %s for %s", action_id, submission.pk) action_data = api.actions.get(action_id) fileref_name = action_data["reference"] logger.info("Existing matter has fileref %s", fileref_name) else: # We need to create a new matter file_ref_prefix = PREFIX_LOOKUP[submission.topic] fileref_name = api.actions.get_next_ref(file_ref_prefix) logger.info("Creating new matter %s for %s", fileref_name, client_name) action_type_name = ACTION_TYPE_LOOKUP[submission.topic] action_type_data = api.actions.action_types.get_for_name( action_type_name) action_type_id = action_type_data["id"] action_data = api.actions.create( submission_id=submission.pk, action_type_id=action_type_id, action_name=client_name, file_reference=fileref_name, participant_id=owner_data["id"], ) action_id = action_data["id"] client_id = participant_data["id"] api.participants.set_action_participant(action_id, client_id, Participant.CLIENT) # Upload files. Note that multiple uploads will create copies. logger.info("Generating PDF for Submission<%s>", submission.id) pdf_bytes = create_pdf(submission) pdf_filename = f"client-intake-{submission_pk}.pdf" logger.info("Uploading PDF for Submission<%s>", submission.id) file_data = api.files.upload(pdf_filename, pdf_bytes) file_id = file_data["id"] folder_name = "Client" logger.info("Attaching PDF for Submission<%s>", submission.id) api.files.attach(pdf_filename, file_id, action_id, folder_name) logger.info("Setting up training materials for Actionstep action %s", action_id) topic_docs = ActionDocument.objects.filter(topic=submission.topic) for doc in topic_docs: name = doc.get_filename() logger.info("Attaching doc %s to Actionstep action %s", name, action_id) api.files.attach(name, doc.actionstep_id, action_id, doc.folder) logger.info("Marking Actionstep integration complete for Submission<%s>", submission.id) Submission.objects.filter(pk=submission.pk).update(is_case_sent=True) # Try send a Slack message logging.info( "Notifying Slack of Actionstep integration for Submission<%s>", submission_pk) action_url = urljoin( settings.ACTIONSTEP_WEB_URI, f"/mym/asfw/workflow/action/overview/action_id/{action_id}", ) text = ( f"Submission {submission.topic}: {submission.pk} has been uploaded to Actionstep with file reference {fileref_name}.\n" f"You can find the action at {action_url}") send_slack_message(settings.SLACK_MESSAGE.ACTIONSTEP_CREATE, text)