Allow add domain aliases.

This implies some minor refactor of domains app code.
remotes/origin/enhancement/email-actions
Andrey Antukh 2014-03-22 15:49:05 +01:00
parent a3b8362a9e
commit cbcf9dddc3
5 changed files with 186 additions and 10 deletions

View File

@ -7,8 +7,8 @@ from rest_framework.permissions import AllowAny, IsAuthenticated
from django.http import Http404
from taiga.base.api import ModelCrudViewSet, UpdateModelMixin
from taiga.base.domains import get_active_domain
from .base import get_active_domain
from .serializers import DomainSerializer, DomainMemberSerializer
from .permissions import DomainMembersPermission, DomainPermission
from .models import DomainMember, Domain

View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
import logging
import functools
import threading
from django.db.models import get_model
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _
from taiga.base import exceptions as exc
log = logging.getLogger("taiga.domains")
_local = threading.local()
class DomainNotFound(exc.BaseException):
pass
@functools.lru_cache(maxsize=1)
def get_default_domain():
from django.conf import settings
try:
sid = settings.DOMAIN_ID
except AttributeError:
raise ImproperlyConfigured("You're using the \"domains framework\" without having "
"set the DOMAIN_ID setting. Create a domain in your database "
"and set the DOMAIN_ID setting to fix this error.")
model_cls = get_model("domains", "Domain")
try:
return model_cls.objects.get(pk=sid)
except model_cls.DoesNotExist:
raise ImproperlyConfigured("default domain not found on database.")
@functools.lru_cache(maxsize=100, typed=True)
def get_domain_for_domain_name(domain:str, follow_alias:bool=True):
log.debug("Trying activate domain for domain name: {}".format(domain))
model_cls = get_model("domains", "Domain")
try:
domain = model_cls.objects.get(domain=domain)
except model_cls.DoesNotExist:
log.warning("Domain does not exist for domain: {}".format(domain))
raise DomainNotFound(_("domain not found"))
# Use `alias_of_id` instead of simple `alias_of` for performace reasons.
if domain.alias_of_id is None or not follow_alias:
return domain
return domain.alias_of
def activate(domain):
log.debug("Activating domain: {}".format(domain))
_local.active_domain = domain
def deactivate():
if hasattr(_local, "active_domain"):
log.debug("Deactivating domain: {}".format(_local.active_domain))
del _local.active_domain
def get_active_domain():
active_domain = getattr(_local, "active_domain", None)
if active_domain is None:
return get_default_domain()
return active_domain
def clear_domain_cache(**kwargs):
get_default_domain.cache_clear()
get_domain_for_domain_name.cache_clear()

View File

@ -1,29 +1,38 @@
# -*- coding: utf-8 -*-
import json
from django import http
from taiga.base import domains
from taiga.base.exceptions import format_exception
from .base import get_domain_for_domain_name
from .base import activate as activate_domain
from .base import deactivate as deactivate_domain
from .base import get_default_domain
from .base import DomainNotFound
class DomainsMiddleware(object):
"""
Domain middlewate: process request and try resolve domain
from HTTP_X_HOST header. If no header is specified, one
default is used.
"""
def process_request(self, request):
domain = request.META.get("HTTP_X_HOST", None)
if domain is not None:
try:
domain = domains.get_domain_for_domain_name(domain)
except domains.DomainNotFound as e:
domain = get_domain_for_domain_name(domain, follow_alias=True)
except DomainNotFound as e:
detail = format_exception(e)
return http.HttpResponseBadRequest(json.dumps(detail))
else:
domain = domains.get_default_domain()
domain = get_default_domain()
request.domain = domain
domains.activate(domain)
activate_domain(domain)
def process_response(self, request, response):
domains.deactivate()
deactivate_domain()
if hasattr(request, "domain"):
response["X-Site-Host"] = request.domain.domain

View File

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Domain.alias_of'
db.add_column('domains_domain', 'alias_of',
self.gf('django.db.models.fields.related.ForeignKey')(to=orm['domains.Domain'], default=None, blank=True, null=True, related_name='+'),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Domain.alias_of'
db.delete_column('domains_domain', 'alias_of_id')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'object_name': 'Permission', 'unique_together': "(('content_type', 'codename'),)", 'ordering': "('content_type__app_label', 'content_type__model', 'codename')"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'contenttypes.contenttype': {
'Meta': {'object_name': 'ContentType', 'unique_together': "(('app_label', 'model'),)", 'ordering': "('name',)", 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'domains.domain': {
'Meta': {'object_name': 'Domain', 'ordering': "('domain',)"},
'alias_of': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'default': 'None', 'blank': 'True', 'null': 'True', 'related_name': "'+'"}),
'default_language': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': "''", 'max_length': '20'}),
'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'public_register': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'scheme': ('django.db.models.fields.CharField', [], {'default': 'None', 'null': 'True', 'max_length': '60'})
},
'domains.domainmember': {
'Meta': {'object_name': 'DomainMember', 'unique_together': "(('domain', 'user'),)", 'ordering': "['email']"},
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'null': 'True', 'related_name': "'members'"}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.User']", 'null': 'True', 'related_name': "'+'"})
},
'users.user': {
'Meta': {'object_name': 'User', 'ordering': "['username']"},
'color': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': "'#28261c'", 'max_length': '9'}),
'colorize_tags': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'default_language': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': "''", 'max_length': '20'}),
'default_timezone': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': "''", 'max_length': '20'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'blank': 'True', 'max_length': '75'}),
'first_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True', 'symmetrical': 'False', 'related_name': "'user_set'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'notify_changes_by_me': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'notify_level': ('django.db.models.fields.CharField', [], {'default': "'all_owned_projects'", 'max_length': '32'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'photo': ('django.db.models.fields.files.FileField', [], {'blank': 'True', 'null': 'True', 'max_length': '500'}),
'token': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': 'None', 'null': 'True', 'max_length': '200'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True', 'symmetrical': 'False', 'related_name': "'user_set'"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
}
}
complete_apps = ['domains']

View File

@ -8,7 +8,7 @@ from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from . import clear_domain_cache
from .base import clear_domain_cache
def _simple_domain_name_validator(value):
@ -38,6 +38,9 @@ class Domain(models.Model):
default_language = models.CharField(max_length=20, null=False, blank=True, default="",
verbose_name=_("default language"))
alias_of = models.ForeignKey("self", null=True, default=None, blank=True,
verbose_name=_("Mark as alias of"), related_name="+")
class Meta:
verbose_name = _('domain')
verbose_name_plural = _('domain')