示例#1
0
class CampaignProperties(Resource):
    def __init__(self):
        super(Resource, self).__init__()
        self.campaign_table = DynamoTable('campaigns')
        self.donation_table = DynamoTable('donations')

    @swagger.operation(notes='Get the properties of a campaign by ID',
                       nickname='Get Campaign Details',
                       parameters=[{
                           "name": "campaign_id",
                           "description": "UUID of the campaign",
                           "required": True,
                           "allowMultiple": False,
                           "dataType": 'string',
                           "paramType": "path"
                       }])
    def get(self, campaign_id):
        """Get Campaign Details"""
        # Get the campaign
        data = {"campaign_id": campaign_id}
        item = None
        try:
            item = self.campaign_table.get_item(data)
        except IOError as e:
            abort(400, description=e.message)

        if not item:
            abort(404,
                  description="Campaign '{}' not found".format(campaign_id))

        item["donation_email"] = "{}@donatemates.com".format(
            item["campaign_id"])

        # Get donor amount stats
        amounts = self.donation_table.query_biggest("campaign_id",
                                                    campaign_id,
                                                    5,
                                                    index="DonationIndex")

        # Get donor time stats
        donors = self.donation_table.query_most_recent(
            "campaign_id",
            campaign_id,
            "donation_on",
            arrow.utcnow().isoformat(),
            limit=5)

        item["large_donors"] = [{
            "donor_name": x["donor_name"],
            "donation_cents": float(x["donation_cents"])
        } for x in amounts]
        item["recent_donors"] = [{
            "donor_name": x["donor_name"],
            "donation_cents": float(x["donation_cents"])
        } for x in donors]

        # Sum donors
        item[
            "donation_total_cents"] = self.donation_table.integer_sum_attribute(
                "campaign_id", campaign_id, "donation_cents")

        # Get charity information
        charity = next(c for (i, c) in enumerate(SUPPORTED_CHARITIES)
                       if c["id"] == item["charity_id"])

        item["donation_url"] = charity["donation_url"]
        item["charity_name"] = charity["conversational_name"]
        del item["secret_id"]

        item = clean_dynamo_response(item)

        return item, 200

    def put(self, campaign_id):
        abort(403, description="Missing Authorization Key")

    def post(self, campaign_id):
        abort(403, description="Missing Authorization Key")
示例#2
0
def process_email_handler(event, context):
    logger = logging.getLogger("boto3")
    logger.setLevel(logging.WARN)

    print("Received event: " + json.dumps(event, indent=2))

    # Check if S3 event or CloudWatch invocation. If just keeping things hot, exit.
    if "Records" in event:
        if "s3" in event["Records"][0]:
            key = event["Records"][0]["s3"]["object"]["key"]
            bucket = event["Records"][0]["s3"]["bucket"]["name"]
    else:
        print("Not an email. Move along...")
        return

    # Load message from S3
    s3 = boto3.resource('s3')
    email_obj = s3.Object(bucket, key)
    email_mime = email_obj.get()['Body'].read().decode('utf-8')

    # Detect Charity
    for sup_charity in SUPPORTED_CHARITIES:
        class_ = getattr(charity, sup_charity["class"])
        charity_class = class_(email_mime)

        # Detect charity
        if charity_class.is_receipt():
            # Found the charity

            # Get campaign ID and campaign data
            campaign_id = charity_class.get_campaign_id()
            print("CAMPAIGN ID: {}".format(campaign_id))
            campaign_table = DynamoTable('campaigns')
            campaign_key = {"campaign_id": campaign_id}
            campaign = campaign_table.get_item(campaign_key)

            if not campaign:
                print("WARNING: **** CAMPAIGN DOES NOT EXIST ****")
                dm_email = DonatematesEmail(charity_class.from_email)
                dm_email.send_campaign_does_not_exist()
                return True

            # Setup email sender
            dm_email = DonatematesEmail(charity_class.from_email,
                                        campaign["campaigner_email"])

            # Get donation receipt
            data = charity_class.parse_email()
            data["receipt_id"] = data["receipt_id"].strip()

            # Validate this is a new donation
            donation_table = DynamoTable('donations')
            existing_receipts = donation_table.query_hash("receipt_id",
                                                          data["receipt_id"],
                                                          index="ReceiptIndex",
                                                          limit=10)
            if existing_receipts:
                # This receipt already exists!
                print(
                    "WARNING: **** Duplicate receipt detected - Campaign: {} - Receipt: {} - Bucket: {} - Key: {} ****"
                    .format(campaign_id, data["receipt_id"], bucket, key))
                # Notify user we didn't process it
                dm_email.send_duplicate_receipt(campaign_id,
                                                data["receipt_id"], key)
                return True

            # Add donation record
            data["campaign_id"] = campaign_id
            data["donation_on"] = arrow.utcnow().isoformat()
            data["email_bucket"] = bucket
            data["email_key"] = key
            print("DONATION DATA:")
            print(data)
            store_donation(data)

            # Get updated total donation
            donation_total_cents = donation_table.integer_sum_attribute(
                "campaign_id", campaign_id, "donation_cents")

            # Notify the Donor
            if campaign["campaign_status"] == "cancelled":
                # If cancelled, only notify donor and let them know the campaign isn't going on.
                dm_email.send_campaign_cancelled()
            else:
                # Send standard confirmation to donor
                dm_email.send_donation_confirmation(data["donation_cents"])

            # Notify the campaigner if the campaign is active only
            if campaign["campaign_status"] == "active":
                # Update notification time (for future possible digest emails)
                campaign_table.update_attribute(campaign_key, "notified_on",
                                                arrow.utcnow().isoformat())

                if donation_total_cents >= campaign["match_cents"]:
                    # Update campaign status to "matched"
                    campaign_table.update_attribute(campaign_key,
                                                    "campaign_status",
                                                    "matched")

                    # Send campaign completion email!
                    dm_email.send_campaign_matched(data["donor_name"],
                                                   data["donation_cents"],
                                                   donation_total_cents,
                                                   campaign["match_cents"])
                else:
                    # Send normal update
                    dm_email.send_campaign_update(data["donor_name"],
                                                  data["donation_cents"],
                                                  donation_total_cents,
                                                  campaign["match_cents"])

            # Exit
            return True

    # If you get here, you didn't successfully parse the email or it was unsupported
    # Save email to error bucket
    s3.Object('parse-fail-donatemates', '{}'.format(
        shortuuid.uuid())).copy_from(CopySource='{}/{}'.format(bucket, key))

    # Reply to user
    print(
        "WARNING: **** Failed to detect a supported charity - Email Key: {} ****"
        .format(key))