i18n in emails
parent
027e15475d
commit
2d960c7a5d
|
@ -58,7 +58,7 @@ def send_register_email(user) -> bool:
|
||||||
cancel_token = get_token_for_user(user, "cancel_account")
|
cancel_token = get_token_for_user(user, "cancel_account")
|
||||||
context = {"user": user, "cancel_token": cancel_token}
|
context = {"user": user, "cancel_token": cancel_token}
|
||||||
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
||||||
email = mbuilder.registered_user(user.email, context)
|
email = mbuilder.registered_user(user, context)
|
||||||
return bool(email.send())
|
return bool(email.send())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from optparse import make_option
|
||||||
|
|
||||||
from django.db.models.loading import get_model
|
from django.db.models.loading import get_model
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -30,6 +32,11 @@ from taiga.users.models import User
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
args = '<email>'
|
args = '<email>'
|
||||||
|
option_list = BaseCommand.option_list + (
|
||||||
|
make_option('--locale', '-l', default=None, dest='locale',
|
||||||
|
help='Send emails in an specific language.'),
|
||||||
|
)
|
||||||
|
|
||||||
help = 'Send an example of all emails'
|
help = 'Send an example of all emails'
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
@ -37,12 +44,13 @@ class Command(BaseCommand):
|
||||||
print("Usage: ./manage.py test_emails <email-address>")
|
print("Usage: ./manage.py test_emails <email-address>")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
locale = options.get('locale')
|
||||||
test_email = args[0]
|
test_email = args[0]
|
||||||
|
|
||||||
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
||||||
|
|
||||||
# Register email
|
# Register email
|
||||||
context = {"user": User.objects.all().order_by("?").first(), "cancel_token": "cancel-token"}
|
context = {"lang": locale, "user": User.objects.all().order_by("?").first(), "cancel_token": "cancel-token"}
|
||||||
email = mbuilder.registered_user(test_email, context)
|
email = mbuilder.registered_user(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
|
@ -51,17 +59,18 @@ class Command(BaseCommand):
|
||||||
membership.invited_by = User.objects.all().order_by("?").first()
|
membership.invited_by = User.objects.all().order_by("?").first()
|
||||||
membership.invitation_extra_text = "Text example, Text example,\nText example,\n\nText example"
|
membership.invitation_extra_text = "Text example, Text example,\nText example,\n\nText example"
|
||||||
|
|
||||||
context = {"membership": membership}
|
context = {"lang": locale, "membership": membership}
|
||||||
email = mbuilder.membership_invitation(test_email, context)
|
email = mbuilder.membership_invitation(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Membership notification
|
# Membership notification
|
||||||
context = {"membership": Membership.objects.order_by("?").filter(user__isnull=False).first()}
|
context = {"lang": locale, "membership": Membership.objects.order_by("?").filter(user__isnull=False).first()}
|
||||||
email = mbuilder.membership_notification(test_email, context)
|
email = mbuilder.membership_notification(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Feedback
|
# Feedback
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"feedback_entry": {
|
"feedback_entry": {
|
||||||
"full_name": "Test full name",
|
"full_name": "Test full name",
|
||||||
"email": "test@email.com",
|
"email": "test@email.com",
|
||||||
|
@ -76,17 +85,18 @@ class Command(BaseCommand):
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Password recovery
|
# Password recovery
|
||||||
context = {"user": User.objects.all().order_by("?").first()}
|
context = {"lang": locale, "user": User.objects.all().order_by("?").first()}
|
||||||
email = mbuilder.password_recovery(test_email, context)
|
email = mbuilder.password_recovery(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Change email
|
# Change email
|
||||||
context = {"user": User.objects.all().order_by("?").first()}
|
context = {"lang": locale, "user": User.objects.all().order_by("?").first()}
|
||||||
email = mbuilder.change_email(test_email, context)
|
email = mbuilder.change_email(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Export/Import emails
|
# Export/Import emails
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"user": User.objects.all().order_by("?").first(),
|
"user": User.objects.all().order_by("?").first(),
|
||||||
"project": Project.objects.all().order_by("?").first(),
|
"project": Project.objects.all().order_by("?").first(),
|
||||||
"error_subject": "Error generating project dump",
|
"error_subject": "Error generating project dump",
|
||||||
|
@ -95,6 +105,7 @@ class Command(BaseCommand):
|
||||||
email = mbuilder.export_error(test_email, context)
|
email = mbuilder.export_error(test_email, context)
|
||||||
email.send()
|
email.send()
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"user": User.objects.all().order_by("?").first(),
|
"user": User.objects.all().order_by("?").first(),
|
||||||
"error_subject": "Error importing project dump",
|
"error_subject": "Error importing project dump",
|
||||||
"error_message": "Error importing project dump",
|
"error_message": "Error importing project dump",
|
||||||
|
@ -104,6 +115,7 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
deletion_date = timezone.now() + datetime.timedelta(seconds=60*60*24)
|
deletion_date = timezone.now() + datetime.timedelta(seconds=60*60*24)
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"url": "http://dummyurl.com",
|
"url": "http://dummyurl.com",
|
||||||
"user": User.objects.all().order_by("?").first(),
|
"user": User.objects.all().order_by("?").first(),
|
||||||
"project": Project.objects.all().order_by("?").first(),
|
"project": Project.objects.all().order_by("?").first(),
|
||||||
|
@ -113,6 +125,7 @@ class Command(BaseCommand):
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"user": User.objects.all().order_by("?").first(),
|
"user": User.objects.all().order_by("?").first(),
|
||||||
"project": Project.objects.all().order_by("?").first(),
|
"project": Project.objects.all().order_by("?").first(),
|
||||||
}
|
}
|
||||||
|
@ -139,6 +152,7 @@ class Command(BaseCommand):
|
||||||
]
|
]
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
"lang": locale,
|
||||||
"project": Project.objects.all().order_by("?").first(),
|
"project": Project.objects.all().order_by("?").first(),
|
||||||
"changer": User.objects.all().order_by("?").first(),
|
"changer": User.objects.all().order_by("?").first(),
|
||||||
"history_entries": HistoryEntry.objects.all().order_by("?")[0:5],
|
"history_entries": HistoryEntry.objects.all().order_by("?")[0:5],
|
||||||
|
|
|
@ -49,7 +49,7 @@ def dump_project(self, user, project):
|
||||||
"error_message": "Error generating project dump",
|
"error_message": "Error generating project dump",
|
||||||
"project": project
|
"project": project
|
||||||
}
|
}
|
||||||
email = mbuilder.export_error(user.email, ctx)
|
email = mbuilder.export_error(user, ctx)
|
||||||
email.send()
|
email.send()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ def dump_project(self, user, project):
|
||||||
"user": user,
|
"user": user,
|
||||||
"deletion_date": deletion_date
|
"deletion_date": deletion_date
|
||||||
}
|
}
|
||||||
email = mbuilder.dump_project(user.email, ctx)
|
email = mbuilder.dump_project(user, ctx)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,10 +81,10 @@ def load_project_dump(user, dump):
|
||||||
"error_subject": "Error loading project dump",
|
"error_subject": "Error loading project dump",
|
||||||
"error_message": "Error loading project dump",
|
"error_message": "Error loading project dump",
|
||||||
}
|
}
|
||||||
email = mbuilder.import_error(user.email, ctx)
|
email = mbuilder.import_error(user, ctx)
|
||||||
email.send()
|
email.send()
|
||||||
return
|
return
|
||||||
|
|
||||||
ctx = {"user": user, "project": project}
|
ctx = {"user": user, "project": project}
|
||||||
email = mbuilder.load_dump(user.email, ctx)
|
email = mbuilder.load_dump(user, ctx)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
|
@ -269,6 +269,7 @@ def send_sync_notifications(notification_id):
|
||||||
|
|
||||||
for user in notification.notify_users.distinct():
|
for user in notification.notify_users.distinct():
|
||||||
context["user"] = user
|
context["user"] = user
|
||||||
|
context["lang"] = user.lang
|
||||||
email.send(user.email, context)
|
email.send(user.email, context)
|
||||||
|
|
||||||
notification.delete()
|
notification.delete()
|
||||||
|
|
|
@ -9,10 +9,11 @@ def send_invitation(invitation):
|
||||||
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
||||||
if invitation.user:
|
if invitation.user:
|
||||||
template = mbuilder.membership_notification
|
template = mbuilder.membership_notification
|
||||||
|
email = template(invitation.user, {"membership": invitation})
|
||||||
else:
|
else:
|
||||||
template = mbuilder.membership_invitation
|
template = mbuilder.membership_invitation
|
||||||
|
email = template(invitation.email, {"membership": invitation})
|
||||||
|
|
||||||
email = template(invitation.email, {"membership": invitation})
|
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class UserAdmin(DjangoUserAdmin):
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('username', 'password')}),
|
(None, {'fields': ('username', 'password')}),
|
||||||
(_('Personal info'), {'fields': ('full_name', 'email', 'bio', 'photo')}),
|
(_('Personal info'), {'fields': ('full_name', 'email', 'bio', 'photo')}),
|
||||||
(_('Extra info'), {'fields': ('color', 'default_language', 'default_timezone', 'token', 'colorize_tags', 'email_token', 'new_email')}),
|
(_('Extra info'), {'fields': ('color', 'lang', 'timezone', 'token', 'colorize_tags', 'email_token', 'new_email')}),
|
||||||
(_('Permissions'), {'fields': ('is_active', 'is_superuser',)}),
|
(_('Permissions'), {'fields': ('is_active', 'is_superuser',)}),
|
||||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -97,7 +97,7 @@ class UsersViewSet(ModelCrudViewSet):
|
||||||
user.save(update_fields=["token"])
|
user.save(update_fields=["token"])
|
||||||
|
|
||||||
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
||||||
email = mbuilder.password_recovery(user.email, {"user": user})
|
email = mbuilder.password_recovery(user, {"user": user})
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
return response.Ok({"detail": _("Mail sended successful!"),
|
return response.Ok({"detail": _("Mail sended successful!"),
|
||||||
|
@ -231,7 +231,8 @@ class UsersViewSet(ModelCrudViewSet):
|
||||||
request.user.new_email = new_email
|
request.user.new_email = new_email
|
||||||
request.user.save(update_fields=["email_token", "new_email"])
|
request.user.save(update_fields=["email_token", "new_email"])
|
||||||
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
mbuilder = MagicMailBuilder(template_mail_cls=InlineCSSTemplateMail)
|
||||||
email = mbuilder.change_email(request.user.new_email, {"user": request.user})
|
email = mbuilder.change_email(request.user.new_email, {"user": request.user,
|
||||||
|
"lang": request.user.lang})
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
"username": "admin",
|
"username": "admin",
|
||||||
"full_name": "",
|
"full_name": "",
|
||||||
"bio": "",
|
"bio": "",
|
||||||
"default_language": "",
|
"lang": "",
|
||||||
"color": "",
|
"color": "",
|
||||||
"photo": "",
|
"photo": "",
|
||||||
"is_active": true,
|
"is_active": true,
|
||||||
"colorize_tags": false,
|
"colorize_tags": false,
|
||||||
"default_timezone": "",
|
"timezone": "",
|
||||||
"is_superuser": true,
|
"is_superuser": true,
|
||||||
"token": "",
|
"token": "",
|
||||||
"last_login": "2013-04-04T07:36:09.880Z",
|
"last_login": "2013-04-04T07:36:09.880Z",
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0008_auto_20150213_1701'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='user',
|
||||||
|
old_name='default_language',
|
||||||
|
new_name='lang',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='user',
|
||||||
|
old_name='default_timezone',
|
||||||
|
new_name='timezone',
|
||||||
|
),
|
||||||
|
]
|
|
@ -116,10 +116,10 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||||
max_length=500, null=True, blank=True,
|
max_length=500, null=True, blank=True,
|
||||||
verbose_name=_("photo"))
|
verbose_name=_("photo"))
|
||||||
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
||||||
default_language = models.CharField(max_length=20, null=False, blank=True, default="",
|
lang = models.CharField(max_length=20, null=False, blank=True, default="",
|
||||||
verbose_name=_("default language"))
|
verbose_name=_("default language"))
|
||||||
default_timezone = models.CharField(max_length=20, null=False, blank=True, default="",
|
timezone = models.CharField(max_length=20, null=False, blank=True, default="",
|
||||||
verbose_name=_("default timezone"))
|
verbose_name=_("default timezone"))
|
||||||
colorize_tags = models.BooleanField(null=False, blank=True, default=False,
|
colorize_tags = models.BooleanField(null=False, blank=True, default=False,
|
||||||
verbose_name=_("colorize tags"))
|
verbose_name=_("colorize tags"))
|
||||||
token = models.CharField(max_length=200, null=True, blank=True, default=None,
|
token = models.CharField(max_length=200, null=True, blank=True, default=None,
|
||||||
|
@ -166,8 +166,8 @@ class User(AbstractBaseUser, PermissionsMixin):
|
||||||
self.full_name = "Deleted user"
|
self.full_name = "Deleted user"
|
||||||
self.color = ""
|
self.color = ""
|
||||||
self.bio = ""
|
self.bio = ""
|
||||||
self.default_language = ""
|
self.lang = ""
|
||||||
self.default_timezone = ""
|
self.timezone = ""
|
||||||
self.colorize_tags = True
|
self.colorize_tags = True
|
||||||
self.token = None
|
self.token = None
|
||||||
self.set_unusable_password()
|
self.set_unusable_password()
|
||||||
|
|
|
@ -43,8 +43,8 @@ class UserSerializer(ModelSerializer):
|
||||||
# IMPORTANT: Maintain the UserAdminSerializer Meta up to date
|
# IMPORTANT: Maintain the UserAdminSerializer Meta up to date
|
||||||
# with this info (including there the email)
|
# with this info (including there the email)
|
||||||
fields = ("id", "username", "full_name", "full_name_display",
|
fields = ("id", "username", "full_name", "full_name_display",
|
||||||
"color", "bio", "default_language",
|
"color", "bio", "lang", "timezone", "is_active",
|
||||||
"default_timezone", "is_active", "photo", "big_photo")
|
"photo", "big_photo")
|
||||||
read_only_fields = ("id",)
|
read_only_fields = ("id",)
|
||||||
|
|
||||||
def validate_username(self, attrs, source):
|
def validate_username(self, attrs, source):
|
||||||
|
@ -81,8 +81,8 @@ class UserAdminSerializer(UserSerializer):
|
||||||
# IMPORTANT: Maintain the UserSerializer Meta up to date
|
# IMPORTANT: Maintain the UserSerializer Meta up to date
|
||||||
# with this info (including here the email)
|
# with this info (including here the email)
|
||||||
fields = ("id", "username", "full_name", "full_name_display", "email",
|
fields = ("id", "username", "full_name", "full_name_display", "email",
|
||||||
"color", "bio", "default_language",
|
"color", "bio", "lang", "timezone", "is_active", "photo",
|
||||||
"default_timezone", "is_active", "photo", "big_photo")
|
"big_photo")
|
||||||
read_only_fields = ("id", "email")
|
read_only_fields = ("id", "email")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ def test_api_create_bulk_members_with_extra_text(client, outbox):
|
||||||
|
|
||||||
|
|
||||||
def test_api_resend_invitation(client, outbox):
|
def test_api_resend_invitation(client, outbox):
|
||||||
invitation = f.create_invitation()
|
invitation = f.create_invitation(user=None)
|
||||||
f.MembershipFactory(project=invitation.project, user=invitation.project.owner, is_owner=True)
|
f.MembershipFactory(project=invitation.project, user=invitation.project.owner, is_owner=True)
|
||||||
url = reverse("memberships-resend-invitation", kwargs={"pk": invitation.pk})
|
url = reverse("memberships-resend-invitation", kwargs={"pk": invitation.pk})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue