Replace JavaScript-based dependent checkboxes with WTForms BooleanFields

This commit is contained in:
Andrew Dickinson 2020-04-17 16:16:32 -04:00
parent 114c151501
commit 0b206daab2
5 changed files with 73 additions and 77 deletions

View file

@ -1,7 +1,7 @@
from flask_wtf.form import FlaskForm
from wtforms.fields.core import SelectField, SelectMultipleField
from wtforms.fields.html5 import DateField, DecimalField, URLField
from wtforms.fields.simple import PasswordField, SubmitField, StringField
from wtforms.fields.simple import PasswordField, SubmitField, StringField, BooleanField
from wtforms.validators import (
Email,
DataRequired,
@ -89,25 +89,28 @@ class EditProjectForm(FlaskForm):
name = StringField(_("Project name"), validators=[DataRequired()])
password = StringField(_("Private code"), validators=[DataRequired()])
contact_email = StringField(_("Email"), validators=[DataRequired(), Email()])
logging_preferences = SelectField(
_("Logging Preferences"),
choices=LoggingMode.choices(),
coerce=LoggingMode.coerce,
default=LoggingMode.default(),
validators=[DataRequired()],
)
project_history = BooleanField(_("Enable project history"))
ip_recording = BooleanField(_("Use IP tracking for project history"))
def save(self):
"""Create a new project with the information given by this form.
Returns the created instance
"""
if not self.project_history.data:
new_logging_preference = LoggingMode.DISABLED
else:
if self.ip_recording.data:
new_logging_preference = LoggingMode.RECORD_IP
else:
new_logging_preference = LoggingMode.ENABLED
project = Project(
name=self.name.data,
id=self.id.data,
password=generate_password_hash(self.password.data),
contact_email=self.contact_email.data,
logging_preference=self.logging_preferences.data,
logging_preference=new_logging_preference,
)
return project
@ -120,7 +123,16 @@ class EditProjectForm(FlaskForm):
project.password = generate_password_hash(self.password.data)
project.contact_email = self.contact_email.data
project.logging_preference = self.logging_preferences.data
if not self.project_history.data:
new_logging_preference = LoggingMode.DISABLED
else:
if self.ip_recording.data:
new_logging_preference = LoggingMode.RECORD_IP
else:
new_logging_preference = LoggingMode.ENABLED
project.logging_preference = new_logging_preference
return project
@ -139,6 +151,14 @@ class ProjectForm(EditProjectForm):
password = PasswordField(_("Private code"), validators=[DataRequired()])
submit = SubmitField(_("Create the project"))
def save(self):
# WTForms Boolean Fields don't insert the default value when the
# request doesn't include any value the way that other fields do,
# so we'll manually do it here
self.project_history.data = LoggingMode.default() != LoggingMode.DISABLED
self.ip_recording.data = LoggingMode.default() == LoggingMode.RECORD_IP
return super().save()
def validate_id(form, field):
form.id.data = slugify(field.data)
if (form.id.data == "dashboard") or Project.query.get(form.id.data):

View file

@ -5,46 +5,3 @@ function selectCheckboxes(value){
els[i].checked = value;
}
}
function updateCheckBoxesFromPrivacySelect() {
var history_checkbox = document.getElementById('logging_enabled');
var record_ip_checkbox = document.getElementById('record_ip');
var record_ip_checkbox_text = document.getElementById("record_ip_label");
var select_input = document.getElementById("logging_preferences");
if (select_input.selectedIndex === 0) {
history_checkbox.checked = false;
record_ip_checkbox.checked = false;
record_ip_checkbox.disabled = true;
record_ip_checkbox_text.classList.add("text-muted");
} else if (select_input.selectedIndex === 1 || select_input.selectedIndex === 2) {
history_checkbox.checked = true;
record_ip_checkbox.disabled = false;
record_ip_checkbox_text.classList.remove("text-muted");
if (select_input.selectedIndex === 2) {
record_ip_checkbox.checked = true
}
}
}
function updatePrivacySelectFromCheckBoxes() {
var history_checkbox = document.getElementById('logging_enabled');
var record_ip_checkbox = document.getElementById('record_ip');
var record_ip_checkbox_text = document.getElementById("record_ip_label");
var select_input = document.getElementById("logging_preferences");
if (!history_checkbox.checked) {
record_ip_checkbox.checked = false;
record_ip_checkbox.disabled = true;
record_ip_checkbox_text.classList.add("text-muted");
select_input.selectedIndex = 0
} else {
record_ip_checkbox.disabled = false;
record_ip_checkbox_text.classList.remove("text-muted");
if (record_ip_checkbox.checked){
select_input.selectedIndex = 2
} else {
select_input.selectedIndex = 1
}
}
}

View file

@ -20,6 +20,16 @@
</div>
{% endmacro %}
{% macro checkbox(field) %}
<div class="controls{% if inline %} col-9{% endif %}">
{{ field(id=field.name) }}
<label for="{{ field.name }}">{{ field.label() }}</label>
{% if field.description %}
<small id="{{field.name}}_description"" class="form-text text-muted">{{ field.description }}</small>
{% endif %}
</div>
{% endmacro %}
{% macro submit(field, cancel=False, home=False) -%}
<div class="actions">
<button type="submit" class="btn btn-primary">{{ field.name }}</button>
@ -81,20 +91,8 @@
<div class="form-group">
<label for="privacy_checkboxes">{{ _("Privacy Settings") }}</label>
<div id="privacy_checkboxes" class="card card-body bg-light">
<div class="controls">
<input id="logging_enabled" type="checkbox" onchange="updatePrivacySelectFromCheckBoxes()">
<label for="logging_enabled">{{ _("Enable Project History") }}</label>
</div>
<div class="controls">
<div class="ml-4">
<input id="record_ip" type="checkbox" onchange="updatePrivacySelectFromCheckBoxes()">
<label id="record_ip_label" for="record_ip">{{ _("Record IP Adressses") }}</label>
</div>
</div>
</div>
<div class="d-none">
{{ form.logging_preferences }}
<script>updateCheckBoxesFromPrivacySelect()</script>
{{ checkbox(form.project_history) }}
{{ checkbox(form.ip_recording) }}
</div>
</div>

View file

@ -2276,9 +2276,13 @@ class HistoryTestCase(IhatemoneyTestCase):
"name": "demo",
"contact_email": "demo@notmyidea.org",
"password": "demo",
"logging_preferences": logging_preference.value,
}
if logging_preference != LoggingMode.DISABLED:
new_data["project_history"] = "y"
if logging_preference == LoggingMode.RECORD_IP:
new_data["ip_recording"] = "y"
# Disable History
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
self.assertEqual(resp.status_code, 200)
@ -2286,12 +2290,18 @@ class HistoryTestCase(IhatemoneyTestCase):
resp = self.client.get("/demo/edit")
self.assertEqual(resp.status_code, 200)
if logging_preference == LoggingMode.DISABLED:
self.assertIn('<input id="project_history"', resp.data.decode("utf-8"))
else:
self.assertIn(
'<option selected value="%i">%s</option>'
% (logging_preference.value, logging_preference.name),
resp.data.decode("utf-8"),
'<input checked id="project_history"', resp.data.decode("utf-8")
)
if logging_preference == LoggingMode.RECORD_IP:
self.assertIn('<input checked id="ip_recording"', resp.data.decode("utf-8"))
else:
self.assertIn('<input id="ip_recording"', resp.data.decode("utf-8"))
def assert_empty_history_logging_disabled(self):
resp = self.client.get("/demo/history")
self.assertIn(
@ -2319,6 +2329,7 @@ class HistoryTestCase(IhatemoneyTestCase):
"name": "demo2",
"contact_email": "demo2@notmyidea.org",
"password": "123456",
"project_history": "y",
}
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
@ -2354,7 +2365,8 @@ class HistoryTestCase(IhatemoneyTestCase):
resp = self.client.get("/demo/edit")
self.assertEqual(resp.status_code, 200)
self.assertIn(
'<option selected value="1">ENABLED</option>', resp.data.decode("utf-8")
'<input checked id="project_history" name="project_history" type="checkbox" value="y">',
resp.data.decode("utf-8"),
)
self.change_privacy_to(LoggingMode.DISABLED)
@ -2415,10 +2427,14 @@ class HistoryTestCase(IhatemoneyTestCase):
"name": "demo2",
"contact_email": "demo2@notmyidea.org",
"password": "123456",
"logging_preferences": logging_mode.value,
# Keep privacy settings where they were
}
# Keep privacy settings where they were
if logging_mode != LoggingMode.DISABLED:
new_data["project_history"] = "y"
if logging_mode == LoggingMode.RECORD_IP:
new_data["ip_recording"] = "y"
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
self.assertEqual(resp.status_code, 200)

View file

@ -406,7 +406,12 @@ def edit_project():
return redirect(url_for("main.list_bills"))
else:
edit_form.name.data = g.project.name
edit_form.logging_preferences.data = g.project.logging_preference
if g.project.logging_preference != LoggingMode.DISABLED:
edit_form.project_history.data = True
if g.project.logging_preference == LoggingMode.RECORD_IP:
edit_form.ip_recording.data = True
edit_form.contact_email.data = g.project.contact_email
return render_template(