richie 2.34.1.dev9__py2.py3-none-any.whl → 2.34.1.dev16__py2.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.

Potentially problematic release.


This version of richie might be problematic. Click here for more details.

Files changed (27) hide show
  1. frontend/scss/colors/_theme.scss +8 -0
  2. frontend/scss/components/_header.scss +103 -14
  3. frontend/scss/objects/_selector.scss +1 -0
  4. richie/apps/core/cache.py +175 -2
  5. richie/apps/core/storage.py +63 -0
  6. richie/apps/core/templates/menu/header_menu.html +31 -11
  7. richie/apps/core/templates/richie/base.html +149 -6
  8. richie/apps/core/tests/test_cache.py +159 -0
  9. richie/apps/core/tests/test_settings.py +52 -0
  10. richie/apps/core/utils.py +60 -0
  11. richie/apps/courses/migrations/0037_alter_blogpostpluginmodel_cmsplugin_ptr_and_more.py +230 -0
  12. richie/apps/courses/migrations/0038_alter_mainmenuentry_menu_color.py +25 -0
  13. richie/apps/courses/models/course.py +1 -1
  14. richie/apps/courses/models/menuentry.py +1 -1
  15. richie/plugins/glimpse/migrations/0004_alter_glimpse_cmsplugin_ptr_alter_glimpse_variant.py +49 -0
  16. richie/plugins/html_sitemap/migrations/0002_alter_htmlsitemappage_cmsplugin_ptr.py +28 -0
  17. richie/plugins/large_banner/migrations/0004_alter_largebanner_cmsplugin_ptr.py +28 -0
  18. richie/plugins/lti_consumer/migrations/0004_alter_lticonsumer_cmsplugin_ptr.py +28 -0
  19. richie/plugins/nesteditem/migrations/0004_alter_nesteditem_cmsplugin_ptr.py +28 -0
  20. richie/plugins/plain_text/migrations/0002_alter_plaintext_cmsplugin_ptr.py +28 -0
  21. richie/static/richie/css/main.css +1 -1
  22. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/METADATA +3 -1
  23. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/RECORD +27 -15
  24. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/WHEEL +1 -1
  25. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/LICENSE +0 -0
  26. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/top_level.txt +0 -0
  27. {richie-2.34.1.dev9.dist-info → richie-2.34.1.dev16.dist-info}/zip-safe +0 -0
@@ -0,0 +1,159 @@
1
+ """Test site cache plugin"""
2
+
3
+ import datetime
4
+ from unittest import mock
5
+
6
+ from django.core.cache.backends.dummy import DummyCache
7
+ from django.test import TestCase, override_settings
8
+
9
+ from django_redis.cache import RedisCache
10
+
11
+ from richie.apps.core.cache import RedisCacheWithFallback
12
+
13
+
14
+ class RedisCacheWithFallbackTestCase(TestCase):
15
+ """
16
+ Test suite for the RedisCacheWithFallback
17
+
18
+ Credits:
19
+ - https://github.com/Kub-AT/django-cache-fallback
20
+ """
21
+
22
+ @override_settings(
23
+ CACHES={
24
+ "default": {
25
+ "BACKEND": "apps.core.cache.RedisCacheWithFallback",
26
+ "LOCATION": "mymaster/redis-sentinel:26379,redis-sentinel:26379/0",
27
+ "OPTIONS": {
28
+ "CLIENT_CLASS": "richie.apps.core.cache.SentinelClient",
29
+ },
30
+ },
31
+ "memory_cache": {
32
+ "BACKEND": "django.core.cache.backends.dummy.DummyCache",
33
+ },
34
+ }
35
+ )
36
+ def test_client(self):
37
+ """Test class instance of caches"""
38
+ client = RedisCacheWithFallback(None, {})
39
+ self.assertIs(type(client), RedisCacheWithFallback)
40
+ self.assertIs(type(client.redis_cache), RedisCache)
41
+ self.assertIs(type(client.fallback_cache), DummyCache)
42
+
43
+ @mock.patch.object(RedisCacheWithFallback, "_call_fallback_cache")
44
+ @mock.patch.object(RedisCacheWithFallback, "_call_redis_cache")
45
+ def test_get_redis_cache(self, redis_cache_mock, fallback_cache_mock):
46
+ """Test that redis_cache is used by default."""
47
+ client = RedisCacheWithFallback(None, {})
48
+ client.get("irrelevent")
49
+
50
+ redis_cache_mock.assert_called_once()
51
+ fallback_cache_mock.assert_not_called()
52
+
53
+ @mock.patch("apps.core.cache.logger")
54
+ @mock.patch.object(RedisCacheWithFallback, "_call_fallback_cache")
55
+ @mock.patch.object(RedisCacheWithFallback, "_call_redis_cache")
56
+ def test_get_fallback_cache(
57
+ self, redis_cache_mock, fallback_cache_mock, logger_mock
58
+ ):
59
+ """
60
+ Test case when redis_cache raises an exception,
61
+ logger logs the exception then fallback_cache takes over
62
+ """
63
+ client = RedisCacheWithFallback(None, {})
64
+ client.get("irrelevent")
65
+
66
+ redis_cache_mock.assert_called_once()
67
+ fallback_cache_mock.assert_not_called()
68
+
69
+ redis_cache_mock.side_effect = Exception()
70
+ client.get("irrelevent")
71
+
72
+ logger_mock.warning.assert_called_with(
73
+ "[DEGRADED CACHE MODE] - Switch to fallback cache"
74
+ )
75
+ logger_mock.exception.assert_called_once()
76
+ fallback_cache_mock.assert_called_once()
77
+
78
+ @override_settings(
79
+ CACHES={
80
+ "default": {
81
+ "BACKEND": "apps.core.cache.RedisCacheWithFallback",
82
+ "LOCATION": "mymaster/redis-sentinel:26379,redis-sentinel:26379/0",
83
+ "OPTIONS": {
84
+ "CLIENT_CLASS": "richie.apps.core.cache.SentinelClient",
85
+ },
86
+ },
87
+ "memory_cache": {
88
+ "BACKEND": "django.core.cache.backends.dummy.DummyCache",
89
+ },
90
+ }
91
+ )
92
+ @mock.patch.object(DummyCache, "delete")
93
+ @mock.patch.object(RedisCacheWithFallback, "_call_redis_cache")
94
+ def test_invalidate_fallback_cache(self, redis_cache_mock, delete_mock):
95
+ """
96
+ Test that fallback_cache is invalidated every 60 seconds
97
+ when Redis is up
98
+ """
99
+ now = datetime.datetime.now()
100
+
101
+ client = RedisCacheWithFallback(None, {})
102
+ client.get("round_0")
103
+ redis_cache_mock.reset_mock()
104
+ delete_mock.reset_mock()
105
+
106
+ # A second cache access should not delete the fallback cache again
107
+ client.get("round_1")
108
+ redis_cache_mock.assert_called_once()
109
+ delete_mock.assert_not_called()
110
+ redis_cache_mock.reset_mock()
111
+ delete_mock.reset_mock()
112
+
113
+ # Another call to Redis cache 120 seconds later
114
+ # should delete the fallback cache again
115
+ read_time = now + datetime.timedelta(seconds=120)
116
+ with mock.patch("base.utils.datetime") as mock_datetime:
117
+ mock_datetime.now.return_value = read_time
118
+ client.get("round_2")
119
+
120
+ redis_cache_mock.assert_called_once()
121
+ delete_mock.assert_called_once()
122
+ redis_cache_mock.reset_mock()
123
+ delete_mock.reset_mock()
124
+
125
+ # Another call to Redis cache 30 seconds later (<1 minute)
126
+ # should not delete the fallback cache again
127
+ read_time += datetime.timedelta(seconds=30)
128
+ with mock.patch("base.utils.datetime") as mock_datetime:
129
+ mock_datetime.now.return_value = read_time
130
+ client.get("round_3")
131
+
132
+ redis_cache_mock.assert_called_once()
133
+ delete_mock.assert_not_called()
134
+ redis_cache_mock.reset_mock()
135
+ delete_mock.reset_mock()
136
+
137
+ # Another call to Redis cache exactly 1 minute after
138
+ # the latest call should not delete the fallback cache again
139
+ read_time += datetime.timedelta(seconds=30)
140
+ with mock.patch("base.utils.datetime") as mock_datetime:
141
+ mock_datetime.now.return_value = read_time
142
+ client.get("round_4")
143
+
144
+ redis_cache_mock.assert_called_once()
145
+ delete_mock.assert_not_called()
146
+ redis_cache_mock.reset_mock()
147
+ delete_mock.reset_mock()
148
+
149
+ # Another call to Redis cache exactly 1 minute and 1 second after
150
+ # the latest call should delete the fallback cache again
151
+ read_time += datetime.timedelta(seconds=1)
152
+ with mock.patch("base.utils.datetime") as mock_datetime:
153
+ mock_datetime.now.return_value = read_time
154
+ client.get("round_5")
155
+
156
+ redis_cache_mock.assert_called_once()
157
+ delete_mock.assert_called_once()
158
+ redis_cache_mock.reset_mock()
159
+ delete_mock.reset_mock()
@@ -0,0 +1,52 @@
1
+ """Test cnfpt configuration."""
2
+
3
+ from unittest import mock
4
+
5
+ from django.conf import settings
6
+ from django.test import TestCase, override_settings
7
+
8
+ from rest_framework.response import Response
9
+ from rest_framework.settings import DEFAULTS, api_settings
10
+
11
+ from richie.apps.search.viewsets.courses import CoursesViewSet
12
+
13
+
14
+ class ConfigurationTestCase(TestCase):
15
+ """Validate that our configuration works as expected."""
16
+
17
+ @mock.patch.object(CoursesViewSet, "list", spec=True, return_value=Response({}))
18
+ def test_configuration_restframework_htaccess(self, _mock_list):
19
+ """The search API endpoint should work behind an htaccess."""
20
+ # First, check that API calls were broken with the default DRF configuration
21
+ # What was happening is that DRF defines Basic Authentication as a fallback by default
22
+ # and our query has a basic auth header with the username and password of the htaccess
23
+ # defined in nginx. Django was trying to authenticate a user with these credentials,
24
+ # which of course failed.
25
+ with override_settings(
26
+ REST_FRAMEWORK={
27
+ **settings.REST_FRAMEWORK,
28
+ "DEFAULT_AUTHENTICATION_CLASSES": DEFAULTS[
29
+ "DEFAULT_AUTHENTICATION_CLASSES"
30
+ ],
31
+ }
32
+ ):
33
+ authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
34
+
35
+ # The authentication classes are loaded before settings are overriden so we need
36
+ # to mock them on the APIView
37
+ with mock.patch(
38
+ "rest_framework.views.APIView.authentication_classes",
39
+ new_callable=mock.PropertyMock,
40
+ return_value=authentication_classes,
41
+ ):
42
+ response = self.client.get(
43
+ "/api/v1.0/courses/",
44
+ HTTP_AUTHORIZATION="Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
45
+ )
46
+ self.assertEqual(response.status_code, 403)
47
+
48
+ # Check that the project configuration solves it
49
+ response = self.client.get(
50
+ "/api/v1.0/courses/", HTTP_AUTHORIZATION="Basic dXNlcm5hbWU6cGFzc3dvcmQ="
51
+ )
52
+ self.assertEqual(response.status_code, 200)
@@ -0,0 +1,60 @@
1
+ """
2
+ This module contains utility function and the `Throttle` decorator used across the Richie project.
3
+ """
4
+
5
+ import collections.abc
6
+ from datetime import datetime, timedelta
7
+ from functools import wraps
8
+
9
+
10
+ def merge_dict(base_dict, update_dict):
11
+ """Utility for deep dictionary updates.
12
+
13
+ >>> d1 = {'k1':{'k11':{'a': 0, 'b': 1}}}
14
+ >>> d2 = {'k1':{'k11':{'b': 10}, 'k12':{'a': 3}}}
15
+ >>> merge_dict(d1, d2)
16
+ {'k1': {'k11': {'a': 0, 'b': 10}, 'k12':{'a': 3}}}
17
+
18
+ """
19
+ for key, value in update_dict.items():
20
+ if isinstance(value, collections.abc.Mapping):
21
+ base_dict[key] = merge_dict(base_dict.get(key, {}), value)
22
+ else:
23
+ base_dict[key] = value
24
+ return base_dict
25
+
26
+
27
+ class Throttle:
28
+ """
29
+ Throttle Decorator
30
+
31
+ Limit execution of a function to a defined interval
32
+ """
33
+
34
+ def __init__(self, interval):
35
+ """
36
+ Initialize throttle decorator
37
+ Define the throttle_interval with the provided interval (in seconds)
38
+ and set time_of_last_call to the earliest representable datetime
39
+ """
40
+ self.throttle_interval = timedelta(seconds=interval)
41
+ self.time_of_last_call = datetime.min
42
+
43
+ def __call__(self, callback):
44
+ """
45
+ Process `elapsed_since_last_call`,
46
+ if it is greater than `throttle_interval`, callback is executed.
47
+ """
48
+
49
+ @wraps(callback)
50
+ def wrapper(*args, **kwargs):
51
+ now = datetime.now()
52
+ elapsed_since_last_call = now - self.time_of_last_call
53
+
54
+ if elapsed_since_last_call < self.throttle_interval:
55
+ return None
56
+
57
+ self.time_of_last_call = now
58
+ return callback(*args, **kwargs)
59
+
60
+ return wrapper
@@ -0,0 +1,230 @@
1
+ # Generated by Django 4.2.19 on 2025-02-25 09:38
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+ import richie.apps.core.fields.multiselect
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+
11
+ dependencies = [
12
+ ("cms", "0022_auto_20180620_1551"),
13
+ ("courses", "0036_courserun_certificate_offer_and_more"),
14
+ ]
15
+
16
+ operations = [
17
+ migrations.AlterField(
18
+ model_name="blogpostpluginmodel",
19
+ name="cmsplugin_ptr",
20
+ field=models.OneToOneField(
21
+ auto_created=True,
22
+ on_delete=django.db.models.deletion.CASCADE,
23
+ parent_link=True,
24
+ primary_key=True,
25
+ related_name="%(app_label)s_%(class)s",
26
+ serialize=False,
27
+ to="cms.cmsplugin",
28
+ ),
29
+ ),
30
+ migrations.AlterField(
31
+ model_name="categorypluginmodel",
32
+ name="cmsplugin_ptr",
33
+ field=models.OneToOneField(
34
+ auto_created=True,
35
+ on_delete=django.db.models.deletion.CASCADE,
36
+ parent_link=True,
37
+ primary_key=True,
38
+ related_name="%(app_label)s_%(class)s",
39
+ serialize=False,
40
+ to="cms.cmsplugin",
41
+ ),
42
+ ),
43
+ migrations.AlterField(
44
+ model_name="coursepluginmodel",
45
+ name="cmsplugin_ptr",
46
+ field=models.OneToOneField(
47
+ auto_created=True,
48
+ on_delete=django.db.models.deletion.CASCADE,
49
+ parent_link=True,
50
+ primary_key=True,
51
+ related_name="%(app_label)s_%(class)s",
52
+ serialize=False,
53
+ to="cms.cmsplugin",
54
+ ),
55
+ ),
56
+ migrations.AlterField(
57
+ model_name="courserun",
58
+ name="languages",
59
+ field=richie.apps.core.fields.multiselect.MultiSelectField(
60
+ choices=[
61
+ ("af", "Afrikaans"),
62
+ ("ar", "Arabic"),
63
+ ("ar-dz", "Algerian Arabic"),
64
+ ("ast", "Asturian"),
65
+ ("az", "Azerbaijani"),
66
+ ("bg", "Bulgarian"),
67
+ ("be", "Belarusian"),
68
+ ("bn", "Bengali"),
69
+ ("br", "Breton"),
70
+ ("bs", "Bosnian"),
71
+ ("ca", "Catalan"),
72
+ ("ckb", "Central Kurdish (Sorani)"),
73
+ ("cs", "Czech"),
74
+ ("cy", "Welsh"),
75
+ ("da", "Danish"),
76
+ ("de", "German"),
77
+ ("dsb", "Lower Sorbian"),
78
+ ("el", "Greek"),
79
+ ("en", "English"),
80
+ ("en-au", "Australian English"),
81
+ ("en-gb", "British English"),
82
+ ("eo", "Esperanto"),
83
+ ("es", "Spanish"),
84
+ ("es-ar", "Argentinian Spanish"),
85
+ ("es-co", "Colombian Spanish"),
86
+ ("es-mx", "Mexican Spanish"),
87
+ ("es-ni", "Nicaraguan Spanish"),
88
+ ("es-ve", "Venezuelan Spanish"),
89
+ ("et", "Estonian"),
90
+ ("eu", "Basque"),
91
+ ("fa", "Persian"),
92
+ ("fi", "Finnish"),
93
+ ("fr", "French"),
94
+ ("fy", "Frisian"),
95
+ ("ga", "Irish"),
96
+ ("gd", "Scottish Gaelic"),
97
+ ("gl", "Galician"),
98
+ ("he", "Hebrew"),
99
+ ("hi", "Hindi"),
100
+ ("hr", "Croatian"),
101
+ ("hsb", "Upper Sorbian"),
102
+ ("hu", "Hungarian"),
103
+ ("hy", "Armenian"),
104
+ ("ia", "Interlingua"),
105
+ ("id", "Indonesian"),
106
+ ("ig", "Igbo"),
107
+ ("io", "Ido"),
108
+ ("is", "Icelandic"),
109
+ ("it", "Italian"),
110
+ ("ja", "Japanese"),
111
+ ("ka", "Georgian"),
112
+ ("kab", "Kabyle"),
113
+ ("kk", "Kazakh"),
114
+ ("km", "Khmer"),
115
+ ("kn", "Kannada"),
116
+ ("ko", "Korean"),
117
+ ("ky", "Kyrgyz"),
118
+ ("lb", "Luxembourgish"),
119
+ ("lt", "Lithuanian"),
120
+ ("lv", "Latvian"),
121
+ ("mk", "Macedonian"),
122
+ ("ml", "Malayalam"),
123
+ ("mn", "Mongolian"),
124
+ ("mr", "Marathi"),
125
+ ("ms", "Malay"),
126
+ ("my", "Burmese"),
127
+ ("nb", "Norwegian Bokmål"),
128
+ ("ne", "Nepali"),
129
+ ("nl", "Dutch"),
130
+ ("nn", "Norwegian Nynorsk"),
131
+ ("os", "Ossetic"),
132
+ ("pa", "Punjabi"),
133
+ ("pl", "Polish"),
134
+ ("pt", "Portuguese"),
135
+ ("pt-br", "Brazilian Portuguese"),
136
+ ("ro", "Romanian"),
137
+ ("ru", "Russian"),
138
+ ("sk", "Slovak"),
139
+ ("sl", "Slovenian"),
140
+ ("sq", "Albanian"),
141
+ ("sr", "Serbian"),
142
+ ("sr-latn", "Serbian Latin"),
143
+ ("sv", "Swedish"),
144
+ ("sw", "Swahili"),
145
+ ("ta", "Tamil"),
146
+ ("te", "Telugu"),
147
+ ("tg", "Tajik"),
148
+ ("th", "Thai"),
149
+ ("tk", "Turkmen"),
150
+ ("tr", "Turkish"),
151
+ ("tt", "Tatar"),
152
+ ("udm", "Udmurt"),
153
+ ("uk", "Ukrainian"),
154
+ ("ur", "Urdu"),
155
+ ("uz", "Uzbek"),
156
+ ("vi", "Vietnamese"),
157
+ ("zh-hans", "Simplified Chinese"),
158
+ ("zh-hant", "Traditional Chinese"),
159
+ ],
160
+ help_text="The list of languages in which the course content is available.",
161
+ max_choices=50,
162
+ max_length=255,
163
+ ),
164
+ ),
165
+ migrations.AlterField(
166
+ model_name="licencepluginmodel",
167
+ name="cmsplugin_ptr",
168
+ field=models.OneToOneField(
169
+ auto_created=True,
170
+ on_delete=django.db.models.deletion.CASCADE,
171
+ parent_link=True,
172
+ primary_key=True,
173
+ related_name="%(app_label)s_%(class)s",
174
+ serialize=False,
175
+ to="cms.cmsplugin",
176
+ ),
177
+ ),
178
+ migrations.AlterField(
179
+ model_name="organizationpluginmodel",
180
+ name="cmsplugin_ptr",
181
+ field=models.OneToOneField(
182
+ auto_created=True,
183
+ on_delete=django.db.models.deletion.CASCADE,
184
+ parent_link=True,
185
+ primary_key=True,
186
+ related_name="%(app_label)s_%(class)s",
187
+ serialize=False,
188
+ to="cms.cmsplugin",
189
+ ),
190
+ ),
191
+ migrations.AlterField(
192
+ model_name="organizationsbycategorypluginmodel",
193
+ name="cmsplugin_ptr",
194
+ field=models.OneToOneField(
195
+ auto_created=True,
196
+ on_delete=django.db.models.deletion.CASCADE,
197
+ parent_link=True,
198
+ primary_key=True,
199
+ related_name="%(app_label)s_%(class)s",
200
+ serialize=False,
201
+ to="cms.cmsplugin",
202
+ ),
203
+ ),
204
+ migrations.AlterField(
205
+ model_name="personpluginmodel",
206
+ name="cmsplugin_ptr",
207
+ field=models.OneToOneField(
208
+ auto_created=True,
209
+ on_delete=django.db.models.deletion.CASCADE,
210
+ parent_link=True,
211
+ primary_key=True,
212
+ related_name="%(app_label)s_%(class)s",
213
+ serialize=False,
214
+ to="cms.cmsplugin",
215
+ ),
216
+ ),
217
+ migrations.AlterField(
218
+ model_name="programpluginmodel",
219
+ name="cmsplugin_ptr",
220
+ field=models.OneToOneField(
221
+ auto_created=True,
222
+ on_delete=django.db.models.deletion.CASCADE,
223
+ parent_link=True,
224
+ primary_key=True,
225
+ related_name="%(app_label)s_%(class)s",
226
+ serialize=False,
227
+ to="cms.cmsplugin",
228
+ ),
229
+ ),
230
+ ]
@@ -0,0 +1,25 @@
1
+ # Generated by Django 4.2.19 on 2025-02-25 09:40
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("courses", "0037_alter_blogpostpluginmodel_cmsplugin_ptr_and_more"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="mainmenuentry",
15
+ name="menu_color",
16
+ field=models.CharField(
17
+ blank=True,
18
+ choices=[("", "None")],
19
+ default="",
20
+ help_text="A color used to display page entry in menu.",
21
+ max_length=50,
22
+ verbose_name="Color in menu",
23
+ ),
24
+ ),
25
+ ]
@@ -633,7 +633,7 @@ class Course(EsIdMixin, BasePageExtension):
633
633
 
634
634
  for course_run in self.course_runs.only(
635
635
  "start", "end", "enrollment_start", "enrollment_end"
636
- ):
636
+ ).exclude(catalog_visibility=CourseRunCatalogVisibility.HIDDEN):
637
637
  state = course_run.state
638
638
  best_state = min(state, best_state)
639
639
  if state["priority"] == CourseState.ONGOING_OPEN:
@@ -40,7 +40,7 @@ class MainMenuEntry(BasePageExtension):
40
40
  )
41
41
  menu_color = models.CharField(
42
42
  _("Color in menu"),
43
- max_length=10,
43
+ max_length=50,
44
44
  default="",
45
45
  blank=True,
46
46
  choices=defaults.MENU_ENTRY_COLOR_CLASSES,
@@ -0,0 +1,49 @@
1
+ # Generated by Django 4.2.19 on 2025-02-19 16:43
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("cms", "0022_auto_20180620_1551"),
11
+ ("glimpse", "0003_auto_20201118_1153"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="glimpse",
17
+ name="cmsplugin_ptr",
18
+ field=models.OneToOneField(
19
+ auto_created=True,
20
+ on_delete=django.db.models.deletion.CASCADE,
21
+ parent_link=True,
22
+ primary_key=True,
23
+ related_name="%(app_label)s_%(class)s",
24
+ serialize=False,
25
+ to="cms.cmsplugin",
26
+ ),
27
+ ),
28
+ migrations.AlterField(
29
+ model_name="glimpse",
30
+ name="variant",
31
+ field=models.CharField(
32
+ blank=True,
33
+ choices=[
34
+ (None, "Inherit"),
35
+ ("badge", "Badge"),
36
+ ("card_square", "Square card"),
37
+ ("person", "Person"),
38
+ ("quote", "Quote"),
39
+ ("row_half", "Half row"),
40
+ ("row_full", "Full row"),
41
+ ],
42
+ default=None,
43
+ help_text="Form factor variant",
44
+ max_length=50,
45
+ null=True,
46
+ verbose_name="Variant",
47
+ ),
48
+ ),
49
+ ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 4.2.19 on 2025-02-25 09:35
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("cms", "0022_auto_20180620_1551"),
11
+ ("html_sitemap", "0001_initial"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="htmlsitemappage",
17
+ name="cmsplugin_ptr",
18
+ field=models.OneToOneField(
19
+ auto_created=True,
20
+ on_delete=django.db.models.deletion.CASCADE,
21
+ parent_link=True,
22
+ primary_key=True,
23
+ related_name="%(app_label)s_%(class)s",
24
+ serialize=False,
25
+ to="cms.cmsplugin",
26
+ ),
27
+ ),
28
+ ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 4.2.19 on 2025-02-25 09:35
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("cms", "0022_auto_20180620_1551"),
11
+ ("large_banner", "0003_make_logo_optional"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="largebanner",
17
+ name="cmsplugin_ptr",
18
+ field=models.OneToOneField(
19
+ auto_created=True,
20
+ on_delete=django.db.models.deletion.CASCADE,
21
+ parent_link=True,
22
+ primary_key=True,
23
+ related_name="%(app_label)s_%(class)s",
24
+ serialize=False,
25
+ to="cms.cmsplugin",
26
+ ),
27
+ ),
28
+ ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 4.2.19 on 2025-02-25 09:35
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ("cms", "0022_auto_20180620_1551"),
11
+ ("lti_consumer", "0003_auto_20221005_0931"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="lticonsumer",
17
+ name="cmsplugin_ptr",
18
+ field=models.OneToOneField(
19
+ auto_created=True,
20
+ on_delete=django.db.models.deletion.CASCADE,
21
+ parent_link=True,
22
+ primary_key=True,
23
+ related_name="%(app_label)s_%(class)s",
24
+ serialize=False,
25
+ to="cms.cmsplugin",
26
+ ),
27
+ ),
28
+ ]