Merge pull request #59: Implemented policy parsing

Implemented policy parsing!
This commit is contained in:
Daniel Dupriest 2019-02-07 17:49:05 -08:00 committed by GitHub
commit 21440bf3dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 98 deletions

View file

@ -0,0 +1,18 @@
# 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),
),
]

View file

@ -26,12 +26,13 @@ class Section(models.Model):
class Field(models.Model): class Field(models.Model):
section_id = models.ForeignKey(Section, on_delete=models.CASCADE) section_id = models.ForeignKey(Section, on_delete=models.CASCADE)
field_name = models.CharField(max_length=512, default="field")
label = models.CharField(max_length=512) label = models.CharField(max_length=512)
number = models.IntegerField() number = models.IntegerField()
type = models.CharField(max_length=128) type = models.CharField(max_length=128)
completed = models.BooleanField(default=False) completed = models.BooleanField(default=False)
data_bool = models.BooleanField(default=False) data_bool = models.BooleanField(default=False)
data_decimal = models.DecimalField(max_digits=9,decimal_places=2, null=True, blank=True) data_decimal = models.DecimalField(max_digits=9, decimal_places=2, null=True, blank=True)
data_date = models.DateField(default=datetime.date.today) data_date = models.DateField(default=datetime.date.today)
data_file = models.FileField(upload_to='uploads/%Y/%m/%d/', max_length=512, null=True, blank=True) data_file = models.FileField(upload_to='uploads/%Y/%m/%d/', max_length=512, null=True, blank=True)
data_string = models.TextField(default='', blank=True) data_string = models.TextField(default='', blank=True)

View file

@ -1,10 +1,36 @@
# simple_policy.py
from datetime import date from datetime import date
from policy import Policy, Section
# - For the rules, should one refer to fields by 'section.fields.x' #### Classes for policy, sections.
# or by the section name eg. 'general_section.fields.x'?
class Policy():
def __init__(self):
self.sections = []
def add_section(self, section):
self.sections.append(section)
class Section():
def __init__(self, title="Section", html_description="", required=False, auto_submit=False, fields={}):
self.title = title
self.html_description = html_description
self.required = required
self.auto_submit = auto_submit
self.fields = fields
self.rules = []
def add_rule(self, title="Rule", rule=None, rule_break_text=""):
rule = {
"title": title,
"rule": rule,
"rule_break_text": rule_break_text,
}
self.rules.append(rule)
#### Policy configuration begin here
pol = Policy()
#### General #### General
#### Section 0 #### Section 0
@ -12,7 +38,7 @@ general_section = Section(
title="General Info", title="General Info",
html_description="", html_description="",
fields={ fields={
"destination": {"label": "Destination City", "type": "string"} "destination": {"label": "Destination City", "type": "string"},
} }
) )
@ -22,7 +48,7 @@ general_section.add_rule(
rule_break_text="What did the cowboy say about Tim, his wild horse?" rule_break_text="What did the cowboy say about Tim, his wild horse?"
) )
Policy.add_section(general_section) pol.add_section(general_section)
#### Flight #### Flight
#### Section 1 #### Section 1
@ -43,7 +69,7 @@ flight_section.add_rule(
rule_break_text="Fares cannot be more than $500" rule_break_text="Fares cannot be more than $500"
) )
Policy.add_section(flight_section) pol.add_section(flight_section)
#### Lodging #### Lodging
#### Section 2 #### Section 2
@ -64,13 +90,13 @@ def nightly_rate_check(report, section):
duration = checkout_date - checkin_date duration = checkout_date - checkin_date
return section.fields.cost <= duration * section.fields.rate return section.fields.cost <= duration * section.fields.rate
section.add_rule( lodging_section.add_rule(
title="", title="",
rule=nightly_rate_check, rule=nightly_rate_check,
rule_break_text="The average nightly rate cannot be more than the USGSA rate." rule_break_text="The average nightly rate cannot be more than the USGSA rate."
) )
Policy.add_section(lodging_section) pol.add_section(lodging_section)
#### Local Transportation #### Local Transportation
#### Section 3 #### Section 3
@ -89,7 +115,7 @@ transport_section.add_rule(
rule_break_text="Local transportation costs must be less than $10 per day, on average." rule_break_text="Local transportation costs must be less than $10 per day, on average."
) )
Policy.add_section(transport_section) pol.add_section(transport_section)
#### Per Diem #### Per Diem
#### Section 4 #### Section 4
@ -109,24 +135,4 @@ per_diem_section.add_rule(
rule_break_text="The average cost per day for per diem expenses cannot be more than the rate specified by the USGSA." rule_break_text="The average cost per day for per diem expenses cannot be more than the rate specified by the USGSA."
) )
Policy.add_section(per_diem_section) pol.add_section(per_diem_section)
'''
Section(
title="",
html_description="<p></p>",
fields={
"": {"label": "", "type": ""}
}
)
section.add_rule(
title="",
rule=lambda report, section: boolean_statement,
rule_break_text=""
)
#// or, for a rule which doesnt apply to a specific section...
#//
#// add_general_rule(...)
'''

3
back/backend/test.py Normal file
View file

@ -0,0 +1,3 @@
from policy import pol
print(pol)

View file

@ -1,7 +1,8 @@
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from django.http import JsonResponse from django.http import JsonResponse
from .models import * from .models import *
from .policy import pol
import json
# function that prints all the reports # function that prints all the reports
def get_reports(report_pk): def get_reports(report_pk):
@ -47,15 +48,14 @@ def get_sections(r_id):
def get_fields(s_id): def get_fields(s_id):
# create dict of arrays for fields # create dict of arrays for fields
field_set = {"fields": []} field_set = {"fields": []}
queryset = Field.objects.filter(section_id=s_id) queryset = Field.objects.filter(section_id=s_id).order_by('number')
# queryset = Field.objects.all()
for i in queryset: for i in queryset:
data = { data = {
"field_name": "TODO", "field_name": i.field_name,
"label": i.label, "label": i.label,
"type": i.type, "type": i.type,
"number": i.number, "number": i.number,
"value": "get_value", "value": "i.to_json()",
} }
# append the fields to array # append the fields to array
# use copy() to avoid overwriting # use copy() to avoid overwriting
@ -70,73 +70,34 @@ def report(request):
''' '''
Generate a new empty report and return it Generate a new empty report and return it
''' '''
data = {
"title": "2018 Portland trip", # Create the report
"date_created": "2018-05-22T14:56:28.000Z", report = Report.objects.create(user_id=request.user, title=request.data['title'], date_created=datetime.date.today())
"submitted": False, report.save()
"date_submitted": "0000-00-00T00:00:00.000Z",
"sections": [ # Create the sections
{ for i in range(len(pol.sections)):
"id": 1, section = pol.sections[i]
"completed": True, s = Section.objects.create(report_id=report, auto_submit=section.auto_submit, required=section.required, completed=False, title=section.title, html_description=section.html_description, number=i)
"title": "Flight Info", s.save()
"html_description": "<p>Enter flight details here.</p>",
"fields": { # Create the fields
"international": { j = 0
"label": "International flight", for key in section.fields:
"type": "boolean", field = section.fields[key]
"value": True f = Field.objects.create(section_id=s, field_name=key, label=field['label'], number=j, type=field['type'], completed=False)
}, f.save()
"travel_date": { j = j+1
"label": "Travel start date",
"type": "date", # Return the newly created report
"value": "2016-05-22T14:56:28.000Z" data = get_reports(report.id)
},
"fare": {
"label": "Fare",
"type": "decimal",
"value": "1024.99"
},
"lowest_fare_screenshot": {
"label": "Lowest fare screenshot",
"type": "file",
"value": "e92h842jiu49f8..."
},
"plane_ticket_invoice": {
"label": "Plane ticket invoice PDF",
"type": "file",
"value": ""
}
},
"rule_violations": [
{
"error_text": "Plane ticket invoice must be submitted."
}
]
},
{
"id": 2,
"completed": False,
"title": "Hotel info",
"html_description": "<p>If you used a hotel, please enter the details.</p>",
"fields": {
"total": {
"label": "Total cost",
"type": "decimal"
}
},
"rule_violations": [
]
}
]
}
return JsonResponse(data) return JsonResponse(data)
# List of reports # List of reports
@api_view(['GET']) @api_view(['GET'])
def reports(request): def reports(request):
report_set = {"reports": []} report_set = {"reports": []}
queryset = Report.objects.all() queryset = Report.objects.all().order_by('date_created')
for i in queryset: for i in queryset:
data = { data = {
"report_pk": i.id, "report_pk": i.id,

Binary file not shown.