Merge branch 'master' into display-rule-violations

This commit is contained in:
Preston Doman 2019-02-16 14:40:19 -08:00
commit 8c659bb608
8 changed files with 73 additions and 10 deletions

View file

@ -1,5 +1,5 @@
# reimbursinator # reimbursinator
Open source expense management solution An open source expense management solution, written in python.
Daniel Dupriest, Logan Miller, Jack, Joe Arriaga, Preston, Rupika, Liang Shuaiyi Daniel Dupriest, Logan Miller, Jack, Joe Arriaga, Preston, Rupika, Liang Shuaiyi

View file

@ -87,6 +87,10 @@ def get_fields(s_id):
def generate_named_fields_for_section(fields): def generate_named_fields_for_section(fields):
'''
Converts a section's field data into key-value pairs
for use in policy rule lambda functions.
'''
result = {} result = {}
for field in fields: for field in fields:
key = field['field_name'] key = field['field_name']
@ -145,10 +149,22 @@ def reports(request):
return JsonResponse(report_set) return JsonResponse(report_set)
def user_owns_report(user, report):
'''
Returns true if the specified user is owner of the report
'''
report_to_check = Report.objects.filter(id=report)
if len(report_to_check) < 1:
return False
return report_to_check[0].user_id == user
# actions for an individual report # actions for an individual report
@api_view(['GET', 'PUT', 'DELETE']) @api_view(['GET', 'PUT', 'DELETE'])
def report_detail(request, report_pk): def report_detail(request, report_pk):
# Check that the user owns the report
if not user_owns_report(user=request.user, report=report_pk):
return JsonResponse({"message": "Current user does not own the specified report."}, status=401)
# view the report # view the report
if request.method == 'GET': if request.method == 'GET':
data = get_reports(report_pk) data = get_reports(report_pk)
@ -176,10 +192,22 @@ def report_detail(request, report_pk):
r.delete() r.delete()
return JsonResponse({"message": "Deleted report: {0}.".format(title)}) return JsonResponse({"message": "Deleted report: {0}.".format(title)})
def user_owns_section(user, section):
'''
Returns true if the specified user is owner of the section
'''
section_to_check = Section.objects.filter(id=section)
if len(section_to_check) < 1:
return False
report_to_check = section_to_check[0].report_id
return report_to_check.user_id == user
# update a section with new data # update a section with new data
@api_view(['PUT']) @api_view(['PUT'])
def section(request, report_pk, section_pk): def section(request, report_pk, section_pk):
# Check that the user owns the report
if not user_owns_section(user=request.user, section=section_pk):
return JsonResponse({"message": "Current user does not own the specified section."}, status=401)
for key in request.data: for key in request.data:
# get the matching field object # get the matching field object
@ -250,15 +278,18 @@ def section(request, report_pk, section_pk):
s = Section.objects.get(id=section_pk) s = Section.objects.get(id=section_pk)
if complete: if complete:
s.completed = True s.completed = True
s.save()
else: else:
s.completed = False s.completed = False
s.save()
# get section and field details
data = { data = {
"message": "Updated report {0}, section {1}.".format(report_pk, section_pk), "id": s.id,
"section completion": s.completed, "completed": s.completed,
"request_data": "{}".format(request.data) "title": s.title,
"html_description": s.html_description,
} }
data.update(get_fields(s.id))
return JsonResponse(data) return JsonResponse(data)
# function checks if a field is complete # function checks if a field is complete

Binary file not shown.

View file

@ -8,6 +8,7 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<link rel="shortcut icon" href="img/favicon.ico"> <link rel="shortcut icon" href="img/favicon.ico">
<title>Reimbursinator</title> <title>Reimbursinator</title>
</head> </head>

View file

@ -97,6 +97,18 @@ function createFormGroup(sectionIdStr, field) {
formGroup.appendChild(div); formGroup.appendChild(div);
break; break;
case "date": case "date":
input.type = "date";
input.placeholder = "mm-dd-yyyy";
if (field.value === "None") {
input.value = "";
} else {
input.value = field.value;
}
input.classList.add("form-control");
formGroup.appendChild(label);
div.appendChild(input)
formGroup.appendChild(div);
break;
case "string": case "string":
input.type = "text"; input.type = "text";
input.value = field.value; input.value = field.value;
@ -107,7 +119,11 @@ function createFormGroup(sectionIdStr, field) {
break; break;
case "decimal": case "decimal":
input.type = "text"; input.type = "text";
input.value = field.value; if (field.value === "0.00") {
input.value = "";
} else {
input.value = field.value;
}
input.classList.add("form-control"); input.classList.add("form-control");
input.pattern = "\\d+(\\.\\d{2})?"; input.pattern = "\\d+(\\.\\d{2})?";
formGroup.appendChild(label); formGroup.appendChild(label);
@ -116,7 +132,11 @@ function createFormGroup(sectionIdStr, field) {
break; break;
case "integer": case "integer":
input.type = "number"; input.type = "number";
input.value = field.value; if (field.value === 0) {
input.value = "";
} else {
input.value = field.value;
}
input.classList.add("form-control"); input.classList.add("form-control");
input.step = 1; input.step = 1;
input.min = 0; input.min = 0;
@ -463,6 +483,16 @@ if (newReportForm) {
}); });
} }
document.addEventListener("input", function(event) {
if (event.target.type === "date") {
if (!moment(event.target.value, "YYYY-MM-DD", true).isValid()) {
event.target.setCustomValidity("Invalid date format");
} else {
event.target.setCustomValidity("");
}
}
});
document.addEventListener("submit", function(event) { document.addEventListener("submit", function(event) {
if (event.target.classList.contains("section-form")) { if (event.target.classList.contains("section-form")) {
event.preventDefault(); event.preventDefault();

View file

@ -25,7 +25,7 @@
<form class="form" autocomplete="off"> <form class="form" autocomplete="off">
<div class="form-group"> <div class="form-group">
<label for="email">Email:</label> <label for="email">Email:</label>
<input class="form-control" id="email" type="email" name="email" required> <input class="form-control" id="email" type="email" name="email" autofocus required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="password">Password:</label> <label for="password">Password:</label>

View file

@ -8,6 +8,7 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<link rel="shortcut icon" href="img/favicon.ico"> <link rel="shortcut icon" href="img/favicon.ico">
<title>Reimbursinator</title> <title>Reimbursinator</title>
</head> </head>
@ -47,7 +48,7 @@
<form class="form new-report-form" autocomplete="off"> <form class="form new-report-form" autocomplete="off">
<div class="form-group"> <div class="form-group">
<label for="title">Report title:</label> <label for="title">Report title:</label>
<input type="text" class="form-control" name="title" id="title"> <input type="text" class="form-control" name="title" id="title" autofocus>
</div> </div>
<button type="submit" class="btn btn-primary" data-toggle="modal" data-target="#newReportModal">Create</button> <button type="submit" class="btn btn-primary" data-toggle="modal" data-target="#newReportModal">Create</button>
</form> </form>

View file

@ -25,7 +25,7 @@
<form class="form signup" autocomplete="off" action="index.html"> <form class="form signup" autocomplete="off" action="index.html">
<div class="form-group"> <div class="form-group">
<label for="email">Email:</label> <label for="email">Email:</label>
<input class="form-control" type="email" id="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" oninput="validateEmail(this);" required> <input class="form-control" type="email" id="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$" oninput="validateEmail(this);" autofocus required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="first_name">First Name:</label> <label for="first_name">First Name:</label>