Merge branch 'master' into display-rule-violations
This commit is contained in:
commit
8c659bb608
8 changed files with 73 additions and 10 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
BIN
back/db.sqlite3
BIN
back/db.sqlite3
Binary file not shown.
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue