Improve error handling when sending emails (#595)

In one case, we were not catching a family of possible exceptions
(socket.error), and in the two other cases there was no error handling at
all. Sending emails can easily fail if no email server is configured, so
it is really necessary to handle these errors instead of crashing with a
HTTP 500 error.

Refactor email sending code and add proper error handling.

Show alert messages that tell the user if an email was sent or if there
was an error.

When sending a password reminder email or inviting people by email, we
don't proceed to the next step in case of error, because sending emails is
the whole point of these actions.
This commit is contained in:
zorun 2020-05-21 21:13:33 +02:00 committed by GitHub
parent e10ea6c776
commit df6ffc7d86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 549 additions and 104 deletions

View file

@ -157,13 +157,24 @@ msgstr ""
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "" msgstr ""
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "" msgstr ""
@ -192,6 +203,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""

View file

@ -5,6 +5,8 @@ import io
import json import json
import os import os
import re import re
import smtplib
import socket
from time import sleep from time import sleep
import unittest import unittest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
@ -51,10 +53,10 @@ class BaseTestCase(TestCase):
follow_redirects=True, follow_redirects=True,
) )
def post_project(self, name): def post_project(self, name, follow_redirects=True):
"""Create a fake project""" """Create a fake project"""
# create the project # create the project
self.client.post( return self.client.post(
"/create", "/create",
data={ data={
"name": name, "name": name,
@ -63,6 +65,7 @@ class BaseTestCase(TestCase):
"contact_email": f"{name}@notmyidea.org", "contact_email": f"{name}@notmyidea.org",
"default_currency": "USD", "default_currency": "USD",
}, },
follow_redirects=follow_redirects,
) )
def create_project(self, name): def create_project(self, name):
@ -141,10 +144,15 @@ class BudgetTestCase(IhatemoneyTestCase):
self.login("raclette") self.login("raclette")
self.post_project("raclette") self.post_project("raclette")
self.client.post( resp = self.client.post(
"/raclette/invite", data={"emails": "zorglub@notmyidea.org"} "/raclette/invite",
data={"emails": "zorglub@notmyidea.org"},
follow_redirects=True,
) )
# success notification
self.assertIn("Your invitations have been sent", resp.data.decode("utf-8"))
self.assertEqual(len(outbox), 2) self.assertEqual(len(outbox), 2)
self.assertEqual(outbox[0].recipients, ["raclette@notmyidea.org"]) self.assertEqual(outbox[0].recipients, ["raclette@notmyidea.org"])
self.assertEqual(outbox[1].recipients, ["zorglub@notmyidea.org"]) self.assertEqual(outbox[1].recipients, ["zorglub@notmyidea.org"])
@ -225,7 +233,15 @@ class BudgetTestCase(IhatemoneyTestCase):
self.create_project("raclette") self.create_project("raclette")
# Get password resetting link from mail # Get password resetting link from mail
with self.app.mail.record_messages() as outbox: with self.app.mail.record_messages() as outbox:
self.client.post("/password-reminder", data={"id": "raclette"}) resp = self.client.post(
"/password-reminder", data={"id": "raclette"}, follow_redirects=True
)
# Check that we are redirected to the right page
self.assertIn(
"A link to reset your password has been sent to you",
resp.data.decode("utf-8"),
)
# Check that an email was sent
self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox), 1)
url_start = outbox[0].body.find("You can reset it here: ") + 23 url_start = outbox[0].body.find("You can reset it here: ") + 23
url_end = outbox[0].body.find(".\n", url_start) url_end = outbox[0].body.find(".\n", url_start)
@ -250,8 +266,9 @@ class BudgetTestCase(IhatemoneyTestCase):
def test_project_creation(self): def test_project_creation(self):
with self.app.test_client() as c: with self.app.test_client() as c:
with self.app.mail.record_messages() as outbox:
# add a valid project # add a valid project
c.post( resp = c.post(
"/create", "/create",
data={ data={
"name": "The fabulous raclette party", "name": "The fabulous raclette party",
@ -260,6 +277,14 @@ class BudgetTestCase(IhatemoneyTestCase):
"contact_email": "raclette@notmyidea.org", "contact_email": "raclette@notmyidea.org",
"default_currency": "USD", "default_currency": "USD",
}, },
follow_redirects=True,
)
# an email is sent to the owner with a reminder of the password
self.assertEqual(len(outbox), 1)
self.assertEqual(outbox[0].recipients, ["raclette@notmyidea.org"])
self.assertIn(
"A reminder email has just been sent to you",
resp.data.decode("utf-8"),
) )
# session is updated # session is updated
@ -2265,6 +2290,78 @@ class ModelsTestCase(IhatemoneyTestCase):
self.assertEqual(bill.pay_each(), pay_each_expected) self.assertEqual(bill.pay_each(), pay_each_expected)
class EmailFailureTestCase(IhatemoneyTestCase):
def test_creation_email_failure_smtp(self):
self.login("raclette")
with patch.object(
self.app.mail, "send", MagicMock(side_effect=smtplib.SMTPException)
):
resp = self.post_project("raclette")
# Check that an error message is displayed
self.assertIn(
"We tried to send you an reminder email, but there was an error",
resp.data.decode("utf-8"),
)
# Check that we were redirected to the home page anyway
self.assertIn(
'You probably want to <a href="/raclette/members/add"',
resp.data.decode("utf-8"),
)
def test_creation_email_failure_socket(self):
self.login("raclette")
with patch.object(self.app.mail, "send", MagicMock(side_effect=socket.error)):
resp = self.post_project("raclette")
# Check that an error message is displayed
self.assertIn(
"We tried to send you an reminder email, but there was an error",
resp.data.decode("utf-8"),
)
# Check that we were redirected to the home page anyway
self.assertIn(
'You probably want to <a href="/raclette/members/add"',
resp.data.decode("utf-8"),
)
def test_password_reset_email_failure(self):
self.create_project("raclette")
for exception in (smtplib.SMTPException, socket.error):
with patch.object(self.app.mail, "send", MagicMock(side_effect=exception)):
resp = self.client.post(
"/password-reminder", data={"id": "raclette"}, follow_redirects=True
)
# Check that an error message is displayed
self.assertIn(
"there was an error while sending you an email",
resp.data.decode("utf-8"),
)
# Check that we were not redirected to the success page
self.assertNotIn(
"A link to reset your password has been sent to you",
resp.data.decode("utf-8"),
)
def test_invitation_email_failure(self):
self.login("raclette")
self.post_project("raclette")
for exception in (smtplib.SMTPException, socket.error):
with patch.object(self.app.mail, "send", MagicMock(side_effect=exception)):
resp = self.client.post(
"/raclette/invite",
data={"emails": "toto@notmyidea.org"},
follow_redirects=True,
)
# Check that an error message is displayed
self.assertIn(
"there was an error while trying to send the invitation emails",
resp.data.decode("utf-8"),
)
# Check that we are still on the same page (no redirection)
self.assertIn(
"Invite people to join this project", resp.data.decode("utf-8"),
)
def em_surround(string, regex_escape=False): def em_surround(string, regex_escape=False):
if regex_escape: if regex_escape:
return r'<em class="font-italic">%s<\/em>' % string return r'<em class="font-italic">%s<\/em>' % string

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language: cs\n" "Language: cs\n"
@ -12,7 +12,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -173,13 +173,24 @@ msgstr ""
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "" msgstr ""
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "" msgstr ""
@ -208,6 +219,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -757,3 +774,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "" #~ msgstr ""
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-02-12 10:50+0000\n" "PO-Revision-Date: 2020-02-12 10:50+0000\n"
"Last-Translator: flolilo <flolilo@mailbox.org>\n" "Last-Translator: flolilo <flolilo@mailbox.org>\n"
"Language: de\n" "Language: de\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -182,13 +182,24 @@ msgstr ""
"Du hast gerade das Projekt '%(project)s' erstellt, um deine Ausgaben zu " "Du hast gerade das Projekt '%(project)s' erstellt, um deine Ausgaben zu "
"teilen" "teilen"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Kein Token zur Verfügung gestellt" msgstr "Kein Token zur Verfügung gestellt"
@ -217,6 +228,12 @@ msgstr "Du wurdest eingeladen, deine Ausgaben für %(project)s zu teilen"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Deine Einladungen wurden versendet" msgstr "Deine Einladungen wurden versendet"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -785,3 +802,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "alles" #~ msgstr "alles"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language: el\n" "Language: el\n"
@ -12,7 +12,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -173,13 +173,24 @@ msgstr ""
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "" msgstr ""
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "" msgstr ""
@ -208,6 +219,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -757,3 +774,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "" #~ msgstr ""
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-05-03 15:20+0000\n" "PO-Revision-Date: 2020-05-03 15:20+0000\n"
"Last-Translator: Fabian Rodriguez <fabian@fabianrodriguez.com>\n" "Last-Translator: Fabian Rodriguez <fabian@fabianrodriguez.com>\n"
"Language: es_419\n" "Language: es_419\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -182,13 +182,24 @@ msgstr "Este código privado no es el correcto"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Acabas de crear '%(project)s' para compartir tus gastos" msgstr "Acabas de crear '%(project)s' para compartir tus gastos"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "No se proporciono ningún token" msgstr "No se proporciono ningún token"
@ -217,6 +228,12 @@ msgstr "Usted ha sido invitado a compartir sus gastos para %(project)s"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Sus invitaciones han sido enviadas" msgstr "Sus invitaciones han sido enviadas"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "Se añadieron %(member)s" msgstr "Se añadieron %(member)s"
@ -806,3 +823,6 @@ msgstr "Período"
#~ msgid "each" #~ msgid "each"
#~ msgstr "Cada" #~ msgstr "Cada"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -7,18 +7,17 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-05-15 20:41+0000\n" "PO-Revision-Date: 2020-05-15 20:41+0000\n"
"Last-Translator: Glandos <bugs-github@antipoul.fr>\n" "Last-Translator: Glandos <bugs-github@antipoul.fr>\n"
"Language-Team: French <https://hosted.weblate.org/projects/i-hate-money/"
"i-hate-money/fr/>\n"
"Language: fr\n" "Language: fr\n"
"Language-Team: French <https://hosted.weblate.org/projects/i-hate-money/i"
"-hate-money/fr/>\n"
"Plural-Forms: nplurals=2; plural=n > 1\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n" "Generated-By: Babel 2.8.0\n"
"X-Generator: Weblate 4.1-dev\n"
"Generated-By: Babel 2.7.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -185,13 +184,24 @@ msgstr "Le code que vous avez entré nest pas correct"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Vous venez de créer « %(project)s » pour partager vos dépenses" msgstr "Vous venez de créer « %(project)s » pour partager vos dépenses"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr "Erreur lors de lenvoi du courriel de rappel" msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "Lidentifiant de ce projet est %(project)s" msgstr "Lidentifiant de ce projet est %(project)s"
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Aucun token na été fourni" msgstr "Aucun token na été fourni"
@ -220,6 +230,12 @@ msgstr "Vous avez été invité à partager vos dépenses pour %(project)s"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Vos invitations ont bien été envoyées" msgstr "Vos invitations ont bien été envoyées"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "%(member)s a été ajouté" msgstr "%(member)s a été ajouté"
@ -1019,3 +1035,7 @@ msgstr "Période"
#~ msgid "each" #~ msgid "each"
#~ msgstr "chacun" #~ msgstr "chacun"
#~ msgid "Error while sending reminder email"
#~ msgstr "Erreur lors de lenvoi du courriel de rappel"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2019-11-16 10:04+0000\n" "PO-Revision-Date: 2019-11-16 10:04+0000\n"
"Last-Translator: Muhammad Fauzi <fauzi.padlaw@gmail.com>\n" "Last-Translator: Muhammad Fauzi <fauzi.padlaw@gmail.com>\n"
"Language: id\n" "Language: id\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -178,13 +178,24 @@ msgstr "Kode pribadi ini tidak benar"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Anda baru saja membuat %(project)s untuk membagikan harga Anda" msgstr "Anda baru saja membuat %(project)s untuk membagikan harga Anda"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Belum ada token diberikan" msgstr "Belum ada token diberikan"
@ -213,6 +224,12 @@ msgstr "Anda telah diundang untuk membagikan harga Anda untuk %(project)s"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Undangan Anda telah dikirim" msgstr "Undangan Anda telah dikirim"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -785,3 +802,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "setiap" #~ msgstr "setiap"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -1,19 +1,19 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-05-18 13:02+0000\n" "PO-Revision-Date: 2020-05-18 13:02+0000\n"
"Last-Translator: Anonymous <noreply@weblate.org>\n" "Last-Translator: Anonymous <noreply@weblate.org>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/i-hate-money/"
"i-hate-money/it/>\n"
"Language: it\n" "Language: it\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/i-hate-"
"money/i-hate-money/it/>\n"
"Plural-Forms: nplurals=2; plural=n != 1\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Generated-By: Babel 2.8.0\n"
"X-Generator: Weblate 4.1-dev\n"
"Generated-By: Babel 2.7.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -172,7 +172,8 @@ msgstr ""
msgid "You either provided a bad token or no project identifier." msgid "You either provided a bad token or no project identifier."
msgstr "" msgstr ""
"Hai fornito un token invalido o l'identificatore del progetto non è valido." "Hai fornito un token invalido o l'identificatore del progetto non è "
"valido."
msgid "This private code is not the right one" msgid "This private code is not the right one"
msgstr "Questo codice privato non è quello corretto" msgstr "Questo codice privato non è quello corretto"
@ -181,13 +182,24 @@ msgstr "Questo codice privato non è quello corretto"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Hai appena creato '%(project)s' per condividere le tue spese" msgstr "Hai appena creato '%(project)s' per condividere le tue spese"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr "Errore durante l'invio dell'email di promemoria" msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "L'identificatore del progetto è %(project)s" msgstr "L'identificatore del progetto è %(project)s"
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Nessun token fornito" msgstr "Nessun token fornito"
@ -216,6 +228,12 @@ msgstr "Sei stato invitato a condividere le tue spese per %(project)s"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "I tuoi inviti sono stati spediti" msgstr "I tuoi inviti sono stati spediti"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "%(member)s è stato aggiunto" msgstr "%(member)s è stato aggiunto"
@ -764,3 +782,7 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "" #~ msgstr ""
#~ msgid "Error while sending reminder email"
#~ msgstr "Errore durante l'invio dell'email di promemoria"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2019-11-12 09:04+0000\n" "PO-Revision-Date: 2019-11-12 09:04+0000\n"
"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" "Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
"Language: nb_NO\n" "Language: nb_NO\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -182,13 +182,24 @@ msgstr "Denne private koden er ikke rett"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Du har akkurat opprettet \"%(project)s\" for å dele dine utgifter" msgstr "Du har akkurat opprettet \"%(project)s\" for å dele dine utgifter"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Inget symbol angitt" msgstr "Inget symbol angitt"
@ -221,6 +232,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Invitasjonene dine har blitt sendt" msgstr "Invitasjonene dine har blitt sendt"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -916,3 +933,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "hver" #~ msgstr "hver"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2019-10-07 22:56+0000\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n"
"Last-Translator: Heimen Stoffels <vistausss@outlook.com>\n" "Last-Translator: Heimen Stoffels <vistausss@outlook.com>\n"
"Language: nl\n" "Language: nl\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -176,13 +176,24 @@ msgstr ""
"Je hebt zojuist het project '%(project)s' aangemaakt om je uitgaven te " "Je hebt zojuist het project '%(project)s' aangemaakt om je uitgaven te "
"verdelen" "verdelen"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Geen toegangssleutel opgegeven" msgstr "Geen toegangssleutel opgegeven"
@ -211,6 +222,12 @@ msgstr "Je bent uitgenodigd om je uitgaven te delen met %(project)s"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Je uitnodigingen zijn verstuurd" msgstr "Je uitnodigingen zijn verstuurd"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -774,3 +791,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "per persoon" #~ msgstr "per persoon"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -1,20 +1,20 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-05-13 15:41+0000\n" "PO-Revision-Date: 2020-05-13 15:41+0000\n"
"Last-Translator: Szylu <chipolade@gmail.com>\n" "Last-Translator: Szylu <chipolade@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/i-hate-money/"
"i-hate-money/pl/>\n"
"Language: pl\n" "Language: pl\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/i-hate-money/i"
"-hate-money/pl/>\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && "
"(n%100<10 || n%100>=20) ? 1 : 2\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "Generated-By: Babel 2.8.0\n"
"|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.1-dev\n"
"Generated-By: Babel 2.7.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -179,13 +179,24 @@ msgstr "Ten prywatny kod jest niewłaściwy"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Właśnie utworzyłeś „%(project)s”, aby podzielić się wydatkami" msgstr "Właśnie utworzyłeś „%(project)s”, aby podzielić się wydatkami"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr "Błąd podczas wysyłania wiadomości e-mail z przypomnieniem" msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "Identyfikator projektu to %(project)s" msgstr "Identyfikator projektu to %(project)s"
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Nie podano tokena" msgstr "Nie podano tokena"
@ -214,6 +225,12 @@ msgstr "Zostałeś zaproszony do podzielenia się swoimi wydatkami w %(project)s
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Twoje zaproszenia zostały wysłane" msgstr "Twoje zaproszenia zostały wysłane"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "%(member)s został dodany" msgstr "%(member)s został dodany"
@ -799,3 +816,7 @@ msgstr "Okres"
#~ msgid "each" #~ msgid "each"
#~ msgstr "każdy" #~ msgstr "każdy"
#~ msgid "Error while sending reminder email"
#~ msgstr "Błąd podczas wysyłania wiadomości e-mail z przypomnieniem"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-04-28 07:11+0000\n" "PO-Revision-Date: 2020-04-28 07:11+0000\n"
"Last-Translator: Vsevolod <sevauserg.com@gmail.com>\n" "Last-Translator: Vsevolod <sevauserg.com@gmail.com>\n"
"Language: ru\n" "Language: ru\n"
@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -181,13 +181,24 @@ msgstr "Этот приватный код не подходит"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "Вы только что создали '%(project)s' , чтобы разделить расходы" msgstr "Вы только что создали '%(project)s' , чтобы разделить расходы"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "Не предоставлен токен" msgstr "Не предоставлен токен"
@ -216,6 +227,12 @@ msgstr "Вас пригласили разделить расходы в про
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "Ваш код приглашения был отправлен" msgstr "Ваш код приглашения был отправлен"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "%(member)s был добавлен" msgstr "%(member)s был добавлен"
@ -795,3 +812,6 @@ msgstr "Период"
#~ msgid "each" #~ msgid "each"
#~ msgstr "каждый" #~ msgstr "каждый"
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2019-08-07 13:24+0000\n" "PO-Revision-Date: 2019-08-07 13:24+0000\n"
"Last-Translator: Mesut Akcan <makcan@gmail.com>\n" "Last-Translator: Mesut Akcan <makcan@gmail.com>\n"
"Language: tr\n" "Language: tr\n"
@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -178,13 +178,24 @@ msgstr ""
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "" msgstr ""
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "" msgstr ""
@ -213,6 +224,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -762,3 +779,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "" #~ msgstr ""
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2019-12-08 16:26+0000\n" "PO-Revision-Date: 2019-12-08 16:26+0000\n"
"Last-Translator: Tymofij Lytvynenko <till.svit@gmail.com>\n" "Last-Translator: Tymofij Lytvynenko <till.svit@gmail.com>\n"
"Language: uk\n" "Language: uk\n"
@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.7.0\n" "Generated-By: Babel 2.8.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -175,13 +175,24 @@ msgstr ""
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "" msgstr ""
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr "" msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "" msgstr ""
@ -210,6 +221,12 @@ msgstr ""
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "" msgstr ""
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "" msgstr ""
@ -759,3 +776,6 @@ msgstr ""
#~ msgid "each" #~ msgid "each"
#~ msgstr "" #~ msgstr ""
#~ msgid "Error while sending reminder email"
#~ msgstr ""

View file

@ -1,19 +1,20 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-09 21:41+0200\n" "POT-Creation-Date: 2020-05-18 15:11+0200\n"
"PO-Revision-Date: 2020-05-13 15:41+0000\n" "PO-Revision-Date: 2020-05-13 15:41+0000\n"
"Last-Translator: Muge Niu <mugeniu12138@gmail.com>\n" "Last-Translator: Muge Niu <mugeniu12138@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "Language: zh_HANS_CN\n"
"i-hate-money/i-hate-money/zh_Hans/>\n" "Language-Team: Chinese (Simplified) "
"Language: zh_HANS-CN\n" "<https://hosted.weblate.org/projects/i-hate-money/i-hate-money/zh_Hans/>"
"\n"
"Plural-Forms: nplurals=1; plural=0\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.8.0\n"
"X-Generator: Weblate 4.1-dev\n"
"Generated-By: Babel 2.7.0\n"
msgid "" msgid ""
"Not a valid amount or expression. Only numbers and + - * / operators are " "Not a valid amount or expression. Only numbers and + - * / operators are "
@ -174,13 +175,24 @@ msgstr "专用码不正确"
msgid "You have just created '%(project)s' to share your expenses" msgid "You have just created '%(project)s' to share your expenses"
msgstr "你新建了一个‘%(project)s'来分担你的花费" msgstr "你新建了一个‘%(project)s'来分担你的花费"
msgid "Error while sending reminder email" msgid "A reminder email has just been sent to you"
msgstr "发送提醒邮件时出错" msgstr ""
msgid ""
"We tried to send you an reminder email, but there was an error. You can "
"still use the project normally."
msgstr ""
#, python-format #, python-format
msgid "The project identifier is %(project)s" msgid "The project identifier is %(project)s"
msgstr "项目的标识符是%(project)s" msgstr "项目的标识符是%(project)s"
msgid ""
"Sorry, there was an error while sending you an email with password reset "
"instructions. Please check the email configuration of the server or "
"contact the administrator."
msgstr ""
msgid "No token provided" msgid "No token provided"
msgstr "没有符号" msgstr "没有符号"
@ -209,6 +221,12 @@ msgstr "你被邀请进入 %(project)s来分担你的花费"
msgid "Your invitations have been sent" msgid "Your invitations have been sent"
msgstr "你的申请已发出" msgstr "你的申请已发出"
msgid ""
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server or contact the "
"administrator."
msgstr ""
#, python-format #, python-format
msgid "%(member)s has been added" msgid "%(member)s has been added"
msgstr "已添加%(member)s" msgstr "已添加%(member)s"
@ -771,3 +789,7 @@ msgstr "期间"
#~ msgid "each" #~ msgid "each"
#~ msgstr "每一个·" #~ msgstr "每一个·"
#~ msgid "Error while sending reminder email"
#~ msgstr "发送提醒邮件时出错"

View file

@ -7,6 +7,8 @@ from json import JSONEncoder, dumps
import operator import operator
import os import os
import re import re
import smtplib
import socket
from babel import Locale from babel import Locale
from babel.numbers import get_currency_name, get_currency_symbol from babel.numbers import get_currency_name, get_currency_symbol
@ -28,6 +30,22 @@ def slugify(value):
return re.sub(r"[-\s]+", "-", value) return re.sub(r"[-\s]+", "-", value)
def send_email(mail_message):
"""Send an email using Flask-Mail, with proper error handling.
Return True if everything went well, and False if there was an error.
"""
# Since Python 3.4, SMTPException and socket.error are actually
# identical, but this was not the case before. Also, it is more clear
# to check for both.
try:
current_app.mail.send(mail_message)
except (smtplib.SMTPException, socket.error):
return False
# Email was sent successfully
return True
class Redirect303(HTTPException, RoutingException): class Redirect303(HTTPException, RoutingException):
"""Raise if the map requests a redirect. This is for example the case if """Raise if the map requests a redirect. This is for example the case if

View file

@ -12,7 +12,6 @@ from datetime import datetime
from functools import wraps from functools import wraps
import json import json
import os import os
from smtplib import SMTPRecipientsRefused
from dateutil.parser import parse from dateutil.parser import parse
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -60,6 +59,7 @@ from ihatemoney.utils import (
list_of_dicts2json, list_of_dicts2json,
render_localized_template, render_localized_template,
same_bill, same_bill,
send_email,
) )
main = Blueprint("main", __name__) main = Blueprint("main", __name__)
@ -308,11 +308,21 @@ def create_project():
msg = Message( msg = Message(
message_title, body=message_body, recipients=[project.contact_email] message_title, body=message_body, recipients=[project.contact_email]
) )
try: success = send_email(msg)
current_app.mail.send(msg) if success:
except SMTPRecipientsRefused: flash(
flash(_("Error while sending reminder email"), category="danger") _("A reminder email has just been sent to you"), category="success"
)
else:
# Display the error as a simple "info" alert, because it's
# not critical and doesn't prevent using the project.
flash(
_(
"We tried to send you an reminder email, but there was an error. "
"You can still use the project normally."
),
category="info",
)
# redirect the user to the next step (invite) # redirect the user to the next step (invite)
flash(_("The project identifier is %(project)s", project=project.id)) flash(_("The project identifier is %(project)s", project=project.id))
return redirect(url_for(".list_bills", project_id=project.id)) return redirect(url_for(".list_bills", project_id=project.id))
@ -328,17 +338,25 @@ def remind_password():
# get the project # get the project
project = Project.query.get(form.id.data) project = Project.query.get(form.id.data)
# send a link to reset the password # send a link to reset the password
current_app.mail.send( remind_message = Message(
Message(
"password recovery", "password recovery",
body=render_localized_template( body=render_localized_template("password_reminder", project=project),
"password_reminder", project=project
),
recipients=[project.contact_email], recipients=[project.contact_email],
) )
) success = send_email(remind_message)
if success:
return redirect(url_for(".password_reminder_sent")) return redirect(url_for(".password_reminder_sent"))
else:
flash(
_(
"Sorry, there was an error while sending you an email "
"with password reset instructions. "
"Please check the email configuration of the server "
"or contact the administrator."
),
category="danger",
)
# Fall-through: we stay on the same page and display the form again
return render_template("password_reminder.html", form=form) return render_template("password_reminder.html", form=form)
@ -585,10 +603,20 @@ def invite():
body=message_body, body=message_body,
recipients=[email.strip() for email in form.emails.data.split(",")], recipients=[email.strip() for email in form.emails.data.split(",")],
) )
current_app.mail.send(msg) success = send_email(msg)
flash(_("Your invitations have been sent")) if success:
flash(_("Your invitations have been sent"), category="success")
return redirect(url_for(".list_bills")) return redirect(url_for(".list_bills"))
else:
flash(
_(
"Sorry, there was an error while trying to send the invitation emails. "
"Please check the email configuration of the server "
"or contact the administrator."
),
category="danger",
)
# Fall-through: we stay on the same page and display the form again
return render_template("send_invites.html", form=form) return render_template("send_invites.html", form=form)