From 06b3f3eb63476a0f5810d7ce942b68be32905fb4 Mon Sep 17 00:00:00 2001 From: Patrick Altman Date: Wed, 11 Apr 2012 19:50:56 -0500 Subject: [PATCH 01/44] Enable SettingsForm to process updates without changing the email address --- account/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/account/forms.py b/account/forms.py index a4618806..e6966f6a 100644 --- a/account/forms.py +++ b/account/forms.py @@ -192,6 +192,8 @@ class SettingsForm(forms.Form): def clean_email(self): value = self.cleaned_data["email"] + if self.initial.get("email") == value: + return value qs = EmailAddress.objects.filter(email__iexact=value) if not qs.exists() or not settings.ACCOUNT_EMAIL_UNIQUE: return value From 1d9808f0b541f2080d745e3d56e2df0e01508f6c Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Fri, 13 Apr 2012 00:29:14 -0600 Subject: [PATCH 02/44] allow site object to be passed in to send methods --- account/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/account/models.py b/account/models.py index 86e41f29..447b7878 100644 --- a/account/models.py +++ b/account/models.py @@ -101,9 +101,9 @@ def use(self, user): result.save() signup_code_used.send(sender=result.__class__, signup_code_result=result) - def send(self): + def send(self, **kwargs): protocol = getattr(settings, "DEFAULT_HTTP_PROTOCOL", "http") - current_site = Site.objects.get_current() + current_site = kwargs["site"] if "site" in kwargs else Site.objects.get_current() signup_url = u"%s://%s%s?%s" % ( protocol, unicode(current_site.domain), @@ -206,8 +206,8 @@ def confirm(self): signals.email_confirmed.send(sender=self.__class__, email_address=email_address) return email_address - def send(self): - current_site = Site.objects.get_current() + def send(self, **kwargs): + current_site = kwargs["site"] if "site" in kwargs else Site.objects.get_current() protocol = getattr(settings, "DEFAULT_HTTP_PROTOCOL", "http") activate_url = u"%s://%s%s" % ( protocol, From a04486a3d387c8a7d6b29012ee363ef57f87ed92 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 14 Apr 2012 13:28:27 -0600 Subject: [PATCH 03/44] =?UTF-8?q?fixed=20#15=20=E2=80=94=20always=20overri?= =?UTF-8?q?de=20primary=20email=20and=20never=20add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/account/views.py b/account/views.py index 0b8c8fc5..6a5df7e4 100644 --- a/account/views.py +++ b/account/views.py @@ -513,8 +513,8 @@ def form_valid(self, form): EmailAddress.objects.add_email(self.request.user, form.cleaned_data["email"], primary=True) else: if form.cleaned_data["email"] != self.primary_email_address.email: - email_address = EmailAddress.objects.add_email(self.request.user, form.cleaned_data["email"]) - email_address.set_as_primary() + self.primary_email_address.email = form.cleaned_data["email"] + self.primary_email_address.save() account = self.request.user.account account.timezone = form.cleaned_data["timezone"] From da00bf52a2e0eb94e27a7c8c77cec858ea5d92d5 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 14 Apr 2012 13:40:52 -0600 Subject: [PATCH 04/44] added form to user_signup signal --- account/signals.py | 2 +- account/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/account/signals.py b/account/signals.py index 0d90abf2..00d562e8 100644 --- a/account/signals.py +++ b/account/signals.py @@ -1,7 +1,7 @@ import django.dispatch -user_signed_up = django.dispatch.Signal(providing_args=["user"]) +user_signed_up = django.dispatch.Signal(providing_args=["user", "form"]) user_sign_up_attempt = django.dispatch.Signal(providing_args=["username", "email", "result"]) signup_code_sent = django.dispatch.Signal(providing_args=["signup_code"]) signup_code_used = django.dispatch.Signal(providing_args=["signup_code_result"]) diff --git a/account/views.py b/account/views.py index e5c1938d..29145a7d 100644 --- a/account/views.py +++ b/account/views.py @@ -151,7 +151,7 @@ def generate_username(self, form): "Override SignupView.generate_username in a subclass.") def after_signup(self, user, form): - signals.user_signed_up.send(sender=SignupForm, user=user) + signals.user_signed_up.send(sender=SignupForm, user=user, form=form) def login_user(self, user): # set backend on User object to bypass needing to call auth.authenticate From ff1cde43dda9c9ff7df9d57cc58b8659f607e33c Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Wed, 18 Apr 2012 13:40:52 -0600 Subject: [PATCH 05/44] added Account.now method --- account/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/account/models.py b/account/models.py index b09af868..0c4ee8fe 100644 --- a/account/models.py +++ b/account/models.py @@ -15,6 +15,8 @@ from django.contrib.auth.models import User, AnonymousUser from django.contrib.sites.models import Site +import pytz + from account import signals from account.conf import settings from account.fields import TimeZoneField @@ -47,6 +49,14 @@ def for_request(cls, request): def __unicode__(self): return self.user.username + + def now(self): + """ + Returns a timezone aware datetime localized to the account's timezone. + """ + naive = datetime.datetime.now() + aware = naive.replace(tzinfo=pytz.timezone(settings.TIME_ZONE)) + return aware.astimezone(pytz.timezone(self.timezone)) class AnonymousAccount(object): From 94a83c5058ac7af35b7b01110aa5b43082b70a0e Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 12:51:45 -0600 Subject: [PATCH 06/44] added email to SignupForm initial data if present on signup code --- account/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/account/views.py b/account/views.py index 29145a7d..d7b76584 100644 --- a/account/views.py +++ b/account/views.py @@ -60,6 +60,8 @@ def get_initial(self): initial = super(SignupView, self).get_initial() if self.signup_code: initial["code"] = self.signup_code.code + if self.signup_code.email: + initial["email"] = self.signup_code.email return initial def get_context_data(self, **kwargs): From f0ed951856648673bb5120d1cfd1f31a52a50f91 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 13:30:27 -0600 Subject: [PATCH 07/44] fixed SettingsForm to only include language when settings.I18N is turned on --- account/forms.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/account/forms.py b/account/forms.py index f2754686..6e2bc28a 100644 --- a/account/forms.py +++ b/account/forms.py @@ -194,11 +194,12 @@ class SettingsForm(forms.Form): choices=settings.ACCOUNT_TIMEZONE_CHOICES, required=False ) - language = forms.ChoiceField( - label=_("Language"), - choices=settings.ACCOUNT_LANGUAGES, - required=False - ) + if settings.I18N: + language = forms.ChoiceField( + label=_("Language"), + choices=settings.ACCOUNT_LANGUAGES, + required=False + ) def clean_email(self): value = self.cleaned_data["email"] From 8ad091fe64c8d43c3ae7ebde7714ce4752c67805 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 13:34:55 -0600 Subject: [PATCH 08/44] fixed style issue --- account/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/account/models.py b/account/models.py index 0c4ee8fe..7e094505 100644 --- a/account/models.py +++ b/account/models.py @@ -31,9 +31,9 @@ class Account(models.Model): timezone = TimeZoneField(_("timezone")) language = models.CharField(_("language"), - max_length = 10, - choices = settings.ACCOUNT_LANGUAGES, - default = settings.LANGUAGE_CODE + max_length=10, + choices=settings.ACCOUNT_LANGUAGES, + default=settings.LANGUAGE_CODE ) @classmethod From b58bfdec8f41ade806724ebd213798e07a82a34a Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 13:45:04 -0600 Subject: [PATCH 09/44] fixed SettingsView to check for language before assigning it --- account/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/account/views.py b/account/views.py index d7b76584..ba2c26af 100644 --- a/account/views.py +++ b/account/views.py @@ -521,7 +521,8 @@ def form_valid(self, form): account = self.request.user.account account.timezone = form.cleaned_data["timezone"] - account.language = form.cleaned_data["language"] + if "language" in form.cleaned_data: + account.language = form.cleaned_data["language"] account.save() if self.messages.get("settings_updated"): From 88388b00ccef0def1e80872b55bcaeee2b97c8cb Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 14:05:04 -0600 Subject: [PATCH 10/44] fixed setting name --- account/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account/forms.py b/account/forms.py index 6e2bc28a..01a1db7b 100644 --- a/account/forms.py +++ b/account/forms.py @@ -194,7 +194,7 @@ class SettingsForm(forms.Form): choices=settings.ACCOUNT_TIMEZONE_CHOICES, required=False ) - if settings.I18N: + if settings.USE_I18N: language = forms.ChoiceField( label=_("Language"), choices=settings.ACCOUNT_LANGUAGES, From c68e183a4ecb8e916b5f427dccdf84a4f0eec359 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 14:26:23 -0600 Subject: [PATCH 11/44] improved account creation and language value for accounts --- account/models.py | 31 +++++++++++++++++++++++-------- account/views.py | 4 ++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/account/models.py b/account/models.py index 7e094505..482cc198 100644 --- a/account/models.py +++ b/account/models.py @@ -9,8 +9,8 @@ from django.db.models.signals import post_save from django.dispatch import receiver from django.template.loader import render_to_string -from django.utils import timezone -from django.utils.translation import get_language_from_request, gettext_lazy as _ +from django.utils import timezone, translation +from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import User, AnonymousUser from django.contrib.sites.models import Site @@ -28,7 +28,6 @@ class Account(models.Model): user = models.OneToOneField(User, related_name="account", verbose_name=_("user")) - timezone = TimeZoneField(_("timezone")) language = models.CharField(_("language"), max_length=10, @@ -47,6 +46,17 @@ def for_request(cls, request): account = AnonymousAccount(request) return account + @classmethod + def create(cls, request=None, **kwargs): + account = cls(**kwargs) + if "language" not in kwargs: + if request is None: + account.language = settings.LANGUAGE_CODE + else: + account.language = translation.get_language_from_request(request, check_path=True) + account.save() + return account + def __unicode__(self): return self.user.username @@ -64,10 +74,10 @@ class AnonymousAccount(object): def __init__(self, request=None): self.user = AnonymousUser() self.timezone = settings.TIME_ZONE - if request is not None: - self.language = get_language_from_request(request) - else: + if request is None: self.language = settings.LANGUAGE_CODE + else: + self.language = translation.get_language_from_request(request, check_path=True) def __unicode__(self): return "AnonymousAccount" @@ -284,5 +294,10 @@ def send(self, **kwargs): @receiver(post_save, sender=User) def create_account(sender, **kwargs): - if kwargs["created"]: - Account.objects.create(user=kwargs["instance"]) + user = kwargs["instance"] + try: + account = user.account + except Account.DoesNotExist: + account = None + if account is None and kwargs["created"]: + Account.create(user=user) diff --git a/account/views.py b/account/views.py index ba2c26af..50455709 100644 --- a/account/views.py +++ b/account/views.py @@ -88,6 +88,7 @@ def form_valid(self, form): if settings.ACCOUNT_EMAIL_CONFIRMATION_REQUIRED: new_user.is_active = False new_user.save() + self.create_account(new_user) email_kwargs = {"primary": True} if self.signup_code: self.signup_code.use(new_user) @@ -148,6 +149,9 @@ def create_user(self, form, commit=True, **kwargs): user.save() return user + def create_account(self, new_user, form): + return Account.create(request=self.request, user=new_user) + def generate_username(self, form): raise NotImplementedError("Unable to generate username by default. " "Override SignupView.generate_username in a subclass.") From f755217e8f14805b5fba09da50118f94bf73e3a2 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 14:38:54 -0600 Subject: [PATCH 12/44] changed ChangePasswordForm field names to be consistent with new convention --- account/forms.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/account/forms.py b/account/forms.py index 01a1db7b..df9501d5 100644 --- a/account/forms.py +++ b/account/forms.py @@ -121,15 +121,15 @@ def user_credentials(self): class ChangePasswordForm(forms.Form): - oldpassword = forms.CharField( + password_current = forms.CharField( label=_("Current Password"), widget=forms.PasswordInput(render_value=False) ) - password1 = forms.CharField( + password_new = forms.CharField( label=_("New Password"), widget=forms.PasswordInput(render_value=False) ) - password2 = forms.CharField( + password_new_confirm = forms.CharField( label=_("New Password (again)"), widget=forms.PasswordInput(render_value=False) ) @@ -138,19 +138,19 @@ def __init__(self, *args, **kwargs): self.user = kwargs.pop("user") super(ChangePasswordForm, self).__init__(*args, **kwargs) - def clean_oldpassword(self): - if not self.user.check_password(self.cleaned_data.get("oldpassword")): + def clean_password_current(self): + if not self.user.check_password(self.cleaned_data.get("password_current")): raise forms.ValidationError(_("Please type your current password.")) - return self.cleaned_data["oldpassword"] + return self.cleaned_data["password_current"] - def clean_password2(self): - if "password1" in self.cleaned_data and "password2" in self.cleaned_data: - if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + def clean_password_new_confirm(self): + if "password1" in self.cleaned_data and "password_new_confirm" in self.cleaned_data: + if self.cleaned_data["password_new"] != self.cleaned_data["password_new_confirm"]: raise forms.ValidationError(_("You must type the same password each time.")) - return self.cleaned_data["password2"] + return self.cleaned_data["password_new_confirm"] def save(self, user): - user.set_password(self.cleaned_data["password1"]) + user.set_password(self.cleaned_data["password_new"]) user.save() From 999a7c743f079d6d7e2a0b870790b7294fae08d2 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 14:40:14 -0600 Subject: [PATCH 13/44] updated SignupForm to match password field convention naming --- account/forms.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/account/forms.py b/account/forms.py index df9501d5..513a6783 100644 --- a/account/forms.py +++ b/account/forms.py @@ -21,11 +21,11 @@ class SignupForm(forms.Form): widget=forms.TextInput(), required=True ) - password1 = forms.CharField( + password = forms.CharField( label=_("Password"), widget=forms.PasswordInput(render_value=False) ) - password2 = forms.CharField( + password_confirm = forms.CharField( label=_("Password (again)"), widget=forms.PasswordInput(render_value=False) ) @@ -52,8 +52,8 @@ def clean_email(self): raise forms.ValidationError(_("A user is registered with this email address.")) def clean(self): - if "password1" in self.cleaned_data and "password2" in self.cleaned_data: - if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + if "password" in self.cleaned_data and "password_confirm" in self.cleaned_data: + if self.cleaned_data["password"] != self.cleaned_data["password_confirm"]: raise forms.ValidationError(_("You must type the same password each time.")) return self.cleaned_data From 696bc6b2bee755ff0146eb24ceaa348864b47c20 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Sat, 21 Apr 2012 14:41:29 -0600 Subject: [PATCH 14/44] fixed the remaining password fields to match convention --- account/forms.py | 14 +++++++------- account/views.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/account/forms.py b/account/forms.py index 513a6783..b234b356 100644 --- a/account/forms.py +++ b/account/forms.py @@ -144,7 +144,7 @@ def clean_password_current(self): return self.cleaned_data["password_current"] def clean_password_new_confirm(self): - if "password1" in self.cleaned_data and "password_new_confirm" in self.cleaned_data: + if "password_new" in self.cleaned_data and "password_new_confirm" in self.cleaned_data: if self.cleaned_data["password_new"] != self.cleaned_data["password_new_confirm"]: raise forms.ValidationError(_("You must type the same password each time.")) return self.cleaned_data["password_new_confirm"] @@ -170,20 +170,20 @@ def clean_email(self): class PasswordResetTokenForm(forms.Form): - password1 = forms.CharField( + password = forms.CharField( label = _("New Password"), widget = forms.PasswordInput(render_value=False) ) - password2 = forms.CharField( + password_confirm = forms.CharField( label = _("New Password (again)"), widget = forms.PasswordInput(render_value=False) ) - def clean_password2(self): - if "password1" in self.cleaned_data and "password2" in self.cleaned_data: - if self.cleaned_data["password1"] != self.cleaned_data["password2"]: + def clean_password_confirm(self): + if "password" in self.cleaned_data and "password_confirm" in self.cleaned_data: + if self.cleaned_data["password"] != self.cleaned_data["password_confirm"]: raise forms.ValidationError(_("You must type the same password each time.")) - return self.cleaned_data["password2"] + return self.cleaned_data["password_confirm"] class SettingsForm(forms.Form): diff --git a/account/views.py b/account/views.py index 50455709..1d7bdf88 100644 --- a/account/views.py +++ b/account/views.py @@ -140,7 +140,7 @@ def create_user(self, form, commit=True, **kwargs): username = self.generate_username(form) user.username = username user.email = form.cleaned_data["email"].strip().lower() - password = form.cleaned_data.get("password1") + password = form.cleaned_data.get("password") if password: user.set_password(password) else: @@ -456,7 +456,7 @@ def get_context_data(self, **kwargs): def form_valid(self, form): user = self.get_user() - user.set_password(form.cleaned_data["password1"]) + user.set_password(form.cleaned_data["password"]) user.save() if self.messages.get("password_changed"): messages.add_message( From b6c04278fad9ea66ad417cba4ed1634c6a2a6d8a Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 09:58:57 -0600 Subject: [PATCH 15/44] fixed SignupView.form_valid to pass form to create_account --- account/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account/views.py b/account/views.py index 1d7bdf88..a3cec413 100644 --- a/account/views.py +++ b/account/views.py @@ -88,7 +88,7 @@ def form_valid(self, form): if settings.ACCOUNT_EMAIL_CONFIRMATION_REQUIRED: new_user.is_active = False new_user.save() - self.create_account(new_user) + self.create_account(new_user, form) email_kwargs = {"primary": True} if self.signup_code: self.signup_code.use(new_user) From 27ca4ed95aa8a2beeba05149f55203e9301b2e9c Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 10:49:00 -0600 Subject: [PATCH 16/44] added ACCOUNT_EMAIL_CONFIRMATION_EMAIL to turn off all confirmation emails if desired --- account/conf.py | 1 + account/managers.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/account/conf.py b/account/conf.py index 8f8e7c14..c7858827 100644 --- a/account/conf.py +++ b/account/conf.py @@ -18,6 +18,7 @@ class AccountAppConf(AppConf): USER_DISPLAY = lambda user: user.username EMAIL_UNIQUE = True EMAIL_CONFIRMATION_REQUIRED = False + EMAIL_CONFIRMATION_EMAIL = True EMAIL_CONFIRMATION_EXPIRE_DAYS = 3 EMAIL_CONFIRMATION_ANONYMOUS_REDIRECT_URL = "account_login" EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None diff --git a/account/managers.py b/account/managers.py index cf97a893..4695f160 100644 --- a/account/managers.py +++ b/account/managers.py @@ -1,5 +1,7 @@ from django.db import models, IntegrityError +from account.conf import settings + class EmailAddressManager(models.Manager): @@ -9,7 +11,8 @@ def add_email(self, user, email, **kwargs): except IntegrityError: return None else: - email_address.send_confirmation() + if settings.ACCOUNT_EMAIL_CONFIRMATION_EMAIL: + email_address.send_confirmation() return email_address def get_primary(self, user): From 30807ef10110b5ab44dffc07eb107fc62859415a Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 11:13:09 -0600 Subject: [PATCH 17/44] corrected documentation around ACCOUNT_EMAIL_UNIQUE --- docs/usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 0cccbe83..9e835597 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -198,6 +198,6 @@ tables for django-user-accounts you will need to migrate the ALTER TABLE "account_emailaddress" ADD CONSTRAINT "account_emailaddress_user_id_email_key" UNIQUE ("user_id", "email"); ALTER TABLE "account_emailaddress" DROP CONSTRAINT "account_emailaddress_email_key"; -``ACCOUNT_EMAIL_UNIQUE = False`` will prevent duplicate email addresses per -user. +``ACCOUNT_EMAIL_UNIQUE = False`` will allow duplicate email addresses per +user, but not across users. From 36605da2c1a1e23519f0ea45a94cd209a1c87990 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 11:16:59 -0600 Subject: [PATCH 18/44] updated pytz and added some docs regarding its usage --- README.rst | 1 + docs/installation.rst | 10 +++++++++- setup.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 1ddd0a6e..d1293cef 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,7 @@ Requirements * Django 1.4 * django-appconf (included in ``install_requires``) +* pytz (included in ``install_requires``) Documentation ============= diff --git a/docs/installation.rst b/docs/installation.rst index ea5f383e..96d032ca 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -53,4 +53,12 @@ django-appconf_ We use django-appconf for app settings. It is listed in ``install_requires`` and will be installed when pip installs. -.. _django-appconf: https://github.com/jezdez/django-appconf \ No newline at end of file +.. _django-appconf: https://github.com/jezdez/django-appconf + +pytz_ +----- + +pytz is used for handling timezones for accounts. This dependency is critical +due to its extensive dataset for timezones. + +.. _pytz: http://pypi.python.org/pypi/pytz/ \ No newline at end of file diff --git a/setup.py b/setup.py index bae28687..eb9b5f1b 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ packages = find_packages(), install_requires = [ "django-appconf==0.5", - "pytz==2012b" + "pytz==2012c" ], classifiers = [ "Development Status :: 4 - Beta", From 77d31591ec622df9aeef2859e21e6c7e86cc2176 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 11:22:06 -0600 Subject: [PATCH 19/44] added periods in messages to be consistent --- account/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/account/views.py b/account/views.py index a3cec413..b7c37854 100644 --- a/account/views.py +++ b/account/views.py @@ -33,15 +33,15 @@ class SignupView(FormView): messages = { "email_confirmation_sent": { "level": messages.INFO, - "text": _("Confirmation email sent to %(email)s") + "text": _("Confirmation email sent to %(email)s.") }, "logged_in": { "level": messages.SUCCESS, - "text": _("Successfully logged in as %(user)s") + "text": _("Successfully logged in as %(user)s.") }, "invalid_signup_code": { "level": messages.WARNING, - "text": _("The code %(code)s is invalid") + "text": _("The code %(code)s is invalid.") } } @@ -260,7 +260,7 @@ class ConfirmEmailView(TemplateResponseMixin, View): messages = { "email_confirmed": { "level": messages.SUCCESS, - "text": _("You have confirmed %(email)s") + "text": _("You have confirmed %(email)s.") } } From 808cd13be9fa92be8b3969bd5faf67a0372f1e94 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 11:27:58 -0600 Subject: [PATCH 20/44] changed ACCOUNT_TIMEZONE_CHOICES to ACCOUNT_TIMEZONES to match ACCOUNT_LANGUAGES --- account/conf.py | 2 +- account/fields.py | 2 +- account/forms.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/account/conf.py b/account/conf.py index c7858827..66dd17d9 100644 --- a/account/conf.py +++ b/account/conf.py @@ -24,7 +24,7 @@ class AccountAppConf(AppConf): EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None SETTINGS_REDIRECT_URL = "account_settings" CONTACT_EMAIL = "support@example.com" - TIMEZONE_CHOICES = list(zip(pytz.all_timezones, pytz.all_timezones)) + TIMEZONES = list(zip(pytz.all_timezones, pytz.all_timezones)) LANGUAGES = [ (code, get_language_info(code).get("name_local")) for code, lang in settings.LANGUAGES diff --git a/account/fields.py b/account/fields.py index 114354d5..63363a72 100644 --- a/account/fields.py +++ b/account/fields.py @@ -11,7 +11,7 @@ def __init__(self, *args, **kwargs): defaults = { "max_length": 100, "default": settings.TIME_ZONE, - "choices": settings.ACCOUNT_TIMEZONE_CHOICES + "choices": settings.ACCOUNT_TIMEZONES } defaults.update(kwargs) return super(TimeZoneField, self).__init__(*args, **defaults) diff --git a/account/forms.py b/account/forms.py index b234b356..f512eb3c 100644 --- a/account/forms.py +++ b/account/forms.py @@ -191,7 +191,7 @@ class SettingsForm(forms.Form): email = forms.EmailField(label=_("Email"), required=True) timezone = forms.ChoiceField( label=_("Timezone"), - choices=settings.ACCOUNT_TIMEZONE_CHOICES, + choices=settings.ACCOUNT_TIMEZONES, required=False ) if settings.USE_I18N: From d0fb12e45dddc6afe41f536675cc0f00933768a3 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 24 Apr 2012 11:30:21 -0600 Subject: [PATCH 21/44] removed call to list (not needed) --- account/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account/conf.py b/account/conf.py index 66dd17d9..ed5c2c92 100644 --- a/account/conf.py +++ b/account/conf.py @@ -24,7 +24,7 @@ class AccountAppConf(AppConf): EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None SETTINGS_REDIRECT_URL = "account_settings" CONTACT_EMAIL = "support@example.com" - TIMEZONES = list(zip(pytz.all_timezones, pytz.all_timezones)) + TIMEZONES = zip(pytz.all_timezones, pytz.all_timezones) LANGUAGES = [ (code, get_language_info(code).get("name_local")) for code, lang in settings.LANGUAGES From 6dbd4ed27fd20252ac28f965e16018795ef749f2 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Wed, 25 Apr 2012 10:00:08 -0600 Subject: [PATCH 22/44] =?UTF-8?q?fixed=20#17=20=E2=80=94=20update=20instal?= =?UTF-8?q?lation=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 96d032ca..07b38474 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,9 +4,9 @@ Installation ============ -* To install django-user-accounts (no releases have been yet):: +* Install the development version:: - pip install django-user-accounts + pip install --extra-index-url=http://dist.pinaxproject.com/dev/ django-user-accounts * Add ``account`` to your ``INSTALLED_APPS`` setting:: From 6ab628acfee05cc8cb8ff59653fc86822809d3bd Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Wed, 25 Apr 2012 10:04:17 -0600 Subject: [PATCH 23/44] bump to 1.0b1.dev2 for next release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index eb9b5f1b..c84c4cd1 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name = "django-user-accounts", - version = "1.0b1.dev1", + version = "1.0b1.dev2", author = "Brian Rosner", author_email = "brosner@gmail.com", description = "a Django user account app", From ce05768c12a79ebab64c80eb7150fefd156ceed8 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Thu, 26 Apr 2012 14:26:49 -0600 Subject: [PATCH 24/44] =?UTF-8?q?fixed=20#18=20=E2=80=94=20added=20ACCOUNT?= =?UTF-8?q?=5FREMEMBER=5FME=5FEXPIRY=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account/conf.py | 1 + account/views.py | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/account/conf.py b/account/conf.py index ed5c2c92..633806b4 100644 --- a/account/conf.py +++ b/account/conf.py @@ -15,6 +15,7 @@ class AccountAppConf(AppConf): LOGOUT_REDIRECT_URL = "/" PASSWORD_CHANGE_REDIRECT_URL = "account_password" PASSWORD_RESET_REDIRECT_URL = "account_login" + REMEMBER_ME_EXPIRY = 60*60*24*365*10 USER_DISPLAY = lambda user: user.username EMAIL_UNIQUE = True EMAIL_CONFIRMATION_REQUIRED = False diff --git a/account/views.py b/account/views.py index b7c37854..a3690aa4 100644 --- a/account/views.py +++ b/account/views.py @@ -228,9 +228,8 @@ def get_redirect_field_name(self): def login_user(self, form): auth.login(self.request, form.user) - self.request.session.set_expiry( - 60*60*24*365*10 if form.cleaned_data.get("remember") else 0 - ) + expiry = settings.ACCOUNT_REMEMBER_ME_EXPIRY if form.cleaned_data.get("remember") else 0 + self.request.session.set_expiry(expiry) class LogoutView(TemplateResponseMixin, View): From 35c9b2fa1f29a96b427f189d26329f74f9261add Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Thu, 26 Apr 2012 14:46:49 -0600 Subject: [PATCH 25/44] improved SettingsView extensibility --- account/views.py | 50 +++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/account/views.py b/account/views.py index a3690aa4..9fd3097b 100644 --- a/account/views.py +++ b/account/views.py @@ -509,25 +509,12 @@ def get_initial(self): initial = super(SettingsView, self).get_initial() if self.primary_email_address: initial["email"] = self.primary_email_address.email - initial["timezone"] = self.request.user.account.timezone - initial["language"] = self.request.user.account.language + initial["timezone"] = self.request.user.account.timezone + initial["language"] = self.request.user.account.language return initial def form_valid(self, form): - # @@@ handle multiple emails per user - if not self.primary_email_address: - EmailAddress.objects.add_email(self.request.user, form.cleaned_data["email"], primary=True) - else: - if form.cleaned_data["email"] != self.primary_email_address.email: - self.primary_email_address.email = form.cleaned_data["email"] - self.primary_email_address.save() - - account = self.request.user.account - account.timezone = form.cleaned_data["timezone"] - if "language" in form.cleaned_data: - account.language = form.cleaned_data["language"] - account.save() - + self.update_settings(form) if self.messages.get("settings_updated"): messages.add_message( self.request, @@ -536,5 +523,32 @@ def form_valid(self, form): ) return redirect(self.get_success_url()) - def get_success_url(self): - return default_redirect(self.request, settings.ACCOUNT_SETTINGS_REDIRECT_URL) + def update_settings(self, form): + self.update_email(form) + self.update_account(form) + + def update_email(self, form): + # @@@ handle multiple emails per user + if not self.primary_email_address: + EmailAddress.objects.add_email(self.request.user, form.cleaned_data["email"], primary=True) + else: + if form.cleaned_data["email"] != self.primary_email_address.email: + self.primary_email_address.email = form.cleaned_data["email"] + self.primary_email_address.save() + + def update_account(self, form): + fields = {} + if "timezone" in form.cleaned_data: + fields["timezone"] = form.cleaned_data["timezone"] + if "language" in form.cleaned_data: + fields["language"] = form.cleaned_data["language"] + if fields: + account = self.request.user.account + for k, v in fields.iteritems(): + setattr(account, k, v) + account.save() + + def get_success_url(self, fallback_url=None): + if fallback_url is None: + fallback_url = settings.ACCOUNT_SETTINGS_REDIRECT_URL + return default_redirect(self.request, fallback_url) From f83e4f206a0ea1423d98502f31090dfcebd96320 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Thu, 26 Apr 2012 14:58:07 -0600 Subject: [PATCH 26/44] improved email address handling --- account/views.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/account/views.py b/account/views.py index 9fd3097b..ea147522 100644 --- a/account/views.py +++ b/account/views.py @@ -92,17 +92,17 @@ def form_valid(self, form): email_kwargs = {"primary": True} if self.signup_code: self.signup_code.use(new_user) - if self.signup_code.email and form.cleaned_data["email"] == self.signup_code.email: + if self.signup_code.email and new_user.email == self.signup_code.email: email_kwargs["verified"] = True email_confirmed = True - EmailAddress.objects.add_email(new_user, form.cleaned_data["email"], **email_kwargs) + EmailAddress.objects.add_email(new_user, new_user.email, **email_kwargs) self.after_signup(new_user, form) if settings.ACCOUNT_EMAIL_CONFIRMATION_REQUIRED and not email_confirmed: response_kwargs = { "request": self.request, "template": self.template_name_email_confirmation_sent, "context": { - "email": form.cleaned_data["email"], + "email": new_user.email, "success_url": self.get_success_url(), } } @@ -139,7 +139,7 @@ def create_user(self, form, commit=True, **kwargs): if username is None: username = self.generate_username(form) user.username = username - user.email = form.cleaned_data["email"].strip().lower() + user.email = form.cleaned_data["email"].strip() password = form.cleaned_data.get("password") if password: user.set_password(password) @@ -528,12 +528,18 @@ def update_settings(self, form): self.update_account(form) def update_email(self, form): + user = self.request.user # @@@ handle multiple emails per user + email = form.cleaned_data["email"].strip() if not self.primary_email_address: - EmailAddress.objects.add_email(self.request.user, form.cleaned_data["email"], primary=True) + user.email = email + EmailAddress.objects.add_email(self.request.user, email, primary=True) + user.save() else: - if form.cleaned_data["email"] != self.primary_email_address.email: - self.primary_email_address.email = form.cleaned_data["email"] + if email != self.primary_email_address.email: + user.email = email + self.primary_email_address.email = email + user.save() self.primary_email_address.save() def update_account(self, form): From a1bde1a1d5a617a4ff33266c5b0ce4ada5eabc38 Mon Sep 17 00:00:00 2001 From: madron Date: Fri, 27 Apr 2012 14:18:09 +0200 Subject: [PATCH 27/44] fixed SignupView tests --- account/tests/test_views.py | 30 ++++---- account/views.py | 135 +++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 79 deletions(-) diff --git a/account/tests/test_views.py b/account/tests/test_views.py index 902f9072..ff342e23 100644 --- a/account/tests/test_views.py +++ b/account/tests/test_views.py @@ -8,55 +8,57 @@ class SignupDisabledView(SignupView): - - def disabled(self): - return True + + def is_open(self): + return False class LoginDisabledView(LoginView): - + def disabled(self): return True class SignupViewTestCase(unittest.TestCase): - + def setUp(self): self.factory = RequestFactory() - + def test_get(self): request = self.factory.get(reverse("account_signup")) response = SignupView.as_view()(request) self.assertEqual(response.status_code, 200) - + def test_get_disabled(self): request = self.factory.get(reverse("account_signup")) response = SignupDisabledView.as_view()(request) - self.assertEqual(response.status_code, 404) - + self.assertEqual(response.status_code, 200) + self.assertEqual(response.template_name, 'account/signup_closed.html') + def test_post_disabled(self): request = self.factory.post(reverse("account_signup")) response = SignupDisabledView.as_view()(request) - self.assertEqual(response.status_code, 404) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.template_name, 'account/signup_closed.html') class LoginViewTestCase(unittest.TestCase): - + def setUp(self): self.factory = RequestFactory() - + def test_get(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginView.as_view()(request) self.assertEqual(response.status_code, 200) - + def test_get_disabled(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) - + def test_post_disabled(self): request = self.factory.post(reverse("account_login")) request.user = AnonymousUser() diff --git a/account/views.py b/account/views.py index ea147522..1dee6d95 100644 --- a/account/views.py +++ b/account/views.py @@ -24,7 +24,7 @@ class SignupView(FormView): - + template_name = "account/signup.html" template_name_email_confirmation_sent = "account/email_confirmation_sent.html" template_name_signup_closed = "account/signup_closed.html" @@ -44,18 +44,23 @@ class SignupView(FormView): "text": _("The code %(code)s is invalid.") } } - + def __init__(self, *args, **kwargs): kwargs["signup_code"] = None super(SignupView, self).__init__(*args, **kwargs) - + def get(self, *args, **kwargs): - if self.request.user.is_authenticated(): + if 'user' in self.request and self.request.user.is_authenticated(): return redirect(default_redirect(self.request, settings.ACCOUNT_LOGIN_REDIRECT_URL)) if not self.is_open(): return self.closed() return super(SignupView, self).get(*args, **kwargs) - + + def post(self, *args, **kwargs): + if not self.is_open(): + return self.closed() + return super(SignupView, self).post(*args, **kwargs) + def get_initial(self): initial = super(SignupView, self).get_initial() if self.signup_code: @@ -63,7 +68,7 @@ def get_initial(self): if self.signup_code.email: initial["email"] = self.signup_code.email return initial - + def get_context_data(self, **kwargs): ctx = kwargs redirect_field_name = self.get_redirect_field_name() @@ -72,7 +77,7 @@ def get_context_data(self, **kwargs): "redirect_field_value": self.request.REQUEST.get(redirect_field_name), }) return ctx - + def form_invalid(self, form): signals.user_sign_up_attempt.send( sender=SignupForm, @@ -81,7 +86,7 @@ def form_invalid(self, form): result=form.is_valid() ) return super(SignupView, self).form_invalid(form) - + def form_valid(self, form): email_confirmed = False new_user = self.create_user(form, commit=False) @@ -126,13 +131,13 @@ def form_valid(self, form): } ) return super(SignupView, self).form_valid(form) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_SIGNUP_REDIRECT_URL) - + def get_redirect_field_name(self): return self.redirect_field_name - + def create_user(self, form, commit=True, **kwargs): user = User(**kwargs) username = form.cleaned_data.get("username") @@ -148,23 +153,23 @@ def create_user(self, form, commit=True, **kwargs): if commit: user.save() return user - + def create_account(self, new_user, form): return Account.create(request=self.request, user=new_user) - + def generate_username(self, form): raise NotImplementedError("Unable to generate username by default. " "Override SignupView.generate_username in a subclass.") - + def after_signup(self, user, form): signals.user_signed_up.send(sender=SignupForm, user=user, form=form) - + def login_user(self, user): # set backend on User object to bypass needing to call auth.authenticate user.backend = "django.contrib.auth.backends.ModelBackend" auth.login(self.request, user) self.request.session.set_expiry(0) - + def is_open(self): code = self.request.REQUEST.get("code") if code: @@ -187,7 +192,7 @@ def is_open(self): return True else: return settings.ACCOUNT_OPEN_SIGNUP - + def closed(self): response_kwargs = { "request": self.request, @@ -197,16 +202,16 @@ def closed(self): class LoginView(FormView): - + template_name = "account/login.html" form_class = LoginUsernameForm redirect_field_name = "next" - + def get(self, *args, **kwargs): if self.request.user.is_authenticated(): return redirect(self.get_success_url()) return super(LoginView, self).get(*args, **kwargs) - + def get_context_data(self, **kwargs): ctx = kwargs redirect_field_name = self.get_redirect_field_name() @@ -215,17 +220,17 @@ def get_context_data(self, **kwargs): "redirect_field_value": self.request.REQUEST.get(redirect_field_name), }) return ctx - + def form_valid(self, form): self.login_user(form) return redirect(self.get_success_url()) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_LOGIN_REDIRECT_URL) - + def get_redirect_field_name(self): return self.redirect_field_name - + def login_user(self, form): auth.login(self.request, form.user) expiry = settings.ACCOUNT_REMEMBER_ME_EXPIRY if form.cleaned_data.get("remember") else 0 @@ -233,49 +238,49 @@ def login_user(self, form): class LogoutView(TemplateResponseMixin, View): - + template_name = "account/logout.html" - + def get(self, *args, **kwargs): if not self.request.user.is_authenticated(): return redirect(self.get_redirect_url()) ctx = self.get_context_data() return self.render_to_response(ctx) - + def post(self, *args, **kwargs): if self.request.user.is_authenticated(): auth.logout(self.request) return redirect(self.get_redirect_url()) - + def get_context_data(self): return {} - + def get_redirect_url(self): return default_redirect(self.request, settings.ACCOUNT_LOGOUT_REDIRECT_URL) class ConfirmEmailView(TemplateResponseMixin, View): - + messages = { "email_confirmed": { "level": messages.SUCCESS, "text": _("You have confirmed %(email)s.") } } - + def get_template_names(self): return { "GET": ["account/email_confirm.html"], "POST": ["account/email_confirmed.html"], }[self.request.method] - + def get(self, *args, **kwargs): self.object = confirmation = self.get_object() if confirmation.email_address.user != self.request.user: raise Http404() ctx = self.get_context_data() return self.render_to_response(ctx) - + def post(self, *args, **kwargs): self.object = confirmation = self.get_object() if confirmation.email_address.user != self.request.user: @@ -297,7 +302,7 @@ def post(self, *args, **kwargs): } ) return redirect(redirect_url) - + def get_object(self, queryset=None): if queryset is None: queryset = self.get_queryset() @@ -305,17 +310,17 @@ def get_object(self, queryset=None): return queryset.get(key=self.kwargs["key"].lower()) except EmailConfirmation.DoesNotExist: raise Http404() - + def get_queryset(self): qs = EmailConfirmation.objects.all() qs = qs.select_related("email_address__user") return qs - + def get_context_data(self, **kwargs): ctx = kwargs ctx["confirmation"] = self.object return ctx - + def get_redirect_url(self): if self.request.user.is_authenticated(): if not settings.ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL: @@ -326,7 +331,7 @@ def get_redirect_url(self): class ChangePasswordView(FormView): - + template_name = "account/password_change.html" form_class = ChangePasswordForm messages = { @@ -335,17 +340,17 @@ class ChangePasswordView(FormView): "text": _(u"Password successfully changed.") } } - + def get(self, *args, **kwargs): if not self.request.user.is_authenticated(): return redirect("account_password_reset") return super(ChangePasswordView, self).get(*args, **kwargs) - + def post(self, *args, **kwargs): if not self.request.user.is_authenticated(): return HttpResponseForbidden() return super(ChangePasswordView, self).post(*args, **kwargs) - + def change_password(self, form): user = self.request.user form.save(user) @@ -356,7 +361,7 @@ def change_password(self, form): self.messages["password_changed"]["text"] ) signals.password_changed.send(sender=ChangePasswordForm, user=user) - + def get_form_kwargs(self): """ Returns the keyword arguments for instantiating the form. @@ -368,28 +373,28 @@ def get_form_kwargs(self): "files": self.request.FILES, }) return kwargs - + def form_valid(self, form): self.change_password(form) return redirect(self.get_success_url()) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_PASSWORD_CHANGE_REDIRECT_URL) class PasswordResetView(FormView): - + template_name = "account/password_reset.html" template_name_sent = "account/password_reset_sent.html" form_class = PasswordResetForm token_generator = default_token_generator - + def get_context_data(self, **kwargs): context = kwargs if self.request.method == "POST" and "resend" in self.request.POST: context["resend"] = True return context - + def form_valid(self, form): self.send_email(form.cleaned_data["email"]) response_kwargs = { @@ -398,7 +403,7 @@ def form_valid(self, form): "context": self.get_context_data(form=form) } return self.response_class(**response_kwargs) - + def send_email(self, email): protocol = getattr(settings, "DEFAULT_HTTP_PROTOCOL", "http") current_site = get_current_site(self.request) @@ -419,13 +424,13 @@ def send_email(self, email): subject = "".join(subject.splitlines()) message = render_to_string("account/email/password_reset.txt", ctx) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email]) - + def make_token(self, user): return self.token_generator.make_token(user) class PasswordResetTokenView(FormView): - + template_name = "account/password_reset_token.html" template_name_fail = "account/password_reset_token_fail.html" form_class = PasswordResetTokenForm @@ -436,7 +441,7 @@ class PasswordResetTokenView(FormView): "text": _("Password successfully changed.") }, } - + def get(self, request, **kwargs): form_class = self.get_form_class() form = self.get_form(form_class) @@ -444,7 +449,7 @@ def get(self, request, **kwargs): if not self.check_token(self.get_user(), self.kwargs["token"]): return self.token_fail() return self.render_to_response(ctx) - + def get_context_data(self, **kwargs): ctx = kwargs ctx.update({ @@ -452,7 +457,7 @@ def get_context_data(self, **kwargs): "token": self.kwargs["token"], }) return ctx - + def form_valid(self, form): user = self.get_user() user.set_password(form.cleaned_data["password"]) @@ -464,20 +469,20 @@ def form_valid(self, form): self.messages["password_changed"]["text"] ) return redirect(self.get_success_url()) - + def get_success_url(self): return settings.ACCOUNT_PASSWORD_RESET_REDIRECT_URL - + def get_user(self): try: uid_int = base36_to_int(self.kwargs["uidb36"]) except ValueError: raise Http404() return get_object_or_404(User, id=uid_int) - + def check_token(self, user, token): return self.token_generator.check_token(user, token) - + def token_fail(self): response_kwargs = { "request": self.request, @@ -488,7 +493,7 @@ def token_fail(self): class SettingsView(LoginRequiredMixin, FormView): - + template_name = "account/settings.html" form_class = SettingsForm messages = { @@ -497,14 +502,14 @@ class SettingsView(LoginRequiredMixin, FormView): "text": _("Account settings updated.") }, } - + def get_form_class(self): # @@@ django: this is a workaround to not having a dedicated method # to initialize self with a request in a known good state (of course # this only works with a FormView) self.primary_email_address = EmailAddress.objects.get_primary(self.request.user) return super(SettingsView, self).get_form_class() - + def get_initial(self): initial = super(SettingsView, self).get_initial() if self.primary_email_address: @@ -512,7 +517,7 @@ def get_initial(self): initial["timezone"] = self.request.user.account.timezone initial["language"] = self.request.user.account.language return initial - + def form_valid(self, form): self.update_settings(form) if self.messages.get("settings_updated"): @@ -522,11 +527,11 @@ def form_valid(self, form): self.messages["settings_updated"]["text"] ) return redirect(self.get_success_url()) - + def update_settings(self, form): self.update_email(form) self.update_account(form) - + def update_email(self, form): user = self.request.user # @@@ handle multiple emails per user @@ -541,7 +546,7 @@ def update_email(self, form): self.primary_email_address.email = email user.save() self.primary_email_address.save() - + def update_account(self, form): fields = {} if "timezone" in form.cleaned_data: @@ -553,7 +558,7 @@ def update_account(self, form): for k, v in fields.iteritems(): setattr(account, k, v) account.save() - + def get_success_url(self, fallback_url=None): if fallback_url is None: fallback_url = settings.ACCOUNT_SETTINGS_REDIRECT_URL From a641eb85dc655aca901b459f31c66e3342721663 Mon Sep 17 00:00:00 2001 From: madron Date: Fri, 27 Apr 2012 14:19:41 +0200 Subject: [PATCH 28/44] removed unused TemplateView import from views --- account/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account/views.py b/account/views.py index 1dee6d95..48490d45 100644 --- a/account/views.py +++ b/account/views.py @@ -5,7 +5,7 @@ from django.template.loader import render_to_string from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ -from django.views.generic.base import TemplateResponseMixin, View, TemplateView +from django.views.generic.base import TemplateResponseMixin, View from django.views.generic.edit import FormView from django.contrib import auth, messages From ea84e25c28cd4ddf8202aebefd6a5f8900122f49 Mon Sep 17 00:00:00 2001 From: madron Date: Fri, 27 Apr 2012 14:26:45 +0200 Subject: [PATCH 29/44] reverted SignupView authentication check --- account/tests/test_views.py | 3 +++ account/views.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/account/tests/test_views.py b/account/tests/test_views.py index ff342e23..d947bc1f 100644 --- a/account/tests/test_views.py +++ b/account/tests/test_views.py @@ -26,17 +26,20 @@ def setUp(self): def test_get(self): request = self.factory.get(reverse("account_signup")) + request.user = AnonymousUser() response = SignupView.as_view()(request) self.assertEqual(response.status_code, 200) def test_get_disabled(self): request = self.factory.get(reverse("account_signup")) + request.user = AnonymousUser() response = SignupDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, 'account/signup_closed.html') def test_post_disabled(self): request = self.factory.post(reverse("account_signup")) + request.user = AnonymousUser() response = SignupDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, 'account/signup_closed.html') diff --git a/account/views.py b/account/views.py index 48490d45..c43f0371 100644 --- a/account/views.py +++ b/account/views.py @@ -50,7 +50,7 @@ def __init__(self, *args, **kwargs): super(SignupView, self).__init__(*args, **kwargs) def get(self, *args, **kwargs): - if 'user' in self.request and self.request.user.is_authenticated(): + if self.request.user.is_authenticated(): return redirect(default_redirect(self.request, settings.ACCOUNT_LOGIN_REDIRECT_URL)) if not self.is_open(): return self.closed() From 918e35b4edee9c6cb54c3674faab43470a50a059 Mon Sep 17 00:00:00 2001 From: madron Date: Fri, 27 Apr 2012 14:43:45 +0200 Subject: [PATCH 30/44] made SignupView get test independent from ACCOUNT_OPEN_SIGNUP setting --- account/tests/test_views.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/account/tests/test_views.py b/account/tests/test_views.py index d947bc1f..7917bb94 100644 --- a/account/tests/test_views.py +++ b/account/tests/test_views.py @@ -7,6 +7,12 @@ from account.views import SignupView, LoginView +class SignupEnabledView(SignupView): + + def is_open(self): + return True + + class SignupDisabledView(SignupView): def is_open(self): @@ -27,7 +33,7 @@ def setUp(self): def test_get(self): request = self.factory.get(reverse("account_signup")) request.user = AnonymousUser() - response = SignupView.as_view()(request) + response = SignupEnabledView.as_view()(request) self.assertEqual(response.status_code, 200) def test_get_disabled(self): @@ -55,6 +61,7 @@ def test_get(self): request.user = AnonymousUser() response = LoginView.as_view()(request) self.assertEqual(response.status_code, 200) + self.assertEqual(response.template_name, 'account/login.html') def test_get_disabled(self): request = self.factory.get(reverse("account_login")) From 15d86950def7529a10584df25eaaa35d222b2d1d Mon Sep 17 00:00:00 2001 From: madron Date: Fri, 27 Apr 2012 15:57:39 +0200 Subject: [PATCH 31/44] added test for SignupView successful post --- account/tests/test_views.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/account/tests/test_views.py b/account/tests/test_views.py index 7917bb94..0c099790 100644 --- a/account/tests/test_views.py +++ b/account/tests/test_views.py @@ -2,7 +2,7 @@ from django.test.client import RequestFactory from django.utils import unittest -from django.contrib.auth.models import AnonymousUser +from django.contrib.auth.models import AnonymousUser, User from account.views import SignupView, LoginView @@ -50,6 +50,16 @@ def test_post_disabled(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, 'account/signup_closed.html') + def test_post_successful(self): + post = {"username": "user", "password": "pwd", + "password_confirm": "pwd", "email": "info@example.com"} + request = self.factory.post(reverse("account_signup"), post) + request.user = AnonymousUser() + response = SignupEnabledView.as_view()(request) + self.assertEqual(response.status_code, 302) + user = User.objects.get(username="user") + self.asserEqual(user.email, "info@example.com") + class LoginViewTestCase(unittest.TestCase): From bf731197d47aa50e357a3592383a8254624e95a5 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Mon, 30 Apr 2012 12:51:31 -0600 Subject: [PATCH 32/44] added English django.po --- account/locale/en/LC_MESSAGES/django.po | 154 ++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 account/locale/en/LC_MESSAGES/django.po diff --git a/account/locale/en/LC_MESSAGES/django.po b/account/locale/en/LC_MESSAGES/django.po new file mode 100644 index 00000000..39037a35 --- /dev/null +++ b/account/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,154 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-04-30 12:50-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: forms.py:19 forms.py:92 +msgid "Username" +msgstr "" + +#: forms.py:25 forms.py:64 +msgid "Password" +msgstr "" + +#: forms.py:29 +msgid "Password (again)" +msgstr "" + +#: forms.py:41 +msgid "Usernames can only contain letters, numbers and underscores." +msgstr "" + +#: forms.py:45 +msgid "This username is already taken. Please choose another." +msgstr "" + +#: forms.py:52 forms.py:211 +msgid "A user is registered with this email address." +msgstr "" + +#: forms.py:57 forms.py:149 forms.py:185 +msgid "You must type the same password each time." +msgstr "" + +#: forms.py:68 +msgid "Remember Me" +msgstr "" + +#: forms.py:81 +msgid "This account is inactive." +msgstr "" + +#: forms.py:93 +msgid "The username and/or password you specified are not correct." +msgstr "" + +#: forms.py:108 forms.py:159 forms.py:191 +msgid "Email" +msgstr "" + +#: forms.py:109 +msgid "The email address and/or password you specified are not correct." +msgstr "" + +#: forms.py:125 +msgid "Current Password" +msgstr "" + +#: forms.py:129 forms.py:174 +msgid "New Password" +msgstr "" + +#: forms.py:133 forms.py:178 +msgid "New Password (again)" +msgstr "" + +#: forms.py:143 +msgid "Please type your current password." +msgstr "" + +#: forms.py:164 +msgid "Email address not verified for any user account" +msgstr "" + +#: forms.py:167 +msgid "Email address not found for any user account" +msgstr "" + +#: forms.py:193 +msgid "Timezone" +msgstr "" + +#: forms.py:199 +msgid "Language" +msgstr "" + +#: models.py:30 +msgid "user" +msgstr "" + +#: models.py:31 +msgid "timezone" +msgstr "" + +#: models.py:32 +msgid "language" +msgstr "" + +#: models.py:210 +msgid "email address" +msgstr "" + +#: models.py:211 +msgid "email addresses" +msgstr "" + +#: models.py:247 +msgid "email confirmation" +msgstr "" + +#: models.py:248 +msgid "email confirmations" +msgstr "" + +#: views.py:36 +#, python-format +msgid "Confirmation email sent to %(email)s." +msgstr "" + +#: views.py:40 +#, python-format +msgid "Successfully logged in as %(user)s." +msgstr "" + +#: views.py:44 +#, python-format +msgid "The code %(code)s is invalid." +msgstr "" + +#: views.py:262 +#, python-format +msgid "You have confirmed %(email)s." +msgstr "" + +#: views.py:335 views.py:436 +msgid "Password successfully changed." +msgstr "" + +#: views.py:497 +msgid "Account settings updated." +msgstr "" From c9564a4f06c1f739b3265759146d655b83207e43 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Mon, 30 Apr 2012 12:59:09 -0600 Subject: [PATCH 33/44] added .tx directory --- .tx/config | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .tx/config diff --git a/.tx/config b/.tx/config new file mode 100644 index 00000000..e4f88090 --- /dev/null +++ b/.tx/config @@ -0,0 +1,7 @@ +[main] +host = https://www.transifex.net + +[django-user-accounts.djangopo] +file_filter = translations/django-user-accounts.djangopo/.po +source_lang = en + From 7c53b512bbe63331ff973646ba265ca731c39d3a Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Mon, 30 Apr 2012 15:18:24 -0600 Subject: [PATCH 34/44] updated file_filter to be correct for app --- .tx/config | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.tx/config b/.tx/config index e4f88090..5bc4d8dd 100644 --- a/.tx/config +++ b/.tx/config @@ -2,6 +2,5 @@ host = https://www.transifex.net [django-user-accounts.djangopo] -file_filter = translations/django-user-accounts.djangopo/.po +file_filter = account/locale//LC_MESSAGES/django.po source_lang = en - From 1c5c36cd75213e9fdb3a450ab650d86c060f4a30 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Mon, 30 Apr 2012 15:19:05 -0600 Subject: [PATCH 35/44] removed create_account signal receiver; User.save side-affect is simply not worth it --- account/models.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/account/models.py b/account/models.py index 482cc198..cbd3d166 100644 --- a/account/models.py +++ b/account/models.py @@ -7,7 +7,6 @@ from django.db import models from django.db.models import Q from django.db.models.signals import post_save -from django.dispatch import receiver from django.template.loader import render_to_string from django.utils import timezone, translation from django.utils.translation import gettext_lazy as _ @@ -290,14 +289,3 @@ def send(self, **kwargs): self.sent = timezone.now() self.save() signals.email_confirmation_sent.send(sender=self.__class__, confirmation=self) - - -@receiver(post_save, sender=User) -def create_account(sender, **kwargs): - user = kwargs["instance"] - try: - account = user.account - except Account.DoesNotExist: - account = None - if account is None and kwargs["created"]: - Account.create(user=user) From 7b04035f06da21199ac72d5f92736737fbaeeb48 Mon Sep 17 00:00:00 2001 From: madron Date: Wed, 2 May 2012 01:30:42 +0200 Subject: [PATCH 36/44] fixed whitespaces and quotes --- account/tests/test_views.py | 28 ++++---- account/views.py | 130 ++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/account/tests/test_views.py b/account/tests/test_views.py index 0c099790..11c631f9 100644 --- a/account/tests/test_views.py +++ b/account/tests/test_views.py @@ -8,48 +8,48 @@ class SignupEnabledView(SignupView): - + def is_open(self): return True class SignupDisabledView(SignupView): - + def is_open(self): return False class LoginDisabledView(LoginView): - + def disabled(self): return True class SignupViewTestCase(unittest.TestCase): - + def setUp(self): self.factory = RequestFactory() - + def test_get(self): request = self.factory.get(reverse("account_signup")) request.user = AnonymousUser() response = SignupEnabledView.as_view()(request) self.assertEqual(response.status_code, 200) - + def test_get_disabled(self): request = self.factory.get(reverse("account_signup")) request.user = AnonymousUser() response = SignupDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.template_name, 'account/signup_closed.html') - + self.assertEqual(response.template_name, "account/signup_closed.html") + def test_post_disabled(self): request = self.factory.post(reverse("account_signup")) request.user = AnonymousUser() response = SignupDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.template_name, 'account/signup_closed.html') - + self.assertEqual(response.template_name, "account/signup_closed.html") + def test_post_successful(self): post = {"username": "user", "password": "pwd", "password_confirm": "pwd", "email": "info@example.com"} @@ -62,23 +62,23 @@ def test_post_successful(self): class LoginViewTestCase(unittest.TestCase): - + def setUp(self): self.factory = RequestFactory() - + def test_get(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginView.as_view()(request) self.assertEqual(response.status_code, 200) - self.assertEqual(response.template_name, 'account/login.html') + self.assertEqual(response.template_name, ["account/login.html"]) def test_get_disabled(self): request = self.factory.get(reverse("account_login")) request.user = AnonymousUser() response = LoginDisabledView.as_view()(request) self.assertEqual(response.status_code, 200) - + def test_post_disabled(self): request = self.factory.post(reverse("account_login")) request.user = AnonymousUser() diff --git a/account/views.py b/account/views.py index c43f0371..c0f66737 100644 --- a/account/views.py +++ b/account/views.py @@ -24,7 +24,7 @@ class SignupView(FormView): - + template_name = "account/signup.html" template_name_email_confirmation_sent = "account/email_confirmation_sent.html" template_name_signup_closed = "account/signup_closed.html" @@ -44,23 +44,23 @@ class SignupView(FormView): "text": _("The code %(code)s is invalid.") } } - + def __init__(self, *args, **kwargs): kwargs["signup_code"] = None super(SignupView, self).__init__(*args, **kwargs) - + def get(self, *args, **kwargs): if self.request.user.is_authenticated(): return redirect(default_redirect(self.request, settings.ACCOUNT_LOGIN_REDIRECT_URL)) if not self.is_open(): return self.closed() return super(SignupView, self).get(*args, **kwargs) - + def post(self, *args, **kwargs): if not self.is_open(): return self.closed() return super(SignupView, self).post(*args, **kwargs) - + def get_initial(self): initial = super(SignupView, self).get_initial() if self.signup_code: @@ -68,7 +68,7 @@ def get_initial(self): if self.signup_code.email: initial["email"] = self.signup_code.email return initial - + def get_context_data(self, **kwargs): ctx = kwargs redirect_field_name = self.get_redirect_field_name() @@ -77,7 +77,7 @@ def get_context_data(self, **kwargs): "redirect_field_value": self.request.REQUEST.get(redirect_field_name), }) return ctx - + def form_invalid(self, form): signals.user_sign_up_attempt.send( sender=SignupForm, @@ -86,7 +86,7 @@ def form_invalid(self, form): result=form.is_valid() ) return super(SignupView, self).form_invalid(form) - + def form_valid(self, form): email_confirmed = False new_user = self.create_user(form, commit=False) @@ -131,13 +131,13 @@ def form_valid(self, form): } ) return super(SignupView, self).form_valid(form) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_SIGNUP_REDIRECT_URL) - + def get_redirect_field_name(self): return self.redirect_field_name - + def create_user(self, form, commit=True, **kwargs): user = User(**kwargs) username = form.cleaned_data.get("username") @@ -153,23 +153,23 @@ def create_user(self, form, commit=True, **kwargs): if commit: user.save() return user - + def create_account(self, new_user, form): return Account.create(request=self.request, user=new_user) - + def generate_username(self, form): raise NotImplementedError("Unable to generate username by default. " "Override SignupView.generate_username in a subclass.") - + def after_signup(self, user, form): signals.user_signed_up.send(sender=SignupForm, user=user, form=form) - + def login_user(self, user): # set backend on User object to bypass needing to call auth.authenticate user.backend = "django.contrib.auth.backends.ModelBackend" auth.login(self.request, user) self.request.session.set_expiry(0) - + def is_open(self): code = self.request.REQUEST.get("code") if code: @@ -192,7 +192,7 @@ def is_open(self): return True else: return settings.ACCOUNT_OPEN_SIGNUP - + def closed(self): response_kwargs = { "request": self.request, @@ -202,16 +202,16 @@ def closed(self): class LoginView(FormView): - + template_name = "account/login.html" form_class = LoginUsernameForm redirect_field_name = "next" - + def get(self, *args, **kwargs): if self.request.user.is_authenticated(): return redirect(self.get_success_url()) return super(LoginView, self).get(*args, **kwargs) - + def get_context_data(self, **kwargs): ctx = kwargs redirect_field_name = self.get_redirect_field_name() @@ -220,17 +220,17 @@ def get_context_data(self, **kwargs): "redirect_field_value": self.request.REQUEST.get(redirect_field_name), }) return ctx - + def form_valid(self, form): self.login_user(form) return redirect(self.get_success_url()) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_LOGIN_REDIRECT_URL) - + def get_redirect_field_name(self): return self.redirect_field_name - + def login_user(self, form): auth.login(self.request, form.user) expiry = settings.ACCOUNT_REMEMBER_ME_EXPIRY if form.cleaned_data.get("remember") else 0 @@ -238,49 +238,49 @@ def login_user(self, form): class LogoutView(TemplateResponseMixin, View): - + template_name = "account/logout.html" - + def get(self, *args, **kwargs): if not self.request.user.is_authenticated(): return redirect(self.get_redirect_url()) ctx = self.get_context_data() return self.render_to_response(ctx) - + def post(self, *args, **kwargs): if self.request.user.is_authenticated(): auth.logout(self.request) return redirect(self.get_redirect_url()) - + def get_context_data(self): return {} - + def get_redirect_url(self): return default_redirect(self.request, settings.ACCOUNT_LOGOUT_REDIRECT_URL) class ConfirmEmailView(TemplateResponseMixin, View): - + messages = { "email_confirmed": { "level": messages.SUCCESS, "text": _("You have confirmed %(email)s.") } } - + def get_template_names(self): return { "GET": ["account/email_confirm.html"], "POST": ["account/email_confirmed.html"], }[self.request.method] - + def get(self, *args, **kwargs): self.object = confirmation = self.get_object() if confirmation.email_address.user != self.request.user: raise Http404() ctx = self.get_context_data() return self.render_to_response(ctx) - + def post(self, *args, **kwargs): self.object = confirmation = self.get_object() if confirmation.email_address.user != self.request.user: @@ -302,7 +302,7 @@ def post(self, *args, **kwargs): } ) return redirect(redirect_url) - + def get_object(self, queryset=None): if queryset is None: queryset = self.get_queryset() @@ -310,17 +310,17 @@ def get_object(self, queryset=None): return queryset.get(key=self.kwargs["key"].lower()) except EmailConfirmation.DoesNotExist: raise Http404() - + def get_queryset(self): qs = EmailConfirmation.objects.all() qs = qs.select_related("email_address__user") return qs - + def get_context_data(self, **kwargs): ctx = kwargs ctx["confirmation"] = self.object return ctx - + def get_redirect_url(self): if self.request.user.is_authenticated(): if not settings.ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL: @@ -331,7 +331,7 @@ def get_redirect_url(self): class ChangePasswordView(FormView): - + template_name = "account/password_change.html" form_class = ChangePasswordForm messages = { @@ -340,17 +340,17 @@ class ChangePasswordView(FormView): "text": _(u"Password successfully changed.") } } - + def get(self, *args, **kwargs): if not self.request.user.is_authenticated(): return redirect("account_password_reset") return super(ChangePasswordView, self).get(*args, **kwargs) - + def post(self, *args, **kwargs): if not self.request.user.is_authenticated(): return HttpResponseForbidden() return super(ChangePasswordView, self).post(*args, **kwargs) - + def change_password(self, form): user = self.request.user form.save(user) @@ -361,7 +361,7 @@ def change_password(self, form): self.messages["password_changed"]["text"] ) signals.password_changed.send(sender=ChangePasswordForm, user=user) - + def get_form_kwargs(self): """ Returns the keyword arguments for instantiating the form. @@ -373,28 +373,28 @@ def get_form_kwargs(self): "files": self.request.FILES, }) return kwargs - + def form_valid(self, form): self.change_password(form) return redirect(self.get_success_url()) - + def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_PASSWORD_CHANGE_REDIRECT_URL) class PasswordResetView(FormView): - + template_name = "account/password_reset.html" template_name_sent = "account/password_reset_sent.html" form_class = PasswordResetForm token_generator = default_token_generator - + def get_context_data(self, **kwargs): context = kwargs if self.request.method == "POST" and "resend" in self.request.POST: context["resend"] = True return context - + def form_valid(self, form): self.send_email(form.cleaned_data["email"]) response_kwargs = { @@ -403,7 +403,7 @@ def form_valid(self, form): "context": self.get_context_data(form=form) } return self.response_class(**response_kwargs) - + def send_email(self, email): protocol = getattr(settings, "DEFAULT_HTTP_PROTOCOL", "http") current_site = get_current_site(self.request) @@ -424,13 +424,13 @@ def send_email(self, email): subject = "".join(subject.splitlines()) message = render_to_string("account/email/password_reset.txt", ctx) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email]) - + def make_token(self, user): return self.token_generator.make_token(user) class PasswordResetTokenView(FormView): - + template_name = "account/password_reset_token.html" template_name_fail = "account/password_reset_token_fail.html" form_class = PasswordResetTokenForm @@ -441,7 +441,7 @@ class PasswordResetTokenView(FormView): "text": _("Password successfully changed.") }, } - + def get(self, request, **kwargs): form_class = self.get_form_class() form = self.get_form(form_class) @@ -449,7 +449,7 @@ def get(self, request, **kwargs): if not self.check_token(self.get_user(), self.kwargs["token"]): return self.token_fail() return self.render_to_response(ctx) - + def get_context_data(self, **kwargs): ctx = kwargs ctx.update({ @@ -457,7 +457,7 @@ def get_context_data(self, **kwargs): "token": self.kwargs["token"], }) return ctx - + def form_valid(self, form): user = self.get_user() user.set_password(form.cleaned_data["password"]) @@ -469,20 +469,20 @@ def form_valid(self, form): self.messages["password_changed"]["text"] ) return redirect(self.get_success_url()) - + def get_success_url(self): return settings.ACCOUNT_PASSWORD_RESET_REDIRECT_URL - + def get_user(self): try: uid_int = base36_to_int(self.kwargs["uidb36"]) except ValueError: raise Http404() return get_object_or_404(User, id=uid_int) - + def check_token(self, user, token): return self.token_generator.check_token(user, token) - + def token_fail(self): response_kwargs = { "request": self.request, @@ -493,7 +493,7 @@ def token_fail(self): class SettingsView(LoginRequiredMixin, FormView): - + template_name = "account/settings.html" form_class = SettingsForm messages = { @@ -502,14 +502,14 @@ class SettingsView(LoginRequiredMixin, FormView): "text": _("Account settings updated.") }, } - + def get_form_class(self): # @@@ django: this is a workaround to not having a dedicated method # to initialize self with a request in a known good state (of course # this only works with a FormView) self.primary_email_address = EmailAddress.objects.get_primary(self.request.user) return super(SettingsView, self).get_form_class() - + def get_initial(self): initial = super(SettingsView, self).get_initial() if self.primary_email_address: @@ -517,7 +517,7 @@ def get_initial(self): initial["timezone"] = self.request.user.account.timezone initial["language"] = self.request.user.account.language return initial - + def form_valid(self, form): self.update_settings(form) if self.messages.get("settings_updated"): @@ -527,11 +527,11 @@ def form_valid(self, form): self.messages["settings_updated"]["text"] ) return redirect(self.get_success_url()) - + def update_settings(self, form): self.update_email(form) self.update_account(form) - + def update_email(self, form): user = self.request.user # @@@ handle multiple emails per user @@ -546,7 +546,7 @@ def update_email(self, form): self.primary_email_address.email = email user.save() self.primary_email_address.save() - + def update_account(self, form): fields = {} if "timezone" in form.cleaned_data: @@ -558,7 +558,7 @@ def update_account(self, form): for k, v in fields.iteritems(): setattr(account, k, v) account.save() - + def get_success_url(self, fallback_url=None): if fallback_url is None: fallback_url = settings.ACCOUNT_SETTINGS_REDIRECT_URL From 67f3c4f4e9553f7dc1ec099fc2b39cbd8fbeb311 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Thu, 3 May 2012 12:34:03 -0600 Subject: [PATCH 37/44] moved middleware into the package --- middleware.py => account/middleware.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename middleware.py => account/middleware.py (100%) diff --git a/middleware.py b/account/middleware.py similarity index 100% rename from middleware.py rename to account/middleware.py From 4072fcd471f304fe658cf48b65d730aed903e0a7 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 8 May 2012 21:06:34 -0600 Subject: [PATCH 38/44] changed to use redirect in SignupView.form_valid --- account/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account/views.py b/account/views.py index c0f66737..19e30bac 100644 --- a/account/views.py +++ b/account/views.py @@ -130,7 +130,7 @@ def form_valid(self, form): "user": user_display(new_user) } ) - return super(SignupView, self).form_valid(form) + return redirect(self.get_success_url()) def get_success_url(self): return default_redirect(self.request, settings.ACCOUNT_SIGNUP_REDIRECT_URL) From 3676d2c7ea0e9a5c3f8510ac8e6f8d58175e6b5f Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 8 May 2012 21:30:41 -0600 Subject: [PATCH 39/44] added admin.py with SignupCode --- account/admin.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 account/admin.py diff --git a/account/admin.py b/account/admin.py new file mode 100644 index 00000000..169e62b2 --- /dev/null +++ b/account/admin.py @@ -0,0 +1,12 @@ +from django.contrib import admin + +from account.models import SignupCode + + +class SignupCodeAdmin(admin.ModelAdmin): + list_display = ["code", "max_uses", "use_count", "expiry", "created"] + search_fields = ["code", "email"] + list_filter = ["created"] + + +admin.site.register(SignupCode, SignupCodeAdmin) \ No newline at end of file From 15110dbed51146df1b1059c55f203624ed264821 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 15 May 2012 13:38:01 -0600 Subject: [PATCH 40/44] added source_file to .tx/config to enable tx push -s --- .tx/config | 1 + 1 file changed, 1 insertion(+) diff --git a/.tx/config b/.tx/config index 5bc4d8dd..222ad582 100644 --- a/.tx/config +++ b/.tx/config @@ -4,3 +4,4 @@ host = https://www.transifex.net [django-user-accounts.djangopo] file_filter = account/locale//LC_MESSAGES/django.po source_lang = en +source_file = account/locale/en/LC_MESSAGES/django.po From 271ffeb9aaaec92a037c07e9efe0ffd9b5c8c400 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 15 May 2012 13:39:50 -0600 Subject: [PATCH 41/44] updated translations --- account/locale/en/LC_MESSAGES/django.mo | Bin 0 -> 378 bytes account/locale/en/LC_MESSAGES/django.po | 22 ++-- account/locale/es/LC_MESSAGES/django.mo | Bin 0 -> 3287 bytes account/locale/es/LC_MESSAGES/django.po | 155 ++++++++++++++++++++++++ account/locale/it/LC_MESSAGES/django.mo | Bin 0 -> 2979 bytes account/locale/it/LC_MESSAGES/django.po | 154 +++++++++++++++++++++++ 6 files changed, 320 insertions(+), 11 deletions(-) create mode 100644 account/locale/en/LC_MESSAGES/django.mo create mode 100644 account/locale/es/LC_MESSAGES/django.mo create mode 100644 account/locale/es/LC_MESSAGES/django.po create mode 100644 account/locale/it/LC_MESSAGES/django.mo create mode 100644 account/locale/it/LC_MESSAGES/django.po diff --git a/account/locale/en/LC_MESSAGES/django.mo b/account/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..1b3e8ef8c6d1fccb7a65a65372232ccbc863a51e GIT binary patch literal 378 zcmYL^K~KUk7=|%=+R?Lz9=z#?8w4{e8Y(Ne*luJD61`QZa|T<|6{A1Izvpl9TVmu* zp7hY?Yv1qZ_~^TXIY3U3Q{)giN7}^52rsYjY@PqioPE)oZxhRSlGul3D?sLuFmj($nVvo684rYNJd{qEW~01yluQ;vkc>%AhFr2#j98Ksd_KQL z)l@rGX(+XNr$n%9x@ap8g&1w>u65Pk!KyNqe7|4R4TG^YUK{-GYm2?T{`42yjjGKx hS-mRPXn(UPClK$ww$_Vwz|G38Yg17YKi59!`~q7%W=a46 literal 0 HcmV?d00001 diff --git a/account/locale/en/LC_MESSAGES/django.po b/account/locale/en/LC_MESSAGES/django.po index 39037a35..d4bf4f12 100644 --- a/account/locale/en/LC_MESSAGES/django.po +++ b/account/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-04-30 12:50-0600\n" +"POT-Creation-Date: 2012-05-15 13:38-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -97,31 +97,31 @@ msgstr "" msgid "Language" msgstr "" -#: models.py:30 +#: models.py:29 msgid "user" msgstr "" -#: models.py:31 +#: models.py:30 msgid "timezone" msgstr "" -#: models.py:32 +#: models.py:31 msgid "language" msgstr "" -#: models.py:210 +#: models.py:209 msgid "email address" msgstr "" -#: models.py:211 +#: models.py:210 msgid "email addresses" msgstr "" -#: models.py:247 +#: models.py:246 msgid "email confirmation" msgstr "" -#: models.py:248 +#: models.py:247 msgid "email confirmations" msgstr "" @@ -140,15 +140,15 @@ msgstr "" msgid "The code %(code)s is invalid." msgstr "" -#: views.py:262 +#: views.py:267 #, python-format msgid "You have confirmed %(email)s." msgstr "" -#: views.py:335 views.py:436 +#: views.py:340 views.py:441 msgid "Password successfully changed." msgstr "" -#: views.py:497 +#: views.py:502 msgid "Account settings updated." msgstr "" diff --git a/account/locale/es/LC_MESSAGES/django.mo b/account/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f0ef3f3ba5d163abe306b441ca0e496ea163af21 GIT binary patch literal 3287 zcmbuBJ8T?97{`Ys1UMdn010m8Tv2o+UIL<6Kif{v>ZB|=D4R6vss3K0KqckkiEih@{q_jfxx`^`81@3H=6 z_l{2(j%RQ_fph#e#;V})ZMfk06AZw=z(>J@+Zj6mPJ{P@E%0`59UKQQf%N|8;GN*l z;6324;6vcGVtnV0{QX_vQyAwU`S1#OH`oB51vU62_z`#l`~o}%UIWRW0E-_5&w#Yv zrGoE)$8rB5Nbi3SJ`es5-V5&8$=EJ%Ke!uw5quCl1CpJ$3PvE7VhQ*aw6WkB+#kTC z=V%-}30?-t&W|A3`3;-~|0#IlF2?XGdl!5Fd>?!q{1l}9ehoeh_P{du6F3HLFENHc zHjc|-@FkFRS_R(*KL8iNKR~iqhp{Q}0!X@F25G%3;2d}rB;Ec7DPDUqiTphU()zE1 z`#}vJ1V0AJ?{7i;vF~uX1N;Gm9N9t7IZo1m9f+nK)P6X{2`=^)?l!%04o9Xg)Q zkzEmKW}C+UjqF{DoBE5P>Br8vm1{;>@|u(d44G)6f}`=w(KPRN?&A)Dr@ zla?#Tt!ydhrIit1Q@+i88-p?tD&``JtaPrzro+&r+H)tpSGwhR+KGghQH9MI-BdOa zUKw4y-mSkt;+Hm2~8$KplLg_LaxYhr0!xQe(FoYD%G>$iT*oJM|{bDSI zliY7~B;PQp8 zbI#2UyHWD9;`cM{UQfvvYim-Ne$66%iRAU#b|ht#BK!2#|_gMn~Tgh+mP zRAHMG-h3xrabK*FCH@vej>Y}_Bb(VSNg%dp%?ctB%tgTkxQ?=^^JoQgO+e3sLSI)} zk{x4xu;5xM3Qndi7c84PFD<^d9LzvmD!AYjim=WPP1Ftr6GwvD5nel7KRg*s9G#fJ z#9&Ew6|Jzvyvcg4_QC{?(!6j!ShhmDSa@UWeAcQ}zJ$11!H=WFRx6fnPPC|IE1^kV z#yfd!1eL*`YMG%0vl0#-n=#%LrVZd$|r9F;e0f6{1B?nmWIHI+z^Jqve{= za#o{+(68!zvZ4II>pGXNv>2yW#KCD}6IbWDlij+hL&tdjb81ZUeN((vF0u0(xt$8D z3>qLZtZ125M21og*1X`6LV<;T}6(F(Of6REIL!~%f4|mYIK0j9&I&-ZowsFqxWI8 zBaj3d5~h0KEnF|;p!R=*RkDzG=I~Z5%tgv1g1#dIk98`$Ta55AD?8FFTOOS~`g>$X zF5o(g^h$hf>hPi*k@xN_O3>%MT13aC$Syx_O770Q-a(=8u5*4 zw(zKj@1$8;%A)UQy2G@?F0(`oy~rKVCTZY{FpS{;utrH=~kQnRirr5 z;D)sXl?rA`Dky``!ch8Htq5+sg$i#PcZFFUa+gZ^bFuz;`xF2L&sFC(0#R zSq`!SA`9gC#R|(LzOJ(JG5jAj(f}N0=8N5|tVbr1lf!0my)l&+4!$fywF)uVzY$Q# A;Q#;t literal 0 HcmV?d00001 diff --git a/account/locale/es/LC_MESSAGES/django.po b/account/locale/es/LC_MESSAGES/django.po new file mode 100644 index 00000000..fbb57faf --- /dev/null +++ b/account/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,155 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Erik Rivera , 2012. +msgid "" +msgstr "" +"Project-Id-Version: django-user-accounts\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-05-15 13:38-0600\n" +"PO-Revision-Date: 2012-05-15 18:11+0000\n" +"Last-Translator: Erik Rivera \n" +"Language-Team: Spanish (Castilian) (http://www.transifex.net/projects/p/pinax/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: forms.py:19 forms.py:92 +msgid "Username" +msgstr "Nombre de usuario" + +#: forms.py:25 forms.py:64 +msgid "Password" +msgstr "Contraseña" + +#: forms.py:29 +msgid "Password (again)" +msgstr "Contraseña (repetir)" + +#: forms.py:41 +msgid "Usernames can only contain letters, numbers and underscores." +msgstr "Los nombres de usuario solo pueden contener letras, números y subguiones" + +#: forms.py:45 +msgid "This username is already taken. Please choose another." +msgstr "Este nombre de usuario ya está en uso. Por favor elija otro." + +#: forms.py:52 forms.py:211 +msgid "A user is registered with this email address." +msgstr "Un usuario se ha registrado con esta dirección de correo electrónico." + +#: forms.py:57 forms.py:149 forms.py:185 +msgid "You must type the same password each time." +msgstr "Debe escribir la misma contraseña cada vez." + +#: forms.py:68 +msgid "Remember Me" +msgstr "Recordarme" + +#: forms.py:81 +msgid "This account is inactive." +msgstr "Esta cuenta está inactiva." + +#: forms.py:93 +msgid "The username and/or password you specified are not correct." +msgstr "El nombre de usuario y/o la contraseña que ha especificado no son correctas." + +#: forms.py:108 forms.py:159 forms.py:191 +msgid "Email" +msgstr "Correo electrónico" + +#: forms.py:109 +msgid "The email address and/or password you specified are not correct." +msgstr "La dirección de correo electrónico y/o la contraseña que ha especificado no son correctas." + +#: forms.py:125 +msgid "Current Password" +msgstr "Contraseña actual" + +#: forms.py:129 forms.py:174 +msgid "New Password" +msgstr "Contraseña nueva" + +#: forms.py:133 forms.py:178 +msgid "New Password (again)" +msgstr "Contraseña nueva (repetir)" + +#: forms.py:143 +msgid "Please type your current password." +msgstr "Por favor escriba su contraseña actual." + +#: forms.py:164 +msgid "Email address not verified for any user account" +msgstr "Correo electrónico no verificado para ninguna cuenta de usuario." + +#: forms.py:167 +msgid "Email address not found for any user account" +msgstr "Correo electrónico no encontrado para ninguna cuenta de usuario." + +#: forms.py:193 +msgid "Timezone" +msgstr "Zona horaria" + +#: forms.py:199 +msgid "Language" +msgstr "Idioma" + +#: models.py:29 +msgid "user" +msgstr "usuario" + +#: models.py:30 +msgid "timezone" +msgstr "zona horaria" + +#: models.py:31 +msgid "language" +msgstr "idioma" + +#: models.py:209 +msgid "email address" +msgstr "correo electrónico" + +#: models.py:210 +msgid "email addresses" +msgstr "correos electrónicos" + +#: models.py:246 +msgid "email confirmation" +msgstr "confirmación de correo electrónico" + +#: models.py:247 +msgid "email confirmations" +msgstr "confirmaciones de correos electrónicos" + +#: views.py:36 +#, python-format +msgid "Confirmation email sent to %(email)s." +msgstr "La confirmación de correo electrónico se ha enviado a %(email)s." + +#: views.py:40 +#, python-format +msgid "Successfully logged in as %(user)s." +msgstr "Inicio la sesión satisfactoriamente como %(user)s." + +#: views.py:44 +#, python-format +msgid "The code %(code)s is invalid." +msgstr "El código %(code)s no es válido." + +#: views.py:267 +#, python-format +msgid "You have confirmed %(email)s." +msgstr "Has confirmado %(email)s." + +#: views.py:340 views.py:441 +msgid "Password successfully changed." +msgstr "La contraseña se ha cambiado con éxito." + +#: views.py:502 +msgid "Account settings updated." +msgstr "Los ajustes de la cuenta actualizados." diff --git a/account/locale/it/LC_MESSAGES/django.mo b/account/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f214b38cb769a729eb3c8f7b3f8b37c6c1a5e41d GIT binary patch literal 2979 zcmb7_J!~9B6vrnJ0$hNE0O1>6fDk+J?w#!f zID`H*kk|hT9tHmd9|aHY5n>2~~;veuaaM#17|NB7Ap29RmFJuRPow`4$U1&g@j7@O{U1Qq?GAVh+>4i3hc_xNfX|@+LB%e} zet!kxBd%5b??A{=G@d6stTVUg@bH;e8W6X_X!sq375D(-k@=(lCZdFFwQl=tpoyt^5 z>)Lh5bug$Bsbi91m?>+0F&6|TPaRq1oK7Q4c{h|!g}yjv(zebL>9k3!RaW6mXXx-) zvCBBtpUbn1M^~h^>n01uJnvtA_pMNB9JOI4#CJwA-7H;{rR^PF?x{?-HT>T3{Uw=3 zxr~&!sMfa)4|ixxMpCEaV&GQ)$2~J-^B{l}?L3Y*Dd=EtKK)9pq*dfLyNWhVo>5R8 zv|An27pp2!$r_|yR^rm|Cb5aI2kDfgg;pF6ma5fJ6qrz9h%s(CMmp`uSi>OCj>HB! zg>}f)H^^>~?W&+uMrNweH82Q3;K~iyR4Nno|JTBmDjcO(GH|-5cvs8}w&l0tOv!MQ zocvU!K2Q^?3 z#NT1ainyPDyk~Jr7D%jQ<_aR=Er#Cva2?mCN#PZ|YdoI!Dt&EjRdr3~yk#5d(0ep0hK*6Zu*>%L|HQfVw;q9i>{rWIz#2p*|C%k&C=v}P0U-alN9M&*O7OWvol4m(Pz1`D0n&z zb*8tr3>67f6~_n$wh#p5eN{ze6lsGS=%im&wNMv1t58V!u4_z@98TUrVVZL;m$9k} z=;EkFT=kS(W_k#u*lDh;m;p~OL6BUEi#gsNDvu*w8iQjghRlvN^4>|@+GMTp9@nE^ zGmQ^lklNY?nqs+q<79aj)JTmR9LhxV9}TK31Z=l)-E%k!VQ@=_3glvpp-=}y6_SsA z>jo7y64sWE+!YB@bu(g_7g&SzF6tuw)8JwZ^wj4BUK#a%R4XTNDBXh-)$H(| zaIs7ths(9Kg~R!DDNs?YksNt?M8=4nFD~Q|z+^JhMqJ!>>243Z`K_NgYmkQc^Tu&v zoUy2ps;H3=oKWX7b|}@f#`o73@5t>`8~u-78j4J)P(=|4-dGp0LqdkRqMnHz3glh- j4*IZI{IPR!tde=;N{DKLcP%ISE1&_VV|(cAWhBJEh(|;z literal 0 HcmV?d00001 diff --git a/account/locale/it/LC_MESSAGES/django.po b/account/locale/it/LC_MESSAGES/django.po new file mode 100644 index 00000000..ae6eb51d --- /dev/null +++ b/account/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,154 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: django-user-accounts\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-05-15 13:38-0600\n" +"PO-Revision-Date: 2012-05-15 19:23+0000\n" +"Last-Translator: Massimiliano Ravelli \n" +"Language-Team: Italian (http://www.transifex.net/projects/p/pinax/language/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: forms.py:19 forms.py:92 +msgid "Username" +msgstr "Nome utente" + +#: forms.py:25 forms.py:64 +msgid "Password" +msgstr "Password" + +#: forms.py:29 +msgid "Password (again)" +msgstr "Password (di nuovo)" + +#: forms.py:41 +msgid "Usernames can only contain letters, numbers and underscores." +msgstr "Il nome utente può contenere solo lettere, numeri e trattini bassi." + +#: forms.py:45 +msgid "This username is already taken. Please choose another." +msgstr "Questo nome utente è già utilizzato. Scegline un'altro." + +#: forms.py:52 forms.py:211 +msgid "A user is registered with this email address." +msgstr "Esiste già un utente con questo indirizzo email." + +#: forms.py:57 forms.py:149 forms.py:185 +msgid "You must type the same password each time." +msgstr "La password deve essere inserita due volte." + +#: forms.py:68 +msgid "Remember Me" +msgstr "Ricordami" + +#: forms.py:81 +msgid "This account is inactive." +msgstr "Questo account non è attivo." + +#: forms.py:93 +msgid "The username and/or password you specified are not correct." +msgstr "Il nome utente e/o la password non sono corretti." + +#: forms.py:108 forms.py:159 forms.py:191 +msgid "Email" +msgstr "Email" + +#: forms.py:109 +msgid "The email address and/or password you specified are not correct." +msgstr "L'indirizzo email e/o la password non sono corretti." + +#: forms.py:125 +msgid "Current Password" +msgstr "Password Attuale" + +#: forms.py:129 forms.py:174 +msgid "New Password" +msgstr "Nuova Password" + +#: forms.py:133 forms.py:178 +msgid "New Password (again)" +msgstr "Nuova Password (di nuovo)" + +#: forms.py:143 +msgid "Please type your current password." +msgstr "Inserisci la password attuale." + +#: forms.py:164 +msgid "Email address not verified for any user account" +msgstr "Indirizzo email non verificato" + +#: forms.py:167 +msgid "Email address not found for any user account" +msgstr "Indirizzo email non trovato" + +#: forms.py:193 +msgid "Timezone" +msgstr "Fuso orario" + +#: forms.py:199 +msgid "Language" +msgstr "Lingua" + +#: models.py:29 +msgid "user" +msgstr "utente" + +#: models.py:30 +msgid "timezone" +msgstr "fuso orario" + +#: models.py:31 +msgid "language" +msgstr "lingua" + +#: models.py:209 +msgid "email address" +msgstr "indirizzo email" + +#: models.py:210 +msgid "email addresses" +msgstr "indirizzi email" + +#: models.py:246 +msgid "email confirmation" +msgstr "conferma indirizzo email" + +#: models.py:247 +msgid "email confirmations" +msgstr "conferme indirizzi email" + +#: views.py:36 +#, python-format +msgid "Confirmation email sent to %(email)s." +msgstr "Email di conferma inviata a %(email)s." + +#: views.py:40 +#, python-format +msgid "Successfully logged in as %(user)s." +msgstr "Accesso effettuato come %(user)s." + +#: views.py:44 +#, python-format +msgid "The code %(code)s is invalid." +msgstr "Il codice %(code)s non è valido." + +#: views.py:267 +#, python-format +msgid "You have confirmed %(email)s." +msgstr "Hai confermato %(email)s." + +#: views.py:340 views.py:441 +msgid "Password successfully changed." +msgstr "Password cambiata con successo." + +#: views.py:502 +msgid "Account settings updated." +msgstr "Configurazione account aggiornata." From 90d8c74f479893070ab94329fa65596b5cb6f3eb Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 15 May 2012 14:18:42 -0600 Subject: [PATCH 42/44] Removed user check when confirming email address We can't try to be clever and ensure the email address confirmation is coming from who we expect. This view can be called anonymously due to ACCOUNT_EMAIL_CONFIRMATION_REQUIRED being True. Fixes #21 and #22. --- account/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/account/views.py b/account/views.py index 19e30bac..a881bcc7 100644 --- a/account/views.py +++ b/account/views.py @@ -283,8 +283,6 @@ def get(self, *args, **kwargs): def post(self, *args, **kwargs): self.object = confirmation = self.get_object() - if confirmation.email_address.user != self.request.user: - raise Http404() confirmation.confirm() user = confirmation.email_address.user user.is_active = True From 2be8d9c4ad76f2a78ce93b4e86442f41d53cd4cf Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 15 May 2012 14:29:00 -0600 Subject: [PATCH 43/44] updated version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c84c4cd1..e8b84ae9 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name = "django-user-accounts", - version = "1.0b1.dev2", + version = "1.0b1.dev3", author = "Brian Rosner", author_email = "brosner@gmail.com", description = "a Django user account app", From 67ce6b1420fdf8f083e63b632eebb5d99016c089 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Tue, 15 May 2012 14:29:44 -0600 Subject: [PATCH 44/44] bumped version to represent current state --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e8b84ae9..afd065f6 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name = "django-user-accounts", - version = "1.0b1.dev3", + version = "1.0b1.dev4", author = "Brian Rosner", author_email = "brosner@gmail.com", description = "a Django user account app",