django-spire 0.23.7__py3-none-any.whl → 0.23.8__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 (538) hide show
  1. django_spire/ai/admin.py +11 -11
  2. django_spire/ai/chat/apps.py +1 -0
  3. django_spire/ai/chat/templates/django_spire/ai/chat/widget/dialog_widget.html +1 -1
  4. django_spire/ai/chat/tests/factories.py +15 -0
  5. django_spire/ai/chat/tests/test_controller.py +45 -0
  6. django_spire/ai/chat/tests/test_models.py +301 -0
  7. django_spire/ai/chat/tests/test_prompts.py +48 -0
  8. django_spire/ai/chat/tests/test_responses.py +208 -0
  9. django_spire/ai/chat/tests/test_router/test_base_chat_router.py +66 -6
  10. django_spire/ai/chat/tests/test_router/test_chat_workflow.py +73 -3
  11. django_spire/ai/chat/tests/test_router/test_integration.py +86 -6
  12. django_spire/ai/chat/tests/test_router/test_intent_decoder.py +93 -1
  13. django_spire/ai/chat/tests/test_router/test_message_intel.py +60 -1
  14. django_spire/ai/chat/tests/test_router/test_spire_chat_router.py +110 -0
  15. django_spire/ai/chat/tests/test_urls/test_json_urls.py +202 -1
  16. django_spire/ai/context/tests/__init__.py +0 -0
  17. django_spire/ai/context/tests/test_context.py +188 -0
  18. django_spire/ai/decorators.py +7 -6
  19. django_spire/ai/prompt/tests/test_bots.py +100 -10
  20. django_spire/ai/prompt/tests/test_prompt_intel.py +83 -0
  21. django_spire/ai/prompt/tests/test_prompt_tuning.py +126 -0
  22. django_spire/ai/sms/decorators.py +8 -2
  23. django_spire/ai/sms/tests/test_sms.py +240 -16
  24. django_spire/ai/sms/tests/test_sms_intel.py +42 -0
  25. django_spire/ai/sms/tests/test_webhook.py +155 -7
  26. django_spire/ai/sms/views.py +23 -24
  27. django_spire/ai/tests/test_ai.py +131 -7
  28. django_spire/auth/apps.py +4 -2
  29. django_spire/auth/controller/controller.py +36 -23
  30. django_spire/auth/controller/exceptions.py +9 -0
  31. django_spire/auth/group/admin.py +1 -0
  32. django_spire/auth/group/apps.py +2 -0
  33. django_spire/auth/group/factories.py +17 -8
  34. django_spire/auth/group/forms.py +7 -0
  35. django_spire/auth/group/tests/test_factories.py +146 -0
  36. django_spire/auth/group/tests/test_forms.py +282 -0
  37. django_spire/auth/group/tests/test_models.py +192 -0
  38. django_spire/auth/group/tests/test_querysets.py +98 -0
  39. django_spire/auth/group/tests/test_utils.py +341 -0
  40. django_spire/auth/group/tests/test_views.py +377 -0
  41. django_spire/auth/group/urls/__init__.py +3 -1
  42. django_spire/auth/group/urls/form_urls.py +2 -0
  43. django_spire/auth/group/urls/json_urls.py +3 -0
  44. django_spire/auth/group/urls/page_urls.py +2 -0
  45. django_spire/auth/group/utils.py +6 -2
  46. django_spire/auth/group/views/form_views.py +6 -3
  47. django_spire/auth/group/views/json_views.py +6 -2
  48. django_spire/auth/mfa/admin.py +2 -0
  49. django_spire/auth/mfa/apps.py +2 -0
  50. django_spire/auth/mfa/forms.py +1 -0
  51. django_spire/auth/mfa/querysets.py +9 -2
  52. django_spire/auth/mfa/tests/test_models.py +233 -0
  53. django_spire/auth/mfa/tests/test_utils.py +106 -0
  54. django_spire/auth/mfa/urls/__init__.py +2 -0
  55. django_spire/auth/mfa/urls/page_urls.py +2 -0
  56. django_spire/auth/mfa/urls/redirect_urls.py +2 -0
  57. django_spire/auth/mfa/views/page_views.py +2 -1
  58. django_spire/auth/permissions/consts.py +2 -2
  59. django_spire/auth/permissions/decorators.py +8 -8
  60. django_spire/auth/permissions/permissions.py +28 -35
  61. django_spire/auth/permissions/tests/test_decorators.py +333 -0
  62. django_spire/auth/permissions/tests/test_permissions.py +337 -0
  63. django_spire/auth/permissions/tests/test_tools.py +305 -0
  64. django_spire/auth/permissions/tools.py +21 -15
  65. django_spire/auth/seeding/seed.py +3 -0
  66. django_spire/auth/seeding/seeder.py +2 -0
  67. django_spire/auth/tests/test_controller.py +323 -0
  68. django_spire/auth/tests/test_url_endpoints.py +9 -9
  69. django_spire/auth/tests/test_views.py +406 -0
  70. django_spire/auth/urls/admin_urls.py +2 -0
  71. django_spire/auth/urls/redirect_urls.py +2 -0
  72. django_spire/auth/user/apps.py +2 -0
  73. django_spire/auth/user/forms.py +9 -0
  74. django_spire/auth/user/models.py +1 -1
  75. django_spire/auth/user/services/services.py +1 -0
  76. django_spire/auth/user/tests/factories.py +14 -13
  77. django_spire/auth/user/tests/test_factories.py +166 -2
  78. django_spire/auth/user/tests/test_forms.py +573 -0
  79. django_spire/auth/user/tests/test_models.py +257 -0
  80. django_spire/auth/user/tests/test_services.py +200 -0
  81. django_spire/auth/user/tests/test_tools.py +153 -0
  82. django_spire/auth/user/tests/test_user_factories.py +139 -0
  83. django_spire/auth/user/tests/test_views.py +363 -0
  84. django_spire/auth/user/tools.py +7 -1
  85. django_spire/auth/user/urls/form_urls.py +3 -0
  86. django_spire/auth/user/urls/page_urls.py +3 -0
  87. django_spire/auth/user/views/form_views.py +19 -10
  88. django_spire/auth/user/views/page_views.py +8 -2
  89. django_spire/auth/views/redirect_views.py +14 -9
  90. django_spire/comment/admin.py +2 -0
  91. django_spire/comment/apps.py +2 -0
  92. django_spire/comment/templatetags/comment_tags.py +1 -0
  93. django_spire/comment/tests/test_forms.py +27 -0
  94. django_spire/comment/tests/test_models.py +215 -0
  95. django_spire/comment/tests/test_querysets.py +101 -0
  96. django_spire/comment/tests/test_utils.py +90 -0
  97. django_spire/comment/urls.py +2 -0
  98. django_spire/comment/utils.py +22 -13
  99. django_spire/comment/views.py +1 -1
  100. django_spire/conf.py +8 -6
  101. django_spire/consts.py +1 -1
  102. django_spire/contrib/breadcrumb/apps.py +2 -0
  103. django_spire/contrib/breadcrumb/breadcrumbs.py +18 -18
  104. django_spire/contrib/breadcrumb/tests/test_breadcrumbs.py +198 -0
  105. django_spire/contrib/constructor/__init__.py +3 -3
  106. django_spire/contrib/constructor/constructor.py +15 -15
  107. django_spire/contrib/constructor/django_model_constructor.py +5 -4
  108. django_spire/contrib/constructor/exceptions.py +5 -3
  109. django_spire/contrib/constructor/tests/__init__.py +0 -0
  110. django_spire/contrib/constructor/tests/test_constructor.py +193 -0
  111. django_spire/contrib/form/tests/__init__.py +0 -0
  112. django_spire/contrib/form/tests/test_forms.py +203 -0
  113. django_spire/contrib/generic_views/modal_views.py +2 -1
  114. django_spire/contrib/generic_views/portal_views.py +20 -19
  115. django_spire/contrib/generic_views/tests/__init__.py +0 -0
  116. django_spire/contrib/generic_views/tests/test_views.py +459 -0
  117. django_spire/contrib/help/apps.py +2 -0
  118. django_spire/contrib/help/templatetags/help.py +1 -0
  119. django_spire/contrib/help/tests/__init__.py +0 -0
  120. django_spire/contrib/help/tests/test_templatetags.py +100 -0
  121. django_spire/contrib/options/mixins.py +6 -5
  122. django_spire/contrib/options/tests/factories.py +5 -1
  123. django_spire/contrib/options/tests/test_options.py +234 -0
  124. django_spire/contrib/ordering/exceptions.py +7 -3
  125. django_spire/contrib/ordering/mixins.py +2 -0
  126. django_spire/contrib/ordering/querysets.py +3 -1
  127. django_spire/contrib/ordering/services/processor_service.py +8 -4
  128. django_spire/contrib/ordering/services/service.py +1 -2
  129. django_spire/contrib/ordering/tests/__init__.py +0 -0
  130. django_spire/contrib/ordering/tests/test_ordering.py +165 -0
  131. django_spire/contrib/ordering/validators.py +6 -6
  132. django_spire/contrib/pagination/templatetags/pagination_tags.py +12 -5
  133. django_spire/contrib/pagination/tests/__init__.py +0 -0
  134. django_spire/contrib/pagination/tests/test_pagination.py +179 -0
  135. django_spire/contrib/performance/decorators.py +16 -6
  136. django_spire/contrib/performance/tests/__init__.py +0 -0
  137. django_spire/contrib/performance/tests/test_performance.py +107 -0
  138. django_spire/contrib/queryset/enums.py +3 -1
  139. django_spire/contrib/queryset/filter_tools.py +10 -5
  140. django_spire/contrib/queryset/mixins.py +16 -16
  141. django_spire/contrib/queryset/tests/__init__.py +0 -0
  142. django_spire/contrib/queryset/tests/test_queryset.py +137 -0
  143. django_spire/contrib/seeding/field/base.py +13 -7
  144. django_spire/contrib/seeding/field/callable.py +8 -1
  145. django_spire/contrib/seeding/field/cleaners.py +5 -5
  146. django_spire/contrib/seeding/field/custom.py +20 -10
  147. django_spire/contrib/seeding/field/django/seeder.py +8 -6
  148. django_spire/contrib/seeding/field/enums.py +7 -5
  149. django_spire/contrib/seeding/field/override.py +16 -6
  150. django_spire/contrib/seeding/field/static.py +9 -2
  151. django_spire/contrib/seeding/field/tests/test_base.py +18 -14
  152. django_spire/contrib/seeding/field/tests/test_callable.py +13 -9
  153. django_spire/contrib/seeding/field/tests/test_cleaners.py +51 -38
  154. django_spire/contrib/seeding/field/tests/test_static.py +13 -9
  155. django_spire/contrib/seeding/intelligence/bots/seeder_generator_bot.py +2 -0
  156. django_spire/contrib/seeding/intelligence/intel.py +5 -1
  157. django_spire/contrib/seeding/intelligence/prompts/factory.py +6 -1
  158. django_spire/contrib/seeding/intelligence/prompts/foreign_key_selection_prompt.py +6 -1
  159. django_spire/contrib/seeding/intelligence/prompts/generate_django_model_seeder_prompts.py +2 -0
  160. django_spire/contrib/seeding/intelligence/prompts/generic_relationship_selection_prompt.py +7 -1
  161. django_spire/contrib/seeding/intelligence/prompts/hierarchical_selection_prompt.py +6 -2
  162. django_spire/contrib/seeding/intelligence/prompts/model_field_choices_prompt.py +8 -2
  163. django_spire/contrib/seeding/intelligence/prompts/negation_prompt.py +2 -0
  164. django_spire/contrib/seeding/intelligence/prompts/objective_prompt.py +6 -1
  165. django_spire/contrib/seeding/management/commands/seeding.py +9 -3
  166. django_spire/contrib/seeding/management/example.py +2 -0
  167. django_spire/contrib/seeding/model/base.py +16 -7
  168. django_spire/contrib/seeding/model/config.py +31 -15
  169. django_spire/contrib/seeding/model/django/config.py +13 -13
  170. django_spire/contrib/seeding/model/django/seeder.py +4 -4
  171. django_spire/contrib/seeding/model/django/tests/test_seeder.py +34 -23
  172. django_spire/contrib/seeding/model/enums.py +2 -0
  173. django_spire/contrib/seeding/tests/test_config.py +71 -0
  174. django_spire/contrib/seeding/tests/test_custom.py +35 -0
  175. django_spire/contrib/seeding/tests/test_enums.py +40 -0
  176. django_spire/contrib/seeding/tests/test_intel.py +32 -0
  177. django_spire/contrib/seeding/tests/test_override.py +63 -0
  178. django_spire/contrib/service/__init__.py +2 -2
  179. django_spire/contrib/service/django_model_service.py +16 -15
  180. django_spire/contrib/service/exceptions.py +5 -3
  181. django_spire/contrib/service/tests/__init__.py +0 -0
  182. django_spire/contrib/service/tests/test_service.py +153 -0
  183. django_spire/contrib/session/apps.py +2 -0
  184. django_spire/contrib/session/controller.py +48 -42
  185. django_spire/contrib/session/templatetags/session_tags.py +11 -2
  186. django_spire/contrib/session/tests/test_session_controller.py +117 -53
  187. django_spire/contrib/tests/__init__.py +0 -0
  188. django_spire/contrib/tests/test_utils.py +37 -0
  189. django_spire/contrib/utils.py +4 -1
  190. django_spire/core/apps.py +2 -0
  191. django_spire/core/converters/tests/test_to_data.py +353 -0
  192. django_spire/core/converters/tests/test_to_enums.py +61 -41
  193. django_spire/core/converters/tests/test_to_pydantic.py +138 -109
  194. django_spire/core/converters/to_data.py +29 -10
  195. django_spire/core/converters/to_enums.py +4 -2
  196. django_spire/core/converters/to_pydantic.py +22 -22
  197. django_spire/core/decorators.py +19 -6
  198. django_spire/core/forms/widgets.py +4 -0
  199. django_spire/core/maps.py +3 -1
  200. django_spire/core/middleware/maintenance.py +3 -3
  201. django_spire/core/middleware.py +8 -6
  202. django_spire/core/redirect/__init__.py +5 -0
  203. django_spire/core/redirect/generic_redirect.py +1 -2
  204. django_spire/core/redirect/tests/__init__.py +0 -0
  205. django_spire/core/redirect/tests/test_generic_redirect.py +34 -0
  206. django_spire/core/{tests/tests_redirect.py → redirect/tests/test_safe_redirect.py} +55 -81
  207. django_spire/core/shortcuts.py +3 -3
  208. django_spire/core/static/django_spire/css/app-layout.css +1 -1
  209. django_spire/core/static/django_spire/css/app-navigation.css +3 -3
  210. django_spire/core/static/django_spire/css/bootstrap-override.css +4 -0
  211. django_spire/core/tag/admin.py +12 -0
  212. django_spire/core/tag/intelligence/tag_set_bot.py +2 -0
  213. django_spire/core/tag/mixins.py +2 -0
  214. django_spire/core/tag/models.py +2 -0
  215. django_spire/core/tag/querysets.py +2 -0
  216. django_spire/core/tag/service/tag_service.py +6 -3
  217. django_spire/core/tag/tests/test_intelligence.py +9 -9
  218. django_spire/core/tag/tests/test_tags.py +44 -54
  219. django_spire/core/tag/tests/test_tools.py +191 -0
  220. django_spire/core/tag/tools.py +3 -0
  221. django_spire/core/templates/django_spire/card/card.html +5 -2
  222. django_spire/core/templates/django_spire/card/title_card.html +9 -4
  223. django_spire/core/templates/django_spire/infinite_scroll/base.html +1 -0
  224. django_spire/core/templates/django_spire/navigation/side_navigation.html +19 -24
  225. django_spire/core/templates/django_spire/page/full_page.html +46 -16
  226. django_spire/core/templates/django_spire/table/base.html +4 -2
  227. django_spire/core/templatetags/json.py +6 -2
  228. django_spire/core/templatetags/message.py +13 -8
  229. django_spire/core/templatetags/string_formating.py +8 -5
  230. django_spire/core/templatetags/tests/__init__.py +0 -0
  231. django_spire/core/templatetags/tests/test_templatetags.py +427 -0
  232. django_spire/core/templatetags/variable_types.py +17 -9
  233. django_spire/core/tests/test_cases.py +1 -1
  234. django_spire/core/tests/test_conf.py +43 -0
  235. django_spire/core/tests/test_consts.py +28 -0
  236. django_spire/core/tests/test_context_processors.py +93 -0
  237. django_spire/core/tests/test_decorators.py +95 -0
  238. django_spire/core/tests/test_django_spire_utils.py +56 -0
  239. django_spire/core/tests/test_exceptions.py +37 -0
  240. django_spire/core/tests/test_models.py +54 -0
  241. django_spire/core/tests/test_settings.py +45 -0
  242. django_spire/core/tests/test_shortcuts.py +74 -0
  243. django_spire/core/tests/test_urls.py +16 -0
  244. django_spire/core/tests/test_utils.py +58 -0
  245. django_spire/core/urls.py +4 -1
  246. django_spire/core/utils.py +12 -8
  247. django_spire/exceptions.py +16 -1
  248. django_spire/file/admin.py +4 -2
  249. django_spire/file/apps.py +8 -10
  250. django_spire/file/fields.py +7 -7
  251. django_spire/file/forms.py +1 -1
  252. django_spire/file/interfaces.py +15 -15
  253. django_spire/file/mixins.py +1 -4
  254. django_spire/file/models.py +3 -5
  255. django_spire/file/tests/factories.py +59 -0
  256. django_spire/file/tests/test_admin.py +69 -0
  257. django_spire/file/tests/test_apps.py +24 -0
  258. django_spire/file/tests/test_fields.py +114 -0
  259. django_spire/file/tests/test_forms.py +20 -0
  260. django_spire/file/tests/test_interfaces.py +183 -0
  261. django_spire/file/tests/test_models.py +82 -0
  262. django_spire/file/tests/test_querysets.py +102 -0
  263. django_spire/file/tests/test_utils.py +32 -0
  264. django_spire/file/tests/test_views.py +145 -0
  265. django_spire/file/tests/test_widgets.py +82 -0
  266. django_spire/file/tools.py +8 -2
  267. django_spire/file/views.py +7 -3
  268. django_spire/file/widgets.py +12 -12
  269. django_spire/help_desk/admin.py +15 -0
  270. django_spire/help_desk/apps.py +2 -0
  271. django_spire/help_desk/auth/controller.py +2 -0
  272. django_spire/help_desk/choices.py +2 -0
  273. django_spire/help_desk/enums.py +2 -0
  274. django_spire/help_desk/exceptions.py +31 -3
  275. django_spire/help_desk/forms.py +2 -0
  276. django_spire/help_desk/models.py +2 -0
  277. django_spire/help_desk/querysets.py +4 -1
  278. django_spire/help_desk/services/notification_service.py +26 -27
  279. django_spire/help_desk/services/service.py +2 -3
  280. django_spire/help_desk/tests/factories.py +8 -3
  281. django_spire/help_desk/tests/test_admin.py +41 -0
  282. django_spire/help_desk/tests/test_apps.py +41 -0
  283. django_spire/help_desk/tests/test_choices.py +50 -0
  284. django_spire/help_desk/tests/test_controller.py +87 -0
  285. django_spire/help_desk/tests/test_enums.py +18 -0
  286. django_spire/help_desk/tests/test_exceptions.py +37 -0
  287. django_spire/help_desk/tests/test_forms.py +89 -0
  288. django_spire/help_desk/tests/test_models.py +59 -0
  289. django_spire/help_desk/tests/test_querysets.py +38 -0
  290. django_spire/help_desk/tests/test_services/test_notification_service.py +15 -8
  291. django_spire/help_desk/tests/test_services/test_service.py +92 -0
  292. django_spire/help_desk/tests/test_urls/test_form_urls.py +6 -6
  293. django_spire/help_desk/tests/test_urls/test_page_urls.py +8 -9
  294. django_spire/help_desk/tests/test_views/test_form_views.py +46 -19
  295. django_spire/help_desk/tests/test_views/test_page_views.py +32 -9
  296. django_spire/help_desk/urls/__init__.py +4 -1
  297. django_spire/help_desk/urls/form_urls.py +3 -0
  298. django_spire/help_desk/urls/page_urls.py +3 -0
  299. django_spire/help_desk/views/form_views.py +13 -5
  300. django_spire/help_desk/views/page_views.py +11 -3
  301. django_spire/history/activity/admin.py +2 -0
  302. django_spire/history/activity/apps.py +3 -1
  303. django_spire/history/activity/mixins.py +13 -7
  304. django_spire/history/activity/models.py +6 -5
  305. django_spire/history/activity/querysets.py +2 -0
  306. django_spire/history/activity/tests/__init__.py +0 -0
  307. django_spire/history/activity/tests/test_activity.py +176 -0
  308. django_spire/history/admin.py +9 -2
  309. django_spire/history/choices.py +3 -0
  310. django_spire/history/models.py +5 -5
  311. django_spire/history/tests/test_admin.py +93 -0
  312. django_spire/history/tests/test_history.py +101 -0
  313. django_spire/history/tests/test_mixins.py +84 -0
  314. django_spire/history/viewed/admin.py +3 -1
  315. django_spire/history/viewed/apps.py +3 -1
  316. django_spire/history/viewed/models.py +2 -0
  317. django_spire/history/viewed/tests/__init__.py +0 -0
  318. django_spire/history/viewed/tests/test_viewed.py +46 -0
  319. django_spire/knowledge/auth/tests/__init__.py +0 -0
  320. django_spire/knowledge/auth/tests/test_controller.py +116 -0
  321. django_spire/knowledge/collection/admin.py +5 -1
  322. django_spire/knowledge/collection/models.py +3 -1
  323. django_spire/knowledge/collection/seeding/seed.py +1 -0
  324. django_spire/knowledge/collection/services/factory_service.py +10 -11
  325. django_spire/knowledge/collection/services/ordering_service.py +1 -2
  326. django_spire/knowledge/collection/services/service.py +5 -10
  327. django_spire/knowledge/collection/services/tag_service.py +5 -2
  328. django_spire/knowledge/collection/tests/factories.py +28 -1
  329. django_spire/knowledge/collection/tests/test_models.py +48 -0
  330. django_spire/knowledge/collection/tests/test_querysets.py +93 -0
  331. django_spire/knowledge/collection/tests/test_services/test_factory_service.py +100 -0
  332. django_spire/knowledge/collection/tests/test_services/test_services.py +160 -0
  333. django_spire/knowledge/collection/tests/test_urls/test_form_urls.py +21 -3
  334. django_spire/knowledge/collection/tests/test_urls/test_json_urls.py +39 -1
  335. django_spire/knowledge/collection/tests/test_urls/test_page_urls.py +12 -4
  336. django_spire/knowledge/collection/urls/__init__.py +3 -0
  337. django_spire/knowledge/collection/urls/form_urls.py +2 -0
  338. django_spire/knowledge/collection/urls/json_urls.py +2 -0
  339. django_spire/knowledge/collection/urls/page_urls.py +2 -0
  340. django_spire/knowledge/collection/views/form_views.py +4 -4
  341. django_spire/knowledge/collection/views/json_views.py +5 -1
  342. django_spire/knowledge/collection/views/page_views.py +5 -2
  343. django_spire/knowledge/entry/admin.py +7 -1
  344. django_spire/knowledge/entry/forms.py +2 -0
  345. django_spire/knowledge/entry/models.py +2 -0
  346. django_spire/knowledge/entry/seeding/seed.py +3 -0
  347. django_spire/knowledge/entry/services/automation_service.py +5 -4
  348. django_spire/knowledge/entry/services/factory_service.py +7 -5
  349. django_spire/knowledge/entry/services/service.py +4 -7
  350. django_spire/knowledge/entry/services/tag_service.py +0 -1
  351. django_spire/knowledge/entry/services/tool_service.py +1 -0
  352. django_spire/knowledge/entry/services/transformation_services.py +1 -5
  353. django_spire/knowledge/entry/tests/factories.py +1 -2
  354. django_spire/knowledge/entry/tests/test_factory_service.py +20 -0
  355. django_spire/knowledge/entry/tests/test_models.py +41 -0
  356. django_spire/knowledge/entry/tests/test_querysets.py +71 -0
  357. django_spire/knowledge/entry/tests/test_services.py +94 -0
  358. django_spire/knowledge/entry/tests/test_urls/test_form_urls.py +9 -14
  359. django_spire/knowledge/entry/tests/test_urls/test_json_urls.py +48 -5
  360. django_spire/knowledge/entry/tests/test_urls/test_page_urls.py +6 -8
  361. django_spire/knowledge/entry/tests/test_urls/test_template_urls.py +40 -0
  362. django_spire/knowledge/entry/urls/form_urls.py +2 -0
  363. django_spire/knowledge/entry/urls/json_urls.py +2 -0
  364. django_spire/knowledge/entry/urls/page_urls.py +2 -0
  365. django_spire/knowledge/entry/urls/template_urls.py +2 -0
  366. django_spire/knowledge/entry/version/block/choices.py +2 -0
  367. django_spire/knowledge/entry/version/block/data/data.py +1 -0
  368. django_spire/knowledge/entry/version/block/data/list/data.py +8 -13
  369. django_spire/knowledge/entry/version/block/data/list/maps.py +3 -0
  370. django_spire/knowledge/entry/version/block/data/list/meta.py +1 -2
  371. django_spire/knowledge/entry/version/block/data/list/tests/__init__.py +0 -0
  372. django_spire/knowledge/entry/version/block/data/list/tests/test_maps.py +32 -0
  373. django_spire/knowledge/entry/version/block/data/list/tests/test_meta.py +58 -0
  374. django_spire/knowledge/entry/version/block/data/maps.py +3 -6
  375. django_spire/knowledge/entry/version/block/models.py +7 -5
  376. django_spire/knowledge/entry/version/block/seeding/constants.py +5 -4
  377. django_spire/knowledge/entry/version/block/services/service.py +2 -3
  378. django_spire/knowledge/entry/version/block/tests/factories.py +4 -10
  379. django_spire/knowledge/entry/version/block/tests/test_choices.py +56 -0
  380. django_spire/knowledge/entry/version/block/tests/test_data.py +90 -0
  381. django_spire/knowledge/entry/version/block/tests/test_maps.py +37 -0
  382. django_spire/knowledge/entry/version/block/tests/test_models.py +55 -0
  383. django_spire/knowledge/entry/version/block/tests/test_querysets.py +35 -0
  384. django_spire/knowledge/entry/version/block/tests/test_services.py +65 -0
  385. django_spire/knowledge/entry/version/choices.py +2 -0
  386. django_spire/knowledge/entry/version/converters/converter.py +1 -1
  387. django_spire/knowledge/entry/version/converters/docx_converter.py +4 -7
  388. django_spire/knowledge/entry/version/converters/markdown_converter.py +20 -20
  389. django_spire/knowledge/entry/version/maps.py +4 -5
  390. django_spire/knowledge/entry/version/querysets.py +1 -1
  391. django_spire/knowledge/entry/version/seeding/seeder.py +1 -2
  392. django_spire/knowledge/entry/version/services/processor_service.py +5 -4
  393. django_spire/knowledge/entry/version/services/service.py +1 -2
  394. django_spire/knowledge/entry/version/tests/factories.py +2 -2
  395. django_spire/knowledge/entry/version/tests/test_choices.py +18 -0
  396. django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +56 -8
  397. django_spire/knowledge/entry/version/tests/test_converters/test_markdown_converter.py +78 -0
  398. django_spire/knowledge/entry/version/tests/test_maps.py +58 -0
  399. django_spire/knowledge/entry/version/tests/test_models.py +23 -0
  400. django_spire/knowledge/entry/version/tests/test_querysets.py +26 -0
  401. django_spire/knowledge/entry/version/tests/test_services.py +62 -0
  402. django_spire/knowledge/entry/version/tests/test_urls/test_json_urls.py +27 -8
  403. django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +15 -8
  404. django_spire/knowledge/entry/version/tests/test_urls/test_redirect_urls.py +38 -0
  405. django_spire/knowledge/entry/version/urls/__init__.py +3 -0
  406. django_spire/knowledge/entry/version/urls/json_urls.py +2 -1
  407. django_spire/knowledge/entry/version/urls/page_urls.py +2 -0
  408. django_spire/knowledge/entry/version/urls/redirect_urls.py +2 -0
  409. django_spire/knowledge/entry/version/views/json_views.py +5 -1
  410. django_spire/knowledge/entry/version/views/page_views.py +10 -3
  411. django_spire/knowledge/entry/version/views/redirect_views.py +5 -1
  412. django_spire/knowledge/entry/views/form_views.py +16 -8
  413. django_spire/knowledge/entry/views/json_views.py +3 -1
  414. django_spire/knowledge/entry/views/page_views.py +8 -2
  415. django_spire/knowledge/entry/views/template_views.py +7 -1
  416. django_spire/knowledge/exceptions.py +2 -1
  417. django_spire/knowledge/intelligence/intel/answer_intel.py +2 -1
  418. django_spire/knowledge/intelligence/intel/entry_intel.py +0 -1
  419. django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +4 -5
  420. django_spire/knowledge/models.py +1 -2
  421. django_spire/knowledge/tests/__init__.py +0 -0
  422. django_spire/knowledge/tests/test_templatetags.py +40 -0
  423. django_spire/knowledge/tests/test_urls/__init__.py +0 -0
  424. django_spire/knowledge/tests/test_urls/test_page_urls.py +24 -0
  425. django_spire/knowledge/urls/__init__.py +2 -0
  426. django_spire/knowledge/urls/page_urls.py +2 -0
  427. django_spire/knowledge/views/page_views.py +8 -3
  428. django_spire/notification/admin.py +3 -1
  429. django_spire/notification/app/admin.py +2 -0
  430. django_spire/notification/app/apps.py +3 -1
  431. django_spire/notification/app/exceptions.py +9 -2
  432. django_spire/notification/app/models.py +8 -4
  433. django_spire/notification/app/processor.py +22 -26
  434. django_spire/notification/app/querysets.py +2 -0
  435. django_spire/notification/app/tests/__init__.py +0 -0
  436. django_spire/notification/app/tests/factories.py +34 -0
  437. django_spire/notification/app/tests/test_apps.py +24 -0
  438. django_spire/notification/app/tests/test_models.py +72 -0
  439. django_spire/notification/app/tests/test_processor.py +111 -0
  440. django_spire/notification/app/tests/test_querysets.py +90 -0
  441. django_spire/notification/app/tests/test_views/__init__.py +0 -0
  442. django_spire/notification/app/tests/test_views/test_json_views.py +48 -0
  443. django_spire/notification/app/tests/test_views/test_page_views.py +19 -0
  444. django_spire/notification/app/urls/__init__.py +3 -1
  445. django_spire/notification/app/urls/json_urls.py +6 -4
  446. django_spire/notification/app/urls/page_urls.py +4 -3
  447. django_spire/notification/app/urls/template_urls.py +4 -2
  448. django_spire/notification/apps.py +4 -1
  449. django_spire/notification/email/admin.py +5 -1
  450. django_spire/notification/email/apps.py +3 -1
  451. django_spire/notification/email/exceptions.py +4 -2
  452. django_spire/notification/email/helper.py +5 -3
  453. django_spire/notification/email/models.py +4 -0
  454. django_spire/notification/email/processor.py +19 -15
  455. django_spire/notification/email/querysets.py +3 -0
  456. django_spire/notification/email/tests/__init__.py +0 -0
  457. django_spire/notification/email/tests/factories.py +35 -0
  458. django_spire/notification/email/tests/test_apps.py +24 -0
  459. django_spire/notification/email/tests/test_models.py +52 -0
  460. django_spire/notification/email/tests/test_processor.py +92 -0
  461. django_spire/notification/email/tests/test_querysets.py +43 -0
  462. django_spire/notification/exceptions.py +17 -2
  463. django_spire/notification/managers.py +7 -1
  464. django_spire/notification/maps.py +4 -1
  465. django_spire/notification/mixins.py +2 -0
  466. django_spire/notification/models.py +3 -1
  467. django_spire/notification/processors/notification.py +12 -5
  468. django_spire/notification/processors/processor.py +2 -0
  469. django_spire/notification/processors/tests/__init__.py +0 -0
  470. django_spire/notification/processors/tests/test_notification.py +106 -0
  471. django_spire/notification/push/admin.py +10 -1
  472. django_spire/notification/push/apps.py +3 -1
  473. django_spire/notification/push/models.py +2 -3
  474. django_spire/notification/push/tests/__init__.py +0 -0
  475. django_spire/notification/push/tests/test_apps.py +24 -0
  476. django_spire/notification/push/tests/test_models.py +28 -0
  477. django_spire/notification/querysets.py +7 -1
  478. django_spire/notification/sms/admin.py +2 -0
  479. django_spire/notification/sms/apps.py +4 -1
  480. django_spire/notification/sms/automations.py +2 -0
  481. django_spire/notification/sms/choices.py +2 -0
  482. django_spire/notification/sms/exceptions.py +19 -5
  483. django_spire/notification/sms/helper.py +33 -23
  484. django_spire/notification/sms/models.py +5 -1
  485. django_spire/notification/sms/processor.py +20 -20
  486. django_spire/notification/sms/querysets.py +2 -0
  487. django_spire/notification/sms/tests/factories.py +33 -0
  488. django_spire/notification/sms/tests/test_apps.py +24 -0
  489. django_spire/notification/sms/tests/test_automation.py +38 -0
  490. django_spire/notification/sms/tests/test_choices.py +15 -0
  491. django_spire/notification/sms/tests/test_consts.py +17 -0
  492. django_spire/notification/sms/tests/test_exceptions.py +27 -0
  493. django_spire/notification/sms/tests/test_helper.py +50 -0
  494. django_spire/notification/sms/tests/test_models.py +81 -0
  495. django_spire/notification/sms/tests/test_processor.py +107 -0
  496. django_spire/notification/sms/tests/test_tools.py +25 -11
  497. django_spire/notification/sms/tools.py +16 -5
  498. django_spire/notification/sms/urls/__init__.py +3 -1
  499. django_spire/notification/sms/urls/media_urls.py +2 -0
  500. django_spire/notification/sms/views/media_views.py +14 -4
  501. django_spire/notification/tests/__init__.py +0 -0
  502. django_spire/notification/tests/factories.py +26 -0
  503. django_spire/notification/tests/test_admin.py +55 -0
  504. django_spire/notification/tests/test_apps.py +30 -0
  505. django_spire/notification/tests/test_automation.py +18 -0
  506. django_spire/notification/tests/test_choices.py +59 -0
  507. django_spire/notification/tests/test_exceptions.py +58 -0
  508. django_spire/notification/tests/test_managers.py +100 -0
  509. django_spire/notification/tests/test_maps.py +31 -0
  510. django_spire/notification/tests/test_models.py +76 -0
  511. django_spire/notification/tests/test_querysets.py +184 -0
  512. django_spire/notification/tests/test_utils.py +23 -0
  513. django_spire/notification/urls.py +3 -1
  514. django_spire/notification/utils.py +3 -1
  515. django_spire/settings.py +3 -0
  516. django_spire/theme/tests/test_context_processor.py +15 -13
  517. django_spire/theme/tests/test_enums.py +2 -2
  518. django_spire/theme/tests/test_filesystem.py +2 -5
  519. django_spire/theme/tests/test_integration.py +12 -12
  520. django_spire/theme/tests/test_model.py +40 -38
  521. django_spire/theme/tests/test_views/test_json_views.py +33 -33
  522. django_spire/theme/urls/json_urls.py +3 -0
  523. django_spire/theme/urls/page_urls.py +3 -0
  524. django_spire/urls.py +19 -15
  525. django_spire/utils.py +13 -4
  526. {django_spire-0.23.7.dist-info → django_spire-0.23.8.dist-info}/METADATA +1 -1
  527. {django_spire-0.23.7.dist-info → django_spire-0.23.8.dist-info}/RECORD +530 -358
  528. django_spire/contrib/options/tests/test_unit.py +0 -148
  529. django_spire/contrib/seeding/tests/test_seeding.py +0 -25
  530. django_spire/core/tests/test_templatetags.py +0 -117
  531. django_spire/core/tests/tests_shortcuts.py +0 -73
  532. django_spire/history/activity/tests.py +0 -3
  533. django_spire/history/activity/views.py +0 -3
  534. django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +0 -71
  535. django_spire/notification/app/tests.py +0 -3
  536. {django_spire-0.23.7.dist-info → django_spire-0.23.8.dist-info}/WHEEL +0 -0
  537. {django_spire-0.23.7.dist-info → django_spire-0.23.8.dist-info}/licenses/LICENSE.md +0 -0
  538. {django_spire-0.23.7.dist-info → django_spire-0.23.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ from django_spire.auth.user.tests.factories import create_user
4
+ from django_spire.core.tests.test_cases import BaseTestCase
5
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
6
+ from django_spire.knowledge.entry.models import Entry
7
+ from django_spire.knowledge.entry.tests.factories import create_test_entry
8
+ from django_spire.knowledge.entry.version.choices import EntryVersionStatusChoices
9
+ from django_spire.knowledge.entry.version.tests.factories import create_test_entry_version
10
+
11
+
12
+ class EntryQuerySetTests(BaseTestCase):
13
+ def setUp(self):
14
+ super().setUp()
15
+ self.user = create_user(username='test_entry_queryset_user')
16
+ self.collection = create_test_collection()
17
+ self.entry = create_test_entry(collection=self.collection)
18
+ self.entry_version = create_test_entry_version(entry=self.entry)
19
+ self.entry.current_version = self.entry_version
20
+ self.entry.save()
21
+
22
+ def test_has_current_version(self):
23
+ result = Entry.objects.has_current_version()
24
+ assert self.entry in result
25
+
26
+ def test_has_current_version_excludes_none(self):
27
+ entry_without_version = create_test_entry(
28
+ collection=self.collection,
29
+ name='No Version'
30
+ )
31
+ result = Entry.objects.has_current_version()
32
+ assert entry_without_version not in result
33
+
34
+ def test_id_in(self):
35
+ entry2 = create_test_entry(collection=self.collection, name='Entry 2')
36
+ result = Entry.objects.id_in([self.entry.pk, entry2.pk])
37
+ assert self.entry in result
38
+ assert entry2 in result
39
+
40
+ def test_user_has_access_published(self):
41
+ self.entry_version.status = EntryVersionStatusChoices.PUBLISHED
42
+ self.entry_version.save()
43
+
44
+ result = Entry.objects.user_has_access(user=self.user)
45
+ assert self.entry in result
46
+
47
+ def test_user_has_access_draft_own(self):
48
+ self.entry_version.status = EntryVersionStatusChoices.DRAFT
49
+ self.entry_version.author = self.user
50
+ self.entry_version.save()
51
+
52
+ result = Entry.objects.user_has_access(user=self.user)
53
+ assert self.entry in result
54
+
55
+ def test_user_has_access_draft_other(self):
56
+ other_user = create_user(username='other_user')
57
+ self.entry_version.status = EntryVersionStatusChoices.DRAFT
58
+ self.entry_version.author = other_user
59
+ self.entry_version.save()
60
+
61
+ result = Entry.objects.user_has_access(user=self.user)
62
+ assert self.entry not in result
63
+
64
+ def test_get_by_version_block_id(self):
65
+ from django_spire.knowledge.entry.version.block.tests.factories import (
66
+ create_test_version_block,
67
+ )
68
+
69
+ version_block = create_test_version_block(version=self.entry_version)
70
+ result = Entry.objects.get_by_version_block_id(version_block_id=version_block.pk)
71
+ assert result == self.entry
@@ -0,0 +1,94 @@
1
+ from __future__ import annotations
2
+
3
+ from django_spire.core.tests.test_cases import BaseTestCase
4
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
5
+ from django_spire.knowledge.entry.models import Entry
6
+ from django_spire.knowledge.entry.tests.factories import create_test_entry
7
+ from django_spire.knowledge.entry.version.tests.factories import create_test_entry_version
8
+
9
+
10
+ class EntryServiceTests(BaseTestCase):
11
+ def setUp(self):
12
+ super().setUp()
13
+ self.collection = create_test_collection()
14
+ self.entry = create_test_entry(collection=self.collection)
15
+
16
+ def test_save_model_obj_creates_new_with_version(self):
17
+ entry, created = Entry.services.save_model_obj(
18
+ author=self.super_user,
19
+ name='New Entry',
20
+ collection=self.collection
21
+ )
22
+ assert created is True
23
+ assert entry.name == 'New Entry'
24
+ assert entry.current_version is not None
25
+
26
+ def test_save_model_obj_updates_existing(self):
27
+ entry_version = create_test_entry_version(entry=self.entry)
28
+ self.entry.current_version = entry_version
29
+ self.entry.save()
30
+
31
+ self.entry.services.obj = self.entry
32
+ updated_entry, created = self.entry.services.save_model_obj(
33
+ author=self.super_user,
34
+ name='Updated Name'
35
+ )
36
+ assert created is False
37
+ assert updated_entry.name == 'Updated Name'
38
+
39
+
40
+ class EntryProcessorServiceTests(BaseTestCase):
41
+ def setUp(self):
42
+ super().setUp()
43
+ self.collection = create_test_collection()
44
+ self.entry = create_test_entry(collection=self.collection)
45
+
46
+ def test_set_deleted(self):
47
+ self.entry.services.processor.set_deleted()
48
+ self.entry.refresh_from_db()
49
+ assert self.entry.is_deleted is True
50
+
51
+
52
+ class EntryToolServiceTests(BaseTestCase):
53
+ def setUp(self):
54
+ super().setUp()
55
+ self.collection = create_test_collection()
56
+ self.entry = create_test_entry(collection=self.collection)
57
+
58
+ def test_get_files_to_convert(self):
59
+ result = Entry.services.tool.get_files_to_convert()
60
+ assert result.count() == 0
61
+
62
+ def test_get_files_to_convert_json(self):
63
+ result = Entry.services.tool.get_files_to_convert_json()
64
+ assert result == '[]'
65
+
66
+
67
+ class EntryTransformationServiceTests(BaseTestCase):
68
+ def setUp(self):
69
+ super().setUp()
70
+ self.collection = create_test_collection()
71
+ self.entry = create_test_entry(collection=self.collection)
72
+ self.entry_version = create_test_entry_version(entry=self.entry)
73
+ self.entry.current_version = self.entry_version
74
+ self.entry.save()
75
+
76
+ def test_to_dict(self):
77
+ self.entry.services.transformation.obj = self.entry
78
+ result = self.entry.services.transformation.to_dict()
79
+
80
+ assert result['entry_id'] == self.entry.pk
81
+ assert result['name'] == self.entry.name
82
+ assert 'version_id' in result
83
+ assert 'author' in result
84
+ assert 'status' in result
85
+ assert 'delete_url' in result
86
+ assert 'edit_url' in result
87
+ assert 'view_url' in result
88
+
89
+ def test_queryset_to_navigation_list(self):
90
+ result = Entry.services.transformation.queryset_to_navigation_list(
91
+ queryset=Entry.objects.filter(pk=self.entry.pk)
92
+ )
93
+ assert len(result) == 1
94
+ assert result[0]['entry_id'] == self.entry.pk
@@ -5,33 +5,29 @@ from django.urls import reverse
5
5
  from django_spire.core.tests.test_cases import BaseTestCase
6
6
  from django_spire.knowledge.collection.tests.factories import create_test_collection
7
7
  from django_spire.knowledge.entry.tests.factories import create_test_entry
8
- from django_spire.knowledge.entry.version.tests.factories import \
9
- create_test_entry_version
8
+ from django_spire.knowledge.entry.version.tests.factories import create_test_entry_version
10
9
 
11
10
 
12
- class EntryPageUrlsTests(BaseTestCase):
11
+ class EntryFormUrlsTests(BaseTestCase):
13
12
  def setUp(self):
14
13
  super().setUp()
15
14
 
16
15
  self.collection = create_test_collection()
17
- self.test_entry = create_test_entry(
18
- collection=self.collection
19
- )
20
- self.test_entry_version = create_test_entry_version(
21
- entry=self.test_entry
22
- )
16
+ self.test_entry = create_test_entry(collection=self.collection)
17
+ self.test_entry_version = create_test_entry_version(entry=self.test_entry)
23
18
  self.test_entry.current_version = self.test_entry_version
24
19
  self.test_entry.save()
25
20
 
26
- def test_form_view_url_path(self):
21
+ def test_create_form_view_url_path(self):
27
22
  response = self.client.get(
28
23
  reverse(
29
24
  'django_spire:knowledge:entry:form:create',
30
25
  kwargs={'collection_pk': self.collection.pk}
31
26
  )
32
27
  )
33
- self.assertEqual(response.status_code, 200)
28
+ assert response.status_code == 200
34
29
 
30
+ def test_update_form_view_url_path(self):
35
31
  response = self.client.get(
36
32
  reverse(
37
33
  'django_spire:knowledge:entry:form:update',
@@ -41,8 +37,7 @@ class EntryPageUrlsTests(BaseTestCase):
41
37
  }
42
38
  )
43
39
  )
44
-
45
- self.assertEqual(response.status_code, 200)
40
+ assert response.status_code == 200
46
41
 
47
42
  def test_import_form_view_url_path(self):
48
43
  response = self.client.get(
@@ -51,4 +46,4 @@ class EntryPageUrlsTests(BaseTestCase):
51
46
  kwargs={'collection_pk': self.collection.pk}
52
47
  )
53
48
  )
54
- self.assertEqual(response.status_code, 200)
49
+ assert response.status_code == 200
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from django.urls import reverse
4
4
 
5
5
  from django_spire.core.tests.test_cases import BaseTestCase
6
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
6
7
  from django_spire.knowledge.entry.tests.factories import create_test_entry
7
8
 
8
9
 
@@ -10,21 +11,63 @@ class EntryJsonUrlsTests(BaseTestCase):
10
11
  def setUp(self):
11
12
  super().setUp()
12
13
 
13
- self.test_entry = create_test_entry()
14
+ self.collection = create_test_collection()
15
+ self.test_entry = create_test_entry(collection=self.collection)
14
16
 
15
17
  def test_reorder_view_url_path(self):
16
18
  response = self.client.post(
17
19
  reverse('django_spire:knowledge:entry:json:reorder'),
18
- data={'entry_id': self.test_entry.pk, 'order': 0},
20
+ data={
21
+ 'entry_id': self.test_entry.pk,
22
+ 'order': 0,
23
+ 'collection_id': self.collection.pk
24
+ },
19
25
  content_type='application/json',
20
26
  )
27
+ assert response.status_code == 200
21
28
 
22
- self.assertEqual(response.status_code, 200)
29
+ def test_reorder_view_invalid_entry(self):
30
+ response = self.client.post(
31
+ reverse('django_spire:knowledge:entry:json:reorder'),
32
+ data={
33
+ 'entry_id': 99999,
34
+ 'order': 0,
35
+ 'collection_id': self.collection.pk
36
+ },
37
+ content_type='application/json',
38
+ )
39
+ assert response.status_code == 200
40
+ assert response.json()['type'] == 'error'
41
+
42
+ def test_reorder_view_missing_order(self):
43
+ response = self.client.post(
44
+ reverse('django_spire:knowledge:entry:json:reorder'),
45
+ data={
46
+ 'entry_id': self.test_entry.pk,
47
+ 'collection_id': self.collection.pk
48
+ },
49
+ content_type='application/json',
50
+ )
51
+ assert response.status_code == 200
52
+ assert response.json()['type'] == 'error'
53
+
54
+ def test_reorder_view_invalid_collection(self):
55
+ response = self.client.post(
56
+ reverse('django_spire:knowledge:entry:json:reorder'),
57
+ data={
58
+ 'entry_id': self.test_entry.pk,
59
+ 'order': 0,
60
+ 'collection_id': 99999
61
+ },
62
+ content_type='application/json',
63
+ )
64
+ assert response.status_code == 200
65
+ assert response.json()['type'] == 'error'
23
66
 
24
67
  def test_update_files_view_url_path(self):
25
68
  response = self.client.post(
26
69
  reverse('django_spire:knowledge:entry:json:update_files'),
27
70
  content_type='application/json',
28
71
  )
29
-
30
- self.assertEqual(response.status_code, 200)
72
+ assert response.status_code == 200
73
+ assert 'files_json' in response.json()
@@ -3,19 +3,18 @@ from __future__ import annotations
3
3
  from django.urls import reverse
4
4
 
5
5
  from django_spire.core.tests.test_cases import BaseTestCase
6
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
6
7
  from django_spire.knowledge.entry.tests.factories import create_test_entry
7
- from django_spire.knowledge.entry.version.tests.factories import \
8
- create_test_entry_version
8
+ from django_spire.knowledge.entry.version.tests.factories import create_test_entry_version
9
9
 
10
10
 
11
11
  class EntryPageUrlsTests(BaseTestCase):
12
12
  def setUp(self):
13
13
  super().setUp()
14
14
 
15
- self.test_entry = create_test_entry()
16
- self.test_entry_version = create_test_entry_version(
17
- entry=self.test_entry
18
- )
15
+ self.collection = create_test_collection()
16
+ self.test_entry = create_test_entry(collection=self.collection)
17
+ self.test_entry_version = create_test_entry_version(entry=self.test_entry)
19
18
  self.test_entry.current_version = self.test_entry_version
20
19
  self.test_entry.save()
21
20
 
@@ -26,5 +25,4 @@ class EntryPageUrlsTests(BaseTestCase):
26
25
  kwargs={'pk': self.test_entry.pk}
27
26
  )
28
27
  )
29
-
30
- self.assertEqual(response.status_code, 200)
28
+ assert response.status_code == 200
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from django.urls import reverse
4
+
5
+ from django_spire.core.tests.test_cases import BaseTestCase
6
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
7
+
8
+
9
+ class EntryTemplateUrlsTests(BaseTestCase):
10
+ def setUp(self):
11
+ super().setUp()
12
+
13
+ self.collection = create_test_collection()
14
+
15
+ def test_file_list_view_url_path(self):
16
+ response = self.client.get(
17
+ reverse(
18
+ 'django_spire:knowledge:entry:template:file_list',
19
+ kwargs={'collection_pk': self.collection.pk}
20
+ )
21
+ )
22
+ assert response.status_code == 200
23
+
24
+ def test_file_list_view_contains_files_json(self):
25
+ response = self.client.get(
26
+ reverse(
27
+ 'django_spire:knowledge:entry:template:file_list',
28
+ kwargs={'collection_pk': self.collection.pk}
29
+ )
30
+ )
31
+ assert 'files_json' in response.context
32
+
33
+ def test_file_list_view_contains_breadcrumbs(self):
34
+ response = self.client.get(
35
+ reverse(
36
+ 'django_spire:knowledge:entry:template:file_list',
37
+ kwargs={'collection_pk': self.collection.pk}
38
+ )
39
+ )
40
+ assert 'breadcrumbs' in response.context
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import path
2
4
 
3
5
  from django_spire.knowledge.entry.views import form_views
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import path
2
4
 
3
5
  from django_spire.knowledge.entry.views import json_views
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import path
2
4
 
3
5
  from django_spire.knowledge.entry.views import page_views
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import path
2
4
 
3
5
  from django_spire.knowledge.entry.views import template_views
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.db.models import TextChoices
2
4
 
3
5
 
@@ -31,4 +31,5 @@ class BaseEditorJsBlockData(BaseModel):
31
31
  NotImplementedError: If the method is not implemented in a subclass.
32
32
 
33
33
  """
34
+
34
35
  raise NotImplementedError
@@ -1,14 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
-
4
3
  from pydantic import model_validator, BaseModel
5
4
 
6
5
  from django_spire.knowledge.entry.version.block.constants import SPACES_PER_INDENT
7
6
  from django_spire.knowledge.entry.version.block.data.data import BaseEditorJsBlockData
8
- from django_spire.knowledge.entry.version.block.data.list.meta import ChecklistItemMeta, \
9
- OrderedListItemMeta
10
- from django_spire.knowledge.entry.version.block.data.list.choices import \
11
- ListEditorBlockDataStyle
7
+ from django_spire.knowledge.entry.version.block.data.list.meta import ChecklistItemMeta, OrderedListItemMeta
8
+ from django_spire.knowledge.entry.version.block.data.list.choices import ListEditorBlockDataStyle
12
9
 
13
10
 
14
11
  class ListEditorBlockData(BaseEditorJsBlockData):
@@ -43,10 +40,10 @@ class ListItemEditorBlockData(BaseModel):
43
40
  items: list[ListItemEditorBlockData] | None = []
44
41
 
45
42
  def get_prefix(
46
- self,
47
- style: ListEditorBlockDataStyle,
48
- indent_level: int,
49
- index = None
43
+ self,
44
+ style: ListEditorBlockDataStyle,
45
+ indent_level: int,
46
+ index = None
50
47
  ):
51
48
  prefix = ' ' * indent_level * SPACES_PER_INDENT
52
49
 
@@ -54,10 +51,8 @@ class ListItemEditorBlockData(BaseModel):
54
51
  index = index or 0
55
52
  start = self.meta.start or 1
56
53
  prefix += f'{start + index}.'
57
-
58
54
  elif style == ListEditorBlockDataStyle.CHECKLIST:
59
55
  prefix += f'[{"X" if self.meta.checked else " "}]'
60
-
61
56
  else:
62
57
  prefix += '-'
63
58
 
@@ -69,12 +64,12 @@ class ListItemEditorBlockData(BaseModel):
69
64
  indent_level: int,
70
65
  index: int
71
66
  ) -> str:
72
- from django_spire.knowledge.entry.version.converters.markdown_converter import \
73
- MarkdownConverter
67
+ from django_spire.knowledge.entry.version.converters.markdown_converter import MarkdownConverter
74
68
 
75
69
  prefix = self.get_prefix(style, indent_level, index)
76
70
  parsed_content = MarkdownConverter.html_to_markdown(self.content)
77
71
  render_string = f'{prefix} {parsed_content}\n'
72
+
78
73
  for i, item in enumerate(self.items):
79
74
  render_string += item.render_to_text(style, indent_level + 1, i)
80
75
 
@@ -2,11 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  from django_spire.knowledge.entry.version.block.data.list import choices, meta
4
4
 
5
+
5
6
  LIST_BLOCK_DATA_META_MAP = {
6
7
  choices.ListEditorBlockDataStyle.ORDERED: meta.OrderedListItemMeta,
7
8
  choices.ListEditorBlockDataStyle.CHECKLIST: meta.ChecklistItemMeta,
8
9
  choices.ListEditorBlockDataStyle.UNORDERED: None,
9
10
  }
11
+
12
+
10
13
  LIST_BLOCK_DATA_REVERSE_META_MAP = {
11
14
  meta.OrderedListItemMeta: choices.ListEditorBlockDataStyle.ORDERED,
12
15
  meta.ChecklistItemMeta: choices.ListEditorBlockDataStyle.CHECKLIST,
@@ -2,8 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
5
- from django_spire.knowledge.entry.version.block.data.list.choices import \
6
- OrderedListCounterType
5
+ from django_spire.knowledge.entry.version.block.data.list.choices import OrderedListCounterType
7
6
 
8
7
 
9
8
  class ChecklistItemMeta(BaseModel):
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ from django_spire.core.tests.test_cases import BaseTestCase
4
+ from django_spire.knowledge.entry.version.block.data.list.choices import ListEditorBlockDataStyle
5
+ from django_spire.knowledge.entry.version.block.data.list.maps import (
6
+ LIST_BLOCK_DATA_META_MAP,
7
+ LIST_BLOCK_DATA_REVERSE_META_MAP,
8
+ )
9
+ from django_spire.knowledge.entry.version.block.data.list.meta import (
10
+ ChecklistItemMeta,
11
+ OrderedListItemMeta,
12
+ )
13
+
14
+
15
+ class ListBlockDataMapTests(BaseTestCase):
16
+ def test_meta_map_ordered(self):
17
+ assert LIST_BLOCK_DATA_META_MAP[ListEditorBlockDataStyle.ORDERED] == OrderedListItemMeta
18
+
19
+ def test_meta_map_checklist(self):
20
+ assert LIST_BLOCK_DATA_META_MAP[ListEditorBlockDataStyle.CHECKLIST] == ChecklistItemMeta
21
+
22
+ def test_meta_map_unordered(self):
23
+ assert LIST_BLOCK_DATA_META_MAP[ListEditorBlockDataStyle.UNORDERED] is None
24
+
25
+ def test_reverse_meta_map_ordered(self):
26
+ assert LIST_BLOCK_DATA_REVERSE_META_MAP[OrderedListItemMeta] == ListEditorBlockDataStyle.ORDERED
27
+
28
+ def test_reverse_meta_map_checklist(self):
29
+ assert LIST_BLOCK_DATA_REVERSE_META_MAP[ChecklistItemMeta] == ListEditorBlockDataStyle.CHECKLIST
30
+
31
+ def test_reverse_meta_map_unordered(self):
32
+ assert LIST_BLOCK_DATA_REVERSE_META_MAP[None] == ListEditorBlockDataStyle.UNORDERED
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ from django_spire.core.tests.test_cases import BaseTestCase
4
+ from django_spire.knowledge.entry.version.block.data.list.choices import OrderedListCounterType
5
+ from django_spire.knowledge.entry.version.block.data.list.meta import (
6
+ ChecklistItemMeta,
7
+ OrderedListItemMeta,
8
+ )
9
+
10
+
11
+ class ChecklistItemMetaTests(BaseTestCase):
12
+ def test_default_unchecked(self):
13
+ meta = ChecklistItemMeta()
14
+ assert meta.checked is False
15
+
16
+ def test_checked_true(self):
17
+ meta = ChecklistItemMeta(checked=True)
18
+ assert meta.checked is True
19
+
20
+ def test_checked_false(self):
21
+ meta = ChecklistItemMeta(checked=False)
22
+ assert meta.checked is False
23
+
24
+
25
+ class OrderedListItemMetaTests(BaseTestCase):
26
+ def test_default_values(self):
27
+ meta = OrderedListItemMeta()
28
+ assert meta.start is None
29
+ assert meta.counterType is None
30
+
31
+ def test_with_start(self):
32
+ meta = OrderedListItemMeta(start=5)
33
+ assert meta.start == 5
34
+
35
+ def test_with_counter_type_numeric(self):
36
+ meta = OrderedListItemMeta(counterType=OrderedListCounterType.NUMERIC)
37
+ assert meta.counterType == OrderedListCounterType.NUMERIC
38
+
39
+ def test_with_counter_type_upper_roman(self):
40
+ meta = OrderedListItemMeta(counterType=OrderedListCounterType.UPPER_ROMAN)
41
+ assert meta.counterType == OrderedListCounterType.UPPER_ROMAN
42
+
43
+ def test_with_counter_type_lower_roman(self):
44
+ meta = OrderedListItemMeta(counterType=OrderedListCounterType.LOWER_ROMAN)
45
+ assert meta.counterType == OrderedListCounterType.LOWER_ROMAN
46
+
47
+ def test_with_counter_type_upper_alpha(self):
48
+ meta = OrderedListItemMeta(counterType=OrderedListCounterType.UPPER_ALPHA)
49
+ assert meta.counterType == OrderedListCounterType.UPPER_ALPHA
50
+
51
+ def test_with_counter_type_lower_alpha(self):
52
+ meta = OrderedListItemMeta(counterType=OrderedListCounterType.LOWER_ALPHA)
53
+ assert meta.counterType == OrderedListCounterType.LOWER_ALPHA
54
+
55
+ def test_with_all_values(self):
56
+ meta = OrderedListItemMeta(start=10, counterType=OrderedListCounterType.NUMERIC)
57
+ assert meta.start == 10
58
+ assert meta.counterType == OrderedListCounterType.NUMERIC
@@ -1,12 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
4
- from django_spire.knowledge.entry.version.block.data.heading_data import \
5
- HeadingEditorBlockData
6
- from django_spire.knowledge.entry.version.block.data.list.data import \
7
- ListEditorBlockData
8
- from django_spire.knowledge.entry.version.block.data.text_data import \
9
- TextEditorBlockData
4
+ from django_spire.knowledge.entry.version.block.data.heading_data import HeadingEditorBlockData
5
+ from django_spire.knowledge.entry.version.block.data.list.data import ListEditorBlockData
6
+ from django_spire.knowledge.entry.version.block.data.text_data import TextEditorBlockData
10
7
 
11
8
 
12
9
  EDITOR_JS_BLOCK_DATA_MAP = {
@@ -1,18 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import TYPE_CHECKING
4
+
3
5
  from django.db import models
4
6
 
5
7
  from django_spire.contrib.ordering.mixins import OrderingModelMixin
6
8
  from django_spire.history.mixins import HistoryModelMixin
7
9
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
8
- from django_spire.knowledge.entry.version.block.data.data import BaseEditorJsBlockData
9
10
  from django_spire.knowledge.entry.version.block.data.maps import EDITOR_JS_BLOCK_DATA_MAP
10
- from django_spire.knowledge.entry.version.block.querysets import \
11
- EntryVersionBlockQuerySet
12
- from django_spire.knowledge.entry.version.block.services.service import \
13
- EntryVersionBlockService
11
+ from django_spire.knowledge.entry.version.block.querysets import EntryVersionBlockQuerySet
12
+ from django_spire.knowledge.entry.version.block.services.service import EntryVersionBlockService
14
13
  from django_spire.knowledge.entry.version.models import EntryVersion
15
14
 
15
+ if TYPE_CHECKING:
16
+ from django_spire.knowledge.entry.version.block.data.data import BaseEditorJsBlockData
17
+
16
18
 
17
19
  class EntryVersionBlock(HistoryModelMixin, OrderingModelMixin):
18
20
  version = models.ForeignKey(
@@ -1,7 +1,8 @@
1
- from django_spire.knowledge.entry.version.block.data.heading_data import \
2
- HeadingEditorBlockData
3
- from django_spire.knowledge.entry.version.block.data.text_data import \
4
- TextEditorBlockData
1
+ from __future__ import annotations
2
+
3
+ from django_spire.knowledge.entry.version.block.data.heading_data import HeadingEditorBlockData
4
+ from django_spire.knowledge.entry.version.block.data.text_data import TextEditorBlockData
5
+
5
6
 
6
7
  LADDER_SAFETY_BLOCKS = [
7
8
  HeadingEditorBlockData(text='Ladder Safety: A Journey Through the Heights',
@@ -3,8 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from django_spire.contrib.service import BaseDjangoModelService
6
- from django_spire.knowledge.entry.version.block.services.factory_service import \
7
- EntryVersionBlockFactoryService
6
+ from django_spire.knowledge.entry.version.block.services.factory_service import EntryVersionBlockFactoryService
8
7
 
9
8
  if TYPE_CHECKING:
10
9
  from django_spire.knowledge.entry.version.block.models import EntryVersionBlock
@@ -12,4 +11,4 @@ if TYPE_CHECKING:
12
11
 
13
12
  class EntryVersionBlockService(BaseDjangoModelService['EntryVersionBlock']):
14
13
  obj: EntryVersionBlock
15
- factory = EntryVersionBlockFactoryService()
14
+ factory = EntryVersionBlockFactoryService()