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 all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions account/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from django.conf import settings
from django.utils.translation import get_language_info

import pytz

from appconf import AppConf

Expand All @@ -20,3 +23,8 @@ 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))
LANGUAGES = [
(code, get_language_info(code).get("name_local"))
for code, lang in settings.LANGUAGES
]
3 changes: 3 additions & 0 deletions account/context_processors.py
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions account/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from django.db import models

from account.conf import settings


class TimeZoneField(models.CharField):

__metaclass__ = models.SubfieldBase

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

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


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

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

def clean_email(self):
value = self.cleaned_data["email"]
Expand Down
53 changes: 51 additions & 2 deletions account/models.py
Original file line number Diff line number Diff line change
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.ACCOUNT_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.create(user=kwargs["instance"])
10 changes: 9 additions & 1 deletion account/views.py
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
packages = find_packages(),
install_requires = [
"django-appconf==0.5",
"pytz==2012b"
],
classifiers = [
"Development Status :: 4 - Beta",
Expand Down