From a3b8362a9e50c0aea9bdb13810e1f65c987f3f5b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 15:47:35 +0100 Subject: [PATCH 1/8] Move all logic from __init__.py to base. --- taiga/base/domains/__init__.py | 94 +++++----------------------------- 1 file changed, 12 insertions(+), 82 deletions(-) diff --git a/taiga/base/domains/__init__.py b/taiga/base/domains/__init__.py index 6f64e702..78816b6f 100644 --- a/taiga/base/domains/__init__.py +++ b/taiga/base/domains/__init__.py @@ -1,83 +1,13 @@ -# -*- coding: utf-8 -*- +from .base import get_default_domain +from .base import get_domain_for_domain_name +from .base import activate +from .base import deactivate +from .base import get_default_domain +from .base import DomainNotFound -import logging -from threading import local - -from django.db.models import get_model -from django.core.exceptions import ImproperlyConfigured -from django.utils.translation import ugettext_lazy as _ - -from .. import exceptions as exc - - -_local = local() -log = logging.getLogger("taiga.domains") - - -class DomainNotFound(exc.BaseException): - pass - - -def get_default_domain(): - from django.conf import settings - try: - sid = settings.SITE_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") - cached = getattr(_local, "default_domain", None) - if cached is None: - try: - cached = _local.default_domain = model_cls.objects.get(pk=sid) - except model_cls.DoesNotExist: - raise ImproperlyConfigured("default domain not found on database.") - - return cached - - -def get_domain_for_domain_name(domain): - log.debug("Trying activate domain for domain name: {}".format(domain)) - cache = getattr(_local, "cache", {}) - - if domain in cache: - return cache[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")) - else: - cache[domain] = domain - - return domain - - -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): - if hasattr(_local, "default_domain"): - del _local.default_domain - - if hasattr(_local, "cache"): - del _local.cache +__all__ = ["get_default_domain", + "get_domain_for_domain_name", + "activate", + "deactivate", + "get_default_domain", + "DomainNotFound"] From cbcf9dddc36125852482b28c43f0fd0b850caa44 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 15:49:05 +0100 Subject: [PATCH 2/8] Allow add domain aliases. This implies some minor refactor of domains app code. --- taiga/base/domains/api.py | 2 +- taiga/base/domains/base.py | 75 ++++++++++++++++ taiga/base/domains/middleware.py | 25 ++++-- .../0006_auto__add_field_domain_alias_of.py | 89 +++++++++++++++++++ taiga/base/domains/models.py | 5 +- 5 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 taiga/base/domains/base.py create mode 100644 taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py diff --git a/taiga/base/domains/api.py b/taiga/base/domains/api.py index d9eb06d2..3a2853b2 100644 --- a/taiga/base/domains/api.py +++ b/taiga/base/domains/api.py @@ -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 diff --git a/taiga/base/domains/base.py b/taiga/base/domains/base.py new file mode 100644 index 00000000..2b2d4243 --- /dev/null +++ b/taiga/base/domains/base.py @@ -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() diff --git a/taiga/base/domains/middleware.py b/taiga/base/domains/middleware.py index 36931857..d6f3b197 100644 --- a/taiga/base/domains/middleware.py +++ b/taiga/base/domains/middleware.py @@ -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 diff --git a/taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py b/taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py new file mode 100644 index 00000000..b78cb4c2 --- /dev/null +++ b/taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py @@ -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'] \ No newline at end of file diff --git a/taiga/base/domains/models.py b/taiga/base/domains/models.py index 1f5ab093..eabce8d4 100644 --- a/taiga/base/domains/models.py +++ b/taiga/base/domains/models.py @@ -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') From 564b62fd1b48c1b8318a3b336bbf2914f936731a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 15:50:35 +0100 Subject: [PATCH 3/8] Add tests for domain app. --- taiga/base/domains/tests.py | 105 ++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 taiga/base/domains/tests.py diff --git a/taiga/base/domains/tests.py b/taiga/base/domains/tests.py new file mode 100644 index 00000000..0281b99c --- /dev/null +++ b/taiga/base/domains/tests.py @@ -0,0 +1,105 @@ +from django import test +from django.test.utils import override_settings +from django.core.exceptions import ImproperlyConfigured +from django.db.models import get_model +from django.http import HttpResponse + +from . import base +from .models import Domain +from .middleware import DomainsMiddleware + + + +class DomainCoreTests(test.TestCase): + fixtures = ["initial_domains.json"] + + def setUp(self): + base.clear_domain_cache() + + @override_settings(DOMAIN_ID=1) + def test_get_default_domain(self): + default_domain = base.get_default_domain() + self.assertEqual(default_domain.domain, "localhost") + + @override_settings(DOMAIN_ID=2) + def test_get_wrong_default_domain(self): + with self.assertRaises(ImproperlyConfigured): + default_domain = base.get_default_domain() + + def test_get_domain_by_name(self): + domain = base.get_domain_for_domain_name("localhost") + self.assertEqual(domain.id, 1) + self.assertEqual(domain.domain, "localhost") + + def test_get_domain_by_name_aliased(self): + main_domain = base.get_default_domain() + aliased_domain = Domain.objects.create(domain="beta.localhost", scheme="http", + alias_of=main_domain) + + resolved_domain = base.get_domain_for_domain_name("beta.localhost", follow_alias=False) + self.assertEqual(resolved_domain.domain, "beta.localhost") + + resolved_domain = base.get_domain_for_domain_name("beta.localhost", follow_alias=True) + self.assertEqual(resolved_domain.domain, "localhost") + + def test_lru_cache_for_get_default_domain(self): + with self.assertNumQueries(1): + base.get_default_domain() + base.get_default_domain() + + def test_lru_cache_for_get_domain_for_domain_name(self): + with self.assertNumQueries(2): + base.get_domain_for_domain_name("localhost", follow_alias=True) + base.get_domain_for_domain_name("localhost", follow_alias=True) + base.get_domain_for_domain_name("localhost", follow_alias=False) + base.get_domain_for_domain_name("localhost", follow_alias=False) + + def test_activate_deactivate_domain(self): + main_domain = base.get_default_domain() + aliased_domain = Domain.objects.create(domain="beta.localhost", scheme="http", + alias_of=main_domain) + + self.assertEqual(base.get_active_domain(), main_domain) + + base.activate(aliased_domain) + self.assertEqual(base.get_active_domain(), aliased_domain) + + base.deactivate() + self.assertEqual(base.get_active_domain(), main_domain) + + +from django.test.client import RequestFactory + +class DomainMiddlewareTests(test.TestCase): + fixtures = ["initial_domains.json"] + + def setUp(self): + self.main_domain = base.get_default_domain() + self.aliased_domain = Domain.objects.create(domain="beta.localhost", scheme="http", + alias_of=self.main_domain) + self.factory = RequestFactory() + + def test_process_request(self): + request = self.factory.get("/", HTTP_X_HOST="beta.localhost") + middleware = DomainsMiddleware() + ret = middleware.process_request(request) + + self.assertEqual(request.domain, self.main_domain) + self.assertEqual(ret, None) + + def test_process_request_with_wrong_domain(self): + request = self.factory.get("/", HTTP_X_HOST="beta2.localhost") + middleware = DomainsMiddleware() + ret = middleware.process_request(request) + + self.assertFalse(hasattr(request, "domain")) + self.assertNotEqual(ret, None) + self.assertIsInstance(ret, HttpResponse) + + def test_process_request_without_host_header(self): + request = self.factory.get("/") + middleware = DomainsMiddleware() + ret = middleware.process_request(request) + + self.assertEqual(request.domain, self.main_domain) + self.assertEqual(ret, None) From 8318c928f097a0d97c13c0c87c7f0391d30f93a1 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 15:52:02 +0100 Subject: [PATCH 4/8] Add mission apache license header on main domain modules. --- taiga/base/domains/__init__.py | 14 ++++++++++++++ taiga/base/domains/admin.py | 14 ++++++++++++++ taiga/base/domains/api.py | 14 +++++++++++++- taiga/base/domains/middleware.py | 14 ++++++++++++++ taiga/base/domains/models.py | 14 +++++++++++++- taiga/base/domains/permissions.py | 14 ++++++++++++++ taiga/base/domains/serializers.py | 14 +++++++++++++- taiga/base/domains/tests.py | 15 ++++++++++++++- 8 files changed, 109 insertions(+), 4 deletions(-) diff --git a/taiga/base/domains/__init__.py b/taiga/base/domains/__init__.py index 78816b6f..2750719d 100644 --- a/taiga/base/domains/__init__.py +++ b/taiga/base/domains/__init__.py @@ -1,3 +1,17 @@ +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from .base import get_default_domain from .base import get_domain_for_domain_name from .base import activate diff --git a/taiga/base/domains/admin.py b/taiga/base/domains/admin.py index d90935f8..32da3519 100644 --- a/taiga/base/domains/admin.py +++ b/taiga/base/domains/admin.py @@ -1,3 +1,17 @@ +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from django.contrib import admin from .models import Domain, DomainMember diff --git a/taiga/base/domains/api.py b/taiga/base/domains/api.py index 3a2853b2..174e6dc4 100644 --- a/taiga/base/domains/api.py +++ b/taiga/base/domains/api.py @@ -1,4 +1,16 @@ -# -*- coding: utf-8 -*- +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. from rest_framework import viewsets from rest_framework.response import Response diff --git a/taiga/base/domains/middleware.py b/taiga/base/domains/middleware.py index d6f3b197..29dfacb4 100644 --- a/taiga/base/domains/middleware.py +++ b/taiga/base/domains/middleware.py @@ -1,3 +1,17 @@ +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import json from django import http diff --git a/taiga/base/domains/models.py b/taiga/base/domains/models.py index eabce8d4..211eed1c 100644 --- a/taiga/base/domains/models.py +++ b/taiga/base/domains/models.py @@ -1,4 +1,16 @@ -# -*- coding: utf-8 -*- +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. import string diff --git a/taiga/base/domains/permissions.py b/taiga/base/domains/permissions.py index d6a0d752..89af16d3 100644 --- a/taiga/base/domains/permissions.py +++ b/taiga/base/domains/permissions.py @@ -1,3 +1,17 @@ +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from rest_framework import permissions from taiga.base.domains.models import DomainMember diff --git a/taiga/base/domains/serializers.py b/taiga/base/domains/serializers.py index 5976f3da..51ff718c 100644 --- a/taiga/base/domains/serializers.py +++ b/taiga/base/domains/serializers.py @@ -1,4 +1,16 @@ -# -*- coding: utf-8 -*- +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. from rest_framework import serializers from taiga.base.users.serializers import UserSerializer diff --git a/taiga/base/domains/tests.py b/taiga/base/domains/tests.py index 0281b99c..a20d8724 100644 --- a/taiga/base/domains/tests.py +++ b/taiga/base/domains/tests.py @@ -1,3 +1,17 @@ +# Copyright 2014 Andrey Antukh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# y ou may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from django import test from django.test.utils import override_settings from django.core.exceptions import ImproperlyConfigured @@ -9,7 +23,6 @@ from .models import Domain from .middleware import DomainsMiddleware - class DomainCoreTests(test.TestCase): fixtures = ["initial_domains.json"] From b633c8c11512b23bed46aafdd252f8aadb7ef03e Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 16:01:30 +0100 Subject: [PATCH 5/8] Move taiga.base.domains to taiga.domains --- taiga/{base => }/domains/__init__.py | 0 taiga/{base => }/domains/admin.py | 0 taiga/{base => }/domains/api.py | 0 taiga/{base => }/domains/base.py | 0 taiga/{base => }/domains/fixtures/initial_domains.json | 0 taiga/{base => }/domains/middleware.py | 0 taiga/{base => }/domains/migrations/0001_initial.py | 0 ..._field_domainmember_domain__chg_field_domainmember_site.py | 0 .../domains/migrations/0003_change_sites_for_domains.py | 0 ..._domainmember_site__del_unique_domainmember_site_user__.py | 0 .../0005_auto__add_field_domain_default_language.py | 0 .../migrations/0006_auto__add_field_domain_alias_of.py | 0 taiga/{base => }/domains/migrations/__init__.py | 0 taiga/{base => }/domains/models.py | 0 taiga/{base => }/domains/permissions.py | 4 ++-- taiga/{base => }/domains/serializers.py | 0 taiga/{base => }/domains/tests.py | 0 17 files changed, 2 insertions(+), 2 deletions(-) rename taiga/{base => }/domains/__init__.py (100%) rename taiga/{base => }/domains/admin.py (100%) rename taiga/{base => }/domains/api.py (100%) rename taiga/{base => }/domains/base.py (100%) rename taiga/{base => }/domains/fixtures/initial_domains.json (100%) rename taiga/{base => }/domains/middleware.py (100%) rename taiga/{base => }/domains/migrations/0001_initial.py (100%) rename taiga/{base => }/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py (100%) rename taiga/{base => }/domains/migrations/0003_change_sites_for_domains.py (100%) rename taiga/{base => }/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py (100%) rename taiga/{base => }/domains/migrations/0005_auto__add_field_domain_default_language.py (100%) rename taiga/{base => }/domains/migrations/0006_auto__add_field_domain_alias_of.py (100%) rename taiga/{base => }/domains/migrations/__init__.py (100%) rename taiga/{base => }/domains/models.py (100%) rename taiga/{base => }/domains/permissions.py (93%) rename taiga/{base => }/domains/serializers.py (100%) rename taiga/{base => }/domains/tests.py (100%) diff --git a/taiga/base/domains/__init__.py b/taiga/domains/__init__.py similarity index 100% rename from taiga/base/domains/__init__.py rename to taiga/domains/__init__.py diff --git a/taiga/base/domains/admin.py b/taiga/domains/admin.py similarity index 100% rename from taiga/base/domains/admin.py rename to taiga/domains/admin.py diff --git a/taiga/base/domains/api.py b/taiga/domains/api.py similarity index 100% rename from taiga/base/domains/api.py rename to taiga/domains/api.py diff --git a/taiga/base/domains/base.py b/taiga/domains/base.py similarity index 100% rename from taiga/base/domains/base.py rename to taiga/domains/base.py diff --git a/taiga/base/domains/fixtures/initial_domains.json b/taiga/domains/fixtures/initial_domains.json similarity index 100% rename from taiga/base/domains/fixtures/initial_domains.json rename to taiga/domains/fixtures/initial_domains.json diff --git a/taiga/base/domains/middleware.py b/taiga/domains/middleware.py similarity index 100% rename from taiga/base/domains/middleware.py rename to taiga/domains/middleware.py diff --git a/taiga/base/domains/migrations/0001_initial.py b/taiga/domains/migrations/0001_initial.py similarity index 100% rename from taiga/base/domains/migrations/0001_initial.py rename to taiga/domains/migrations/0001_initial.py diff --git a/taiga/base/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py b/taiga/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py similarity index 100% rename from taiga/base/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py rename to taiga/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py diff --git a/taiga/base/domains/migrations/0003_change_sites_for_domains.py b/taiga/domains/migrations/0003_change_sites_for_domains.py similarity index 100% rename from taiga/base/domains/migrations/0003_change_sites_for_domains.py rename to taiga/domains/migrations/0003_change_sites_for_domains.py diff --git a/taiga/base/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py b/taiga/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py similarity index 100% rename from taiga/base/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py rename to taiga/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py diff --git a/taiga/base/domains/migrations/0005_auto__add_field_domain_default_language.py b/taiga/domains/migrations/0005_auto__add_field_domain_default_language.py similarity index 100% rename from taiga/base/domains/migrations/0005_auto__add_field_domain_default_language.py rename to taiga/domains/migrations/0005_auto__add_field_domain_default_language.py diff --git a/taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py b/taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py similarity index 100% rename from taiga/base/domains/migrations/0006_auto__add_field_domain_alias_of.py rename to taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py diff --git a/taiga/base/domains/migrations/__init__.py b/taiga/domains/migrations/__init__.py similarity index 100% rename from taiga/base/domains/migrations/__init__.py rename to taiga/domains/migrations/__init__.py diff --git a/taiga/base/domains/models.py b/taiga/domains/models.py similarity index 100% rename from taiga/base/domains/models.py rename to taiga/domains/models.py diff --git a/taiga/base/domains/permissions.py b/taiga/domains/permissions.py similarity index 93% rename from taiga/base/domains/permissions.py rename to taiga/domains/permissions.py index 89af16d3..48a309c0 100644 --- a/taiga/base/domains/permissions.py +++ b/taiga/domains/permissions.py @@ -14,8 +14,8 @@ from rest_framework import permissions -from taiga.base.domains.models import DomainMember -from taiga.base.domains import get_active_domain +from .models import DomainMember +from .base import get_active_domain class DomainPermission(permissions.BasePermission): diff --git a/taiga/base/domains/serializers.py b/taiga/domains/serializers.py similarity index 100% rename from taiga/base/domains/serializers.py rename to taiga/domains/serializers.py diff --git a/taiga/base/domains/tests.py b/taiga/domains/tests.py similarity index 100% rename from taiga/base/domains/tests.py rename to taiga/domains/tests.py From 3d932ba569b62d93ec12653c98e3fc0fe04b9557 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 16:01:58 +0100 Subject: [PATCH 6/8] Fix domains module imports due to previous module relocation. --- taiga/base/auth/api.py | 4 ++-- taiga/base/auth/tests/tests_auth.py | 2 +- taiga/front/__init__.py | 3 +-- taiga/projects/api.py | 2 +- taiga/projects/models.py | 5 +++-- taiga/projects/permissions.py | 2 +- taiga/projects/tests/__init__.py | 2 +- taiga/routers.py | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/taiga/base/auth/api.py b/taiga/base/auth/api.py index 8c0fe707..4a2cbe31 100644 --- a/taiga/base/auth/api.py +++ b/taiga/base/auth/api.py @@ -11,8 +11,8 @@ from rest_framework.permissions import AllowAny from rest_framework import status, viewsets from rest_framework.decorators import list_route -from taiga.base.domains.models import DomainMember -from taiga.base.domains import get_active_domain +from taiga.domains.models import DomainMember +from taiga.domains import get_active_domain from taiga.base.users.models import User, Role from taiga.base.users.serializers import UserSerializer from taiga.base import exceptions as exc diff --git a/taiga/base/auth/tests/tests_auth.py b/taiga/base/auth/tests/tests_auth.py index 7072eebe..4adb3f6b 100644 --- a/taiga/base/auth/tests/tests_auth.py +++ b/taiga/base/auth/tests/tests_auth.py @@ -18,7 +18,7 @@ from taiga.base import auth from taiga.base.users.tests import create_user, create_domain from taiga.projects.tests import create_project -from taiga.base.domains.models import Domain, DomainMember +from taiga.domains.models import Domain, DomainMember from taiga.projects.models import Membership diff --git a/taiga/front/__init__.py b/taiga/front/__init__.py index 46ea7231..1222c35b 100644 --- a/taiga/front/__init__.py +++ b/taiga/front/__init__.py @@ -3,8 +3,7 @@ from django.conf import settings from django_jinja import library -from taiga.base import domains - +from taiga import domains URLS = { "home": "/", diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 3becb2d3..fad7b44b 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -15,11 +15,11 @@ from rest_framework import status from djmail.template_mail import MagicMailBuilder +from taiga.domains import get_active_domain from taiga.base import filters from taiga.base import exceptions as exc from taiga.base.permissions import has_project_perm from taiga.base.api import ModelCrudViewSet, ModelListViewSet, RetrieveModelMixin -from taiga.base.domains import get_active_domain from taiga.base.users.models import Role from taiga.base.notifications.api import NotificationSenderMixin from taiga.projects.aggregates.tags import get_all_tags diff --git a/taiga/projects/models.py b/taiga/projects/models.py index 3f270a85..3c0ceca7 100644 --- a/taiga/projects/models.py +++ b/taiga/projects/models.py @@ -19,11 +19,12 @@ from django.utils import timezone from picklefield.fields import PickledObjectField import reversion +from taiga.domains.models import DomainMember +from taiga.projects.userstories.models import UserStory from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.dicts import dict_sum -from taiga.base.domains.models import DomainMember from taiga.base.users.models import Role -from taiga.projects.userstories.models import UserStory + from . import choices diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index 6005b278..6a753bf3 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from taiga.base.permissions import BasePermission -from taiga.base.domains import get_active_domain +from taiga.domains import get_active_domain class ProjectPermission(BasePermission): diff --git a/taiga/projects/tests/__init__.py b/taiga/projects/tests/__init__.py index ed8c9719..3a003f3f 100644 --- a/taiga/projects/tests/__init__.py +++ b/taiga/projects/tests/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from django.db.models.loading import get_model -from taiga.base.domains import get_active_domain +from taiga.domains import get_active_domain def create_project(id, owner, save=True): diff --git a/taiga/routers.py b/taiga/routers.py index 453eb21c..f26e60c5 100644 --- a/taiga/routers.py +++ b/taiga/routers.py @@ -4,12 +4,12 @@ from taiga.base import routers from taiga.base.auth.api import AuthViewSet from taiga.base.users.api import UsersViewSet, PermissionsViewSet from taiga.base.searches.api import SearchViewSet -from taiga.base.domains.api import DomainViewSet, DomainMembersViewSet from taiga.base.resolver.api import ResolverViewSet from taiga.projects.api import (ProjectViewSet, MembershipViewSet, InvitationViewSet, UserStoryStatusViewSet, PointsViewSet, TaskStatusViewSet, IssueStatusViewSet, IssueTypeViewSet, PriorityViewSet, SeverityViewSet, ProjectAdminViewSet, RolesViewSet) #, QuestionStatusViewSet) +from taiga.domains.api import DomainViewSet, DomainMembersViewSet from taiga.projects.milestones.api import MilestoneViewSet from taiga.projects.userstories.api import UserStoryViewSet, UserStoryAttachmentViewSet from taiga.projects.tasks.api import TaskViewSet, TaskAttachmentViewSet From 179915e338ae6cd166f5f244ecdc91f8a1a3aa2a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 16:05:03 +0100 Subject: [PATCH 7/8] Fix domains module path on settings. --- settings/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/settings/common.py b/settings/common.py index fdc7d140..3834fcb1 100644 --- a/settings/common.py +++ b/settings/common.py @@ -116,7 +116,7 @@ TEMPLATE_LOADERS = [ MIDDLEWARE_CLASSES = [ "taiga.base.middleware.cors.CoorsMiddleware", - "taiga.base.domains.middleware.DomainsMiddleware", + "taiga.domains.middleware.DomainsMiddleware", # Common middlewares "django.middleware.common.CommonMiddleware", @@ -154,10 +154,10 @@ INSTALLED_APPS = [ "django.contrib.staticfiles", "taiga.base.users", - "taiga.base.domains", "taiga.base.notifications", "taiga.base.searches", "taiga.base", + "taiga.domains", "taiga.projects", "taiga.projects.mixins.blocked", "taiga.projects.milestones", From d72a3549279ebf21679444ca6606a952880757a9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sat, 22 Mar 2014 16:08:51 +0100 Subject: [PATCH 8/8] Fix typo on function alias on domains/__init__.py file. --- taiga/domains/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taiga/domains/__init__.py b/taiga/domains/__init__.py index 2750719d..75b3c015 100644 --- a/taiga/domains/__init__.py +++ b/taiga/domains/__init__.py @@ -16,12 +16,12 @@ from .base import get_default_domain from .base import get_domain_for_domain_name from .base import activate from .base import deactivate -from .base import get_default_domain +from .base import get_active_domain from .base import DomainNotFound __all__ = ["get_default_domain", "get_domain_for_domain_name", "activate", "deactivate", - "get_default_domain", + "get_active_domain", "DomainNotFound"]