django-spire 0.16.4__py3-none-any.whl → 0.16.6__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.
Files changed (84) hide show
  1. django_spire/auth/group/templates/django_spire/auth/group/navigation/accordion/permission_nav_accordion.html +2 -2
  2. django_spire/auth/mfa/views/page_views.py +1 -2
  3. django_spire/auth/templates/django_spire/auth/page/password_change_done_page.html +2 -2
  4. django_spire/auth/templates/django_spire/auth/page/password_change_page.html +19 -3
  5. django_spire/auth/views/admin_views.py +16 -0
  6. django_spire/consts.py +1 -1
  7. django_spire/core/management/commands/spire_startapp.py +0 -4
  8. django_spire/core/management/commands/spire_startapp_pkg/processor.py +18 -3
  9. django_spire/core/management/commands/spire_startapp_pkg/reporter.py +32 -30
  10. django_spire/core/redirect/generic_redirect.py +1 -1
  11. django_spire/core/static/django_spire/js/theme.js +2 -2
  12. django_spire/core/templates/django_spire/element/pagination_element.html +2 -0
  13. django_spire/core/templates/django_spire/navigation/top_navigation.html +39 -35
  14. django_spire/core/templates/django_spire/page/full_page.html +2 -2
  15. django_spire/core/templatetags/json.py +7 -4
  16. django_spire/knowledge/auth/controller.py +10 -0
  17. django_spire/knowledge/collection/admin.py +10 -3
  18. django_spire/knowledge/collection/models.py +23 -1
  19. django_spire/knowledge/collection/querysets.py +19 -1
  20. django_spire/knowledge/collection/services/factory_service.py +42 -0
  21. django_spire/knowledge/collection/services/service.py +9 -1
  22. django_spire/knowledge/collection/services/transformation_service.py +29 -7
  23. django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +4 -2
  24. django_spire/knowledge/collection/views/form_views.py +20 -4
  25. django_spire/knowledge/context_processors.py +1 -2
  26. django_spire/knowledge/migrations/0004_alter_collection_options_collectiongroup.py +27 -0
  27. django_spire/knowledge/static/django_spire/knowledge/collection/js/managers.js +17 -14
  28. django_spire/knowledge/templates/django_spire/knowledge/collection/card/context_menu_card.html +16 -10
  29. django_spire/knowledge/templates/django_spire/knowledge/collection/form/form.html +10 -1
  30. django_spire/knowledge/templates/django_spire/knowledge/collection/navigation/navigation.html +3 -0
  31. django_spire/knowledge/templates/django_spire/knowledge/entry/card/context_menu_card.html +1 -1
  32. django_spire/knowledge/templates/django_spire/knowledge/page/full_page.html +1 -1
  33. django_spire/theme/tests/test_filesystem.py +2 -2
  34. django_spire/theme/tests/{test_views.py → test_views/test_json_views.py} +14 -14
  35. django_spire/theme/urls/__init__.py +1 -1
  36. django_spire/theme/urls/json_urls.py +10 -0
  37. {django_spire-0.16.4.dist-info → django_spire-0.16.6.dist-info}/METADATA +1 -1
  38. {django_spire-0.16.4.dist-info → django_spire-0.16.6.dist-info}/RECORD +43 -81
  39. django_spire/core/management/commands/spire_startapp_pkg/template/app/apps.py +0 -7
  40. django_spire/core/management/commands/spire_startapp_pkg/template/app/forms.py +0 -15
  41. django_spire/core/management/commands/spire_startapp_pkg/template/app/intelligence/__init__.py +0 -0
  42. django_spire/core/management/commands/spire_startapp_pkg/template/app/intelligence/bots.py +0 -19
  43. django_spire/core/management/commands/spire_startapp_pkg/template/app/intelligence/intel.py +0 -7
  44. django_spire/core/management/commands/spire_startapp_pkg/template/app/intelligence/prompts.py +0 -30
  45. django_spire/core/management/commands/spire_startapp_pkg/template/app/migrations/__init__.py +0 -0
  46. django_spire/core/management/commands/spire_startapp_pkg/template/app/models.py +0 -52
  47. django_spire/core/management/commands/spire_startapp_pkg/template/app/querysets.py +0 -12
  48. django_spire/core/management/commands/spire_startapp_pkg/template/app/seeding/__init__.py +0 -0
  49. django_spire/core/management/commands/spire_startapp_pkg/template/app/seeding/seed.py +0 -3
  50. django_spire/core/management/commands/spire_startapp_pkg/template/app/seeding/seeder.py +0 -13
  51. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/__init__.py +0 -0
  52. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/factory_service.py +0 -11
  53. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/intelligence_service.py +0 -11
  54. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/processor_service.py +0 -11
  55. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/service.py +0 -20
  56. django_spire/core/management/commands/spire_startapp_pkg/template/app/services/transformation_service.py +0 -11
  57. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/__init__.py +0 -0
  58. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_intelligence/__init__.py +0 -0
  59. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_intelligence/test_bots.py +0 -6
  60. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_models.py +0 -6
  61. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/__init__.py +0 -0
  62. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/test_factory_service.py +0 -6
  63. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/test_intelligence_service.py +0 -6
  64. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/test_processor_service.py +0 -6
  65. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/test_service.py +0 -6
  66. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_services/test_transformation_service.py +0 -6
  67. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_urls/__init__.py +0 -0
  68. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_urls/test_form_urls.py +0 -6
  69. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_urls/test_page_urls.py +0 -6
  70. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_views/__init__.py +0 -0
  71. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_views/test_form_views.py +0 -6
  72. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_views/test_page_views.py +0 -6
  73. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/__init__.py +0 -9
  74. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/form_urls.py +0 -13
  75. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/page_urls.py +0 -11
  76. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/__init__.py +0 -0
  77. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/form_views.py +0 -120
  78. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/page_views.py +0 -45
  79. django_spire/theme/urls/ajax_urls.py +0 -10
  80. /django_spire/{core/management/commands/spire_startapp_pkg/template/app → theme/tests/test_views}/__init__.py +0 -0
  81. /django_spire/theme/views/{ajax_views.py → json_views.py} +0 -0
  82. {django_spire-0.16.4.dist-info → django_spire-0.16.6.dist-info}/WHEEL +0 -0
  83. {django_spire-0.16.4.dist-info → django_spire-0.16.6.dist-info}/licenses/LICENSE.md +0 -0
  84. {django_spire-0.16.4.dist-info → django_spire-0.16.6.dist-info}/top_level.txt +0 -0
@@ -4,25 +4,39 @@ import json
4
4
 
5
5
  from django.conf import settings
6
6
  from django.contrib.sites.models import Site
7
- from django.db.models import QuerySet, Prefetch
7
+ from django.db.models import Prefetch
8
8
  from django.urls import reverse
9
9
 
10
+ from django_spire.auth.controller.controller import AppAuthController
10
11
  from django_spire.contrib.service import BaseDjangoModelService
11
12
 
12
13
  from typing import TYPE_CHECKING
13
14
 
14
15
  if TYPE_CHECKING:
15
- from django.contrib.auth.models import User
16
+ from django.core.handlers.wsgi import WSGIRequest
16
17
  from django_spire.knowledge.collection.models import Collection
17
18
 
18
19
 
19
20
  class CollectionTransformationService(BaseDjangoModelService['Collection']):
20
21
  obj: Collection
21
22
 
22
- @staticmethod
23
- def to_hierarchy_json(queryset: QuerySet[Collection], user: User) -> str:
23
+ def to_hierarchy_json(self, request: WSGIRequest) -> str:
24
+ user = request.user
25
+
26
+ collections = (
27
+ self.obj_class.objects
28
+ .active()
29
+ .select_related('parent')
30
+ )
31
+
32
+ if not (
33
+ user.is_superuser or
34
+ AppAuthController('knowledge', request).can_access_all_collections()
35
+ ):
36
+ collections = collections.user_has_access(user=user)
37
+
24
38
  entry_queryset = (
25
- queryset.model._meta.fields_map.get('entry')
39
+ collections.model._meta.fields_map.get('entry')
26
40
  .related_model
27
41
  .objects
28
42
  .active()
@@ -33,7 +47,7 @@ class CollectionTransformationService(BaseDjangoModelService['Collection']):
33
47
  )
34
48
 
35
49
  collections = list(
36
- queryset.prefetch_related(Prefetch('entries', queryset=entry_queryset))
50
+ collections.prefetch_related(Prefetch('entries', queryset=entry_queryset))
37
51
  .active()
38
52
  .order_by('order')
39
53
  )
@@ -44,7 +58,7 @@ class CollectionTransformationService(BaseDjangoModelService['Collection']):
44
58
 
45
59
  tree = []
46
60
  for collection in collections:
47
- if collection.parent_id:
61
+ if collection.parent_id and collection.parent_id in collection_map:
48
62
  collection_map[collection.parent_id]['children'].append(
49
63
  collection_map[collection.pk]
50
64
  )
@@ -74,6 +88,14 @@ class CollectionTransformationService(BaseDjangoModelService['Collection']):
74
88
  )
75
89
  }
76
90
  ''',
91
+ 'edit_url': f'''
92
+ {site}{
93
+ reverse(
94
+ 'django_spire:knowledge:collection:form:update',
95
+ kwargs={'pk': self.obj.pk},
96
+ )
97
+ }
98
+ ''',
77
99
  'create_entry_url': f'''
78
100
  {site}{
79
101
  reverse(
@@ -2,6 +2,7 @@ import json
2
2
 
3
3
  from django.contrib.sites.models import Site
4
4
  from django.conf import settings
5
+ from django.test import RequestFactory
5
6
 
6
7
  from django_spire.core.tests.test_cases import BaseTestCase
7
8
  from django_spire.knowledge.collection.models import Collection
@@ -29,9 +30,10 @@ class TestCollectionTransformationService(BaseTestCase):
29
30
  self.test_collection_2 = Collection.objects.create(name='Parent A1', id=2, parent_id=1)
30
31
  self.test_collection_3 = Collection.objects.create(name='Child A1a', id=3, parent_id=2)
31
32
 
33
+ request = RequestFactory().get('/')
34
+ request.user = self.super_user
32
35
  family_tree = Collection.services.transformation.to_hierarchy_json(
33
- queryset=Collection.objects.all().select_related('parent'),
34
- user=self.super_user
36
+ request=request
35
37
  )
36
38
 
37
39
  for collection_json in json.loads(family_tree):
@@ -8,10 +8,11 @@ from django.http import HttpResponseRedirect
8
8
  from django.urls import reverse
9
9
 
10
10
  from django_spire.auth.controller.controller import AppAuthController
11
+ from django_spire.auth.group.models import AuthGroup
11
12
  from django_spire.contrib.form.utils import show_form_errors
12
13
  from django_spire.contrib.generic_views import portal_views
13
14
  from django_spire.core.shortcuts import get_object_or_null_obj
14
- from django_spire.knowledge.collection.models import Collection
15
+ from django_spire.knowledge.collection.models import Collection, CollectionGroup
15
16
  from django_spire.knowledge.collection.forms import CollectionForm
16
17
 
17
18
  if TYPE_CHECKING:
@@ -30,7 +31,13 @@ def form_view(
30
31
  dg.glue_query_set(
31
32
  request,
32
33
  unique_name='collections',
33
- target=Collection.objects.active(),
34
+ target=Collection.objects.active().user_has_access(request.user),
35
+ fields=['name']
36
+ )
37
+ dg.glue_query_set(
38
+ request,
39
+ unique_name='group_query_set',
40
+ target=AuthGroup.objects.all(),
34
41
  fields=['name']
35
42
  )
36
43
 
@@ -38,7 +45,13 @@ def form_view(
38
45
  form = CollectionForm(request.POST, instance=collection)
39
46
 
40
47
  if form.is_valid():
41
- _, _ = collection.services.save_model_obj(**form.cleaned_data)
48
+ collection, _ = collection.services.save_model_obj(**form.cleaned_data)
49
+
50
+ _ = CollectionGroup.services.factory.replace_groups(
51
+ request=request,
52
+ group_pks=dict(request.POST).get('groups'),
53
+ collection=collection,
54
+ )
42
55
 
43
56
  return HttpResponseRedirect(
44
57
  reverse('django_spire:knowledge:collection:page:list')
@@ -53,7 +66,10 @@ def form_view(
53
66
  form=form,
54
67
  obj=collection,
55
68
  context_data={
56
- 'collection': collection
69
+ 'collection': collection,
70
+ 'group_ids': list(
71
+ collection.groups.all().values_list('auth_group_id', flat=True)
72
+ ) if collection.id else [],
57
73
  },
58
74
  template='django_spire/knowledge/collection/page/form_page.html'
59
75
  )
@@ -11,7 +11,6 @@ def django_spire_knowledge(request: WSGIRequest) -> dict[str, Any]:
11
11
 
12
12
  return {
13
13
  'collection_tree_json': Collection.services.transformation.to_hierarchy_json(
14
- queryset=Collection.objects.all().select_related('parent').order_by('name'),
15
- user=request.user,
14
+ request=request,
16
15
  )
17
16
  }
@@ -0,0 +1,27 @@
1
+ # Generated by Django 5.2.6 on 2025-09-23 14:11
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
+ ('django_spire_auth_group', '0001_initial'),
11
+ ('django_spire_knowledge', '0003_alter_collection_order_alter_entry_order_and_more'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterModelOptions(
16
+ name='collection',
17
+ options={'permissions': [('can_access_all_collections', 'Can Access All Collections'), ('can_change_collection_groups', 'Can Change Collection Groups')], 'verbose_name': 'Collection', 'verbose_name_plural': 'Collections'},
18
+ ),
19
+ migrations.CreateModel(
20
+ name='CollectionGroup',
21
+ fields=[
22
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23
+ ('auth_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='collection_groups', related_query_name='collection_group', to='django_spire_auth_group.authgroup')),
24
+ ('collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', related_query_name='group', to='django_spire_knowledge.collection')),
25
+ ],
26
+ ),
27
+ ]
@@ -28,27 +28,29 @@ class Entry {
28
28
 
29
29
  class Collection {
30
30
  constructor({
31
- children = [],
32
- create_entry_url = '',
33
- delete_url = '',
34
- description = '',
35
- entries = [],
36
31
  id = -1,
37
- import_entry_url = '',
38
32
  name = 'None',
33
+ description = '',
39
34
  order = 0,
40
35
  parent = null,
36
+ children = [],
37
+ entries = [],
38
+ delete_url = '',
39
+ edit_url = '',
40
+ create_entry_url = '',
41
+ import_entry_url = '',
41
42
  }) {
42
- this.children = children
43
- this.create_entry_url = create_entry_url
44
- this.delete_url = delete_url
45
- this.description = description
46
- this.entries = entries
47
43
  this.id = id
48
- this.import_entry_url = import_entry_url
49
44
  this.name = name
45
+ this.description = description
50
46
  this.order = order
51
47
  this.parent = parent
48
+ this.children = children
49
+ this.entries = entries
50
+ this.delete_url = delete_url
51
+ this.edit_url = edit_url
52
+ this.create_entry_url = create_entry_url
53
+ this.import_entry_url = import_entry_url
52
54
  this.show_details = false
53
55
  }
54
56
 
@@ -107,9 +109,10 @@ class CollectionManager {
107
109
  parent: new Collection({}),
108
110
  children: this._create_tree_structure({collections: collection.children}),
109
111
  entries: this._create_entries({entries_json: collection.entries}),
112
+ delete_url: collection.delete_url,
113
+ edit_url: collection.edit_url,
110
114
  create_entry_url: collection.create_entry_url,
111
- import_entry_url: collection.import_entry_url,
112
- delete_url: collection.delete_url
115
+ import_entry_url: collection.import_entry_url
113
116
  })
114
117
 
115
118
  this.collection_lookup_map.set(collection_object.id, collection_object)
@@ -7,21 +7,27 @@
7
7
  top: y + 'px',
8
8
  left: x + 'px',
9
9
  }"
10
- class="position-fixed card shadow-lg z-3 vstack cursor-pointer"
10
+ class="position-fixed card shadow-lg z-3 vstack cursor-pointer bg-app-layer-one"
11
11
  @click.away="hide_menu()"
12
12
  >
13
13
  <span class="px-2 py-1" x-text="title"></span>
14
14
 
15
+ {% if AuthController.knowledge.can_change %}
16
+ <span class="border-top bg-app-layer-one-hover px-3 text-app-default-link-color" @click="edit_collection()">
17
+ <i class="bi bi-pencil pe-1"></i>
18
+ Edit Collection
19
+ </span>
20
+ {% endif %}
15
21
  {% if AuthController.knowledge.can_add %}
16
- <span class="border-top bg-app-layer-one-hover px-3 text-app-default-link-color" @click="add_entry()">
17
- <i class="bi bi-plus pe-1"></i>
18
- Add Entry
19
- </span>
20
- <span class="border-top bg-app-layer-one-hover px-3 text-app-default-link-color" @click="import_entry()">
21
- <i class="bi bi-upload pe-1">
22
- </i>
23
- Import Entry
24
- </span>
22
+ <span class="border-top bg-app-layer-one-hover px-3 text-app-default-link-color" @click="add_entry()">
23
+ <i class="bi bi-plus pe-1"></i>
24
+ Add Entry
25
+ </span>
26
+ <span class="border-top bg-app-layer-one-hover px-3 text-app-default-link-color" @click="import_entry()">
27
+ <i class="bi bi-upload pe-1">
28
+ </i>
29
+ Import Entry
30
+ </span>
25
31
  {% endif %}
26
32
 
27
33
  {% if AuthController.knowledge.can_delete %}
@@ -5,11 +5,15 @@
5
5
  x-data="{
6
6
  collection: new ModelObjectGlue('collection'),
7
7
  collection_query_set: new QuerySetGlue('collections'),
8
+ groups: new GlueCharField('groups'),
9
+ group_query_set: new QuerySetGlue('group_query_set'),
8
10
  async init() {
9
11
  await this.collection.get()
10
12
  this.collection.glue_fields.parent.choices = await this.collection_query_set.to_choices()
11
-
12
13
  this.collection.glue_fields.parent.label = 'Parent Collection'
14
+
15
+ this.groups.choices = await this.group_query_set.to_choices()
16
+ this.groups.value = JSON.parse('{{ group_ids }}')
13
17
  }
14
18
  }"
15
19
  >
@@ -23,6 +27,11 @@
23
27
  <div class="col-12 mt-2">
24
28
  {% include 'django_glue/form/field/search_and_select_field.html' with glue_model_field='collection.parent' %}
25
29
  </div>
30
+ {% if AuthController.knowledge.can_change_collection_groups %}
31
+ <div class="col-12 mt-2">
32
+ {% include 'django_glue/form/field/multi_select_field.html' with glue_field='groups' %}
33
+ </div>
34
+ {% endif %}
26
35
  <div class="col-12 mt-2">
27
36
  {% include 'django_spire/contrib/form/button/form_submit_button.html' %}
28
37
  </div>
@@ -105,6 +105,9 @@
105
105
  {% endif %}
106
106
 
107
107
  {% if AuthController.knowledge.can_change %}
108
+ edit_collection() {
109
+ window.location.href = this.focused_object.edit_url
110
+ },
108
111
  edit_entry() {
109
112
  window.location.href = this.focused_object.edit_url
110
113
  },
@@ -7,7 +7,7 @@
7
7
  top: y + 'px',
8
8
  left: x + 'px',
9
9
  }"
10
- class="position-fixed card shadow-lg z-3 vstack cursor-pointer"
10
+ class="position-fixed card shadow-lg z-3 vstack cursor-pointer bg-app-layer-one"
11
11
  @click.away="hide_menu()"
12
12
  >
13
13
  <span class="px-2 py-1" x-text="title"></span>
@@ -51,7 +51,7 @@
51
51
  ></i>
52
52
  </div>
53
53
  <div
54
- class="offcanvas offcanvas-end rounded-3"
54
+ class="offcanvas offcanvas-end rounded-3 bg-app-layer-one"
55
55
  data-bs-scroll="true"
56
56
  data-bs-backdrop="false"
57
57
  tabindex="-1"
@@ -15,7 +15,7 @@ class ThemeFilesystemValidationTests(TestCase):
15
15
  def _get_themes_base_path(self) -> Path:
16
16
  file = Path(__file__)
17
17
  root = file.parent.parent.parent.parent
18
- return root / 'django_spire' / 'static' / 'django_spire' / 'css' / 'themes'
18
+ return root / 'django_spire' / 'core' / 'static' / 'django_spire' / 'css' / 'themes'
19
19
 
20
20
  def test_themes_directory_exists(self) -> None:
21
21
  if not self.base_path.exists():
@@ -98,7 +98,7 @@ class ThemeFilesystemValidationTests(TestCase):
98
98
 
99
99
  file = Path(__file__)
100
100
  root = file.parent.parent.parent.parent
101
- path = root / 'django_spire' / 'static' / expected
101
+ path = root / 'django_spire' / 'core' / 'static' / expected
102
102
 
103
103
  if not path.exists():
104
104
  missing.append(f'{theme.value}: {expected}')
@@ -11,7 +11,7 @@ from django.http import JsonResponse
11
11
  from django_spire.core.tests.test_cases import BaseTestCase
12
12
  from django_spire.theme.enums import ThemeFamily
13
13
  from django_spire.theme.utils import get_theme_cookie_name
14
- from django_spire.theme.views import ajax_views
14
+ from django_spire.theme.views import json_views
15
15
 
16
16
 
17
17
  class ThemeViewTests(TestCase):
@@ -19,8 +19,8 @@ class ThemeViewTests(TestCase):
19
19
  self.factory = RequestFactory()
20
20
 
21
21
  def test_get_config_success(self) -> None:
22
- request = self.factory.get('/theme/ajax/get_config/')
23
- response = ajax_views.get_config(request)
22
+ request = self.factory.get('/django_spire/theme/json/get_config/')
23
+ response = json_views.get_config(request)
24
24
 
25
25
  self.assertIsInstance(response, JsonResponse)
26
26
  self.assertEqual(response.status_code, HTTPStatus.OK)
@@ -42,18 +42,18 @@ class ThemeViewTests(TestCase):
42
42
  self.assertEqual(set(family_config['modes']), {'dark', 'light'})
43
43
 
44
44
  def test_get_config_cache_header(self) -> None:
45
- _ = self.factory.get('/theme/ajax/get_config/')
45
+ _ = self.factory.get('/django_spire/theme/json/get_config/')
46
46
 
47
- with patch('django_spire.theme.views.ajax_views.cache_page') as _:
48
- self.assertTrue(hasattr(ajax_views.get_config, '__wrapped__'))
47
+ with patch('django_spire.theme.views.json_views.cache_page') as _:
48
+ self.assertTrue(hasattr(json_views.get_config, '__wrapped__'))
49
49
 
50
50
  def test_set_theme_success(self) -> None:
51
51
  request = self.factory.post(
52
- '/theme/ajax/set_theme/',
52
+ '/django_spire/theme/json/set_theme/',
53
53
  data=json.dumps({'theme': 'dracula-dark'}),
54
54
  content_type='application/json'
55
55
  )
56
- response = ajax_views.set_theme(request)
56
+ response = json_views.set_theme(request)
57
57
 
58
58
  self.assertIsInstance(response, JsonResponse)
59
59
  self.assertEqual(response.status_code, HTTPStatus.OK)
@@ -72,11 +72,11 @@ class ThemeViewTests(TestCase):
72
72
 
73
73
  def test_set_theme_missing_theme(self) -> None:
74
74
  request = self.factory.post(
75
- '/theme/ajax/set_theme/',
75
+ '/django_spire/theme/json/set_theme/',
76
76
  data=json.dumps({}),
77
77
  content_type='application/json'
78
78
  )
79
- response = ajax_views.set_theme(request)
79
+ response = json_views.set_theme(request)
80
80
 
81
81
  self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST)
82
82
  data = json.loads(response.content)
@@ -86,11 +86,11 @@ class ThemeViewTests(TestCase):
86
86
 
87
87
  def test_set_theme_invalid_theme(self) -> None:
88
88
  request = self.factory.post(
89
- '/theme/ajax/set_theme/',
89
+ '/django_spire/theme/json/set_theme/',
90
90
  data=json.dumps({'theme': 'invalid-theme'}),
91
91
  content_type='application/json'
92
92
  )
93
- response = ajax_views.set_theme(request)
93
+ response = json_views.set_theme(request)
94
94
 
95
95
  self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST)
96
96
  data = json.loads(response.content)
@@ -102,7 +102,7 @@ class ThemeViewTests(TestCase):
102
102
  class ThemeViewIntegrationTests(BaseTestCase):
103
103
  def test_set_theme_with_authenticated_client(self) -> None:
104
104
  response = self.client.post(
105
- '/theme/ajax/set_theme/',
105
+ '/django_spire/theme/json/set_theme/',
106
106
  data=json.dumps({'theme': 'dracula-dark'}),
107
107
  content_type='application/json'
108
108
  )
@@ -112,7 +112,7 @@ class ThemeViewIntegrationTests(BaseTestCase):
112
112
  self.assertTrue(data['success'])
113
113
 
114
114
  def test_get_config_with_authenticated_client(self) -> None:
115
- response = self.client.get('/theme/ajax/get_config/')
115
+ response = self.client.get('/django_spire/theme/json/get_config/')
116
116
  self.assertEqual(response.status_code, HTTPStatus.OK)
117
117
 
118
118
  data = json.loads(response.content)
@@ -4,6 +4,6 @@ from django.urls.conf import path, include
4
4
  app_name = 'theme'
5
5
 
6
6
  urlpatterns = [
7
- path('ajax/', include('django_spire.theme.urls.ajax_urls', namespace='ajax')),
7
+ path('json/', include('django_spire.theme.urls.json_urls', namespace='json')),
8
8
  path('page/', include('django_spire.theme.urls.page_urls', namespace='page')),
9
9
  ]
@@ -0,0 +1,10 @@
1
+ from django.urls import path
2
+
3
+ from django_spire.theme.views import json_views
4
+
5
+ app_name = 'json'
6
+
7
+ urlpatterns = [
8
+ path('get_config/', json_views.get_config, name='get_config'),
9
+ path('set_theme/', json_views.set_theme, name='set_theme'),
10
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-spire
3
- Version: 0.16.4
3
+ Version: 0.16.6
4
4
  Summary: A project for Django Spire
5
5
  Author-email: Brayden Carlson <braydenc@stratusadv.com>, Nathan Johnson <nathanj@stratusadv.com>
6
6
  License: Copyright (c) 2024 Stratus Advanced Technologies and Contributors.