Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for timezone/language settings #11

Merged
merged 5 commits into from Apr 13, 2012
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions account/context_processors.py
@@ -1,8 +1,11 @@
from account.conf import settings

from account.models import Account


def account(request):
ctx = {
"account": Account.for_request(request),
"ACCOUNT_OPEN_SIGNUP": settings.ACCOUNT_OPEN_SIGNUP,
"ACCOUNT_CONTACT_EMAIL": settings.ACCOUNT_CONTACT_EMAIL,
}
Expand Down
21 changes: 21 additions & 0 deletions account/fields.py
@@ -0,0 +1,21 @@
from django.conf import settings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect. You need: from account.conf import settings

from django.db import models

import pytz


TIMEZONE_CHOICES = tuple(zip(pytz.all_timezones, pytz.all_timezones))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constant seems useless to me. Either we should inline this or make it configurable via settings.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see it being used elsewhere. Let's make it configurable via settings in conf.py.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I don't know what I was smoking to allow this to be a tuple. Uselist instead as it that is the correct data structure for choices.



class TimeZoneField(models.CharField):

__metaclass__ = models.SubfieldBase

def __init__(self, *args, **kwargs):
defaults = {
"max_length": 100,
"default": settings.TIME_ZONE,
"choices": TIMEZONE_CHOICES
}
defaults.update(kwargs)
return super(TimeZoneField, self).__init__(*args, **defaults)
13 changes: 12 additions & 1 deletion account/forms.py
Expand Up @@ -7,7 +7,8 @@
from django.contrib.auth.models import User

from account.conf import settings
from account.models import SignupCode, EmailAddress
from account.fields import TIMEZONE_CHOICES
from account.models import EmailAddress


alnum_re = re.compile(r"^\w+$")
Expand Down Expand Up @@ -189,6 +190,16 @@ def clean_password2(self):
class SettingsForm(forms.Form):

email = forms.EmailField(label=_("Email"), required=True)
timezone = forms.ChoiceField(
label=_("Timezone"),
choices=TIMEZONE_CHOICES,
required=False
)
language = forms.ChoiceField(
label=_("Language"),
choices=settings.LANGUAGES,
required=False
)

def clean_email(self):
value = self.cleaned_data["email"]
Expand Down
53 changes: 51 additions & 2 deletions account/models.py
Expand Up @@ -6,20 +6,63 @@
from django.core.urlresolvers import reverse
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
from django.utils.translation import gettext_lazy as _
from django.utils.translation import get_language_from_request, gettext_lazy as _

from django.contrib.auth.models import User
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.sites.models import Site

from account import signals
from account.conf import settings
from account.fields import TimeZoneField
from account.managers import EmailAddressManager, EmailConfirmationManager
from account.signals import signup_code_sent, signup_code_used
from account.utils import random_token


class Account(models.Model):

user = models.OneToOneField(User, related_name="account", verbose_name=_("user"))

timezone = TimeZoneField(_("timezone"))
language = models.CharField(_("language"),
max_length = 10,
choices = settings.LANGUAGES,
default = settings.LANGUAGE_CODE
)

@classmethod
def for_request(cls, request):
if request.user.is_authenticated():
try:
account = Account._default_manager.get(user=request.user)
except Account.DoesNotExist:
account = AnonymousAccount(request)
else:
account = AnonymousAccount(request)
return account

def __unicode__(self):
return self.user.username


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:
self.language = settings.LANGUAGE_CODE

def __unicode__(self):
return "AnonymousAccount"


class SignupCode(models.Model):

class AlreadyExists(Exception):
Expand Down Expand Up @@ -227,3 +270,9 @@ def send(self):
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):
if kwargs["created"]:
Account.objects.get_or_create(user=kwargs["instance"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about not using get_or_create because we check for created in kwargs.

10 changes: 9 additions & 1 deletion account/views.py
Expand Up @@ -19,7 +19,7 @@
from account.forms import ChangePasswordForm, PasswordResetForm, PasswordResetTokenForm
from account.forms import SettingsForm
from account.mixins import LoginRequiredMixin
from account.models import SignupCode, EmailAddress, EmailConfirmation
from account.models import SignupCode, EmailAddress, EmailConfirmation, Account
from account.utils import default_redirect, user_display


Expand Down Expand Up @@ -503,6 +503,8 @@ 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
return initial

def form_valid(self, form):
Expand All @@ -513,6 +515,12 @@ def form_valid(self, form):
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()

account = self.request.user.account
account.timezone = form.cleaned_data["timezone"]
account.language = form.cleaned_data["language"]
account.save()

if self.messages.get("settings_updated"):
messages.add_message(
self.request,
Expand Down
33 changes: 33 additions & 0 deletions middleware.py
@@ -0,0 +1,33 @@
from django.utils import translation
from django.utils.cache import patch_vary_headers

from account.models import Account


class LocaleMiddleware(object):
"""
This is a very simple middleware that parses a request
and decides what translation object to install in the current
thread context depending on the user's account. This allows pages
to be dynamically translated to the language the user desires
(if the language is available, of course).
"""

def get_language_for_user(self, request):
if request.user.is_authenticated():
try:
account = Account.objects.get(user=request.user)
return account.language
except Account.DoesNotExist:
pass
return translation.get_language_from_request(request)

def process_request(self, request):
translation.activate(self.get_language_for_user(request))
request.LANGUAGE_CODE = translation.get_language()

def process_response(self, request, response):
patch_vary_headers(response, ("Accept-Language",))
response["Content-Language"] = translation.get_language()
translation.deactivate()
return response
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -13,6 +13,7 @@
packages = find_packages(),
install_requires = [
"django-appconf==0.5",
"pytz==2012b"
],
classifiers = [
"Development Status :: 4 - Beta",
Expand Down