aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst6
-rw-r--r--ihatemoney/forms.py8
-rw-r--r--ihatemoney/messages.pot3
-rw-r--r--ihatemoney/migrations/versions/a67119aa3ee5_migrate_negative_weights.py38
-rw-r--r--ihatemoney/models.py5
-rw-r--r--ihatemoney/tests/tests.py12
-rw-r--r--ihatemoney/translations/fr/LC_MESSAGES/messages.po3
7 files changed, 70 insertions, 5 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a1d8b75..37d7dcb 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -8,10 +8,16 @@ This document describes changes between each past release.
Added
=====
+
- Add CORS headers in the API (#407)
- Document database migrations (#390)
- Allow basic math operations in amount field (#413)
+Fixed
+=====
+
+- Do not allow negative weights on users (#366)
+
3.0 (2018-11-25)
----------------
diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py
index 5374fd9..be04c8f 100644
--- a/ihatemoney/forms.py
+++ b/ihatemoney/forms.py
@@ -2,7 +2,7 @@ from flask_wtf.form import FlaskForm
from wtforms.fields.core import SelectField, SelectMultipleField
from wtforms.fields.html5 import DateField, DecimalField
from wtforms.fields.simple import PasswordField, SubmitField, TextAreaField, StringField
-from wtforms.validators import Email, Required, ValidationError, EqualTo
+from wtforms.validators import Email, Required, ValidationError, EqualTo, NumberRange
from flask_babel import lazy_gettext as _
from flask import request
from werkzeug.security import generate_password_hash
@@ -174,9 +174,11 @@ class BillForm(FlaskForm):
class MemberForm(FlaskForm):
-
name = StringField(_("Name"), validators=[Required()])
- weight = CommaDecimalField(_("Weight"), default=1)
+
+ weight_validators = [NumberRange(min=0.1, message=_("Weights should be positive"))]
+ weight = CommaDecimalField(_("Weight"), default=1,
+ validators=weight_validators)
submit = SubmitField(_("Add"))
def __init__(self, project, edit=False, *args, **kwargs):
diff --git a/ihatemoney/messages.pot b/ihatemoney/messages.pot
index ba81d22..fb69539 100644
--- a/ihatemoney/messages.pot
+++ b/ihatemoney/messages.pot
@@ -79,6 +79,9 @@ msgstr ""
msgid "Weight"
msgstr ""
+msgid "Weights should be positive"
+msgstr ""
+
msgid "Add"
msgstr ""
diff --git a/ihatemoney/migrations/versions/a67119aa3ee5_migrate_negative_weights.py b/ihatemoney/migrations/versions/a67119aa3ee5_migrate_negative_weights.py
new file mode 100644
index 0000000..ec23470
--- /dev/null
+++ b/ihatemoney/migrations/versions/a67119aa3ee5_migrate_negative_weights.py
@@ -0,0 +1,38 @@
+"""Migrate negative weights
+
+Revision ID: a67119aa3ee5
+Revises: afbf27e6ef20
+Create Date: 2018-12-25 18:34:20.220844
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'a67119aa3ee5'
+down_revision = 'afbf27e6ef20'
+
+from alembic import op
+import sqlalchemy as sa
+# Snapshot of the person table
+person_helper = sa.Table(
+ 'person', sa.MetaData(),
+ sa.Column('id', sa.Integer(), nullable=False),
+ sa.Column('project_id', sa.String(length=64), nullable=True),
+ sa.Column('name', sa.UnicodeText(), nullable=True),
+ sa.Column('activated', sa.Boolean(), nullable=True),
+ sa.Column('weight', sa.Float(), nullable=True),
+ sa.ForeignKeyConstraint(['project_id'], ['project.id'], ),
+ sa.PrimaryKeyConstraint('id')
+)
+
+
+def upgrade():
+ op.execute(
+ person_helper.update()
+ .where(person_helper.c.weight <= 0)
+ .values(weight=1)
+ )
+
+
+def downgrade():
+ # Downgrade path is not possible, because information has been lost.
+ pass
diff --git a/ihatemoney/models.py b/ihatemoney/models.py
index 3c36e76..b9cff4f 100644
--- a/ihatemoney/models.py
+++ b/ihatemoney/models.py
@@ -376,8 +376,9 @@ class Bill(db.Model):
def pay_each(self):
"""Compute what each share has to pay"""
if self.owers:
- # FIXME: SQL might dot that more efficiently
- return self.amount / sum(i.weight for i in self.owers)
+ # FIXME: SQL might do that more efficiently
+ weights = sum(i.weight for i in self.owers)
+ return self.amount / weights
else:
return 0
diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py
index 9f9d8fa..d29ec62 100644
--- a/ihatemoney/tests/tests.py
+++ b/ihatemoney/tests/tests.py
@@ -621,6 +621,18 @@ class BudgetTestCase(IhatemoneyTestCase):
resp = self.client.get("/raclette/")
self.assertNotIn('extra-info', resp.data.decode('utf-8'))
+ def test_negative_weight(self):
+ self.post_project("raclette")
+
+ # Add one user and edit it to have a negative share
+ self.client.post("/raclette/members/add", data={'name': 'alexis'})
+ resp = self.client.post("/raclette/members/1/edit", data={'name': 'alexis', 'weight': -1})
+
+ # An error should be generated, and its weight should still be 1.
+ self.assertIn('<p class="alert alert-danger">', resp.data.decode('utf-8'))
+ self.assertEqual(len(models.Project.query.get('raclette').members), 1)
+ self.assertEqual(models.Project.query.get('raclette').members[0].weight, 1)
+
def test_rounding(self):
self.post_project("raclette")
diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po
index 2516d56..d610145 100644
--- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po
+++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po
@@ -105,6 +105,9 @@ msgstr "Nom"
msgid "Weight"
msgstr "Parts"
+msgid "Weights should be positive"
+msgstr "Les parts doivent ĂȘtre positives"
+
msgid "Add"
msgstr "Ajouter"