accrete 0.0.123__py3-none-any.whl → 0.0.125__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- accrete/admin.py +4 -3
- accrete/config.py +5 -0
- accrete/contrib/country/migrations/0003_alter_country_options.py +17 -0
- accrete/contrib/country/models.py +1 -2
- accrete/migrations/0004_rename_accessgroupmember_memberaccessgrouprel_and_more.py +42 -0
- accrete/models.py +10 -19
- accrete/tenant.py +13 -0
- accrete/views.py +60 -1
- {accrete-0.0.123.dist-info → accrete-0.0.125.dist-info}/METADATA +1 -1
- {accrete-0.0.123.dist-info → accrete-0.0.125.dist-info}/RECORD +12 -10
- {accrete-0.0.123.dist-info → accrete-0.0.125.dist-info}/WHEEL +0 -0
- {accrete-0.0.123.dist-info → accrete-0.0.125.dist-info}/licenses/LICENSE +0 -0
accrete/admin.py
CHANGED
@@ -9,12 +9,12 @@ class MemberInLine(admin.TabularInline):
|
|
9
9
|
|
10
10
|
class TenantAccessGroupInLine(admin.TabularInline):
|
11
11
|
|
12
|
-
model = models.
|
12
|
+
model = models.TenantAccessGroupRel
|
13
13
|
|
14
14
|
|
15
15
|
class AccessGroupMemberInLine(admin.TabularInline):
|
16
16
|
|
17
|
-
model = models.
|
17
|
+
model = models.MemberAccessGroupRel
|
18
18
|
|
19
19
|
|
20
20
|
class TenantAdmin(admin.ModelAdmin):
|
@@ -46,4 +46,5 @@ class AccessGroupAdmin(admin.ModelAdmin):
|
|
46
46
|
admin.site.register(models.Tenant, TenantAdmin)
|
47
47
|
admin.site.register(models.Member, MemberAdmin)
|
48
48
|
admin.site.register(models.AccessGroup, AccessGroupAdmin)
|
49
|
-
admin.site.register(models.
|
49
|
+
admin.site.register(models.MemberAccessGroupRel)
|
50
|
+
admin.site.register(models.TenantAccessGroupRel)
|
accrete/config.py
CHANGED
@@ -8,6 +8,11 @@ ACCRETE_TENANT_NOT_SET_URL = getattr(
|
|
8
8
|
False
|
9
9
|
)
|
10
10
|
|
11
|
+
ACCRETE_GROUP_NOT_SET_URL = getattr(
|
12
|
+
settings, 'ACCRETE_GROUP_NOT_SET_URL',
|
13
|
+
False
|
14
|
+
)
|
15
|
+
|
11
16
|
if not ACCRETE_TENANT_NOT_SET_URL:
|
12
17
|
_logger.warning(
|
13
18
|
'Setting ACCRETE_TENANT_NOT_SET_URL missing.'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2025-02-19 18:25
|
2
|
+
|
3
|
+
from django.db import migrations
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('country', '0002_auto_20250219_1759'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterModelOptions(
|
14
|
+
name='country',
|
15
|
+
options={'ordering': ['-order_priority', 'name'], 'verbose_name': 'Country', 'verbose_name_plural': 'Countries'},
|
16
|
+
),
|
17
|
+
]
|
@@ -1,5 +1,4 @@
|
|
1
1
|
from django.db import models
|
2
|
-
from django.db.models.functions import Lower
|
3
2
|
from django.utils.translation import gettext_lazy as _
|
4
3
|
from accrete.fields import TranslatedCharField
|
5
4
|
|
@@ -10,7 +9,7 @@ class Country(models.Model):
|
|
10
9
|
verbose_name = _('Country')
|
11
10
|
verbose_name_plural = _('Countries')
|
12
11
|
db_table = 'accrete_country'
|
13
|
-
ordering = ['-order_priority',
|
12
|
+
ordering = ['-order_priority', 'name']
|
14
13
|
|
15
14
|
name = TranslatedCharField(
|
16
15
|
verbose_name=_('Name')
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2025-02-24 17:54
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('accrete', '0003_remove_member_name'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.RenameModel(
|
14
|
+
old_name='AccessGroupMember',
|
15
|
+
new_name='MemberAccessGroupRel',
|
16
|
+
),
|
17
|
+
migrations.RenameModel(
|
18
|
+
old_name='TenantAccessGroup',
|
19
|
+
new_name='TenantAccessGroupRel',
|
20
|
+
),
|
21
|
+
migrations.AlterModelOptions(
|
22
|
+
name='memberaccessgrouprel',
|
23
|
+
options={'ordering': ['member'], 'verbose_name': 'Member Access Group Relation', 'verbose_name_plural': 'Member Access Group Relations'},
|
24
|
+
),
|
25
|
+
migrations.AlterModelOptions(
|
26
|
+
name='tenantaccessgrouprel',
|
27
|
+
options={'ordering': ['tenant'], 'verbose_name': 'Tenant Access Group Relation', 'verbose_name_plural': 'Tenant Access Groups Relations'},
|
28
|
+
),
|
29
|
+
migrations.RemoveField(
|
30
|
+
model_name='accessgroup',
|
31
|
+
name='is_public',
|
32
|
+
),
|
33
|
+
migrations.AlterField(
|
34
|
+
model_name='accessgroup',
|
35
|
+
name='code',
|
36
|
+
field=models.CharField(max_length=100, verbose_name='Code'),
|
37
|
+
),
|
38
|
+
migrations.AlterModelTable(
|
39
|
+
name='memberaccessgrouprel',
|
40
|
+
table='accrete_member_access_group_rel',
|
41
|
+
),
|
42
|
+
]
|
accrete/models.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
from django.db import models
|
2
2
|
from django.conf import settings
|
3
3
|
from django.utils.translation import gettext_lazy as _
|
4
|
-
from django.contrib.auth.validators import UnicodeUsernameValidator
|
5
4
|
from accrete.tenant import get_tenant
|
6
5
|
from accrete.managers import TenantManager, MemberManager
|
7
6
|
|
@@ -70,7 +69,7 @@ class Tenant(models.Model):
|
|
70
69
|
|
71
70
|
access_groups = models.ManyToManyField(
|
72
71
|
to='accrete.AccessGroup',
|
73
|
-
through='accrete.
|
72
|
+
through='accrete.TenantAccessGroupRel',
|
74
73
|
through_fields=('tenant', 'access_group')
|
75
74
|
)
|
76
75
|
|
@@ -105,7 +104,7 @@ class Member(models.Model):
|
|
105
104
|
|
106
105
|
access_groups = models.ManyToManyField(
|
107
106
|
to='accrete.AccessGroup',
|
108
|
-
through='accrete.
|
107
|
+
through='accrete.MemberAccessGroupRel',
|
109
108
|
through_fields=('member', 'access_group')
|
110
109
|
)
|
111
110
|
|
@@ -136,28 +135,20 @@ class AccessGroup(models.Model):
|
|
136
135
|
|
137
136
|
code = models.CharField(
|
138
137
|
verbose_name=_('Code'),
|
139
|
-
max_length=
|
140
|
-
)
|
141
|
-
|
142
|
-
is_public = models.BooleanField(
|
143
|
-
verbose_name=_('Is Public'),
|
144
|
-
default=True,
|
145
|
-
help_text=_(
|
146
|
-
'If set, members from all tenants can be assigned to this group.'
|
147
|
-
)
|
138
|
+
max_length=100
|
148
139
|
)
|
149
140
|
|
150
141
|
def __str__(self):
|
151
142
|
return self.name
|
152
143
|
|
153
144
|
|
154
|
-
class
|
145
|
+
class MemberAccessGroupRel(models.Model):
|
155
146
|
|
156
147
|
class Meta:
|
157
|
-
verbose_name = _('Access Group
|
158
|
-
verbose_name_plural = _('Access Group
|
148
|
+
verbose_name = _('Member Access Group Relation')
|
149
|
+
verbose_name_plural = _('Member Access Group Relations')
|
159
150
|
ordering = ['member']
|
160
|
-
db_table = '
|
151
|
+
db_table = 'accrete_member_access_group_rel'
|
161
152
|
constraints = [
|
162
153
|
models.UniqueConstraint(
|
163
154
|
name='unique_member_per_group',
|
@@ -179,11 +170,11 @@ class AccessGroupMember(models.Model):
|
|
179
170
|
return f'{self.member} - {self.access_group}'
|
180
171
|
|
181
172
|
|
182
|
-
class
|
173
|
+
class TenantAccessGroupRel(models.Model):
|
183
174
|
|
184
175
|
class Meta:
|
185
|
-
verbose_name = _('Tenant Access Group')
|
186
|
-
verbose_name_plural = _('Tenant Access Groups')
|
176
|
+
verbose_name = _('Tenant Access Group Relation')
|
177
|
+
verbose_name_plural = _('Tenant Access Groups Relations')
|
187
178
|
ordering = ['tenant']
|
188
179
|
db_table = 'accrete_tenant_access_group_rel'
|
189
180
|
constraints = [
|
accrete/tenant.py
CHANGED
@@ -73,3 +73,16 @@ def per_tenant(include: Q = None, exclude: Q = None):
|
|
73
73
|
return wrapper
|
74
74
|
return decorator
|
75
75
|
|
76
|
+
|
77
|
+
def tenant_has_group(access_group_code: str) -> bool:
|
78
|
+
tenant = get_tenant()
|
79
|
+
if not tenant:
|
80
|
+
return False
|
81
|
+
return tenant.access_groups.filter(code__in=[access_group_code]).exists()
|
82
|
+
|
83
|
+
|
84
|
+
def member_has_group(access_group_code: str) -> bool:
|
85
|
+
member = get_member()
|
86
|
+
if not member:
|
87
|
+
return False
|
88
|
+
return member.access_groups.filter(code__in=[access_group_code]).exists()
|
accrete/views.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
from enum import Enum
|
2
3
|
from functools import wraps
|
3
4
|
from django.http import HttpResponse, HttpResponseNotFound
|
4
5
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
@@ -7,24 +8,43 @@ from django.core.exceptions import ImproperlyConfigured
|
|
7
8
|
from django.shortcuts import redirect, get_object_or_404
|
8
9
|
from django.conf import settings
|
9
10
|
from accrete.models import Tenant, Member
|
10
|
-
from accrete.tenant import get_tenant
|
11
|
+
from accrete.tenant import get_tenant, tenant_has_group, member_has_group
|
11
12
|
from . import config
|
12
13
|
|
13
14
|
|
15
|
+
class GroupType(Enum):
|
16
|
+
|
17
|
+
TENANT: str = 'tenant'
|
18
|
+
MEMBER: str = 'member'
|
19
|
+
|
20
|
+
|
14
21
|
class TenantRequiredMixin(LoginRequiredMixin):
|
15
22
|
|
16
23
|
TENANT_NOT_SET_URL = None
|
24
|
+
GROUP_NOT_SET_URL = None
|
25
|
+
TENANT_GROUPS = []
|
26
|
+
MEMBER_GROUPS = []
|
17
27
|
|
18
28
|
def dispatch(self, request, *args, **kwargs):
|
19
29
|
res = super().dispatch(request, *args, **kwargs)
|
20
30
|
tenant = self.get_tenant()
|
21
31
|
if not tenant:
|
22
32
|
return self.handle_tenant_not_set()
|
33
|
+
if not self.check_tenant_group():
|
34
|
+
return self.handle_tenant_group_not_set()
|
35
|
+
if not self.check_member_group():
|
36
|
+
return self.handle_member_group_not_set()
|
23
37
|
return res
|
24
38
|
|
25
39
|
def handle_tenant_not_set(self):
|
26
40
|
return redirect(self.get_tenant_not_set_url())
|
27
41
|
|
42
|
+
def handle_tenant_group_not_set(self):
|
43
|
+
return redirect(self.get_group_not_set_url(GroupType.TENANT))
|
44
|
+
|
45
|
+
def handle_member_group_not_set(self):
|
46
|
+
return redirect(self.get_group_not_set_url(GroupType.MEMBER))
|
47
|
+
|
28
48
|
def get_tenant_not_set_url(self):
|
29
49
|
tenant_not_set_url = (
|
30
50
|
self.TENANT_NOT_SET_URL
|
@@ -40,12 +60,45 @@ class TenantRequiredMixin(LoginRequiredMixin):
|
|
40
60
|
)
|
41
61
|
return tenant_not_set_url
|
42
62
|
|
63
|
+
def get_group_not_set_url(self, group_type: GroupType):
|
64
|
+
group_not_set_url = (
|
65
|
+
self.GROUP_NOT_SET_URL
|
66
|
+
or settings.ACCRETE_GROUP_NOT_SET_URL
|
67
|
+
)
|
68
|
+
if not group_not_set_url:
|
69
|
+
cls_name = self.__class__.__name__
|
70
|
+
raise ImproperlyConfigured(
|
71
|
+
f"{cls_name} is missing the group_not_set_url attribute. "
|
72
|
+
f"Define {cls_name}.GROUP_NOT_SET_URL, "
|
73
|
+
f"settings.ACCRETE_GROUP_NOT_SET_URL, or override "
|
74
|
+
f"{cls_name}.get_group_not_set_url()."
|
75
|
+
)
|
76
|
+
return group_not_set_url
|
77
|
+
|
78
|
+
def check_tenant_group(self) -> bool:
|
79
|
+
if not self.TENANT_GROUPS:
|
80
|
+
return True
|
81
|
+
for group in self.TENANT_GROUPS:
|
82
|
+
if tenant_has_group(group):
|
83
|
+
return True
|
84
|
+
return False
|
85
|
+
|
86
|
+
def check_member_group(self) -> bool:
|
87
|
+
if not self.MEMBER_GROUPS:
|
88
|
+
return True
|
89
|
+
for group in self.MEMBER_GROUPS:
|
90
|
+
if member_has_group(group):
|
91
|
+
return True
|
92
|
+
return False
|
93
|
+
|
43
94
|
@staticmethod
|
44
95
|
def get_tenant():
|
45
96
|
return get_tenant()
|
46
97
|
|
47
98
|
|
48
99
|
def tenant_required(
|
100
|
+
tenant_groups: list[str] = None,
|
101
|
+
member_groups: list[str] = None,
|
49
102
|
redirect_field_name: str = None,
|
50
103
|
login_url: str = None
|
51
104
|
):
|
@@ -59,6 +112,12 @@ def tenant_required(
|
|
59
112
|
tenant = request.tenant
|
60
113
|
if not tenant:
|
61
114
|
return redirect(config.ACCRETE_TENANT_NOT_SET_URL)
|
115
|
+
for tenant_group in (tenant_groups or []):
|
116
|
+
if not any([tenant_has_group(tenant_group)]):
|
117
|
+
return redirect(config.ACCRETE_GROUP_NOT_SET_URL)
|
118
|
+
for member_group in (member_groups or []):
|
119
|
+
if not any([member_has_group(member_group)]):
|
120
|
+
return redirect(config.ACCRETE_GROUP_NOT_SET_URL)
|
62
121
|
return f(request, *args, **kwargs)
|
63
122
|
return _wrapped_view
|
64
123
|
return decorator
|
@@ -1,24 +1,25 @@
|
|
1
1
|
accrete/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
accrete/admin.py,sha256=
|
2
|
+
accrete/admin.py,sha256=6NiX8_3pYIhnru5hNzvnW4xfzWsbf7gZj8Z2p38xIOk,1232
|
3
3
|
accrete/apps.py,sha256=F7ynMLHJr_6bRujWtZVUzCliY2CGKiDvyUmL4F68L2E,146
|
4
|
-
accrete/config.py,sha256=
|
4
|
+
accrete/config.py,sha256=1Yubvz5PVdCsX0tA7HvazhtnvCvgCoEl33_dR8SHpb8,392
|
5
5
|
accrete/fields.py,sha256=9SlltB5AJvDfiAbYGWZemrqpjqDl1XNgNrhyTGoBJ2A,4693
|
6
6
|
accrete/forms.py,sha256=H2hPQemslRLvTVV0Wl1TfUmTc5wU3Z98nQTMiLMliqo,1288
|
7
7
|
accrete/managers.py,sha256=DevRVm7cStvlfz6TriitSINr40POCi4HNaHX48VkrMA,1620
|
8
8
|
accrete/middleware.py,sha256=YN73WloNkN01oel9Dcj3xyhurcWoB6zMV0NT3hY8DGw,2264
|
9
|
-
accrete/models.py,sha256=
|
9
|
+
accrete/models.py,sha256=01UPWHmkWg3CcgPjImaSvS7OPh1Xx7lQ1nsJxZNN53k,4879
|
10
10
|
accrete/storage.py,sha256=Jp3oE_uPMqgarjS_G49KDFrR2eSe4XuIJK9oAF_QBxk,1288
|
11
|
-
accrete/tenant.py,sha256
|
11
|
+
accrete/tenant.py,sha256=GGKEhKLsC6JAkNGrMvp4l8ScsyfrDMocwJL5LBPe2Go,2307
|
12
12
|
accrete/tests.py,sha256=Agltbzwwh5htvq_Qi9vqvxutzmg_GwgPS_N19xJZRlw,7197
|
13
13
|
accrete/urls.py,sha256=goDFR-yhOlLLy7AMi9pmh2aBkxdtZtwXNg6mwI2zPhU,227
|
14
|
-
accrete/views.py,sha256=
|
14
|
+
accrete/views.py,sha256=NEDX3yrEGjLe_dP47-B3Y537FvJCwEOBqcPrGS3lfuY,4752
|
15
15
|
accrete/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
16
|
accrete/contrib/country/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
accrete/contrib/country/admin.py,sha256=0dAcFPfC8c80fhKKOL26-5Wl1uWXBYrkUJEjo2sEkk4,329
|
18
18
|
accrete/contrib/country/apps.py,sha256=95KSUCEezHIvXmxGXCST7Ag1xvpREHQGy2mIJWWx9R0,162
|
19
|
-
accrete/contrib/country/models.py,sha256=
|
19
|
+
accrete/contrib/country/models.py,sha256=yEAr-hiqEYcx9nfQRKNl5L-u00Dcm0HtJOiTBAyZbO4,931
|
20
20
|
accrete/contrib/country/migrations/0001_initial.py,sha256=M-wKIa9gFtkZHatg-m-LRvrUrEZcKnenRtxLu7NMLbQ,1261
|
21
21
|
accrete/contrib/country/migrations/0002_auto_20250219_1759.py,sha256=hSP0WEErHHJWCYTYvJSI00JWzH1iEcobNLR_4n8Ygq8,24841
|
22
|
+
accrete/contrib/country/migrations/0003_alter_country_options.py,sha256=0reOOdHuApMA5pw4ga6BW63TCG2U1i8T8oSug7EjUXw,428
|
22
23
|
accrete/contrib/country/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
24
|
accrete/contrib/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
25
|
accrete/contrib/log/admin.py,sha256=xeuLk1GdU_M0rZR8SQUzcMeWvV9ud0hz_LJmaut5eJE,1211
|
@@ -250,6 +251,7 @@ accrete/contrib/user_registration/templates/user_registration/mail_templates/con
|
|
250
251
|
accrete/migrations/0001_initial.py,sha256=azThbc8otEhxJwo8BIgOt5eC30mxXhKJLBAazZFe3BA,4166
|
251
252
|
accrete/migrations/0002_initial.py,sha256=dFOM7kdHlx7pVAh8cTDlZMtciN4O9Z547HAzEKnygZE,1628
|
252
253
|
accrete/migrations/0003_remove_member_name.py,sha256=bnZrzOIXcqsoGfbqgohTN5OHm2IldnLlBz1HNJDeqKc,315
|
254
|
+
accrete/migrations/0004_rename_accessgroupmember_memberaccessgrouprel_and_more.py,sha256=NXEKuRyIjLFXqycWB1jIZFQ0ppevMwz1I6rAr9qKrk4,1404
|
253
255
|
accrete/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
254
256
|
accrete/utils/__init__.py,sha256=saw9zi2XItJOPbv4fjTXOpl7StNtC803jHhapFcGx08,312
|
255
257
|
accrete/utils/dates.py,sha256=apM6kt6JhGrKgoT0jfav1W-8AUVTxNc9xt3fJQ2n0JI,1492
|
@@ -257,7 +259,7 @@ accrete/utils/forms.py,sha256=IvxbXNpSd4a-JBgsTJhs2GHe-DCRWX-xnVPRcoiCzbI,3104
|
|
257
259
|
accrete/utils/log.py,sha256=BH0MBDweAjx30wGBO4F3sFhbgkSoEs7T1lLLjlYZNnA,407
|
258
260
|
accrete/utils/models.py,sha256=2xTacvcpmDK_Bp4rAK7JdVLf8HU009LYNJ6eSpMgYZI,1014
|
259
261
|
accrete/utils/views.py,sha256=AutijWetWGgjdO1PNc4gxCblT-i1fAfldNDFRbO9Sac,5012
|
260
|
-
accrete-0.0.
|
261
|
-
accrete-0.0.
|
262
|
-
accrete-0.0.
|
263
|
-
accrete-0.0.
|
262
|
+
accrete-0.0.125.dist-info/METADATA,sha256=ydqTjC-yrBSis0uMo7-3fD1ua8earnP0149gN6iZrlA,4953
|
263
|
+
accrete-0.0.125.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
264
|
+
accrete-0.0.125.dist-info/licenses/LICENSE,sha256=_7laeMIHnsd3Y2vJEXDYXq_PEXxIcjgJsGt8UIKTRWc,1057
|
265
|
+
accrete-0.0.125.dist-info/RECORD,,
|
File without changes
|
File without changes
|