mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-05-06 13:01:50 +02:00
Replace JavaScript-based dependent checkboxes with WTForms BooleanFields
This commit is contained in:
parent
114c151501
commit
0b206daab2
5 changed files with 73 additions and 77 deletions
|
@ -1,7 +1,7 @@
|
||||||
from flask_wtf.form import FlaskForm
|
from flask_wtf.form import FlaskForm
|
||||||
from wtforms.fields.core import SelectField, SelectMultipleField
|
from wtforms.fields.core import SelectField, SelectMultipleField
|
||||||
from wtforms.fields.html5 import DateField, DecimalField, URLField
|
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 (
|
from wtforms.validators import (
|
||||||
Email,
|
Email,
|
||||||
DataRequired,
|
DataRequired,
|
||||||
|
@ -89,25 +89,28 @@ class EditProjectForm(FlaskForm):
|
||||||
name = StringField(_("Project name"), validators=[DataRequired()])
|
name = StringField(_("Project name"), validators=[DataRequired()])
|
||||||
password = StringField(_("Private code"), validators=[DataRequired()])
|
password = StringField(_("Private code"), validators=[DataRequired()])
|
||||||
contact_email = StringField(_("Email"), validators=[DataRequired(), Email()])
|
contact_email = StringField(_("Email"), validators=[DataRequired(), Email()])
|
||||||
logging_preferences = SelectField(
|
project_history = BooleanField(_("Enable project history"))
|
||||||
_("Logging Preferences"),
|
ip_recording = BooleanField(_("Use IP tracking for project history"))
|
||||||
choices=LoggingMode.choices(),
|
|
||||||
coerce=LoggingMode.coerce,
|
|
||||||
default=LoggingMode.default(),
|
|
||||||
validators=[DataRequired()],
|
|
||||||
)
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Create a new project with the information given by this form.
|
"""Create a new project with the information given by this form.
|
||||||
|
|
||||||
Returns the created instance
|
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(
|
project = Project(
|
||||||
name=self.name.data,
|
name=self.name.data,
|
||||||
id=self.id.data,
|
id=self.id.data,
|
||||||
password=generate_password_hash(self.password.data),
|
password=generate_password_hash(self.password.data),
|
||||||
contact_email=self.contact_email.data,
|
contact_email=self.contact_email.data,
|
||||||
logging_preference=self.logging_preferences.data,
|
logging_preference=new_logging_preference,
|
||||||
)
|
)
|
||||||
return project
|
return project
|
||||||
|
|
||||||
|
@ -120,7 +123,16 @@ class EditProjectForm(FlaskForm):
|
||||||
project.password = generate_password_hash(self.password.data)
|
project.password = generate_password_hash(self.password.data)
|
||||||
|
|
||||||
project.contact_email = self.contact_email.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
|
return project
|
||||||
|
|
||||||
|
@ -139,6 +151,14 @@ class ProjectForm(EditProjectForm):
|
||||||
password = PasswordField(_("Private code"), validators=[DataRequired()])
|
password = PasswordField(_("Private code"), validators=[DataRequired()])
|
||||||
submit = SubmitField(_("Create the project"))
|
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):
|
def validate_id(form, field):
|
||||||
form.id.data = slugify(field.data)
|
form.id.data = slugify(field.data)
|
||||||
if (form.id.data == "dashboard") or Project.query.get(form.id.data):
|
if (form.id.data == "dashboard") or Project.query.get(form.id.data):
|
||||||
|
|
|
@ -5,46 +5,3 @@ function selectCheckboxes(value){
|
||||||
els[i].checked = 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,6 +20,16 @@
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% 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) -%}
|
{% macro submit(field, cancel=False, home=False) -%}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button type="submit" class="btn btn-primary">{{ field.name }}</button>
|
<button type="submit" class="btn btn-primary">{{ field.name }}</button>
|
||||||
|
@ -81,20 +91,8 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="privacy_checkboxes">{{ _("Privacy Settings") }}</label>
|
<label for="privacy_checkboxes">{{ _("Privacy Settings") }}</label>
|
||||||
<div id="privacy_checkboxes" class="card card-body bg-light">
|
<div id="privacy_checkboxes" class="card card-body bg-light">
|
||||||
<div class="controls">
|
{{ checkbox(form.project_history) }}
|
||||||
<input id="logging_enabled" type="checkbox" onchange="updatePrivacySelectFromCheckBoxes()">
|
{{ checkbox(form.ip_recording) }}
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -2276,9 +2276,13 @@ class HistoryTestCase(IhatemoneyTestCase):
|
||||||
"name": "demo",
|
"name": "demo",
|
||||||
"contact_email": "demo@notmyidea.org",
|
"contact_email": "demo@notmyidea.org",
|
||||||
"password": "demo",
|
"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
|
# Disable History
|
||||||
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
@ -2286,12 +2290,18 @@ class HistoryTestCase(IhatemoneyTestCase):
|
||||||
|
|
||||||
resp = self.client.get("/demo/edit")
|
resp = self.client.get("/demo/edit")
|
||||||
self.assertEqual(resp.status_code, 200)
|
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(
|
self.assertIn(
|
||||||
'<option selected value="%i">%s</option>'
|
'<input checked id="project_history"', resp.data.decode("utf-8")
|
||||||
% (logging_preference.value, logging_preference.name),
|
|
||||||
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):
|
def assert_empty_history_logging_disabled(self):
|
||||||
resp = self.client.get("/demo/history")
|
resp = self.client.get("/demo/history")
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
|
@ -2319,6 +2329,7 @@ class HistoryTestCase(IhatemoneyTestCase):
|
||||||
"name": "demo2",
|
"name": "demo2",
|
||||||
"contact_email": "demo2@notmyidea.org",
|
"contact_email": "demo2@notmyidea.org",
|
||||||
"password": "123456",
|
"password": "123456",
|
||||||
|
"project_history": "y",
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
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")
|
resp = self.client.get("/demo/edit")
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
self.assertIn(
|
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)
|
self.change_privacy_to(LoggingMode.DISABLED)
|
||||||
|
@ -2415,10 +2427,14 @@ class HistoryTestCase(IhatemoneyTestCase):
|
||||||
"name": "demo2",
|
"name": "demo2",
|
||||||
"contact_email": "demo2@notmyidea.org",
|
"contact_email": "demo2@notmyidea.org",
|
||||||
"password": "123456",
|
"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)
|
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
|
|
@ -406,7 +406,12 @@ def edit_project():
|
||||||
return redirect(url_for("main.list_bills"))
|
return redirect(url_for("main.list_bills"))
|
||||||
else:
|
else:
|
||||||
edit_form.name.data = g.project.name
|
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
|
edit_form.contact_email.data = g.project.contact_email
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
|
|
Loading…
Reference in a new issue