diff --git a/back/.env b/back/.env
new file mode 100644
index 0000000..b47f7a4
--- /dev/null
+++ b/back/.env
@@ -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
diff --git a/back/Pipfile b/back/Pipfile
index c985465..5ad300d 100644
--- a/back/Pipfile
+++ b/back/Pipfile
@@ -12,6 +12,7 @@ djangorestframework = "==3.8.2"
django-rest-auth = "==0.9.3"
django-allauth = "==0.37.1"
gunicorn = "==19.6.0"
+python-decouple = "==3.1"
[requires]
python_version = "3.5"
diff --git a/back/Pipfile.lock b/back/Pipfile.lock
index a6ed173..eb9c181 100644
--- a/back/Pipfile.lock
+++ b/back/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "b1fc6b06ec8daa4efd9573865bc6c1732ae9354309e036bfe3ce0ab76b1a3bcd"
+ "sha256": "b8697c2d821e12f9f3e7bbad8a765782fc8a89df3f4260bc5f2b6f2e3d454510"
},
"pipfile-spec": 6,
"requires": {
@@ -39,11 +39,11 @@
},
"django": {
"hashes": [
- "sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8",
- "sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3"
+ "sha256:275bec66fd2588dd517ada59b8bfb23d4a9abc5a362349139ddda3c7ff6f5ade",
+ "sha256:939652e9d34d7d53d74d5d8ef82a19e5f8bb2de75618f7e5360691b6e9667963"
],
"index": "pypi",
- "version": "==2.1.5"
+ "version": "==2.1.7"
},
"django-allauth": {
"hashes": [
@@ -97,6 +97,13 @@
],
"version": "==3.0.1"
},
+ "python-decouple": {
+ "hashes": [
+ "sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d"
+ ],
+ "index": "pypi",
+ "version": "==3.1"
+ },
"python3-openid": {
"hashes": [
"sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa",
diff --git a/back/backend/policy.py b/back/backend/policy.py
index 6366018..41f8b73 100644
--- a/back/backend/policy.py
+++ b/back/backend/policy.py
@@ -114,8 +114,8 @@ def fare_limit_rule(report, fields):
planning_section.add_rule(title="Fare limits", rule=fare_limit_rule)
def lowest_fare_rule(report, fields):
- diff = field['lowest_fare_duration'] - field['preferred_flight_duration']
- lowest_Fare = field['lowest_fare']
+ diff = fields['lowest_fare_duration'] - fields['preferred_flight_duration']
+ lowest_fare = fields['lowest_fare']
maximum = 0
if diff <= 0:
maximum = lowest_fare + 100
@@ -127,14 +127,14 @@ def lowest_fare_rule(report, fields):
maximum = lowest_fare + 350
else:
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 None
planning_section.add_rule(title="Lowest fare check", rule=lowest_fare_rule)
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:
return "Flights must be booked at least 14 days in advance."
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):
now = date.today()
- last_travel = date(field['return_date'])
+ last_travel = date(fields['return_date'])
if now - last_travel > 90:
return "Reimbursement requests must be made within 90 days of the last day of travel."
return None
diff --git a/back/backend/templates/backend/email.html b/back/backend/templates/backend/email.html
new file mode 100644
index 0000000..b985302
--- /dev/null
+++ b/back/backend/templates/backend/email.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Title: {{ title }}
+ {% for section in sections %}
+ {% if section.completed %}
+ {{section.title}}
+
+ {% for field in section.fields %}
+
+ {{field.label}} |
+ {{field.value|default:""}} |
+
+ {% endfor %}
+ {% for rule in section.rule_violations %}
+
+ {{rule.label}} {{rule.rule_break_text}} |
+
+ {% endfor %}
+
+ {% endif %}
+ {% endfor %}
+
+
diff --git a/back/backend/templates/backend/email.txt b/back/backend/templates/backend/email.txt
new file mode 100644
index 0000000..43f9df7
--- /dev/null
+++ b/back/backend/templates/backend/email.txt
@@ -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 %}
diff --git a/back/backend/views.py b/back/backend/views.py
index 376bee7..1d55aec 100644
--- a/back/backend/views.py
+++ b/back/backend/views.py
@@ -3,6 +3,11 @@ from django.http import JsonResponse
from .models import *
from .policy import pol
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):
"""
@@ -199,8 +204,8 @@ def report_detail(request, report_pk):
return JsonResponse({"message": "Cannot submit a report that has already been submitted."}, status=409)
rep.submitted = True;
rep.save()
- # Send email here
- #################
+ # Send email
+ send_report_to_admin(request, report_pk)
return JsonResponse({"message": "Report submitted."})
# DELETE: Deletes a report from the user's account.
@@ -365,3 +370,46 @@ def section_complete(section_pk):
if i.completed:
return True
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
diff --git a/back/db.sqlite3 b/back/db.sqlite3
index b0936b9..e1d4159 100644
Binary files a/back/db.sqlite3 and b/back/db.sqlite3 differ
diff --git a/back/reimbursinator/settings.py b/back/reimbursinator/settings.py
index c306f32..5b074f3 100644
--- a/back/reimbursinator/settings.py
+++ b/back/reimbursinator/settings.py
@@ -11,12 +11,11 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
"""
import os
-#from reimbursinator.custom_auth import BearerAuthentication
+from decouple import config
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
# Quick-start development settings - unsuitable for production
# 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']
-
# Application definition
INSTALLED_APPS = [
@@ -157,7 +155,12 @@ STATIC_URL = 'https://192.168.99.100:8445/'
# 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