diff --git a/CHANGELOG.rst b/CHANGELOG.rst index de1356e5..9aa61bef 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,7 +6,10 @@ This document describes changes between each past release. 2.1 (unreleased) ---------------- -- Nothing changed yet. +Fixed +===== + +- Fix the "IOError" crash when running `ihatemoney generate-config` (#308) 2.0 (2017-12-27) diff --git a/MANIFEST.in b/MANIFEST.in index 91d0edb2..74ea23b1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include *.rst -recursive-include ihatemoney *.rst *.py *.yaml *.po *.mo *.html *.css *.js *.eot *.svg *.woff *.txt *.png *.ini *.cfg +recursive-include ihatemoney *.rst *.py *.yaml *.po *.mo *.html *.css *.js *.eot *.svg *.woff *.txt *.png *.ini *.cfg *.j2 include LICENSE CONTRIBUTORS CHANGELOG.rst requirements.txt diff --git a/dev-requirements.txt b/dev-requirements.txt index 04358ae8..28116fac 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -3,3 +3,4 @@ tox pytest Flask-Testing Flake8 +mock; python_version < '3.3' diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index 797e6c4b..315cfac1 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -4,7 +4,7 @@ import os import pkgutil import random import sys -from getpass import getpass +import getpass from flask_script import Manager, Command, Option from flask_migrate import Migrate, MigrateCommand @@ -20,11 +20,11 @@ class GeneratePasswordHash(Command): """Get password from user and hash it without printing it in clear text.""" def run(self): - password = getpass(prompt='Password: ') + password = getpass.getpass(prompt='Password: ') print(generate_password_hash(password)) -class ConfigTemplate(Command): +class GenerateConfig(Command): def get_options(self): return [ Option('config_file', choices=[ @@ -74,7 +74,7 @@ def main(): manager = Manager(app) manager.add_command('db', MigrateCommand) manager.add_command('generate_password_hash', GeneratePasswordHash) - manager.add_command('generate-config', ConfigTemplate) + manager.add_command('generate-config', GenerateConfig) manager.run() diff --git a/ihatemoney/templates/invitation_mail.en b/ihatemoney/templates/invitation_mail.en.j2 similarity index 70% rename from ihatemoney/templates/invitation_mail.en rename to ihatemoney/templates/invitation_mail.en.j2 index eeaafdb9..42be0d25 100644 --- a/ihatemoney/templates/invitation_mail.en +++ b/ihatemoney/templates/invitation_mail.en.j2 @@ -2,10 +2,10 @@ Hi, Someone using the email address {{ g.project.contact_email }} invited you to share your expenses for "{{ g.project.name }}". -It's as simple as saying what did you paid for, for who, and how much did it cost you, we are caring about the rest. +It's as simple as saying what did you pay for, for whom, and how much did it cost you, we are caring about the rest. You can log in using this link: {{ url_for(".authenticate", _external=True, token=g.project.generate_token()) }}. -Once logged in you can use the following link which is easier to remember: {{ url_for(".list_bills", _external=True) }} +Once logged-in, you can use the following link which is easier to remember: {{ url_for(".list_bills", _external=True) }} If your cookie gets deleted or if you log out, you will need to log back in using the first link. Enjoy, diff --git a/ihatemoney/templates/invitation_mail.fr b/ihatemoney/templates/invitation_mail.fr.j2 similarity index 53% rename from ihatemoney/templates/invitation_mail.fr rename to ihatemoney/templates/invitation_mail.fr.j2 index a95f9e9e..197edcca 100644 --- a/ihatemoney/templates/invitation_mail.fr +++ b/ihatemoney/templates/invitation_mail.fr.j2 @@ -1,11 +1,11 @@ Salut, -Quelqu'un avec l'addresse email "{{ g.project.contact_email }}" vous à invité à partager vos dépenses pour "{{ g.project.name }}". +Quelqu'un avec l'adresse "{{ g.project.contact_email }}" vous à invité à partager vos dépenses pour "{{ g.project.name }}". -C'est aussi simple que de dire qui à payé pour quoi, pour qui, et combien celà à coûté, on s'occuppe du reste. +C'est aussi simple que de dire qui à payé pour quoi, pour qui, et combien celà à coûté, on s’occupe du reste. Vous pouvez vous authentifier avec le lien suivant: {{ url_for(".authenticate", _external=True, token=g.project.generate_token()) }}. Une fois authentifié, vous pouvez utiliser le lien suivant qui est plus facile à mémoriser: {{ url_for(".list_bills", _external=True) }} -Si votre cookie est supprimé ou si vous vous déconnectez, voous devrez vous réauthentifier en utilisant le premier lien. +Si votre cookie est supprimé ou si vous vous déconnectez, vous devrez vous authentifier à nouveau en utilisant le premier lien. Have fun, diff --git a/ihatemoney/templates/password_reminder.en b/ihatemoney/templates/password_reminder.en.j2 similarity index 80% rename from ihatemoney/templates/password_reminder.en rename to ihatemoney/templates/password_reminder.en.j2 index bc7e609c..c6543546 100644 --- a/ihatemoney/templates/password_reminder.en +++ b/ihatemoney/templates/password_reminder.en.j2 @@ -1,8 +1,8 @@ Hi, -You requested to reset the password of the following project: "{{ project.name }}". +You requested to reset the password of the following project: "{{ project.name }}". You can reset it here: {{ url_for(".reset_password", _external=True, token=project.generate_token(expiration=3600)) }}. -This link is only valid for 1 hour. +This link is only valid for one hour. Hope this helps, Some weird guys (with beards) diff --git a/ihatemoney/templates/password_reminder.fr b/ihatemoney/templates/password_reminder.fr.j2 similarity index 100% rename from ihatemoney/templates/password_reminder.fr rename to ihatemoney/templates/password_reminder.fr.j2 diff --git a/ihatemoney/templates/reminder_mail.en b/ihatemoney/templates/reminder_mail.en.j2 similarity index 100% rename from ihatemoney/templates/reminder_mail.en rename to ihatemoney/templates/reminder_mail.en.j2 diff --git a/ihatemoney/templates/reminder_mail.fr b/ihatemoney/templates/reminder_mail.fr.j2 similarity index 100% rename from ihatemoney/templates/reminder_mail.fr rename to ihatemoney/templates/reminder_mail.fr.j2 diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index de53c584..d4b6d7a1 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -4,6 +4,10 @@ try: import unittest2 as unittest except ImportError: import unittest # NOQA +try: + from unittest.mock import patch +except ImportError: + from mock import patch import os import json @@ -16,6 +20,7 @@ from flask import session from flask_testing import TestCase from ihatemoney.run import create_app, db, load_configuration +from ihatemoney.manage import GenerateConfig, GeneratePasswordHash from ihatemoney import models from ihatemoney import utils @@ -1406,5 +1411,27 @@ class ServerTestCase(IhatemoneyTestCase): self.assertStatus(200, req) +class CommandTestCase(BaseTestCase): + def test_generate_config(self): + """ Simply checks that all config file generation + - raise no exception + - produce something non-empty + """ + cmd = GenerateConfig() + for config_file in cmd.get_options()[0].kwargs['choices']: + with patch('sys.stdout', new=six.StringIO()) as stdout: + cmd.run(config_file) + print(stdout.getvalue()) + self.assertNotEqual(len(stdout.getvalue().strip()), 0) + + def test_generate_password_hash(self): + cmd = GeneratePasswordHash() + with patch('sys.stdout', new=six.StringIO()) as stdout, \ + patch('getpass.getpass', new=lambda prompt: 'secret'): # NOQA + cmd.run() + print(stdout.getvalue()) + self.assertEqual(len(stdout.getvalue().strip()), 187) + + if __name__ == "__main__": unittest.main() diff --git a/ihatemoney/web.py b/ihatemoney/web.py index e6df385a..6b1b3589 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -242,7 +242,7 @@ def create_project(): message_title = _("You have just created '%(project)s' " "to share your expenses", project=g.project.name) - message_body = render_template("reminder_mail.%s" % + message_body = render_template("reminder_mail.%s.j2" % get_locale().language) msg = Message(message_title, @@ -273,7 +273,7 @@ def remind_password(): project = Project.query.get(form.id.data) # send a link to reset the password - password_reminder = "password_reminder.%s" % get_locale().language + password_reminder = "password_reminder.%s.j2" % get_locale().language current_app.mail.send(Message( "password recovery", body=render_template(password_reminder, project=project), @@ -395,7 +395,7 @@ def invite(): if form.validate(): # send the email - message_body = render_template("invitation_mail.%s" % + message_body = render_template("invitation_mail.%s.j2" % get_locale().language) message_title = _("You have been invited to share your " diff --git a/tox.ini b/tox.ini index ddef0a1a..15c2b40f 100644 --- a/tox.ini +++ b/tox.ini @@ -6,22 +6,31 @@ skip_missing_interpreters = True commands = python --version - py.test ihatemoney/tests/tests.py + py.test --pyargs ihatemoney.tests.tests + deps = -rdev-requirements.txt -rrequirements.txt -install_command = pip install --pre {opts} {packages} +# To be sure we are importing ihatemoney pkg from pip-installed version +changedir = /tmp + +install_command = + pip install --pre {opts} {packages} + pip install . + [testenv:docs] commands = sphinx-build -a -n -b html -d docs/_build/doctrees docs docs/_build/html deps = -rdocs/requirements.txt +changedir = {toxinidir} [testenv:lint] commands = flake8 ihatemoney deps = -rdev-requirements.txt +changedir = {toxinidir} [flake8] exclude = migrations