__init__.py 2.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
"""
Creates Levels for all installed apps that have levels.
"""
from django.db.models import signals
from django.apps import apps
from django.db import DEFAULT_DB_ALIAS
from django.core.exceptions import ImproperlyConfigured

from ..models import Level, AclBase

Szeberényi Imre committed
11 12 13 14 15
try:
    # Python 2: "unicode" is built-in
    unicode
except NameError:
    unicode = str
16 17 18 19 20 21 22 23 24 25 26 27 28

def create_levels(app_config, verbosity=False, using=DEFAULT_DB_ALIAS,
                  **kwargs):
    """Create and set the weights of the configured Levels.

    Based on django.contrib.auth.management.__init__.create_permissions"""
    # if not router.allow_migrate(using, auth_app.Permission):
    #    return

    from django.contrib.contenttypes.models import ContentType

    app_models = [k for k in apps.get_models(app_config)
                  if AclBase in k.__bases__]
Kohl Krisztofer committed
29 30
    print(("Creating levels for models: %s." % ", ".join(
        [m.__name__ for m in app_models])))
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

    # This will hold the levels we're looking for as
    # (content_type, (codename, name))
    searched_levels = list()
    level_weights = list()
    # The codenames and ctypes that should exist.
    ctypes = set()
    for klass in app_models:
        # Force looking up the content types in the current database
        # before creating foreign keys to them.
        ctype1 = ContentType.objects.db_manager(using).get_for_model(klass)
        ctypes.add(ctype1)
        weight = 0
        try:
            for codename, name in klass.ACL_LEVELS:
                searched_levels.append((ctype1, (codename, name)))
                level_weights.append((ctype1, codename, weight))
                weight += 1
        except AttributeError:
            raise ImproperlyConfigured(
                "Class %s doesn't have ACL_LEVELS attribute." % klass)

    # Find all the Levels that have a content_type for a model we're
    # looking for.  We don't need to check for codenames since we already have
    # a list of the ones we're going to create.
    all_levels = set(Level.objects.using(using).filter(
        content_type__in=ctypes,
    ).values_list(
        "content_type", "codename"
    ))

    levels = [
        Level(codename=codename, name=name, content_type=ctype)
        for ctype, (codename, name) in searched_levels
        if (ctype.pk, codename) not in all_levels
    ]
    Level.objects.using(using).bulk_create(levels)
    if verbosity >= 2:
Szeberényi Imre committed
69
        print(("Adding levels [%s]." % ", ".join(unicode(l) for l in levels)))
Kohl Krisztofer committed
70
        print(("Searched: [%s]." % ", ".join(
Szeberényi Imre committed
71 72
            unicode(l) for l in searched_levels)))
        print(("All: [%s]." % ", ".join(unicode(l) for l in all_levels)))
73 74 75 76 77 78 79 80 81

    # set weights
    for ctype, codename, weight in level_weights:
        Level.objects.filter(codename=codename,
                             content_type=ctype).update(weight=weight)


signals.post_migrate.connect(
    create_levels, dispatch_uid="circle.acl.management.create_levels")