From 2b087678b9ec9c0b4b547b992d02126851c4e60c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 May 2014 12:59:44 +0200 Subject: [PATCH] Remove domains. --- .gitignore | 1 + regenerate.sh | 2 - requirements.txt | 4 +- settings/common.py | 9 +- taiga/auth/api.py | 18 +- taiga/auth/services.py | 24 +- taiga/base/serializers.py | 16 -- taiga/domains/__init__.py | 27 --- taiga/domains/admin.py | 27 --- taiga/domains/api.py | 64 ----- taiga/domains/base.py | 87 ------- taiga/domains/fixtures/initial_domains.json | 12 - taiga/domains/middleware.py | 54 ----- taiga/domains/migrations/0001_initial.py | 112 --------- ...ber_domain__chg_field_domainmember_site.py | 98 -------- .../0003_change_sites_for_domains.py | 89 ------- ...te__del_unique_domainmember_site_user__.py | 99 -------- ...auto__add_field_domain_default_language.py | 88 ------- .../0006_auto__add_field_domain_alias_of.py | 89 ------- taiga/domains/migrations/__init__.py | 0 taiga/domains/models.py | 98 -------- taiga/domains/permissions.py | 43 ---- taiga/domains/serializers.py | 42 ---- taiga/domains/services.py | 65 ----- taiga/domains/tests.py | 118 --------- taiga/front/__init__.py | 18 +- taiga/projects/admin.py | 2 +- taiga/projects/api.py | 29 +-- .../fixtures/initial_project_templates.json | 6 +- .../management/commands/sample_data.py | 1 - ..._domain__add_unique_projecttemplate_slu.py | 224 ++++++++++++++++++ taiga/projects/models.py | 31 +-- taiga/projects/permissions.py | 30 +-- taiga/projects/serializers.py | 6 +- taiga/routers.py | 6 - taiga/users/api.py | 2 - taiga/users/fixtures/initial_user.json | 21 -- tests/factories.py | 15 +- .../test_project_references_sequences.py | 8 +- 39 files changed, 273 insertions(+), 1412 deletions(-) delete mode 100644 taiga/domains/__init__.py delete mode 100644 taiga/domains/admin.py delete mode 100644 taiga/domains/api.py delete mode 100644 taiga/domains/base.py delete mode 100644 taiga/domains/fixtures/initial_domains.json delete mode 100644 taiga/domains/middleware.py delete mode 100644 taiga/domains/migrations/0001_initial.py delete mode 100644 taiga/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py delete mode 100644 taiga/domains/migrations/0003_change_sites_for_domains.py delete mode 100644 taiga/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py delete mode 100644 taiga/domains/migrations/0005_auto__add_field_domain_default_language.py delete mode 100644 taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py delete mode 100644 taiga/domains/migrations/__init__.py delete mode 100644 taiga/domains/models.py delete mode 100644 taiga/domains/permissions.py delete mode 100644 taiga/domains/serializers.py delete mode 100644 taiga/domains/services.py delete mode 100644 taiga/domains/tests.py create mode 100644 taiga/projects/migrations/0023_auto__del_field_projecttemplate_domain__add_unique_projecttemplate_slu.py diff --git a/.gitignore b/.gitignore index 11a4aa6f..2e58a859 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ media *.mo .venv .coverage +.\#* \ No newline at end of file diff --git a/regenerate.sh b/regenerate.sh index c7761833..0b422c6c 100755 --- a/regenerate.sh +++ b/regenerate.sh @@ -11,8 +11,6 @@ python manage.py syncdb --all --noinput --traceback python manage.py migrate --fake # echo "-> Load initial Site" # python manage.py loaddata initial_site --traceback -echo "-> Load initial domain" -python manage.py loaddata initial_domains --traceback echo "-> Load initial user" python manage.py loaddata initial_user --traceback echo "-> Load initial project_templates" diff --git a/requirements.txt b/requirements.txt index ffa8388a..5589ed9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,10 +12,10 @@ pytz>=2013.9 six>=1.4.1 djmail>=0.4 django-pgjson==0.1.2 -django-jinja>=0.23 +django-jinja>=1.0.1 jinja2==2.7.1 pygments>=1.6 -django-sites==0.4 +django-sites==0.6 Markdown==2.4 fn==0.2.13 diff-match-patch==20110725.1 diff --git a/settings/common.py b/settings/common.py index 54254bcb..b5016666 100644 --- a/settings/common.py +++ b/settings/common.py @@ -73,11 +73,11 @@ LOGIN_URL="/auth/login/" USE_TZ = True SITES = { - 1: {"domain": "localhost:8000", "scheme": "http"}, + "api": {"domain": "localhost:8000", "scheme": "http", "name": "api"}, + "front": {"domain": "localhost:9001", "scheme": "http", "name": "front"}, } -DOMAIN_ID = 1 -SITE_ID = 1 +SITE_ID = "api" # Session configuration (only used for admin) SESSION_ENGINE="django.contrib.sessions.backends.db" @@ -133,7 +133,6 @@ TEMPLATE_LOADERS = [ MIDDLEWARE_CLASSES = [ "taiga.base.middleware.cors.CoorsMiddleware", - "taiga.domains.middleware.DomainsMiddleware", "taiga.events.middleware.SessionIDMiddleware", # Common middlewares @@ -174,7 +173,6 @@ INSTALLED_APPS = [ "taiga.base", "taiga.base.searches", "taiga.events", - "taiga.domains", "taiga.front", "taiga.users", "taiga.userstorage", @@ -294,6 +292,7 @@ REST_FRAMEWORK = { } DEFAULT_PROJECT_TEMPLATE = "scrum" +PUBLIC_REGISTER_ENABLED = False # NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE diff --git a/taiga/auth/api.py b/taiga/auth/api.py index 500b12bf..4987ee8b 100644 --- a/taiga/auth/api.py +++ b/taiga/auth/api.py @@ -18,6 +18,7 @@ from functools import partial from enum import Enum from django.utils.translation import ugettext_lazy as _ +from django.conf import settings from rest_framework.response import Response from rest_framework.permissions import AllowAny @@ -28,7 +29,6 @@ from rest_framework import serializers from taiga.base.decorators import list_route from taiga.base import exceptions as exc from taiga.users.services import get_and_validate_user -from taiga.domains.services import is_public_register_enabled_for_domain from .serializers import PublicRegisterSerializer from .serializers import PrivateRegisterForExistingUserSerializer @@ -96,16 +96,16 @@ class AuthViewSet(viewsets.ViewSet): permission_classes = (AllowAny,) def _public_register(self, request): - if not is_public_register_enabled_for_domain(request.domain): - raise exc.BadRequest(_("Public register is disabled for this domain.")) + if not settings.PUBLIC_REGISTER_ENABLED: + raise exc.BadRequest(_("Public register is disabled.")) try: data = parse_public_register_data(request.DATA) - user = public_register(request.domain, **data) + user = public_register(**data) except exc.IntegrityError as e: raise exc.BadRequest(e.detail) - data = make_auth_response_data(request.domain, user) + data = make_auth_response_data(user) return Response(data, status=status.HTTP_201_CREATED) def _private_register(self, request): @@ -113,12 +113,12 @@ class AuthViewSet(viewsets.ViewSet): if register_type is RegisterTypeEnum.existing_user: data = parse_private_register_for_existing_user_data(request.DATA) - user = private_register_for_existing_user(request.domain, **data) + user = private_register_for_existing_user(**data) else: data = parse_private_register_for_new_user_data(request.DATA) - user = private_register_for_new_user(request.domain, **data) + user = private_register_for_new_user(**data) - data = make_auth_response_data(request.domain, user) + data = make_auth_response_data(user) return Response(data, status=status.HTTP_201_CREATED) @list_route(methods=["POST"], permission_classes=[AllowAny]) @@ -136,5 +136,5 @@ class AuthViewSet(viewsets.ViewSet): password = request.DATA.get('password', None) user = get_and_validate_user(username=username, password=password) - data = make_auth_response_data(request.domain, user) + data = make_auth_response_data(user) return Response(data, status=status.HTTP_200_OK) diff --git a/taiga/auth/services.py b/taiga/auth/services.py index b31734ef..f7dda5d7 100644 --- a/taiga/auth/services.py +++ b/taiga/auth/services.py @@ -34,8 +34,6 @@ from djmail.template_mail import MagicMailBuilder from taiga.base import exceptions as exc from taiga.users.serializers import UserSerializer from taiga.users.services import get_and_validate_user -from taiga.domains.services import (create_domain_member, - is_user_exists_on_domain) from .backends import get_token_for_user @@ -92,8 +90,7 @@ def get_membership_by_token(token:str): @tx.atomic -def public_register(domain, *, username:str, password:str, - email:str, first_name:str, last_name:str): +def public_register(username:str, password:str, email:str, first_name:str, last_name:str): """ Given a parsed parameters, try register a new user knowing that it follows a public register flow. @@ -115,15 +112,12 @@ def public_register(domain, *, username:str, password:str, user.set_password(password) user.save() - if not is_user_exists_on_domain(domain, user): - create_domain_member(domain, user) - # send_public_register_email(user) return user @tx.atomic -def private_register_for_existing_user(domain, *, token:str, username:str, password:str): +def private_register_for_existing_user(token:str, username:str, password:str): """ Register works not only for register users, also serves for accept inviatations for projects as existing user. @@ -135,9 +129,6 @@ def private_register_for_existing_user(domain, *, token:str, username:str, passw user = get_and_validate_user(username=username, password=password) membership = get_membership_by_token(token) - if not is_user_exists_on_domain(domain, user): - create_domain_member(domain, user) - membership.user = user membership.save(update_fields=["user"]) @@ -146,7 +137,7 @@ def private_register_for_existing_user(domain, *, token:str, username:str, passw @tx.atomic -def private_register_for_new_user(domain, *, token:str, username:str, email:str, +def private_register_for_new_user(token:str, username:str, email:str, first_name:str, last_name:str, password:str): """ Given a inviation token, try register new user matching @@ -169,9 +160,6 @@ def private_register_for_new_user(domain, *, token:str, username:str, email:str, except IntegrityError: raise exc.IntegrityError(_("Error on creating new user.")) - if not is_user_exists_on_domain(domain, user): - create_domain_member(domain, user) - membership = get_membership_by_token(token) membership.user = user membership.save(update_fields=["user"]) @@ -179,7 +167,7 @@ def private_register_for_new_user(domain, *, token:str, username:str, email:str, return user -def make_auth_response_data(domain, user) -> dict: +def make_auth_response_data(user) -> dict: """ Given a domain and user, creates data structure using python dict containing a representation @@ -187,9 +175,5 @@ def make_auth_response_data(domain, user) -> dict: """ serializer = UserSerializer(user) data = dict(serializer.data) - - data['is_site_owner'] = domain.user_is_owner(user) - data['is_site_staff'] = domain.user_is_staff(user) data["auth_token"] = get_token_for_user(user) - return data diff --git a/taiga/base/serializers.py b/taiga/base/serializers.py index c5c8caf7..5c0b9dde 100644 --- a/taiga/base/serializers.py +++ b/taiga/base/serializers.py @@ -18,8 +18,6 @@ from django.forms import widgets from rest_framework import serializers -from taiga.domains.base import get_active_domain -from taiga.domains.models import Domain from .neighbors import get_neighbors @@ -47,20 +45,6 @@ class JsonField(serializers.WritableField): return data -class AutoDomainField(serializers.WritableField): - """ - Automatically set domain field serializer. - """ - def to_native(self, obj): - if obj: - return obj.id - return obj - - def from_native(self, data): - domain = get_active_domain() - return domain - - class NeighborsSerializerMixin: def __init__(self, *args, **kwargs): diff --git a/taiga/domains/__init__.py b/taiga/domains/__init__.py deleted file mode 100644 index 723a630e..00000000 --- a/taiga/domains/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -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_active_domain -from .base import DomainNotFound - -__all__ = ["get_default_domain", - "get_domain_for_domain_name", - "activate", - "deactivate", - "get_active_domain", - "DomainNotFound"] diff --git a/taiga/domains/admin.py b/taiga/domains/admin.py deleted file mode 100644 index 7decab04..00000000 --- a/taiga/domains/admin.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from django.contrib import admin - -from .models import Domain, DomainMember - -class DomainMemberInline(admin.TabularInline): - model = DomainMember - -class DomainAdmin(admin.ModelAdmin): - list_display = ('domain', 'name') - search_fields = ('domain', 'name') - inlines = [ DomainMemberInline, ] - -admin.site.register(Domain, DomainAdmin) diff --git a/taiga/domains/api.py b/taiga/domains/api.py deleted file mode 100644 index af4febca..00000000 --- a/taiga/domains/api.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from rest_framework.response import Response -from rest_framework.permissions import IsAuthenticated - -from taiga.base.api import GenericViewSet -from taiga.base.api import ListModelMixin -from taiga.base.api import UpdateModelMixin -from taiga.base import exceptions as exc - -from .base import get_active_domain -from .serializers import DomainSerializer -from .serializers import DomainMemberSerializer -from .permissions import DomainPermission -from .permissions import DomainMembersPermission -from .models import Domain -from .models import DomainMember - - -class DomainViewSet(UpdateModelMixin, GenericViewSet): - permission_classes = (DomainPermission,) - serializer_class = DomainSerializer - queryset = Domain.objects.all() - - def list(self, request, **kwargs): - domain_data = DomainSerializer(request.domain).data - if request.domain.user_is_normal_user(request.user): - domain_data['projects'] = None - elif request.user.is_anonymous(): - domain_data['projects'] = None - return Response(domain_data) - - def update(self, request, *args, **kwargs): - raise exc.NotSupported() - - def partial_update(self, request, *args, **kwargs): - raise exc.NotSupported() - - def create(self, request, **kwargs): - self.kwargs['pk'] = request.domain.pk - return super().update(request, pk=request.domain.pk, **kwargs) - - -class DomainMembersViewSet(ListModelMixin, UpdateModelMixin, GenericViewSet): - permission_classes = (IsAuthenticated, DomainMembersPermission,) - serializer_class = DomainMemberSerializer - queryset = DomainMember.objects.all() - - def get_queryset(self): - domain = get_active_domain() - qs = super().get_queryset() - return qs.filter(domain=domain).distinct() diff --git a/taiga/domains/base.py b/taiga/domains/base.py deleted file mode 100644 index 91d64699..00000000 --- a/taiga/domains/base.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -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/domains/fixtures/initial_domains.json b/taiga/domains/fixtures/initial_domains.json deleted file mode 100644 index 99138275..00000000 --- a/taiga/domains/fixtures/initial_domains.json +++ /dev/null @@ -1,12 +0,0 @@ -[ -{ - "model": "domains.domain", - "fields": { - "public_register": false, - "domain": "localhost", - "scheme": null, - "name": "localhost" - }, - "pk": 1 -} -] diff --git a/taiga/domains/middleware.py b/taiga/domains/middleware.py deleted file mode 100644 index 0591f236..00000000 --- a/taiga/domains/middleware.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import json - -from django import http -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 = 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 = get_default_domain() - - request.domain = domain - activate_domain(domain) - - def process_response(self, request, response): - deactivate_domain() - - if hasattr(request, "domain"): - response["X-Site-Host"] = request.domain.domain - - return response diff --git a/taiga/domains/migrations/0001_initial.py b/taiga/domains/migrations/0001_initial.py deleted file mode 100644 index 99200993..00000000 --- a/taiga/domains/migrations/0001_initial.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- 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 model 'Domain' - db.create_table('domains_domain', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('domain', self.gf('django.db.models.fields.CharField')(max_length=255, unique=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('scheme', self.gf('django.db.models.fields.CharField')(max_length=60, null=True, default=None)), - ('public_register', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('domains', ['Domain']) - - # Adding model 'DomainMember' - db.create_table('domains_domainmember', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('site', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', to=orm['domains.Domain'])), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', null=True, to=orm['users.User'])), - ('email', self.gf('django.db.models.fields.EmailField')(max_length=255)), - ('is_owner', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('is_staff', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('domains', ['DomainMember']) - - # Adding unique constraint on 'DomainMember', fields ['site', 'user'] - db.create_unique('domains_domainmember', ['site_id', 'user_id']) - - - def backwards(self, orm): - # Removing unique constraint on 'DomainMember', fields ['site', 'user'] - db.delete_unique('domains_domainmember', ['site_id', 'user_id']) - - # Deleting model 'Domain' - db.delete_table('domains_domain') - - # Deleting model 'DomainMember' - db.delete_table('domains_domainmember') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True', 'symmetrical': 'False'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'object_name': 'Permission', 'unique_together': "(('content_type', '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': {'ordering': "('name',)", 'db_table': "'django_content_type'", 'object_name': 'ContentType', 'unique_together': "(('app_label', 'model'),)"}, - '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': {'ordering': "('domain',)", 'object_name': 'Domain'}, - 'domain': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True'}), - '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', [], {'max_length': '60', 'null': 'True', 'default': 'None'}) - }, - 'domains.domainmember': { - 'Meta': {'ordering': "['email']", 'object_name': 'DomainMember', 'unique_together': "(('site', 'user'),)"}, - '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'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['domains.Domain']"}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': "orm['users.User']"}) - }, - 'users.user': { - 'Meta': {'ordering': "['username']", 'object_name': 'User'}, - 'color': ('django.db.models.fields.CharField', [], {'max_length': '9', 'blank': 'True', 'default': "'#669933'"}), - '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', [], {'max_length': '20', 'blank': 'True', 'default': "''"}), - 'default_timezone': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True', 'default': "''"}), - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), - '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', [], {'max_length': '30', 'blank': 'True'}), - 'notify_changes_by_me': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'notify_level': ('django.db.models.fields.CharField', [], {'max_length': '32', 'default': "'all_owned_projects'"}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'photo': ('django.db.models.fields.files.FileField', [], {'max_length': '500', 'blank': 'True', 'null': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True', 'null': 'True', 'default': 'None'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), - 'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'}) - } - } - - complete_apps = ['domains'] \ No newline at end of file diff --git a/taiga/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 deleted file mode 100644 index f5fd97d7..00000000 --- a/taiga/domains/migrations/0002_auto__add_field_domainmember_domain__chg_field_domainmember_site.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- 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 'DomainMember.domain' - db.add_column('domains_domainmember', 'domain', - self.gf('django.db.models.fields.related.ForeignKey')(to=orm['domains.Domain'], null=True, related_name='+'), - keep_default=False) - - - # Changing field 'DomainMember.site' - db.alter_column('domains_domainmember', 'site_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['domains.Domain'], null=True)) - - def backwards(self, orm): - # Deleting field 'DomainMember.domain' - db.delete_column('domains_domainmember', 'domain_id') - - - # User chose to not deal with backwards NULL issues for 'DomainMember.site' - raise RuntimeError("Cannot reverse this migration. 'DomainMember.site' and its values cannot be restored.") - - # The following code is provided here to aid in writing a correct migration - # Changing field 'DomainMember.site' - db.alter_column('domains_domainmember', 'site_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['domains.Domain'])) - - 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']", 'blank': 'True', 'symmetrical': 'False'}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'object_name': 'Permission'}, - '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': {'db_table': "'django_content_type'", 'unique_together': "(('app_label', 'model'),)", 'ordering': "('name',)", 'object_name': 'ContentType'}, - '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': {'ordering': "('domain',)", 'object_name': 'Domain'}, - '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', [], {'null': 'True', 'default': 'None', 'max_length': '60'}) - }, - 'domains.domainmember': { - 'Meta': {'unique_together': "(('site', 'user'),)", 'ordering': "['email']", 'object_name': 'DomainMember'}, - 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'null': 'True', 'related_name': "'+'"}), - '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'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'null': 'True', 'related_name': "'+'"}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.User']", 'null': 'True', 'related_name': "'+'"}) - }, - 'users.user': { - 'Meta': {'ordering': "['username']", 'object_name': 'User'}, - 'color': ('django.db.models.fields.CharField', [], {'blank': 'True', 'default': "'#669933'", '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']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), - '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', [], {'null': 'True', 'blank': 'True', 'max_length': '500'}), - 'token': ('django.db.models.fields.CharField', [], {'null': 'True', 'default': 'None', 'max_length': '200', 'blank': 'True'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - } - } - - complete_apps = ['domains'] \ No newline at end of file diff --git a/taiga/domains/migrations/0003_change_sites_for_domains.py b/taiga/domains/migrations/0003_change_sites_for_domains.py deleted file mode 100644 index df81bca5..00000000 --- a/taiga/domains/migrations/0003_change_sites_for_domains.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -from south.utils import datetime_utils as datetime -from south.db import db -from south.v2 import DataMigration -from django.db import models - -class Migration(DataMigration): - - def forwards(self, orm): - "Write your forwards methods here." - # Note: Don't use "from appname.models import ModelName". - # Use orm.ModelName to refer to models in this application, - # and orm['appname.ModelName'] for models in other applications. - - for dm in orm["domains.DomainMember"].objects.all(): - dm.domain = dm.site - dm.save() - - def backwards(self, orm): - "Write your backwards methods here." - - 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', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['auth.Permission']"}) - }, - 'auth.permission': { - 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission', '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': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'", 'ordering': "('name',)"}, - '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',)"}, - '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', 'max_length': '60', 'null': 'True'}) - }, - 'domains.domainmember': { - 'Meta': {'unique_together': "(('site', 'user'),)", 'object_name': 'DomainMember', 'ordering': "['email']"}, - 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'null': 'True', 'related_name': "'+'"}), - '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'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'null': 'True', 'related_name': "'+'"}), - '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', [], {'default': "'#669933'", 'blank': 'True', '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', [], {'default': "''", 'blank': 'True', 'max_length': '20'}), - 'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'blank': 'True', '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', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['auth.Group']", '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', [], {'max_length': '500', 'blank': 'True', 'null': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'blank': 'True', 'max_length': '200', 'null': 'True'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['auth.Permission']", 'related_name': "'user_set'"}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - } - } - - complete_apps = ['domains'] - symmetrical = True diff --git a/taiga/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 deleted file mode 100644 index 79754c77..00000000 --- a/taiga/domains/migrations/0004_auto__del_field_domainmember_site__del_unique_domainmember_site_user__.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- 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): - # Removing unique constraint on 'DomainMember', fields ['site', 'user'] - db.delete_unique('domains_domainmember', ['site_id', 'user_id']) - - # Deleting field 'DomainMember.site' - db.delete_column('domains_domainmember', 'site_id') - - # Adding unique constraint on 'DomainMember', fields ['domain', 'user'] - db.create_unique('domains_domainmember', ['domain_id', 'user_id']) - - - def backwards(self, orm): - # Removing unique constraint on 'DomainMember', fields ['domain', 'user'] - db.delete_unique('domains_domainmember', ['domain_id', 'user_id']) - - # Adding field 'DomainMember.site' - db.add_column('domains_domainmember', 'site', - self.gf('django.db.models.fields.related.ForeignKey')(to=orm['domains.Domain'], related_name='+', null=True), - keep_default=False) - - # Adding unique constraint on 'DomainMember', fields ['site', 'user'] - db.create_unique('domains_domainmember', ['site_id', 'user_id']) - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True', 'symmetrical': 'False'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - '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': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'", 'object_name': 'ContentType'}, - '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': {'ordering': "('domain',)", 'object_name': 'Domain'}, - 'domain': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True'}), - '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', [], {'max_length': '60', 'default': 'None', 'null': 'True'}) - }, - 'domains.domainmember': { - 'Meta': {'ordering': "['email']", 'unique_together': "(('domain', 'user'),)", 'object_name': 'DomainMember'}, - 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['domains.Domain']", 'related_name': "'+'", 'null': 'True'}), - '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']", 'related_name': "'+'", 'null': 'True'}) - }, - 'users.user': { - 'Meta': {'ordering': "['username']", 'object_name': 'User'}, - 'color': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '9', 'default': "'#669933'"}), - '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', 'max_length': '20', 'default': "''"}), - 'default_timezone': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '20', 'default': "''"}), - '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', [], {'max_length': '32', 'default': "'all_owned_projects'"}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'photo': ('django.db.models.fields.files.FileField', [], {'blank': 'True', 'max_length': '500', 'null': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '200', 'default': 'None', 'null': 'True'}), - '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', [], {'max_length': '30', 'unique': 'True'}) - } - } - - complete_apps = ['domains'] \ No newline at end of file diff --git a/taiga/domains/migrations/0005_auto__add_field_domain_default_language.py b/taiga/domains/migrations/0005_auto__add_field_domain_default_language.py deleted file mode 100644 index 63b25cf0..00000000 --- a/taiga/domains/migrations/0005_auto__add_field_domain_default_language.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- 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.default_language' - db.add_column('domains_domain', 'default_language', - self.gf('django.db.models.fields.CharField')(default='', max_length=20, blank=True), - keep_default=False) - - - def backwards(self, orm): - # Deleting field 'Domain.default_language' - db.delete_column('domains_domain', 'default_language') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Permission']", 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - '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': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', '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': {'ordering': "('domain',)", 'object_name': 'Domain'}, - 'default_language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), - 'domain': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True'}), - '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', 'max_length': '60', 'null': 'True'}) - }, - 'domains.domainmember': { - 'Meta': {'ordering': "['email']", 'unique_together': "(('domain', 'user'),)", 'object_name': 'DomainMember'}, - 'domain': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['domains.Domain']", 'null': 'True'}), - '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', [], {'related_name': "'+'", 'to': "orm['users.User']", 'null': 'True'}) - }, - 'users.user': { - 'Meta': {'ordering': "['username']", 'object_name': 'User'}, - 'color': ('django.db.models.fields.CharField', [], {'default': "'#669933'", 'max_length': '9', 'blank': 'True'}), - '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', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), - 'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'to': "orm['auth.Group']", 'blank': 'True'}), - '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', [], {'max_length': '30', 'blank': 'True'}), - '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', [], {'null': 'True', 'max_length': '500', 'blank': 'True'}), - 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'null': 'True', 'max_length': '200', 'blank': 'True'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'to': "orm['auth.Permission']", 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'}) - } - } - - complete_apps = ['domains'] \ No newline at end of file diff --git a/taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py b/taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py deleted file mode 100644 index b78cb4c2..00000000 --- a/taiga/domains/migrations/0006_auto__add_field_domain_alias_of.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- 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/domains/migrations/__init__.py b/taiga/domains/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/taiga/domains/models.py b/taiga/domains/models.py deleted file mode 100644 index 13e5effe..00000000 --- a/taiga/domains/models.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import string - -from django.db import models -from django.db.models.signals import pre_save, pre_delete -from django.dispatch import receiver -from django.utils.translation import ugettext_lazy as _ -from django.core.exceptions import ValidationError - -from .base import clear_domain_cache - - -def _simple_domain_name_validator(value): - """ - Validates that the given value contains no whitespaces to prevent common - typos. - """ - if not value: - return - - checks = ((s in value) for s in string.whitespace) - if any(checks): - raise ValidationError( - _("The domain name cannot contain any spaces or tabs."), - code='invalid', - ) - - -class Domain(models.Model): - domain = models.CharField(_('domain name'), max_length=255, unique=True, - validators=[_simple_domain_name_validator]) - name = models.CharField(_('display name'), max_length=255) - scheme = models.CharField(_('scheme'), max_length=60, null=True, default=None) - - # Site Metadata - public_register = models.BooleanField(default=False) - 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') - ordering = ('domain',) - - def __str__(self): - return self.domain - - def user_is_owner(self, user): - return self.members.filter(user_id=user.id, is_owner=True).exists() - - def user_is_staff(self, user): - return self.members.filter(user_id=user.id, is_staff=True).exists() - - def user_is_normal_user(self, user): - return self.members.filter(user_id=user.id, is_owner=False, is_staff=False).exists() - - -class DomainMember(models.Model): - domain = models.ForeignKey("Domain", related_name="members", null=True) - user = models.ForeignKey("users.User", related_name="+", null=True) - - email = models.EmailField(max_length=255) - is_owner = models.BooleanField(default=False) - is_staff = models.BooleanField(default=False) - - class Meta: - ordering = ["email"] - verbose_name = "Domain Member" - verbose_name_plural = "Domain Members" - unique_together = ("domain", "user") - - def __str__(self): - return "DomainMember: {0}:{1}".format(self.domain, self.user) - - -pre_save.connect(clear_domain_cache, sender=Domain) -pre_delete.connect(clear_domain_cache, sender=Domain) - -@receiver(pre_delete, sender=DomainMember, dispatch_uid="domain_member_pre_delete") -def domain_member_pre_delete(sender, instance, *args, **kwargs): - for domain_project in instance.domain.projects.all(): - domain_project.memberships.filter(user=instance.user).delete() diff --git a/taiga/domains/permissions.py b/taiga/domains/permissions.py deleted file mode 100644 index da089d45..00000000 --- a/taiga/domains/permissions.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from rest_framework import permissions - -from .models import DomainMember -from .base import get_active_domain - - -class DomainPermission(permissions.BasePermission): - safe_methods = ['HEAD', 'OPTIONS', 'GET'] - - def has_object_permission(self, request, view, obj): - if request.method in self.safe_methods: - return True - - domain = get_active_domain() - return domain.user_is_owner(request.user) - - -class DomainMembersPermission(permissions.BasePermission): - safe_methods = ['HEAD', 'OPTIONS'] - - def has_permission(self, request, view): - if request.method in self.safe_methods: - return True - - domain = get_active_domain() - if request.method in ["POST", "PUT", "PATCH", "GET"]: - return domain.user_is_owner(request.user) - - return False diff --git a/taiga/domains/serializers.py b/taiga/domains/serializers.py deleted file mode 100644 index 3f0ccb26..00000000 --- a/taiga/domains/serializers.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from django.conf import settings - -from rest_framework import serializers -from taiga.users.serializers import UserSerializer - -from .models import Domain, DomainMember - - -class DomainSerializer(serializers.ModelSerializer): - projects = serializers.SerializerMethodField('get_projects') - default_project_template = serializers.SerializerMethodField('get_default_project_template') - - class Meta: - model = Domain - fields = ('public_register', 'default_language', "projects", "default_project_template") - - def get_projects(self, obj): - return map(lambda x: {"id": x.id, "name": x.name, "slug": x.slug, "owner": x.owner.id}, obj.projects.all().order_by('name')) - - def get_default_project_template(self, obj): - return settings.DEFAULT_PROJECT_TEMPLATE - - -class DomainMemberSerializer(serializers.ModelSerializer): - user = UserSerializer() - - class Meta: - model = DomainMember diff --git a/taiga/domains/services.py b/taiga/domains/services.py deleted file mode 100644 index d636b89e..00000000 --- a/taiga/domains/services.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# Copyright (C) 2014 Jesús Espino -# Copyright (C) 2014 David Barragán -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -""" -This module contains a domain logic for domains application. -""" - -from django.db.models.loading import get_model -from django.db import transaction as tx -from django.db import IntegrityError - -from taiga.base import exceptions as exc - - -def is_user_exists_on_domain(domain, user) -> bool: - """ - Checks if user is alredy exists on domain. - """ - return domain.members.filter(user=user).exists() - - -def is_public_register_enabled_for_domain(domain) -> bool: - """ - Checks if a specified domain have public register - activated. - - The implementation is very simple but it encapsulates - request attribute access into more semantic function - call. - """ - return domain.public_register - - -@tx.atomic -def create_domain_member(domain, user): - """ - Given a domain and user, add user as member to - specified domain. - - :returns: DomainMember - """ - domain_member_model = get_model("domains", "DomainMember") - - try: - domain_member = domain_member_model(domain=domain, user=user, - email=user.email, is_owner=False, - is_staff=False) - domain_member.save() - except IntegrityError: - raise exc.IntegrityError("User is already member in a site") - - return domain_member diff --git a/taiga/domains/tests.py b/taiga/domains/tests.py deleted file mode 100644 index a50d4aa7..00000000 --- a/taiga/domains/tests.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (C) 2014 Andrey Antukh -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -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) diff --git a/taiga/front/__init__.py b/taiga/front/__init__.py index 267fb543..b89b1369 100644 --- a/taiga/front/__init__.py +++ b/taiga/front/__init__.py @@ -13,11 +13,12 @@ # along with this program. If not, see . from django.conf import settings + from django_jinja import library +from django_sites import get_by_id as get_site_by_id -from taiga import domains -URLS = { +urls = { "home": "/", "backlog": "/#/project/{0}/backlog/", "taskboard": "/#/project/{0}/taskboard/{1}", @@ -31,14 +32,11 @@ URLS = { } -lib = library.Library() - - -@lib.global_function(name="resolve_front_url") +@library.global_function(name="resolve_front_url") def resolve(type, *args): - domain = domains.get_active_domain() + site = get_site_by_id("front") url_tmpl = "{scheme}//{domain}{url}" - scheme = domain.scheme and "{0}:".format(domain.scheme) or "" - url = URLS[type].format(*args) - return url_tmpl.format(scheme=scheme, domain=domain.domain, url=url) + scheme = site.scheme and "{0}:".format(site.scheme) or "" + url = urlsp[type].format(*args) + return url_tmpl.format(scheme=scheme, domain=site.domain, url=url) diff --git a/taiga/projects/admin.py b/taiga/projects/admin.py index 1f6e4edd..1f6e15f5 100644 --- a/taiga/projects/admin.py +++ b/taiga/projects/admin.py @@ -34,7 +34,7 @@ class MembershipInline(admin.TabularInline): class ProjectAdmin(admin.ModelAdmin): list_display = ["name", "owner", "created_date", "total_milestones", - "total_story_points", "domain"] + "total_story_points"] list_display_links = list_display inlines = [RoleInline, MembershipInline, MilestoneInline] diff --git a/taiga/projects/api.py b/taiga/projects/api.py index e9c39e49..2a607c61 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -28,7 +28,6 @@ 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.decorators import list_route, detail_route @@ -50,8 +49,7 @@ class ProjectAdminViewSet(ModelCrudViewSet): permission_classes = (IsAuthenticated, permissions.ProjectAdminPermission) def get_queryset(self): - domain = get_active_domain() - return domain.projects.all() + return models.Project.objects.all() def pre_save(self, obj): if not obj.id: @@ -61,13 +59,6 @@ class ProjectAdminViewSet(ModelCrudViewSet): if not obj.id: obj.template = self.request.QUERY_PARAMS.get('template', None) - # FIXME - - # Assign domain only if it current - # value is None - if not obj.domain: - obj.domain = self.request.domain - super().pre_save(obj) @@ -100,20 +91,13 @@ class ProjectViewSet(ModelCrudViewSet): def get_queryset(self): qs = super().get_queryset() qs = qs.filter(Q(owner=self.request.user) | - Q(members=self.request.user)).filter(domain=get_active_domain()) + Q(members=self.request.user)) return qs.distinct() def pre_save(self, obj): if not obj.id: obj.owner = self.request.user - # FIXME - - # Assign domain only if it current - # value is None - if not obj.domain: - obj.domain = self.request.domain - super().pre_save(obj) @@ -310,10 +294,8 @@ class ProjectTemplateViewSet(ModelCrudViewSet): template_slug = slugify_uniquely(template_name, models.ProjectTemplate) - domain = get_active_domain() - try: - project = models.Project.objects.get(domain=domain, pk=project_id) + project = models.Project.objects.get(pk=project_id) except models.Project.DoesNotExist: raise ParseError("Not valid project_id") @@ -321,12 +303,11 @@ class ProjectTemplateViewSet(ModelCrudViewSet): name=template_name, slug=template_slug, description=template_description, - domain=domain, ) + template.load_data_from_project(project) template.save() return Response(self.serializer_class(template).data, status=201) def get_queryset(self): - domain = get_active_domain() - return models.ProjectTemplate.objects.filter(Q(domain=domain) | Q(domain__isnull=True)) + return models.ProjectTemplate.objects.all() diff --git a/taiga/projects/fixtures/initial_project_templates.json b/taiga/projects/fixtures/initial_project_templates.json index e2c5caad..6c3a0758 100644 --- a/taiga/projects/fixtures/initial_project_templates.json +++ b/taiga/projects/fixtures/initial_project_templates.json @@ -23,8 +23,7 @@ "us_statuses": "[{\"order\": 1, \"name\": \"Open\", \"color\": \"#669933\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 2, \"name\": \"Closed\", \"color\": \"#999999\", \"is_closed\": true, \"wip_limit\": null}]", "videoconferences_salt": null, "priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#666666\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#669933\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]", - "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]", - "domain": null + "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]" } }, { @@ -51,8 +50,7 @@ "us_statuses": "[{\"order\": 1, \"name\": \"To do\", \"color\": \"#999999\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 2, \"name\": \"Doing\", \"color\": \"#ff9900\", \"is_closed\": false, \"wip_limit\": null}, {\"order\": 3, \"name\": \"Done\", \"color\": \"#ffcc00\", \"is_closed\": true, \"wip_limit\": null}]", "videoconferences_salt": null, "priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#666666\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#669933\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]", - "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]", - "domain": null + "severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]" } } ] diff --git a/taiga/projects/management/commands/sample_data.py b/taiga/projects/management/commands/sample_data.py index 70faa0aa..838905eb 100644 --- a/taiga/projects/management/commands/sample_data.py +++ b/taiga/projects/management/commands/sample_data.py @@ -281,7 +281,6 @@ class Command(BaseCommand): name='Project Example {0}'.format(counter), description='Project example {0} description'.format(counter), owner=random.choice(self.users), - domain_id=1, public=True, total_story_points=self.sd.int(600, 3000), total_milestones=self.sd.int(5,10)) diff --git a/taiga/projects/migrations/0023_auto__del_field_projecttemplate_domain__add_unique_projecttemplate_slu.py b/taiga/projects/migrations/0023_auto__del_field_projecttemplate_domain__add_unique_projecttemplate_slu.py new file mode 100644 index 00000000..20f1deb5 --- /dev/null +++ b/taiga/projects/migrations/0023_auto__del_field_projecttemplate_domain__add_unique_projecttemplate_slu.py @@ -0,0 +1,224 @@ +# -*- 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): + # Removing unique constraint on 'ProjectTemplate', fields ['slug', 'domain'] + db.delete_unique('projects_projecttemplate', ['slug', 'domain_id']) + + # Deleting field 'ProjectTemplate.domain' + db.delete_column('projects_projecttemplate', 'domain_id') + + # Adding unique constraint on 'ProjectTemplate', fields ['slug'] + db.create_unique('projects_projecttemplate', ['slug']) + + # Deleting field 'Project.domain' + db.delete_column('projects_project', 'domain_id') + + + def backwards(self, orm): + # Removing unique constraint on 'ProjectTemplate', fields ['slug'] + db.delete_unique('projects_projecttemplate', ['slug']) + + # Adding field 'ProjectTemplate.domain' + db.add_column('projects_projecttemplate', 'domain', + self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='templates', to=orm['domains.Domain'], blank=True, null=True), + keep_default=False) + + # Adding unique constraint on 'ProjectTemplate', fields ['slug', 'domain'] + db.create_unique('projects_projecttemplate', ['slug', 'domain_id']) + + # Adding field 'Project.domain' + db.add_column('projects_project', 'domain', + self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='projects', to=orm['domains.Domain'], blank=True, null=True), + keep_default=False) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True', 'symmetrical': 'False'}) + }, + 'auth.permission': { + 'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission', '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': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', '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'}) + }, + 'projects.issuestatus': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'IssueStatus', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'issue_statuses'"}) + }, + 'projects.issuetype': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'IssueType', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'issue_types'"}) + }, + 'projects.membership': { + 'Meta': {'unique_together': "(('user', 'project'),)", 'object_name': 'Membership', 'ordering': "['project', 'role']"}, + 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now_add': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'memberships'"}), + 'role': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.Role']", 'related_name': "'memberships'"}), + 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '60', 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'null': 'True', 'to': "orm['users.User']", 'related_name': "'memberships'", 'blank': 'True'}) + }, + 'projects.points': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Points', 'ordering': "['project', 'order', 'name']"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'points'"}), + 'value': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}) + }, + 'projects.priority': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Priority', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'priorities'"}) + }, + 'projects.project': { + 'Meta': {'object_name': 'Project', 'ordering': "['name']"}, + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'creation_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'null': 'True', 'to': "orm['projects.ProjectTemplate']", 'related_name': "'projects'", 'blank': 'True'}), + 'default_issue_status': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.IssueStatus']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_issue_type': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.IssueType']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_points': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.Points']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_priority': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.Priority']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_severity': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.Severity']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_task_status': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.TaskStatus']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'default_us_status': ('django.db.models.fields.related.OneToOneField', [], {'unique': 'True', 'related_name': "'+'", 'to': "orm['projects.UserStoryStatus']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['users.User']", 'related_name': "'projects'", 'through': "orm['projects.Membership']", 'symmetrical': 'False'}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '250', 'unique': 'True'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['users.User']", 'related_name': "'owned_projects'"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'unique': 'True', 'blank': 'True'}), + 'tags': ('picklefield.fields.PickledObjectField', [], {'blank': 'True'}), + 'total_milestones': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), + 'total_story_points': ('django.db.models.fields.FloatField', [], {'default': 'None', 'null': 'True'}), + 'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}), + 'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}) + }, + 'projects.projecttemplate': { + 'Meta': {'object_name': 'ProjectTemplate', 'ordering': "['name']"}, + 'created_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'default_options': ('django_pgjson.fields.JsonField', [], {}), + 'default_owner_role': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'description': ('django.db.models.fields.TextField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_backlog_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_issues_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_kanban_activated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_wiki_activated': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'issue_statuses': ('django_pgjson.fields.JsonField', [], {}), + 'issue_types': ('django_pgjson.fields.JsonField', [], {}), + 'modified_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}), + 'points': ('django_pgjson.fields.JsonField', [], {}), + 'priorities': ('django_pgjson.fields.JsonField', [], {}), + 'roles': ('django_pgjson.fields.JsonField', [], {}), + 'severities': ('django_pgjson.fields.JsonField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'unique': 'True', 'blank': 'True'}), + 'task_statuses': ('django_pgjson.fields.JsonField', [], {}), + 'us_statuses': ('django_pgjson.fields.JsonField', [], {}), + 'videoconferences': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}), + 'videoconferences_salt': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True', 'blank': 'True'}) + }, + 'projects.severity': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'Severity', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'severities'"}) + }, + 'projects.taskstatus': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'TaskStatus', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'task_statuses'"}) + }, + 'projects.userstorystatus': { + 'Meta': {'unique_together': "(('project', 'name'),)", 'object_name': 'UserStoryStatus', 'ordering': "['project', 'order', 'name']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#999999'", 'max_length': '20'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'us_statuses'"}), + 'wip_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}) + }, + 'users.role': { + 'Meta': {'unique_together': "(('slug', 'project'),)", 'object_name': 'Role', 'ordering': "['order', 'slug']"}, + 'computable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '10'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'related_name': "'roles'", 'symmetrical': 'False'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['projects.Project']", 'related_name': "'roles'"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '250', 'blank': 'True'}) + }, + 'users.user': { + 'Meta': {'object_name': 'User', 'ordering': "['username']"}, + 'color': ('django.db.models.fields.CharField', [], {'default': "'#9d3a9a'", 'max_length': '9', 'blank': 'True'}), + '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', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), + 'default_timezone': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), + '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', [], {'max_length': '30', 'blank': 'True'}), + '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', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), + 'token': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'related_name': "'user_set'", 'blank': 'True', 'symmetrical': 'False'}), + 'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'}) + } + } + + complete_apps = ['projects'] \ No newline at end of file diff --git a/taiga/projects/models.py b/taiga/projects/models.py index 01db17a1..2618a95f 100644 --- a/taiga/projects/models.py +++ b/taiga/projects/models.py @@ -31,8 +31,6 @@ from picklefield.fields import PickledObjectField from django_pgjson.fields import JsonField from taiga.users.models import Role -from taiga.domains.models import DomainMember -from taiga.domains import get_active_domain from taiga.projects.userstories.models import UserStory from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.dicts import dict_sum @@ -154,9 +152,6 @@ class Project(ProjectDefaults, models.Model): blank=True, default=None, verbose_name=_("creation template")) - domain = models.ForeignKey("domains.Domain", related_name="projects", null=True, blank=True, - default=None, verbose_name=_("domain")) - class Meta: verbose_name = "project" verbose_name_plural = "projects" @@ -441,15 +436,13 @@ class ProjectTemplate(models.Model): name = models.CharField(max_length=250, null=False, blank=False, verbose_name=_("name")) slug = models.SlugField(max_length=250, null=False, blank=True, - verbose_name=_("slug")) + verbose_name=_("slug"), unique=True) description = models.TextField(null=False, blank=False, verbose_name=_("description")) created_date = models.DateTimeField(auto_now_add=True, null=False, blank=False, verbose_name=_("created date")) modified_date = models.DateTimeField(auto_now=True, null=False, blank=False, verbose_name=_("modified date")) - domain = models.ForeignKey("domains.Domain", related_name="templates", null=True, blank=True, - default=None, verbose_name=_("domain")) default_owner_role = models.CharField(max_length=50, null=False, blank=False, verbose_name=_("default owner's role")) @@ -481,7 +474,6 @@ class ProjectTemplate(models.Model): class Meta: verbose_name = "project template" verbose_name_plural = "project templates" - unique_together = ["slug", "domain"] ordering = ["name"] def __str__(self): @@ -704,21 +696,6 @@ class ProjectTemplate(models.Model): return project -# On membership object is created/changed, update -# role-points relation. -@receiver(signals.post_save, sender=Membership, dispatch_uid='membership_post_save') -def membership_post_save(sender, instance, created, **kwargs): - instance.project.update_role_points() - exists_user_on_domain = instance.project.domain.members.filter(user=instance.user).exists() - - if instance.user and instance.project.domain and not exists_user_on_domain: - DomainMember.objects.create(domain=instance.project.domain, - user=instance.user, - email=instance.email, - is_owner=False, - is_staff=False) - - # On membership object is deleted, update role-points relation. @receiver(signals.pre_delete, sender=Membership, dispatch_uid='membership_pre_delete') def membership_post_delete(sender, instance, using, **kwargs): @@ -748,9 +725,7 @@ def project_post_save(sender, instance, created, **kwargs): return template_slug = getattr(instance, "template", settings.DEFAULT_PROJECT_TEMPLATE) - template = ProjectTemplate.objects.filter(slug=template_slug).get( - models.Q(domain__isnull=True) | models.Q(domain=get_active_domain()) - ) - + template = ProjectTemplate.objects.get(slug=template_slug) template.apply_to_project(instance) + instance.save() diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index d2714470..de20c845 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -15,7 +15,6 @@ from taiga.base.permissions import BasePermission -from taiga.domains import get_active_domain class ProjectPermission(BasePermission): @@ -27,28 +26,16 @@ class ProjectPermission(BasePermission): safe_methods = ["HEAD", "OPTIONS"] path_to_project = [] + class ProjectAdminPermission(BasePermission): def has_permission(self, request, view): if request.method in self.safe_methods: return True - - domain = get_active_domain() - if request.method in ["POST", "PUT", "GET", "PATCH"]: - return domain.user_is_staff(request.user) or domain.user_is_owner(request.user) - elif request.method == "DELETE": - return domain.user_is_owner(request.user) return super().has_permission(request, view) def has_object_permission(self, request, view, obj): if request.method in self.safe_methods: return True - - domain = get_active_domain() - if request.method in ["POST", "PUT", "GET", "PATCH"]: - return domain.user_is_staff(request.user) or domain.user_is_owner(request.user) - elif request.method == "DELETE": - return domain.user_is_owner(request.user) or ( - domain.user_is_staff(request.user) and obj.user == request.user) return super().has_object_permission(request, view, obj) @@ -151,16 +138,5 @@ class RolesPermission(BasePermission): # Project Templates class ProjectTemplatePermission(BasePermission): - def has_permission(self, request, view): - domain = get_active_domain() - return domain.user_is_owner(request.user) - - def has_object_permission(self, request, view, obj): - current_domain = get_active_domain() - if obj.domain: - return obj.domain == current_domain and current_domain.user_is_owner(request.user) - else: - if request.method == "GET": - return current_domain.user_is_owner(request.user) - else: - False + # TODO: should be improved in permissions refactor + pass diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index 6f3d592c..8ca57b96 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -18,7 +18,7 @@ from os import path from rest_framework import serializers from django.utils.translation import ugettext_lazy as _ -from taiga.base.serializers import PickleField, JsonField, AutoDomainField +from taiga.base.serializers import PickleField, JsonField from taiga.users.models import Role from . import models @@ -87,7 +87,7 @@ class ProjectSerializer(serializers.ModelSerializer): class Meta: model = models.Project - read_only_fields = ("created_date", "modified_date", "owner", "domain") + read_only_fields = ("created_date", "modified_date", "owner") exclude = ("last_us_ref", "last_task_ref", "last_issue_ref") @@ -138,8 +138,6 @@ class RoleSerializer(serializers.ModelSerializer): class ProjectTemplateSerializer(serializers.ModelSerializer): - domain = AutoDomainField(required=False, label=_("Domain")) - default_options = JsonField(required=False, label=_("Default options")) us_statuses = JsonField(required=False, label=_("User story's statuses")) points = JsonField(required=False, label=_("Points")) diff --git a/taiga/routers.py b/taiga/routers.py index dda1af13..436b07d6 100644 --- a/taiga/routers.py +++ b/taiga/routers.py @@ -42,13 +42,7 @@ router.register(r"resolver", ResolverViewSet, base_name="resolver") router.register(r"search", SearchViewSet, base_name="search") -# Domains -from taiga.domains.api import DomainViewSet -from taiga.domains.api import DomainMembersViewSet from taiga.projects.api import ProjectAdminViewSet - -router.register(r"sites", DomainViewSet, base_name="sites") -router.register(r"site-members", DomainMembersViewSet, base_name="site-members") router.register(r"site-projects", ProjectAdminViewSet, base_name="site-projects") diff --git a/taiga/users/api.py b/taiga/users/api.py index 685bc9cc..ee280d65 100644 --- a/taiga/users/api.py +++ b/taiga/users/api.py @@ -63,14 +63,12 @@ class PermissionsViewSet(ModelListViewSet): "add_permission", "change_permission", "delete_permission", "add_contenttype", "change_contenttype", "delete_contenttype", "add_message", "change_message", "delete_message", - "add_domain", "change_domain", "delete_domain", "add_session", "change_session", "delete_session", "add_migrationhistory", "change_migrationhistory", "delete_migrationhistory", "add_version", "change_version", "delete_version", "add_revision", "change_revision", "delete_revision", "add_user", "delete_user", "add_project", - "add_domainmember", "change_domainmember", "delete_domainmember", ] def get_queryset(self): diff --git a/taiga/users/fixtures/initial_user.json b/taiga/users/fixtures/initial_user.json index 7b077ce7..4381031f 100644 --- a/taiga/users/fixtures/initial_user.json +++ b/taiga/users/fixtures/initial_user.json @@ -23,26 +23,5 @@ "email": "niwi@niwi.be", "date_joined": "2013-04-01T13:48:21.711Z" } - }, - { - "model": "domains.domain", - "pk": 1, - "fields": { - "domain": "localhost", - "name": "localhost", - "scheme": "http", - "public_register": false - } - }, - { - "model": "domains.domainmember", - "pk": 1, - "fields": { - "is_staff": true, - "is_owner": true, - "user": 1, - "domain": 1, - "email": "niwi@niwi.be" - } } ] diff --git a/tests/factories.py b/tests/factories.py index 73455e7a..29472888 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -3,7 +3,6 @@ import uuid import factory from django.conf import settings -import taiga.domains.models import taiga.projects.models import taiga.projects.userstories.models import taiga.projects.issues.models @@ -12,18 +11,9 @@ import taiga.users.models import taiga.userstorage.models -class DomainFactory(factory.DjangoModelFactory): - FACTORY_FOR = taiga.domains.models.Domain - FACTORY_DJANGO_GET_OR_CREATE = ("domain",) - - name = "Default domain" - domain = "default" - scheme = None - public_register = False - - class ProjectTemplateFactory(factory.DjangoModelFactory): FACTORY_FOR = taiga.projects.models.ProjectTemplate + FACTORY_DJANGO_GET_OR_CREATE = ("slug", ) name = "Template name" slug = settings.DEFAULT_PROJECT_TEMPLATE @@ -45,7 +35,6 @@ class ProjectFactory(factory.DjangoModelFactory): slug = factory.Sequence(lambda n: "project-{}-slug".format(n)) description = "Project description" owner = factory.SubFactory("tests.factories.UserFactory") - domain = factory.SubFactory("tests.factories.DomainFactory") creation_template = factory.SubFactory("tests.factories.ProjectTemplateFactory") @@ -67,7 +56,7 @@ class UserFactory(factory.DjangoModelFactory): class MembershipFactory(factory.DjangoModelFactory): FACTORY_FOR = taiga.projects.models.Membership - token = factory.LazyAttribute(lambda obj: uuid.uuid1()) + token = factory.LazyAttribute(lambda obj: str(uuid.uuid1())) project = factory.SubFactory("tests.factories.ProjectFactory") role = factory.SubFactory("tests.factories.RoleFactory") user = factory.SubFactory("tests.factories.UserFactory") diff --git a/tests/integration/test_project_references_sequences.py b/tests/integration/test_project_references_sequences.py index 17b6b472..0570ca6d 100644 --- a/tests/integration/test_project_references_sequences.py +++ b/tests/integration/test_project_references_sequences.py @@ -11,11 +11,13 @@ def seq(): from taiga.projects.references import sequences as seq return seq + @pytest.fixture def refmodels(): from taiga.projects.references import models return models + @pytest.mark.django_db def test_sequences(seq): seqname = "foo" @@ -47,14 +49,10 @@ def test_sequences(seq): @pytest.mark.django_db def test_unique_reference_per_project(seq, refmodels): - # management.call_command("loaddata", "initial_project_templates") - domain = factories.DomainFactory(public_register=True) - settings.DOMAIN_ID = domain.id - project = factories.ProjectFactory.create() seqname = refmodels.make_sequence_name(project) - assert seqname == "references_project1" + assert seqname == "references_project{0}".format(project.id) assert seq.exists(seqname) assert refmodels.make_unique_reference_id(project, create=True) == 1