<commit_before>import json
import hashlib
import logging
import smtplib
from collections import defaultdict
from config import (
    BUSINESS_MEMBER_RECIPIENT,
    DEFAULT_MAIL_SENDER,
    ENABLE_SLACK,
    MAIL_PASSWORD,
    MAIL_PORT,
    MAIL_SERVER,
    MAIL_USERNAME,
    MULTIPLE_ACCOUNT_WARNING_MAIL_RECIPIENT,
    SLACK_API_KEY,
    SLACK_CHANNEL,
)

import requests

from npsp import SalesforceConnection, SalesforceException


def construct_slack_message(contact=None, opportunity=None, rdo=None, account=None):
    reason = ""
    if rdo and opportunity:
        raise SalesforceException("rdo and opportunity can't both be specified")

    if account:
        amount = rdo.amount or opportunity.amount
        message = f"*{account.name}* became a business member at the *${amount}* level."
    elif opportunity:
        if opportunity.encouraged_by:
            reason = f" (encouraged by {opportunity.encouraged_by})"
        message = f"*{contact.name}* ({contact.email}) pledged *${opportunity.amount}*{reason}"
    elif rdo:
        if rdo.encouraged_by:
            reason = f" (encouraged by {rdo.encouraged_by})"
        message = f"*{contact.name}* ({contact.email}) pledged *${rdo.amount}*{reason} [{rdo.installment_period}]"

    logging.info(message)

    return message


def notify_slack(contact=None, opportunity=None, rdo=None, account=None):
    """
    Send a notification about a donation to Slack.
    """

    if rdo and opportunity:
        raise SalesforceException("rdo and opportunity can't both be specified")
    name = account.name if account else contact.name
    source = rdo.lead_source if rdo else opportunity.lead_source
    amount = rdo.amount if rdo else opportunity.amount
    period = rdo.installment_period if rdo else "Single"
    donation_type = rdo.record_type_name if rdo else opportunity.record_type_name

    if rdo and rdo.encouraged_by:
        reason = rdo.encouraged_by
    elif opportunity and opportunity.encouraged_by:
        reason = opportunity.encouraged_by
    else:
        reason = None

    attachment = construct_slack_attachment(
        email=contact.email,
        donor=name,
        source=source,
        amount=amount,
        period=period,
        donation_type=donation_type,
        reason=reason,
    )
    message = {
        "channel": SLACK_CHANNEL,
        "attachments": json.dumps([attachment]),
        "icon_emoji": ":moneybag:",
    }
    send_slack_message(message=message)

    # text = construct_slack_message(
    #     contact=contact, opportunity=opportunity, rdo=rdo, account=account
    # )
    # message = {
    #     "text": text,
    #     "channel": SLACK_CHANNEL,
    #     "username": opportunity.lead_source,
    #     "icon_emoji": ":moneybag:",
    # }

    # send_slack_message(message)


def send_slack_message(message=None, username="moneybot"):

    if not ENABLE_SLACK or not message:
        return
    message["token"] = SLACK_API_KEY
    message["username"] = username
    url = "https://slack.com/api/chat.postMessage"
    try:
        response = requests.post(url, params=message)
        slack_response = json.loads(response.text)
        if not slack_response["ok"]:
            raise Exception(slack_response["error"])
    except Exception as e:
        logging.error(f"Failed to send Slack notification: {e}")


def construct_slack_attachment(
    email=None,
    donor=None,
    source=None,
    amount=None,
    period=None,
    donation_type=None,
    reason=None,
):

    grav_hash = hashlib.md5(email.lower().encode("utf-8")).hexdigest()

    attachment = {
        "fallback": "Donation",
        "color": "good",
        # "pretext": "optional and appears above attachment"
        # # "text": "text",
        "author_name": donor,
        # author_link
        "author_icon": f"https://www.gravatar.com/avatar/{grav_hash}?s=16&r=g&default=robohash",
        "title": email,
        # "title_link":
        # "text": reason,
        # title_link
        "fields": [
            {"title": "Source", "value": source, "short": True},
            {"title": "Amount", "value": f"${amount}", "short": True},
            {"title": "Period", "value": period, "short": True},
            {"title": "Type", "value": donation_type, "short": True},
        ],
        # "image_url":
        # "thumb_url":
        # "footer":
        # "footer_icon":
        # "ts":
    }

    return attachment<commit_msg>fix donation type and reason notification<commit_after>import json
import hashlib
import logging
import smtplib
from collections import defaultdict
from config import (
    BUSINESS_MEMBER_RECIPIENT,
    DEFAULT_MAIL_SENDER,
    ENABLE_SLACK,
    MAIL_PASSWORD,
    MAIL_PORT,
    MAIL_SERVER,
    MAIL_USERNAME,
    MULTIPLE_ACCOUNT_WARNING_MAIL_RECIPIENT,
    SLACK_API_KEY,
    SLACK_CHANNEL,
)

import requests

from npsp import SalesforceConnection, SalesforceException, DEFAULT_RDO_TYPE


def construct_slack_message(contact=None, opportunity=None, rdo=None, account=None):
    reason = ""
    if rdo and opportunity:
        raise SalesforceException("rdo and opportunity can't both be specified")

    if account:
        amount = rdo.amount or opportunity.amount
        message = f"*{account.name}* became a business member at the *${amount}* level."
    elif opportunity:
        if opportunity.encouraged_by:
            reason = f" (encouraged by {opportunity.encouraged_by})"
        message = f"*{contact.name}* ({contact.email}) pledged *${opportunity.amount}*{reason}"
    elif rdo:
        if rdo.encouraged_by:
            reason = f" (encouraged by {rdo.encouraged_by})"
        message = f"*{contact.name}* ({contact.email}) pledged *${rdo.amount}*{reason} [{rdo.installment_period}]"

    logging.info(message)

    return message


def notify_slack(contact=None, opportunity=None, rdo=None, account=None):
    """
    Send a notification about a donation to Slack.
    """

    if rdo and opportunity:
        raise SalesforceException("rdo and opportunity can't both be specified")
    name = account.name if account else contact.name
    source = rdo.lead_source if rdo else opportunity.lead_source
    amount = rdo.amount if rdo else opportunity.amount
    period = rdo.installment_period if rdo else "single"
    donation_type = rdo.type if rdo else opportunity.record_type_name
    if donation_type == "Recurring Donation":
        donation_type = DEFAULT_RDO_TYPE

    if rdo and rdo.encouraged_by:
        reason = rdo.encouraged_by
    elif opportunity and opportunity.encouraged_by:
        reason = opportunity.encouraged_by
    else:
        reason = None

    attachment = construct_slack_attachment(
        email=contact.email,
        donor=name,
        source=source,
        amount=amount,
        period=period,
        donation_type=donation_type,
        reason=reason,
    )
    message = {
        "channel": SLACK_CHANNEL,
        "attachments": json.dumps([attachment]),
        "icon_emoji": ":moneybag:",
    }
    send_slack_message(message=message)

    # text = construct_slack_message(
    #     contact=contact, opportunity=opportunity, rdo=rdo, account=account
    # )
    # message = {
    #     "text": text,
    #     "channel": SLACK_CHANNEL,
    #     "username": opportunity.lead_source,
    #     "icon_emoji": ":moneybag:",
    # }

    # send_slack_message(message)


def send_slack_message(message=None, username="moneybot"):

    if not ENABLE_SLACK or not message:
        return
    message["token"] = SLACK_API_KEY
    message["username"] = username
    url = "https://slack.com/api/chat.postMessage"
    try:
        response = requests.post(url, params=message)
        slack_response = json.loads(response.text)
        if not slack_response["ok"]:
            raise Exception(slack_response["error"])
    except Exception as e:
        logging.error(f"Failed to send Slack notification: {e}")


def construct_slack_attachment(
    email=None,
    donor=None,
    source=None,
    amount=None,
    period=None,
    donation_type=None,
    reason=None,
):

    grav_hash = hashlib.md5(email.lower().encode("utf-8")).hexdigest()

    attachment = {
        "fallback": "Donation",
        "color": "good",
        # "pretext": "optional and appears above attachment"
        # # "text": "text",
        "author_name": donor,
        # author_link
        "author_icon": f"https://www.gravatar.com/avatar/{grav_hash}?s=16&r=g&default=robohash",
        "title": email,
        # "title_link":
        # "text": reason,
        # title_link
        "fields": [
            {"title": "Source", "value": source, "short": True},
            {"title": "Amount", "value": f"${amount}", "short": True},
            {"title": "Period", "value": period, "short": True},
            {"title": "Type", "value": donation_type, "short": True},
        ],
        # "image_url":
        # "thumb_url":
        # "footer":
        # "footer_icon":
        # "ts":
    }
    if reason:
        attachment["text"] = reason

    return attachment
{'fraction_non_alphanumeric': 0.11735372340425532, 'fraction_numerical': 0.0008865248226950354, 'mean_word_length': 2.8700686106346485, 'pattern_counts': {'":': 73, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1899164', 'n_tokens_mistral': 2829, 'n_tokens_neox': 2756, 'n_words': 625}