Skip to content

Commit 480ae17

Browse files
refactor: use swappable dependency to avoid wrong generation for scope
1 parent 9d80013 commit 480ae17

5 files changed

Lines changed: 138 additions & 47 deletions

File tree

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,78 @@
11
# Generated by Django 4.2.24 on 2025-10-24 11:19
22

3+
import django.db.models.deletion
34
from django.conf import settings
45
from django.db import migrations, models
5-
import django.db.models.deletion
66

77

88
class Migration(migrations.Migration):
9-
109
initial = True
1110

1211
dependencies = [
13-
('stubs', '__first__'),
14-
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15-
('casbin_adapter', '0001_initial'),
16-
('openedx_authz', '0001_add_casbin_dependency'),
12+
("casbin_adapter", "0001_initial"),
13+
("openedx_authz", "0001_add_casbin_dependency"),
1714
]
1815

1916
operations = [
2017
migrations.CreateModel(
21-
name='Scope',
18+
name="Scope",
2219
fields=[
23-
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
2421
],
2522
options={
26-
'abstract': False,
23+
"abstract": False,
2724
},
2825
),
2926
migrations.CreateModel(
30-
name='Subject',
27+
name="Subject",
3128
fields=[
32-
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
29+
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
3330
],
3431
options={
35-
'abstract': False,
32+
"abstract": False,
3633
},
3734
),
3835
migrations.CreateModel(
39-
name='ExtendedCasbinRule',
36+
name="ExtendedCasbinRule",
4037
fields=[
41-
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
42-
('casbin_rule_key', models.CharField(max_length=255, unique=True)),
43-
('description', models.TextField(blank=True, null=True)),
44-
('created_at', models.DateTimeField(auto_now_add=True)),
45-
('updated_at', models.DateTimeField(auto_now=True)),
46-
('metadata', models.JSONField(blank=True, null=True)),
47-
('casbin_rule', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='extended_rule', to='casbin_adapter.casbinrule')),
48-
('scope', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='casbin_rules', to='openedx_authz.scope')),
49-
('subject', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='casbin_rules', to='openedx_authz.subject')),
38+
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
39+
("casbin_rule_key", models.CharField(max_length=255, unique=True)),
40+
("description", models.TextField(blank=True, null=True)),
41+
("created_at", models.DateTimeField(auto_now_add=True)),
42+
("updated_at", models.DateTimeField(auto_now=True)),
43+
("metadata", models.JSONField(blank=True, null=True)),
44+
(
45+
"casbin_rule",
46+
models.OneToOneField(
47+
on_delete=django.db.models.deletion.CASCADE,
48+
related_name="extended_rule",
49+
to="casbin_adapter.casbinrule",
50+
),
51+
),
52+
(
53+
"scope",
54+
models.ForeignKey(
55+
blank=True,
56+
null=True,
57+
on_delete=django.db.models.deletion.CASCADE,
58+
related_name="casbin_rules",
59+
to="openedx_authz.scope",
60+
),
61+
),
62+
(
63+
"subject",
64+
models.ForeignKey(
65+
blank=True,
66+
null=True,
67+
on_delete=django.db.models.deletion.CASCADE,
68+
related_name="casbin_rules",
69+
to="openedx_authz.subject",
70+
),
71+
),
5072
],
5173
options={
52-
'verbose_name': 'Extended Casbin Rule',
53-
'verbose_name_plural': 'Extended Casbin Rules',
74+
"verbose_name": "Extended Casbin Rule",
75+
"verbose_name_plural": "Extended Casbin Rules",
5476
},
5577
),
56-
migrations.CreateModel(
57-
name='UserSubject',
58-
fields=[
59-
('subject_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='openedx_authz.subject')),
60-
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='authz_subjects', to=settings.AUTH_USER_MODEL)),
61-
],
62-
bases=('openedx_authz.subject',),
63-
),
64-
migrations.CreateModel(
65-
name='ContentLibraryScope',
66-
fields=[
67-
('scope_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='openedx_authz.scope')),
68-
('content_library', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='authz_scopes', to='stubs.contentlibrary')),
69-
],
70-
bases=('openedx_authz.scope',),
71-
),
7278
]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Generated by Django 4.2.24 on 2025-10-24 11:19
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
11+
("openedx_authz", "0002_initial"),
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name="UserSubject",
17+
fields=[
18+
(
19+
"subject_ptr",
20+
models.OneToOneField(
21+
auto_created=True,
22+
on_delete=django.db.models.deletion.CASCADE,
23+
parent_link=True,
24+
primary_key=True,
25+
serialize=False,
26+
to="openedx_authz.subject",
27+
),
28+
),
29+
(
30+
"user",
31+
models.ForeignKey(
32+
blank=True,
33+
null=True,
34+
on_delete=django.db.models.deletion.CASCADE,
35+
related_name="authz_subjects",
36+
to=settings.AUTH_USER_MODEL,
37+
),
38+
),
39+
],
40+
bases=("openedx_authz.subject",),
41+
),
42+
]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Generated by Django 4.2.24 on 2025-10-24 11:19
2+
# Custom migration - DO NOT REGENERATE
3+
# This migration conditionally depends on the content library model based on settings
4+
5+
import django.db.models.deletion
6+
from django.conf import settings
7+
from django.db import migrations, models
8+
9+
10+
class Migration(migrations.Migration):
11+
dependencies = [
12+
("openedx_authz", "0003_usersubject"),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name="ContentLibraryScope",
18+
fields=[
19+
(
20+
"scope_ptr",
21+
models.OneToOneField(
22+
auto_created=True,
23+
on_delete=django.db.models.deletion.CASCADE,
24+
parent_link=True,
25+
primary_key=True,
26+
serialize=False,
27+
to="openedx_authz.scope",
28+
),
29+
),
30+
(
31+
"content_library",
32+
models.ForeignKey(
33+
blank=True,
34+
null=True,
35+
on_delete=django.db.models.deletion.CASCADE,
36+
related_name="authz_scopes",
37+
to=settings.OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL,
38+
),
39+
),
40+
],
41+
bases=("openedx_authz.scope",),
42+
),
43+
]

openedx_authz/models/scopes.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ def get_content_library_model():
1919
The setting `OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL` should be an
2020
app_label.ModelName string (e.g. 'content_libraries.ContentLibrary').
2121
"""
22-
content_library_app_label = getattr(
22+
CONTENT_LIBRARY_MODEL = getattr(
2323
settings,
2424
"OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL",
2525
"content_libraries.ContentLibrary",
2626
)
2727
try:
28-
app_label, model_name = content_library_app_label.split(".")
28+
app_label, model_name = CONTENT_LIBRARY_MODEL.split(".")
2929
return apps.get_model(app_label, model_name, require_ready=False)
3030
except LookupError:
3131
return None
@@ -52,15 +52,12 @@ class ContentLibraryScope(Scope):
5252
# to import it at model import time. The migration already records the
5353
# dependency on `content_libraries` when the app is present.
5454
content_library = models.ForeignKey(
55-
getattr(
56-
settings,
57-
"OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL",
58-
"content_libraries.ContentLibrary",
59-
),
55+
settings.OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL,
6056
on_delete=models.CASCADE,
6157
null=True,
6258
blank=True,
6359
related_name="authz_scopes",
60+
swappable=True,
6461
)
6562

6663
@classmethod

openedx_authz/settings/common.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ def plugin_settings(settings):
2424
settings.CASBIN_MODEL = os.path.join(ROOT_DIRECTORY, "engine", "config", "model.conf")
2525
if not hasattr(settings, "CASBIN_AUTO_LOAD_POLICY_INTERVAL"):
2626
settings.CASBIN_AUTO_LOAD_POLICY_INTERVAL = 5
27+
# Set default ContentLibrary model for swappable dependency
28+
if not hasattr(settings, "OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL"):
29+
settings.OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL = "content_libraries.ContentLibrary"

0 commit comments

Comments
 (0)