Merge pull request #97 from danieldupriest/implement-sending-email

Implement sending email using Joe's code
This commit is contained in:
ppdom 2019-02-23 14:07:48 -08:00 committed by GitHub
commit b58fff8888
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 15 deletions

4
back/.env Normal file
View file

@ -0,0 +1,4 @@
EMAIL_HOST_USER=accountemail@yourmail.com
EMAIL_HOST_PASSWORD=accountpasswordhere
SUBMIT_REPORT_DESTINATION_EMAIL=to-address@yourmail.com
SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com

View file

@ -12,6 +12,7 @@ djangorestframework = "==3.8.2"
django-rest-auth = "==0.9.3" django-rest-auth = "==0.9.3"
django-allauth = "==0.37.1" django-allauth = "==0.37.1"
gunicorn = "==19.6.0" gunicorn = "==19.6.0"
python-decouple = "==3.1"
[requires] [requires]
python_version = "3.5" python_version = "3.5"

15
back/Pipfile.lock generated
View file

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "b1fc6b06ec8daa4efd9573865bc6c1732ae9354309e036bfe3ce0ab76b1a3bcd" "sha256": "b8697c2d821e12f9f3e7bbad8a765782fc8a89df3f4260bc5f2b6f2e3d454510"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -39,11 +39,11 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8", "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade",
"sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3" "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.1.5" "version": "==2.1.7"
}, },
"django-allauth": { "django-allauth": {
"hashes": [ "hashes": [
@ -97,6 +97,13 @@
], ],
"version": "==3.0.1" "version": "==3.0.1"
}, },
"python-decouple": {
"hashes": [
"sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d"
],
"index": "pypi",
"version": "==3.1"
},
"python3-openid": { "python3-openid": {
"hashes": [ "hashes": [
"sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa", "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa",

View file

@ -114,8 +114,8 @@ def fare_limit_rule(report, fields):
planning_section.add_rule(title="Fare limits", rule=fare_limit_rule) planning_section.add_rule(title="Fare limits", rule=fare_limit_rule)
def lowest_fare_rule(report, fields): def lowest_fare_rule(report, fields):
diff = field['lowest_fare_duration'] - field['preferred_flight_duration'] diff = fields['lowest_fare_duration'] - fields['preferred_flight_duration']
lowest_Fare = field['lowest_fare'] lowest_fare = fields['lowest_fare']
maximum = 0 maximum = 0
if diff <= 0: if diff <= 0:
maximum = lowest_fare + 100 maximum = lowest_fare + 100
@ -127,14 +127,14 @@ def lowest_fare_rule(report, fields):
maximum = lowest_fare + 350 maximum = lowest_fare + 350
else: else:
maximum = lowest_fare + 600 maximum = lowest_fare + 600
if field['preferred_fare'] > maximum: if fields['preferred_fare'] > maximum:
return "For the lowest fare you have provided, your maximum in-policy fare amount is {} USD.".format(maximum) return "For the lowest fare you have provided, your maximum in-policy fare amount is {} USD.".format(maximum)
return None return None
planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule) planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule)
def departure_date_limit_rule(report, fields): def departure_date_limit_rule(report, fields):
days_to_departure = date(field['departure_date']) - date(field['screenshot_date']) days_to_departure = date(fields['departure_date']) - date(fields['screenshot_date'])
if days_to_departure < 14: if days_to_departure < 14:
return "Flights must be booked at least 14 days in advance." return "Flights must be booked at least 14 days in advance."
if days_to_departure > 365: if days_to_departure > 365:
@ -174,7 +174,7 @@ flight_section.add_rule(title="Fare limits", rule=actual_fare_limit_rule)
def request_date_rule(report, fields): def request_date_rule(report, fields):
now = date.today() now = date.today()
last_travel = date(field['return_date']) last_travel = date(fields['return_date'])
if now - last_travel > 90: if now - last_travel > 90:
return "Reimbursement requests must be made within 90 days of the last day of travel." return "Reimbursement requests must be made within 90 days of the last day of travel."
return None return None

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Title: {{ title }}</h1>
{% for section in sections %}
{% if section.completed %}
<h2>{{section.title}}</h2>
<table border="1">
{% for field in section.fields %}
<tr>
<td>{{field.label}}</td>
<td>{{field.value|default:""}}</td>
</tr>
{% endfor %}
{% for rule in section.rule_violations %}
<tr style="color:#ff3333">
<td colspan=2><strong>{{rule.label}}</strong><br/>{{rule.rule_break_text}}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endfor %}
</body>
</html>

View file

@ -0,0 +1,15 @@
***Deprecated:
Replaced by converting html template to plaintext
using the html2text library
***
Title: {{title}}
{% for section in sections %}
{{section.title}}
{% for field in section.fields %}
{{field.label}}: {{field.value|default:"empty"}}
{% endfor %}
{% for rule in section.rule_violations %}
[RULE] {{rule.label}}: {{rule.rule_break_text}}
{% endfor %}
{% endfor %}

View file

@ -3,6 +3,11 @@ from django.http import JsonResponse
from .models import * from .models import *
from .policy import pol from .policy import pol
import os import os
from rest_framework.exceptions import ParseError
from rest_framework.parsers import FileUploadParser, MultiPartParser
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from decouple import config
def get_report(report_pk): def get_report(report_pk):
""" """
@ -199,8 +204,8 @@ def report_detail(request, report_pk):
return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409) return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409)
rep.submitted = True; rep.submitted = True;
rep.save() rep.save()
# Send email here # Send email
################# send_report_to_admin(request, report_pk)
return JsonResponse({"message": "Report submitted."}) return JsonResponse({"message": "Report submitted."})
# DELETE: Deletes a report from the user's account. # DELETE: Deletes a report from the user's account.
@ -365,3 +370,46 @@ def section_complete(section_pk):
if i.completed: if i.completed:
return True return True
return False return False
def send_report_to_admin(request, report_pk):
"""
Sends an email message to admin with html/txt version of report,
along with file attachments. Cc sent to user.
request -- Request object with user info inside
report_pk -- ID of the report to submit
"""
params = get_report(report_pk)
to_email = config('SUBMIT_REPORT_DESTINATION_EMAIL')
from_email = config('SUBMIT_REPORT_FROM_EMAIL')
cc = request.user.email
msg_html = render_to_string('backend/email.html', params)
msg_plain = render_to_string('backend/email.txt', params)
message = EmailMultiAlternatives(
"Reimbursinator - {}".format(params['title']),
msg_plain,
from_email,
[to_email],
cc=[request.user.email],
)
message.attach_alternative(msg_html, "text/html")
for f in get_files(report_pk):
message.attach_file(f)
message.send()
def get_files(report_pk):
"""
collects all the files in a particular report and returns them
in an array.
report_pk -- ID of the report to collect files for
"""
sections = Section.objects.filter(report_id=report_pk)
files = []
for section in sections:
fields = Field.objects.filter(section_id=section.id, completed=True)
for field in fields:
if field.field_type == "file":
print("appending {}".format(field.data_file.name))
files.append(field.data_file.name)
return files

Binary file not shown.

View file

@ -11,12 +11,11 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
""" """
import os import os
#from reimbursinator.custom_auth import BearerAuthentication from decouple import config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
@ -28,7 +27,6 @@ DEBUG = True
ALLOWED_HOSTS = ['localhost','192.168.99.100', '127.0.0.1'] ALLOWED_HOSTS = ['localhost','192.168.99.100', '127.0.0.1']
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@ -157,7 +155,12 @@ STATIC_URL = 'https://192.168.99.100:8445/'
# Email Config # Email Config
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
EMAIL_PORT = 587
SITE_ID = 1 SITE_ID = 1