diff --git a/.gitignore b/.gitignore index d25063b..40497c7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # Edit at https://www.gitignore.io/?templates=linux,macos,python,django,windows,pycharm,intellij,visualstudio ### Django ### +*.env *.log *.pot *.pyc diff --git a/back/.env b/back/.env index b47f7a4..3b79ce5 100644 --- a/back/.env +++ b/back/.env @@ -1,4 +1,4 @@ -EMAIL_HOST_USER=accountemail@yourmail.com -EMAIL_HOST_PASSWORD=accountpasswordhere -SUBMIT_REPORT_DESTINATION_EMAIL=to-address@yourmail.com +EMAIL_HOST_USER=accountemail@youremail.com +EMAIL_HOST_PASSWORD=yourpassword +SUBMIT_REPORT_DESTINATION_EMAIL=administratoremail@yourmail.com SUBMIT_REPORT_FROM_EMAIL=from-address@yourmail.com diff --git a/back/backend/migrations/0001_initial.py b/back/backend/migrations/0001_initial.py index 2f2b805..d36efaa 100644 --- a/back/backend/migrations/0001_initial.py +++ b/back/backend/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 2.1.5 on 2019-02-01 00:21 +# Generated by Django 2.1.7 on 2019-03-03 09:06 +import datetime from django.db import migrations, models import django.db.models.deletion @@ -16,16 +17,17 @@ class Migration(migrations.Migration): name='Field', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('field_name', models.CharField(default='field', max_length=512)), ('label', models.CharField(max_length=512)), - ('number', models.IntegerField()), - ('type', models.CharField(max_length=128)), + ('number', models.IntegerField(default=0)), + ('field_type', models.CharField(max_length=128)), ('completed', models.BooleanField(default=False)), ('data_bool', models.BooleanField(default=False)), - ('data_decimal', models.DecimalField(blank=True, decimal_places=2, max_digits=9, null=True)), + ('data_decimal', models.DecimalField(decimal_places=2, default=0, max_digits=9)), ('data_date', models.DateField(blank=True, null=True)), ('data_file', models.FileField(blank=True, max_length=512, null=True, upload_to='uploads/%Y/%m/%d/')), - ('data_string', models.TextField(default='')), - ('data_integer', models.IntegerField(blank=True, null=True)), + ('data_string', models.TextField(blank=True, default='')), + ('data_integer', models.IntegerField(blank=True, default=0)), ], ), migrations.CreateModel( @@ -33,21 +35,23 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=128)), - ('date_created', models.DateTimeField(verbose_name='date created')), - ('date_submitted', models.DateTimeField(blank=True, null=True, verbose_name='date submitted')), + ('date_created', models.DateTimeField(default=datetime.date.today, verbose_name='date created')), + ('date_submitted', models.DateTimeField(default=datetime.date.today, verbose_name='date submitted')), ('submitted', models.BooleanField(default=False)), + ('reference_number', models.CharField(default='', max_length=32)), ], ), migrations.CreateModel( name='Section', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('auto_submit', models.BooleanField()), - ('required', models.BooleanField()), - ('completed', models.BooleanField()), + ('auto_submit', models.BooleanField(default=False)), + ('required', models.BooleanField(default=False)), + ('completed', models.BooleanField(default=False)), ('title', models.CharField(max_length=256)), ('html_description', models.TextField()), ('number', models.IntegerField()), + ('approved', models.BooleanField(default=False)), ('report_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='backend.Report')), ], ), diff --git a/back/backend/migrations/0002_auto_20190131_1621.py b/back/backend/migrations/0002_auto_20190303_0106.py similarity index 93% rename from back/backend/migrations/0002_auto_20190131_1621.py rename to back/backend/migrations/0002_auto_20190303_0106.py index 1eca0d4..46bbace 100644 --- a/back/backend/migrations/0002_auto_20190131_1621.py +++ b/back/backend/migrations/0002_auto_20190303_0106.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.5 on 2019-02-01 00:21 +# Generated by Django 2.1.7 on 2019-03-03 09:06 from django.conf import settings from django.db import migrations, models @@ -10,8 +10,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('backend', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ diff --git a/back/backend/migrations/0003_auto_20190131_1637.py b/back/backend/migrations/0003_auto_20190131_1637.py deleted file mode 100644 index f01f12b..0000000 --- a/back/backend/migrations/0003_auto_20190131_1637.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-01 00:37 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0002_auto_20190131_1621'), - ] - - operations = [ - migrations.AlterField( - model_name='field', - name='data_date', - field=models.DateField(default=datetime.date.today, verbose_name='date'), - ), - migrations.AlterField( - model_name='field', - name='data_integer', - field=models.IntegerField(blank=True, default=0), - ), - migrations.AlterField( - model_name='field', - name='data_string', - field=models.TextField(blank=True, default=''), - ), - migrations.AlterField( - model_name='report', - name='date_created', - field=models.DateTimeField(default=datetime.date.today, verbose_name='date created'), - ), - migrations.AlterField( - model_name='report', - name='date_submitted', - field=models.DateTimeField(default=datetime.date.today, verbose_name='date submitted'), - ), - ] diff --git a/back/backend/migrations/0004_auto_20190131_1645.py b/back/backend/migrations/0004_auto_20190131_1645.py deleted file mode 100644 index e04e02e..0000000 --- a/back/backend/migrations/0004_auto_20190131_1645.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-01 00:45 - -import datetime -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0003_auto_20190131_1637'), - ] - - operations = [ - migrations.AlterField( - model_name='field', - name='data_date', - field=models.DateField(default=datetime.date.today), - ), - ] diff --git a/back/backend/migrations/0005_field_field_name.py b/back/backend/migrations/0005_field_field_name.py deleted file mode 100644 index caf25f5..0000000 --- a/back/backend/migrations/0005_field_field_name.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-07 22:02 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0004_auto_20190131_1645'), - ] - - operations = [ - migrations.AddField( - model_name='field', - name='field_name', - field=models.CharField(default='field', max_length=512), - ), - ] diff --git a/back/backend/migrations/0006_auto_20190213_1719.py b/back/backend/migrations/0006_auto_20190213_1719.py deleted file mode 100644 index a7780de..0000000 --- a/back/backend/migrations/0006_auto_20190213_1719.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-14 01:19 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0005_field_field_name'), - ] - - operations = [ - migrations.RenameField( - model_name='field', - old_name='type', - new_name='field_type', - ), - ] diff --git a/back/backend/migrations/0006_auto_20190213_2113.py b/back/backend/migrations/0006_auto_20190213_2113.py deleted file mode 100644 index f472fa1..0000000 --- a/back/backend/migrations/0006_auto_20190213_2113.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-14 05:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0005_field_field_name'), - ] - - operations = [ - migrations.AlterField( - model_name='field', - name='data_date', - field=models.DateField(blank=True, null=True), - ), - ] diff --git a/back/backend/migrations/0007_merge_20190213_2318.py b/back/backend/migrations/0007_merge_20190213_2318.py deleted file mode 100644 index aa0cb2c..0000000 --- a/back/backend/migrations/0007_merge_20190213_2318.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-14 07:18 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0006_auto_20190213_1719'), - ('backend', '0006_auto_20190213_2113'), - ] - - operations = [ - ] diff --git a/back/backend/migrations/0008_auto_20190214_1421.py b/back/backend/migrations/0008_auto_20190214_1421.py deleted file mode 100644 index 0aff026..0000000 --- a/back/backend/migrations/0008_auto_20190214_1421.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 2.1.5 on 2019-02-14 22:21 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('backend', '0007_merge_20190213_2318'), - ] - - operations = [ - migrations.AlterField( - model_name='field', - name='data_decimal', - field=models.DecimalField(decimal_places=2, default=0, max_digits=9), - ), - migrations.AlterField( - model_name='field', - name='number', - field=models.IntegerField(default=0), - ), - migrations.AlterField( - model_name='section', - name='auto_submit', - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name='section', - name='completed', - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name='section', - name='required', - field=models.BooleanField(default=False), - ), - ] diff --git a/back/backend/models.py b/back/backend/models.py index 69db8ee..dd47555 100644 --- a/back/backend/models.py +++ b/back/backend/models.py @@ -13,6 +13,7 @@ class Report(models.Model): date_created = models.DateTimeField('date created', default=datetime.date.today) date_submitted = models.DateTimeField('date submitted', default=datetime.date.today) submitted = models.BooleanField(default=False) + reference_number = models.CharField(max_length=32, default='') def __str__(self): """ @@ -33,6 +34,7 @@ class Section(models.Model): title = models.CharField(max_length=256) html_description = models.TextField() number = models.IntegerField() + approved = models.BooleanField(default=False) def __str__(self): """ diff --git a/back/backend/templates/backend/email.html b/back/backend/templates/backend/email.html index b985302..4bfb5f3 100644 --- a/back/backend/templates/backend/email.html +++ b/back/backend/templates/backend/email.html @@ -4,9 +4,10 @@

Title: {{ title }}

+

Reference #: {{ reference_number }}

{% for section in sections %} {% if section.completed %} -

{{section.title}}

+

{{section.title}} (SID: {{section.id}})

{% for field in section.fields %} diff --git a/back/backend/templates/backend/email.txt b/back/backend/templates/backend/email.txt index 43f9df7..698f576 100644 --- a/back/backend/templates/backend/email.txt +++ b/back/backend/templates/backend/email.txt @@ -4,8 +4,9 @@ *** Title: {{title}} +Reference #: {{reference_number}} {% for section in sections %} - {{section.title}} + {{section.title}}(SID: {{section.id}}) {% for field in section.fields %} {{field.label}}: {{field.value|default:"empty"}} {% endfor %} diff --git a/back/backend/views.py b/back/backend/views.py index 1d55aec..d31728f 100644 --- a/back/backend/views.py +++ b/back/backend/views.py @@ -23,6 +23,7 @@ def get_report(report_pk): "date_created": i.date_created, "submitted": i.submitted, "date_submitted": i.date_submitted, + "reference_number": i.reference_number, } # append the sections for each report data.update(get_sections(i.id)) @@ -51,20 +52,23 @@ def get_sections(r_id): # append the fields for corresponding section data.update(get_fields(i.id)) # process rules from the policy file if the section is completed - if i.completed: - rules = pol.sections[index].rules - for rule in rules: - try: - named_fields = generate_named_fields_for_section(data['fields']) - result = rule['rule'](data, named_fields) - if not result is None: - info = { - "label": rule['title'], - "rule_break_text": result, - } - data['rule_violations'].append(info) - except Exception as e: - print('Rule "{}" encountered an error. {}'.format(rule['title'], e)) + if i.completed and not i.approved: + try: + rules = pol.sections[index].rules + for rule in rules: + try: + named_fields = generate_named_fields_for_section(data['fields']) + result = rule['rule'](data, named_fields) + if not result is None: + info = { + "label": rule['title'], + "rule_break_text": result, + } + data['rule_violations'].append(info) + except Exception as e: + print('Rule "{}" encountered an error. {}'.format(rule['title'], e)) + except Exception as e: + print('Error accessing policy section {}. Policy file may have changed.'.format(index)) # append section to the array section_set["sections"].append(data.copy()) @@ -121,8 +125,12 @@ def report(request): } """ # Create the report - report = Report.objects.create(user_id=request.user, title=request.data['title'], - date_created=datetime.date.today()) + report = Report.objects.create( + user_id=request.user, + title=request.data['title'], + date_created=datetime.date.today(), + reference_number=request.data['reference'] + ) report.save() # Create the sections @@ -161,6 +169,7 @@ def reports(request): "date_created": i.date_created, "submitted": i.submitted, "date_submitted": i.date_submitted, + "reference_number": i.reference_number, } # append the sections for each report report_set["reports"].append(data.copy()) @@ -338,20 +347,23 @@ def section(request, report_pk, section_pk): } data.update(get_fields(s.id)) # process rules from the policy file if the section is completed - if s.completed: - rules = pol.sections[s.number].rules - for rule in rules: - try: - named_fields = generate_named_fields_for_section(data['fields']) - result = rule['rule'](data, named_fields) - if not result is None: - info = { - "label": rule['title'], - "rule_break_text": result, - } - data['rule_violations'].append(info) - except Exception as e: - print('Rule "{}" encountered an error. {}'.format(rule['title'], e)) + if s.completed and not s.approved: + try: + rules = pol.sections[s.number].rules + for rule in rules: + try: + named_fields = generate_named_fields_for_section(data['fields']) + result = rule['rule'](data, named_fields) + if not result is None: + info = { + "label": rule['title'], + "rule_break_text": result, + } + data['rule_violations'].append(info) + except Exception as e: + print('Rule "{}" encountered an error. {}'.format(rule['title'], e)) + except Exception as e: + print('Error accessing policy section {}. Policy file may have been changed.'.format(s.number)) return JsonResponse(data) def section_complete(section_pk): @@ -385,13 +397,23 @@ def send_report_to_admin(request, report_pk): 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 = None + if params['reference_number'] == '': + message = EmailMultiAlternatives( + "{}".format(params['title']), + msg_plain, + from_email, + [to_email], + cc=[request.user.email], + ) + else: + message = EmailMultiAlternatives( + "[RT - Request Tracker #{}] {}".format(params['reference_number'], 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) diff --git a/back/db.sqlite3 b/back/db.sqlite3 index e1d4159..06e1e06 100644 Binary files a/back/db.sqlite3 and b/back/db.sqlite3 differ diff --git a/back/users/migrations/0001_initial.py b/back/users/migrations/0001_initial.py index 5992e07..6e4bb9b 100644 --- a/back/users/migrations/0001_initial.py +++ b/back/users/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.5 on 2019-02-01 00:21 +# Generated by Django 2.1.7 on 2019-03-03 09:06 import django.contrib.auth.models import django.contrib.auth.validators diff --git a/front/static/js/viewHistory.js b/front/static/js/viewHistory.js index 99d182e..97b4884 100644 --- a/front/static/js/viewHistory.js +++ b/front/static/js/viewHistory.js @@ -560,7 +560,7 @@ if (newReportForm) { newReportForm.addEventListener("submit", function(event) { event.preventDefault(); const url = getEndpointDomain() + "api/v1/report"; - const payload = JSON.stringify({ "title": event.target.elements.title.value }); + const payload = JSON.stringify({ "title": event.target.elements.title.value, "reference": event.target.elements.reference.value }); console.log("Payload:\n" + payload); const type = reportType.NEW; makeAjaxRequest("POST", url, createReportForm, type, payload); diff --git a/front/static/new_report.html b/front/static/new_report.html index 7caf52b..cda82ca 100644 --- a/front/static/new_report.html +++ b/front/static/new_report.html @@ -51,6 +51,10 @@ +
+ + +