Projet

Général

Profil

0001-a2_rbac-move-signal-handlers-from-django_rbac-69902.patch

Valentin Deniaud, 19 octobre 2022 14:58

Télécharger (21,7 ko)

Voir les différences:

Subject: [PATCH 1/2] a2_rbac: move signal handlers from django_rbac (#69902)

 src/authentic2/a2_rbac/apps.py                | 21 ++++++++-
 src/authentic2/a2_rbac/managers.py            |  8 +++-
 .../migrations/0024_fix_self_admin_perm.py    |  3 +-
 src/authentic2/a2_rbac/models.py              |  8 +++-
 src/authentic2/a2_rbac/signal_handlers.py     | 45 ++++++++++++++++++-
 .../a2_rbac}/signals.py                       |  0
 src/authentic2/a2_rbac/utils.py               |  7 ++-
 .../management/commands/check-and-repair.py   |  2 +-
 src/django_rbac/apps.py                       | 24 ----------
 src/django_rbac/managers.py                   |  6 +--
 src/django_rbac/models.py                     |  9 ----
 src/django_rbac/signal_handlers.py            | 44 ------------------
 tests/api/test_all.py                         |  2 +-
 tests/test_a2_rbac.py                         |  4 +-
 tests/test_api_client.py                      |  3 +-
 tests/test_commands.py                        | 11 ++++-
 tests/test_manager.py                         |  3 +-
 tests/test_user_manager.py                    |  2 +-
 18 files changed, 100 insertions(+), 102 deletions(-)
 rename src/{django_rbac => authentic2/a2_rbac}/signals.py (100%)
 delete mode 100644 src/django_rbac/signal_handlers.py
src/authentic2/a2_rbac/apps.py
25 25
        from django.db.models.signals import post_delete, post_migrate, post_save
26 26

  
27 27
        from authentic2.models import Service
28
        from django_rbac import utils
28 29

  
29
        from . import models, signal_handlers
30
        from . import models, signal_handlers, signals
30 31

  
32
        # update role parenting when new role parenting is created
33
        post_save.connect(signal_handlers.role_parenting_post_save, sender=utils.get_role_parenting_model())
34
        # update role parenting when role parenting is deleted
35
        post_delete.connect(
36
            signal_handlers.role_parenting_post_delete, sender=utils.get_role_parenting_model()
37
        )
38
        # or soft-created
39
        signals.post_soft_create.connect(
40
            signal_handlers.role_parenting_post_soft_delete, sender=utils.get_role_parenting_model()
41
        )
42
        # or soft-deleted
43
        signals.post_soft_delete.connect(
44
            signal_handlers.role_parenting_post_soft_delete, sender=utils.get_role_parenting_model()
45
        )
46
        # create CRUD operations and admin
47
        post_migrate.connect(signal_handlers.create_base_operations, sender=self)
48
        # update role parenting in post migrate
49
        post_migrate.connect(signal_handlers.fix_role_parenting_closure, sender=self)
31 50
        # update rbac on save to contenttype, ou and roles
32 51
        post_save.connect(signal_handlers.update_rbac_on_ou_post_save, sender=models.OrganizationalUnit)
33 52
        post_delete.connect(signal_handlers.update_rbac_on_ou_post_delete, sender=models.OrganizationalUnit)
src/authentic2/a2_rbac/managers.py
19 19
from authentic2.a2_rbac import models
20 20
from django_rbac.managers import AbstractBaseManager
21 21
from django_rbac.managers import RoleManager as BaseRoleManager
22
from django_rbac.models import ADMIN_OP
23 22
from django_rbac.utils import get_operation
24 23

  
25 24

  
......
35 34
        name,
36 35
        slug,
37 36
        ou=None,
38
        operation=ADMIN_OP,
37
        operation=None,
39 38
        update_name=False,
40 39
        update_slug=False,
41 40
        permissions=(),
......
43 42
        create=True,
44 43
    ):
45 44
        '''Get or create the role of manager's of this object instance'''
45
        from .models import ADMIN_OP
46

  
47
        if operation is None:
48
            operation = ADMIN_OP
49

  
46 50
        kwargs = {}
47 51
        assert not ou or isinstance(
48 52
            instance, ContentType
src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
2 2

  
3 3
from django.db import migrations
4 4

  
5
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
6
from django_rbac.models import CHANGE_OP
5
from authentic2.a2_rbac.models import CHANGE_OP, MANAGE_MEMBERS_OP
7 6

  
8 7

  
9 8
def update_self_administration_perm(apps, schema_editor):
src/authentic2/a2_rbac/models.py
39 39
from authentic2.validators import HexaColourValidator
40 40
from django_rbac import managers as rbac_managers
41 41
from django_rbac import utils as rbac_utils
42
from django_rbac.models import VIEW_OP, Operation
42
from django_rbac.models import Operation
43 43

  
44 44
from . import app_settings, fields, managers
45 45

  
......
759 759
)
760 760

  
761 761

  
762
ADMIN_OP = Operation.register(name=pgettext_lazy('permission', 'Management'), slug='admin')
763
CHANGE_OP = Operation.register(name=pgettext_lazy('permission', 'Change'), slug='change')
764
DELETE_OP = Operation.register(name=pgettext_lazy('permission', 'Delete'), slug='delete')
765
ADD_OP = Operation.register(name=pgettext_lazy('permission', 'Add'), slug='add')
766
VIEW_OP = Operation.register(name=pgettext_lazy('permission', 'View'), slug='view')
767
SEARCH_OP = Operation.register(name=pgettext_lazy('permission', 'Search'), slug='search')
762 768
CHANGE_PASSWORD_OP = Operation.register(name=_('Change password'), slug='change_password')
763 769
RESET_PASSWORD_OP = Operation.register(name=_('Password reset'), slug='reset_password')
764 770
ACTIVATE_OP = Operation.register(name=_('Activation'), slug='activate')
src/authentic2/a2_rbac/signal_handlers.py
23 23
from authentic2.a2_rbac.models import OrganizationalUnit, Role
24 24
from authentic2.utils.misc import get_fk_model
25 25
from django_rbac.managers import defer_update_transitive_closure
26
from django_rbac.utils import get_operation
26
from django_rbac.utils import get_operation, get_role_parenting_model
27 27

  
28 28

  
29 29
def create_default_ou(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
......
103 103
        get_operation(CHANGE_EMAIL_OP)
104 104
        get_operation(MANAGE_MEMBERS_OP)
105 105
        get_operation(MANAGE_AUTHORIZATIONS_OP)
106

  
107

  
108
def role_parenting_post_save(sender, instance, raw, created, **kwargs):
109
    '''Close the role parenting relation after instance creation'''
110
    if raw:  # do nothing if save comes from fixture loading
111
        return
112
    if not instance.direct:  # do nothing if instance is not direct
113
        return
114
    sender.objects.update_transitive_closure()
115

  
116

  
117
def role_parenting_post_delete(sender, instance, **kwargs):
118
    '''Close the role parenting relation after instance deletion'''
119
    if not instance.direct:  # do nothing if instance is not direct
120
        return
121
    sender.objects.update_transitive_closure()
122

  
123

  
124
def role_parenting_post_soft_delete(sender, instance, **kwargs):
125
    '''Close the role parenting relation after instance soft-deletion'''
126
    sender.objects.update_transitive_closure()
127

  
128

  
129
def create_base_operations(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
130
    '''Create some basic operations, matching permissions from Django'''
131
    from . import models
132

  
133
    if not router.allow_migrate(using, models.Operation):
134
        return
135

  
136
    get_operation(models.ADD_OP)
137
    get_operation(models.CHANGE_OP)
138
    get_operation(models.DELETE_OP)
139
    get_operation(models.VIEW_OP)
140
    get_operation(models.ADMIN_OP)
141
    get_operation(models.SEARCH_OP)
142

  
143

  
144
def fix_role_parenting_closure(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
145
    '''Close the role parenting relation after migrations'''
146
    if not router.allow_migrate(using, get_role_parenting_model()):
147
        return
148
    get_role_parenting_model().objects.update_transitive_closure()
src/authentic2/a2_rbac/utils.py
19 19
from django.utils.text import slugify
20 20

  
21 21
from django_rbac import utils as rbac_utils
22
from django_rbac.models import SEARCH_OP, VIEW_OP
23 22

  
24 23
from . import models
25 24

  
......
38 37
def get_view_user_perm(ou=None):
39 38
    User = get_user_model()
40 39
    view_user_perm, dummy = models.Permission.objects.get_or_create(
41
        operation=rbac_utils.get_operation(VIEW_OP),
40
        operation=rbac_utils.get_operation(models.VIEW_OP),
42 41
        target_ct=ContentType.objects.get_for_model(ContentType),
43 42
        target_id=ContentType.objects.get_for_model(User).pk,
44 43
        ou__isnull=ou is None,
......
50 49
def get_search_ou_perm(ou=None):
51 50
    if ou:
52 51
        view_ou_perm, dummy = models.Permission.objects.get_or_create(
53
            operation=rbac_utils.get_operation(SEARCH_OP),
52
            operation=rbac_utils.get_operation(models.SEARCH_OP),
54 53
            target_ct=ContentType.objects.get_for_model(ou),
55 54
            target_id=ou.pk,
56 55
            ou__isnull=True,
57 56
        )
58 57
    else:
59 58
        view_ou_perm, dummy = models.Permission.objects.get_or_create(
60
            operation=rbac_utils.get_operation(SEARCH_OP),
59
            operation=rbac_utils.get_operation(models.SEARCH_OP),
61 60
            target_ct=ContentType.objects.get_for_model(ContentType),
62 61
            target_id=ContentType.objects.get_for_model(models.OrganizationalUnit).pk,
63 62
            ou__isnull=True,
src/authentic2/management/commands/check-and-repair.py
29 29
from django.utils.timezone import localtime
30 30

  
31 31
from authentic2 import app_settings
32
from authentic2.a2_rbac.models import ADMIN_OP
32 33
from authentic2.a2_rbac.models import OrganizationalUnit as OU
33 34
from authentic2.a2_rbac.models import Permission, Role
34 35
from authentic2.custom_user.models import User
35
from django_rbac.models import ADMIN_OP
36 36
from django_rbac.utils import get_operation
37 37

  
38 38
try:
src/django_rbac/apps.py
4 4
class DjangoRBACConfig(AppConfig):
5 5
    name = 'django_rbac'
6 6
    verbose_name = 'RBAC engine for Django'
7

  
8
    def ready(self):
9
        from django.db.models.signals import post_delete, post_migrate, post_save
10

  
11
        from . import signal_handlers, signals, utils
12

  
13
        # update role parenting when new role parenting is created
14
        post_save.connect(signal_handlers.role_parenting_post_save, sender=utils.get_role_parenting_model())
15
        # update role parenting when role parenting is deleted
16
        post_delete.connect(
17
            signal_handlers.role_parenting_post_delete, sender=utils.get_role_parenting_model()
18
        )
19
        # or soft-created
20
        signals.post_soft_create.connect(
21
            signal_handlers.role_parenting_post_soft_delete, sender=utils.get_role_parenting_model()
22
        )
23
        # or soft-deleted
24
        signals.post_soft_delete.connect(
25
            signal_handlers.role_parenting_post_soft_delete, sender=utils.get_role_parenting_model()
26
        )
27
        # create CRUD operations and admin
28
        post_migrate.connect(signal_handlers.create_base_operations, sender=self)
29
        # update role parenting in post migrate
30
        post_migrate.connect(signal_handlers.fix_role_parenting_closure, sender=self)
src/django_rbac/managers.py
9 9
from django.db.models.query import Prefetch, Q
10 10
from django.db.transaction import atomic
11 11

  
12
from . import signals, utils
12
from authentic2.a2_rbac import signals
13

  
14
from . import utils
13 15

  
14 16

  
15 17
class AbstractBaseManager(models.Manager):
......
210 212
                signals.post_soft_create.send(sender=self.model, instance=rp)
211 213

  
212 214
    def soft_delete(self, parent, child):
213
        from . import signals
214

  
215 215
        qs = self.filter(parent=parent, child=child, deleted__isnull=True, direct=True)
216 216
        with atomic(savepoint=False):
217 217
            rp = qs.first()
src/django_rbac/models.py
1 1
from django.db import models
2 2
from django.utils.translation import gettext_lazy as _
3
from django.utils.translation import pgettext_lazy
4 3

  
5 4
from . import managers
6 5

  
......
32 31

  
33 32

  
34 33
Operation._meta.natural_key = ['slug']
35

  
36

  
37
ADMIN_OP = Operation.register(name=pgettext_lazy('permission', 'Management'), slug='admin')
38
CHANGE_OP = Operation.register(name=pgettext_lazy('permission', 'Change'), slug='change')
39
DELETE_OP = Operation.register(name=pgettext_lazy('permission', 'Delete'), slug='delete')
40
ADD_OP = Operation.register(name=pgettext_lazy('permission', 'Add'), slug='add')
41
VIEW_OP = Operation.register(name=pgettext_lazy('permission', 'View'), slug='view')
42
SEARCH_OP = Operation.register(name=pgettext_lazy('permission', 'Search'), slug='search')
src/django_rbac/signal_handlers.py
1
from django.db import DEFAULT_DB_ALIAS, router
2

  
3
from . import models, utils
4

  
5

  
6
def role_parenting_post_save(sender, instance, raw, created, **kwargs):
7
    '''Close the role parenting relation after instance creation'''
8
    if raw:  # do nothing if save comes from fixture loading
9
        return
10
    if not instance.direct:  # do nothing if instance is not direct
11
        return
12
    sender.objects.update_transitive_closure()
13

  
14

  
15
def role_parenting_post_delete(sender, instance, **kwargs):
16
    '''Close the role parenting relation after instance deletion'''
17
    if not instance.direct:  # do nothing if instance is not direct
18
        return
19
    sender.objects.update_transitive_closure()
20

  
21

  
22
def role_parenting_post_soft_delete(sender, instance, **kwargs):
23
    '''Close the role parenting relation after instance soft-deletion'''
24
    sender.objects.update_transitive_closure()
25

  
26

  
27
def create_base_operations(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
28
    '''Create some basic operations, matching permissions from Django'''
29
    if not router.allow_migrate(using, models.Operation):
30
        return
31

  
32
    utils.get_operation(models.ADD_OP)
33
    utils.get_operation(models.CHANGE_OP)
34
    utils.get_operation(models.DELETE_OP)
35
    utils.get_operation(models.VIEW_OP)
36
    utils.get_operation(models.ADMIN_OP)
37
    utils.get_operation(models.SEARCH_OP)
38

  
39

  
40
def fix_role_parenting_closure(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
41
    '''Close the role parenting relation after migrations'''
42
    if not router.allow_migrate(using, utils.get_role_parenting_model()):
43
        return
44
    utils.get_role_parenting_model().objects.update_transitive_closure()
tests/api/test_all.py
32 32
from django.utils.text import slugify
33 33
from requests.models import Response
34 34

  
35
from authentic2.a2_rbac.models import SEARCH_OP
35 36
from authentic2.a2_rbac.models import OrganizationalUnit as OU
36 37
from authentic2.a2_rbac.models import Role
37 38
from authentic2.a2_rbac.utils import get_default_ou
......
40 41
from authentic2.models import APIClient, Attribute, AttributeValue, AuthorizedRole, PasswordReset, Service
41 42
from authentic2.utils.misc import good_next_url
42 43
from authentic2_idp_cas.models import Service as CASService
43
from django_rbac.models import SEARCH_OP
44 44

  
45 45
from ..utils import assert_event, basic_authorization_header, get_link_from_mail, login
46 46

  
tests/test_a2_rbac.py
19 19
from django.core.exceptions import ValidationError
20 20
from django.core.management import call_command
21 21

  
22
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
22
from authentic2.a2_rbac.models import CHANGE_OP, MANAGE_MEMBERS_OP
23 23
from authentic2.a2_rbac.models import OrganizationalUnit as OU
24 24
from authentic2.a2_rbac.models import Permission, Role, RoleAttribute
25 25
from authentic2.a2_rbac.utils import get_default_ou
26 26
from authentic2.custom_user.models import User
27 27
from authentic2.models import Service
28 28
from authentic2.utils.misc import get_hex_uuid
29
from django_rbac.models import CHANGE_OP, Operation
29
from django_rbac.models import Operation
30 30
from tests.utils import login, request_select2, scoped_db_fixture
31 31

  
32 32

  
tests/test_api_client.py
6 6
from django.contrib.contenttypes.models import ContentType
7 7
from django.urls import reverse
8 8

  
9
from authentic2.a2_rbac.models import Role
9
from authentic2.a2_rbac.models import ADD_OP, SEARCH_OP, VIEW_OP, Role
10 10
from authentic2.models import APIClient
11
from django_rbac.models import ADD_OP, SEARCH_OP, VIEW_OP
12 11

  
13 12
User = get_user_model()
14 13

  
tests/test_commands.py
27 27
from django.utils.timezone import now
28 28
from jwcrypto.jwk import JWK, JWKSet
29 29

  
30
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP, VIEW_OP, OrganizationalUnit, Permission, Role
30
from authentic2.a2_rbac.models import (
31
    ADMIN_OP,
32
    MANAGE_MEMBERS_OP,
33
    VIEW_OP,
34
    OrganizationalUnit,
35
    Permission,
36
    Role,
37
)
31 38
from authentic2.a2_rbac.utils import get_default_ou
32 39
from authentic2.apps.journal.models import Event
33 40
from authentic2.custom_user.models import DeletedUser
34 41
from authentic2.models import UserExternalId
35 42
from authentic2_auth_oidc.models import OIDCAccount, OIDCProvider
36
from django_rbac.models import ADMIN_OP, Operation
43
from django_rbac.models import Operation
37 44
from django_rbac.utils import get_operation
38 45

  
39 46
from .utils import call_command, login
tests/test_manager.py
28 28
from django.utils.encoding import force_bytes, force_str
29 29
from webtest import Upload
30 30

  
31
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
31
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP, VIEW_OP
32 32
from authentic2.a2_rbac.models import OrganizationalUnit as OU
33 33
from authentic2.a2_rbac.models import Permission, Role
34 34
from authentic2.a2_rbac.utils import get_default_ou
35 35
from authentic2.apps.journal.models import Event
36 36
from authentic2.models import Service
37 37
from authentic2.validators import EmailValidator
38
from django_rbac.models import VIEW_OP
39 38
from django_rbac.utils import get_operation
40 39

  
41 40
from .utils import assert_event, get_link_from_mail, login, request_select2, text_content
tests/test_user_manager.py
27 27
from django.urls import reverse
28 28
from webtest import Upload
29 29

  
30
from authentic2.a2_rbac.models import VIEW_OP
30 31
from authentic2.a2_rbac.models import OrganizationalUnit as OU
31 32
from authentic2.a2_rbac.models import Permission, Role
32 33
from authentic2.a2_rbac.utils import get_default_ou, get_view_user_perm
......
35 36
from authentic2.manager import user_import
36 37
from authentic2.models import Attribute, AttributeValue
37 38
from authentic2_idp_oidc.models import OIDCAuthorization, OIDCClient
38
from django_rbac.models import VIEW_OP
39 39
from django_rbac.utils import get_operation
40 40

  
41 41
from .utils import get_link_from_mail, login, logout
42
-