From 99905562e79fe86c5a851e075f2d535da3964be4 Mon Sep 17 00:00:00 2001 From: mrsaicharan1 Date: Sat, 18 May 2019 19:28:33 +0530 Subject: [PATCH] Attached tickets+invoice to mail hound fixes --- app/api/helpers/mail.py | 14 +++++++----- app/api/helpers/system_mails.py | 2 +- app/api/helpers/tasks.py | 38 ++++++++++++++++++++++----------- app/api/orders.py | 34 +++++++++++++++++++++++++---- requirements/common.txt | 1 + 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/app/api/helpers/mail.py b/app/api/helpers/mail.py index 1ba0835982..80daea666b 100644 --- a/app/api/helpers/mail.py +++ b/app/api/helpers/mail.py @@ -15,7 +15,7 @@ from app.models.user import User -def send_email(to, action, subject, html): +def send_email(to, action, subject, html, attachments=None): """ Sends email and records it in DB """ @@ -30,7 +30,8 @@ def send_email(to, action, subject, html): 'to': to, 'from': email_from, 'subject': subject, - 'html': html + 'html': html, + 'attachments': attachments } if not current_app.config['TESTING']: @@ -278,7 +279,8 @@ def send_email_change_user_email(user, email): send_email_with_action(email, USER_CHANGE_EMAIL, email=email, new_email=user.email) -def send_email_to_attendees(order, purchaser_id): +def send_email_to_attendees(order, purchaser_id, attachments=None): + for holder in order.ticket_holders: if holder.user and holder.user.id == purchaser_id: # Ticket holder is the purchaser @@ -292,7 +294,8 @@ def send_email_to_attendees(order, purchaser_id): html=MAILS[TICKET_PURCHASED]['message'].format( pdf_url=holder.pdf_url, event_name=order.event.name - ) + ), + attachments=attachments ) else: # The Ticket holder is not the purchaser @@ -306,7 +309,8 @@ def send_email_to_attendees(order, purchaser_id): html=MAILS[TICKET_PURCHASED_ATTENDEE]['message'].format( pdf_url=holder.pdf_url, event_name=order.event.name - ) + ), + attachments=attachments ) diff --git a/app/api/helpers/system_mails.py b/app/api/helpers/system_mails.py index 3ea3b154c5..8a6d80a50b 100644 --- a/app/api/helpers/system_mails.py +++ b/app/api/helpers/system_mails.py @@ -145,7 +145,7 @@ 'message': ( u"Hi, this is a confirmation mail of your tickets for the event {event_name}" u"
Your order has been processed successfully." + - u"
Click here to view/download your invoice." + u"
You can find your Tickets and Order Invoice attached to this mail." u"

Looking forward to seeing you at the event." u"
Login to manage your orders at https://eventyay.com
" ) diff --git a/app/api/helpers/tasks.py b/app/api/helpers/tasks.py index 3ddcf9b703..002a581dad 100644 --- a/app/api/helpers/tasks.py +++ b/app/api/helpers/tasks.py @@ -6,6 +6,11 @@ from flask import current_app, render_template from marrow.mailer import Mailer, Message +from app import get_settings +from sendgrid import SendGridAPIClient +from sendgrid.helpers.mail import ( + Mail, Attachment, FileContent, FileName, + FileType, Disposition) from app import make_celery from app.api.helpers.utilities import strip_tags @@ -41,25 +46,33 @@ from app.api.helpers.db import save_to_db from app.api.helpers.files import create_save_pdf import urllib.error +import base64 celery = make_celery() @celery.task(name='send.email.post') def send_email_task(payload, headers): - data = {"personalizations": [{"to": []}]} - data["personalizations"][0]["to"].append({"email": payload["to"]}) - data["from"] = {"email": payload["from"]} - data["subject"] = payload["subject"] - data["content"] = [{"type": "text/html", "value": payload["html"]}] - logging.info('Sending an email regarding {} on behalf of {}'.format(data["subject"], data["from"])) + message = Mail(from_email=payload['from'], + to_emails=payload['to'], + subject=payload['subject'], + html_content=payload["html"]) + if payload['attachments'] is not None: + for attachment in payload['attachments']: + with open(attachment, 'rb') as f: + file_data = f.read() + f.close() + encoded = base64.b64encode(file_data).decode() + attachment = Attachment() + attachment.file_content = FileContent(encoded) + attachment.file_type = FileType('application/pdf') + attachment.file_name = FileName(payload['to']) + attachment.disposition = Disposition('attachment') + message.add_attachment(attachment) + sendgrid_client = SendGridAPIClient(get_settings()['sendgrid_key']) + logging.info('Sending an email regarding {} on behalf of {}'.format(payload["subject"], payload["from"])) try: - requests.post( - "https://api.sendgrid.com/v3/mail/send", - data=json.dumps(data), - headers=headers, - verify=False # doesn't work with verification in celery context - ) + sendgrid_client.send(message) logging.info('Email sent successfully') except Exception: logging.exception('Error occured while sending the email') @@ -84,6 +97,7 @@ def send_mail_via_smtp_task(config, payload): message.subject = payload['subject'] message.plain = strip_tags(payload['html']) message.rich = payload['html'] + message.attach(name=payload['attachments']) mailer.send(message) logging.info('Message sent via SMTP') mailer.stop() diff --git a/app/api/orders.py b/app/api/orders.py index bcfafa0b80..096fd2285b 100644 --- a/app/api/orders.py +++ b/app/api/orders.py @@ -10,6 +10,7 @@ from app.api.bootstrap import api from app.api.data_layers.ChargesLayer import ChargesLayer from app.api.helpers.db import save_to_db, safe_query, safe_query_without_soft_deleted_entries +from app.api.helpers.storage import generate_hash, UPLOAD_PATHS from app.api.helpers.errors import BadRequestError from app.api.helpers.exceptions import ForbiddenException, UnprocessableEntity, ConflictException from app.api.helpers.files import make_frontend_url @@ -139,10 +140,22 @@ def after_create_object(self, order, data, view_kwargs): # send e-mail and notifications if the order status is completed if order.status == 'completed': + # fetch tickets attachment + order_identifier = order.identifier + + key = UPLOAD_PATHS['pdf']['ticket_attendee'].format(identifier=order_identifier) + ticket_path = 'generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' + + key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) + invoice_path = 'generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' + + # send email and notifications. + send_email_to_attendees(order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path]) + + send_notif_to_attendees(order, current_user.id) + if order.payment_mode in ['free', 'bank', 'cheque', 'onsite']: order.completed_at = datetime.utcnow() - send_email_to_attendees(order, current_user.id) - send_notif_to_attendees(order, current_user.id) order_url = make_frontend_url(path='/orders/{identifier}'.format(identifier=order.identifier)) for organizer in order.event.organizers: @@ -310,10 +323,23 @@ def after_update_object(self, order, data, view_kwargs): delete_related_attendees_for_order(order) elif order.status == 'completed': + + # Send email to attendees with invoices and tickets attached + order_identifier = order.identifier + + key = UPLOAD_PATHS['pdf']['ticket_attendee'].format(identifier=order_identifier) + ticket_path = 'generated/tickets/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' + + key = UPLOAD_PATHS['pdf']['order'].format(identifier=order_identifier) + invoice_path = 'generated/invoices/{}/{}/'.format(key, generate_hash(key)) + order_identifier + '.pdf' + + # send email and notifications. + send_email_to_attendees(order=order, purchaser_id=current_user.id, attachments=[ticket_path, invoice_path]) + + send_notif_to_attendees(order, current_user.id) + if order.payment_mode in ['free', 'bank', 'cheque', 'onsite']: order.completed_at = datetime.utcnow() - send_email_to_attendees(order, current_user.id) - send_notif_to_attendees(order, current_user.id) order_url = make_frontend_url(path='/orders/{identifier}'.format(identifier=order.identifier)) for organizer in order.event.organizers: diff --git a/requirements/common.txt b/requirements/common.txt index 4814154381..d8863a27e9 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -17,6 +17,7 @@ celery>=3.1.23,<4 redis>=2.10.5,<3 apscheduler>=3.3.0,<4 pillow +sendgrid>=6.0.5 amqp<2.0,>=1.4.9 gunicorn>=19.6.0,<20 boto>=2.45.0,<3