diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 67f4ec19..d0bcb556 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -215,16 +215,3 @@ class InviteForm(FlaskForm): except email_validator.EmailNotValidError: raise ValidationError(_("The email %(email)s is not valid", email=email)) - - -class ExportForm(FlaskForm): - export_type = SelectField( - _("What do you want to download ?"), - validators=[Required()], - coerce=str, - choices=[("bills", _("bills")), ("transactions", _("transactions"))]) - export_format = SelectField( - _("Export file format"), - validators=[Required()], - coerce=str, - choices=[("csv", "csv"), ("json", "json")]) diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css index ec8c8413..574baa38 100644 --- a/ihatemoney/static/css/main.css +++ b/ihatemoney/static/css/main.css @@ -442,6 +442,11 @@ tr:hover .extra-info { border-bottom: 0.2em solid transparent; height: 1.2em; } + +.download-project .icon svg { + fill: white; +} + .icon.plus svg { margin-right: 3px; } diff --git a/ihatemoney/static/images/file-alt.svg b/ihatemoney/static/images/file-alt.svg new file mode 100644 index 00000000..e1f980c8 --- /dev/null +++ b/ihatemoney/static/images/file-alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ihatemoney/static/images/file-csv-solid.svg b/ihatemoney/static/images/file-csv-solid.svg new file mode 100644 index 00000000..f527c04a --- /dev/null +++ b/ihatemoney/static/images/file-csv-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ihatemoney/templates/edit_project.html b/ihatemoney/templates/edit_project.html index a5e85c33..dcbbbc86 100644 --- a/ihatemoney/templates/edit_project.html +++ b/ihatemoney/templates/edit_project.html @@ -8,12 +8,48 @@ {% endblock %} {% block content %} -

{{ _("Edit this project") }}

-
-{{ forms.edit_project(edit_form) }} -

-

{{ _("Download this project's data") }}

-
-{{ forms.export_project(export_form) }} -
+

{{ _("Edit project") }}

+

+

+ {{ forms.edit_project(edit_form) }} +
+

+ +

{{ _("Download project's data") }}

+

+

+
+
+ {{ _('Bill items') }} + + + {{ static_include("images/file-alt.svg") | safe }} + JSON + + + {{ static_include("images/file-csv-solid.svg") | safe }} + CSV + + +
+

{{ _('Download the list of bills with owner, amount, reason,... ') }}

+
+
+
+ {{ _('Settle plans') }} + + + {{ static_include("images/file-alt.svg") | safe }} + JSON + + + {{ static_include("images/file-csv-solid.svg") | safe }} + CSV + + +
+

{{ _('Download the list of transactions needed to settle the current bills.') }}

+
+
+

{% endblock %} diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index d29ec628..12ad1286 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -912,10 +912,7 @@ class BudgetTestCase(IhatemoneyTestCase): }) # generate json export of bills - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'json', - 'export_type': 'bills' - }) + resp = self.client.get("/raclette/export/bills.json") expected = [{ 'date': '2017-01-01', 'what': 'refund', @@ -941,10 +938,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertEqual(json.loads(resp.data.decode('utf-8')), expected) # generate csv export of bills - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'csv', - 'export_type': 'bills' - }) + resp = self.client.get("/raclette/export/bills.csv") expected = [ "date,what,amount,payer_name,payer_weight,owers", "2017-01-01,refund,13.33,tata,1.0,fred", @@ -959,20 +953,14 @@ class BudgetTestCase(IhatemoneyTestCase): ) # generate json export of transactions - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'json', - 'export_type': 'transactions' - }) + resp = self.client.get("/raclette/export/transactions.json") expected = [{"amount": 127.33, "receiver": "fred", "ower": "alexis"}, {"amount": 55.34, "receiver": "fred", "ower": "tata"}, {"amount": 2.00, "receiver": "fred", "ower": "p\xe9p\xe9"}] self.assertEqual(json.loads(resp.data.decode('utf-8')), expected) # generate csv export of transactions - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'csv', - 'export_type': 'transactions' - }) + resp = self.client.get("/raclette/export/transactions.csv") expected = ["amount,receiver,ower", "127.33,fred,alexis", @@ -986,23 +974,9 @@ class BudgetTestCase(IhatemoneyTestCase): set(received_lines[i].strip("\r").split(",")) ) - # wrong export_format should return a 200 and export form - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'wrong_export_format', - 'export_type': 'transactions' - }) - - self.assertEqual(resp.status_code, 200) - self.assertIn('id="export_format" name="export_format"', resp.data.decode('utf-8')) - - # wrong export_type should return a 200 and export form - resp = self.client.post("/raclette/edit", data={ - 'export_format': 'json', - 'export_type': 'wrong_export_type' - }) - - self.assertEqual(resp.status_code, 200) - self.assertIn('id="export_format" name="export_format"', resp.data.decode('utf-8')) + # wrong export_format should return a 404 + resp = self.client.get("/raclette/export/transactions.wrong") + self.assertEqual(resp.status_code, 404) class APITestCase(IhatemoneyTestCase): diff --git a/ihatemoney/web.py b/ihatemoney/web.py index b70bc5fd..8ab32171 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -11,7 +11,7 @@ and `add_project_id` for a quick overview) import os from flask import ( - Blueprint, current_app, flash, g, redirect, render_template, request, + abort, Blueprint, current_app, flash, g, redirect, render_template, request, session, url_for, send_file, send_from_directory ) from flask_mail import Message @@ -25,8 +25,7 @@ from functools import wraps from ihatemoney.models import db, Project, Person, Bill from ihatemoney.forms import ( AdminAuthenticationForm, AuthenticationForm, EditProjectForm, - InviteForm, MemberForm, PasswordReminder, ResetPasswordForm, ProjectForm, get_billform_for, - ExportForm + InviteForm, MemberForm, PasswordReminder, ResetPasswordForm, ProjectForm, get_billform_for ) from ihatemoney.utils import Redirect303, list_of_dicts2json, list_of_dicts2csv, LoginThrottler @@ -309,7 +308,6 @@ def reset_password(): @main.route("//edit", methods=["GET", "POST"]) def edit_project(): edit_form = EditProjectForm() - export_form = ExportForm() if request.method == "POST": if edit_form.validate(): project = edit_form.update(g.project) @@ -317,28 +315,6 @@ def edit_project(): db.session.commit() return redirect(url_for(".list_bills")) - - if export_form.validate(): - export_format = export_form.export_format.data - export_type = export_form.export_type.data - - if export_type == 'transactions': - export = g.project.get_transactions_to_settle_bill( - pretty_output=True) - if export_type == "bills": - export = g.project.get_pretty_bills( - export_format=export_format) - - if export_format == "json": - file2export = list_of_dicts2json(export) - if export_format == "csv": - file2export = list_of_dicts2csv(export) - - return send_file(file2export, - attachment_filename="%s-%s.%s" % - (g.project.id, export_type, export_format), - as_attachment=True - ) else: edit_form.name.data = g.project.name edit_form.contact_email.data = g.project.contact_email @@ -346,7 +322,6 @@ def edit_project(): return render_template( "edit_project.html", edit_form=edit_form, - export_form=export_form, current_view="edit_project" ) @@ -359,6 +334,29 @@ def delete_project(): return redirect(request.headers.get('Referer') or url_for('.home')) +@main.route("//export/.") +def export_project(file, format): + if file == 'transactions': + export = g.project.get_transactions_to_settle_bill(pretty_output=True) + elif file == "bills": + export = g.project.get_pretty_bills(export_format=format) + else: + abort(404, 'No such export type') + + if format == "json": + file2export = list_of_dicts2json(export) + elif format == "csv": + file2export = list_of_dicts2csv(export) + else: + abort(404, 'No such export format') + + return send_file( + file2export, + attachment_filename="%s-%s.%s" % (g.project.id, file, format), + as_attachment=True + ) + + @main.route("/exit") def exit(): # delete the session