django-spire 0.23.7__py3-none-any.whl → 0.23.9__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 (542) 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/management/commands/spire_startapp_pkg/template/app/apps.py.template +2 -0
  200. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/__init__.py.template +2 -0
  201. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/form_urls.py.template +2 -0
  202. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/page_urls.py.template +2 -0
  203. django_spire/core/maps.py +3 -1
  204. django_spire/core/middleware/maintenance.py +3 -3
  205. django_spire/core/middleware.py +8 -6
  206. django_spire/core/redirect/__init__.py +5 -0
  207. django_spire/core/redirect/generic_redirect.py +1 -2
  208. django_spire/core/redirect/tests/__init__.py +0 -0
  209. django_spire/core/redirect/tests/test_generic_redirect.py +34 -0
  210. django_spire/core/{tests/tests_redirect.py → redirect/tests/test_safe_redirect.py} +55 -81
  211. django_spire/core/shortcuts.py +3 -3
  212. django_spire/core/static/django_spire/css/app-layout.css +1 -1
  213. django_spire/core/static/django_spire/css/app-navigation.css +3 -3
  214. django_spire/core/static/django_spire/css/bootstrap-override.css +4 -0
  215. django_spire/core/tag/admin.py +12 -0
  216. django_spire/core/tag/intelligence/tag_set_bot.py +2 -0
  217. django_spire/core/tag/mixins.py +2 -0
  218. django_spire/core/tag/models.py +2 -0
  219. django_spire/core/tag/querysets.py +2 -0
  220. django_spire/core/tag/service/tag_service.py +6 -3
  221. django_spire/core/tag/tests/test_intelligence.py +9 -9
  222. django_spire/core/tag/tests/test_tags.py +44 -54
  223. django_spire/core/tag/tests/test_tools.py +191 -0
  224. django_spire/core/tag/tools.py +3 -0
  225. django_spire/core/templates/django_spire/card/card.html +5 -2
  226. django_spire/core/templates/django_spire/card/title_card.html +12 -4
  227. django_spire/core/templates/django_spire/infinite_scroll/base.html +1 -0
  228. django_spire/core/templates/django_spire/navigation/side_navigation.html +19 -24
  229. django_spire/core/templates/django_spire/page/full_page.html +46 -16
  230. django_spire/core/templates/django_spire/table/base.html +5 -3
  231. django_spire/core/templatetags/json.py +6 -2
  232. django_spire/core/templatetags/message.py +13 -8
  233. django_spire/core/templatetags/string_formating.py +8 -5
  234. django_spire/core/templatetags/tests/__init__.py +0 -0
  235. django_spire/core/templatetags/tests/test_templatetags.py +427 -0
  236. django_spire/core/templatetags/variable_types.py +17 -9
  237. django_spire/core/tests/test_cases.py +1 -1
  238. django_spire/core/tests/test_conf.py +43 -0
  239. django_spire/core/tests/test_consts.py +28 -0
  240. django_spire/core/tests/test_context_processors.py +93 -0
  241. django_spire/core/tests/test_decorators.py +95 -0
  242. django_spire/core/tests/test_django_spire_utils.py +56 -0
  243. django_spire/core/tests/test_exceptions.py +37 -0
  244. django_spire/core/tests/test_models.py +54 -0
  245. django_spire/core/tests/test_settings.py +45 -0
  246. django_spire/core/tests/test_shortcuts.py +74 -0
  247. django_spire/core/tests/test_urls.py +16 -0
  248. django_spire/core/tests/test_utils.py +58 -0
  249. django_spire/core/urls.py +4 -1
  250. django_spire/core/utils.py +12 -8
  251. django_spire/exceptions.py +16 -1
  252. django_spire/file/admin.py +4 -2
  253. django_spire/file/apps.py +8 -10
  254. django_spire/file/fields.py +7 -7
  255. django_spire/file/forms.py +1 -1
  256. django_spire/file/interfaces.py +15 -15
  257. django_spire/file/mixins.py +1 -4
  258. django_spire/file/models.py +3 -5
  259. django_spire/file/tests/factories.py +59 -0
  260. django_spire/file/tests/test_admin.py +69 -0
  261. django_spire/file/tests/test_apps.py +24 -0
  262. django_spire/file/tests/test_fields.py +114 -0
  263. django_spire/file/tests/test_forms.py +20 -0
  264. django_spire/file/tests/test_interfaces.py +183 -0
  265. django_spire/file/tests/test_models.py +82 -0
  266. django_spire/file/tests/test_querysets.py +102 -0
  267. django_spire/file/tests/test_utils.py +32 -0
  268. django_spire/file/tests/test_views.py +145 -0
  269. django_spire/file/tests/test_widgets.py +82 -0
  270. django_spire/file/tools.py +8 -2
  271. django_spire/file/views.py +7 -3
  272. django_spire/file/widgets.py +12 -12
  273. django_spire/help_desk/admin.py +15 -0
  274. django_spire/help_desk/apps.py +2 -0
  275. django_spire/help_desk/auth/controller.py +2 -0
  276. django_spire/help_desk/choices.py +2 -0
  277. django_spire/help_desk/enums.py +2 -0
  278. django_spire/help_desk/exceptions.py +31 -3
  279. django_spire/help_desk/forms.py +2 -0
  280. django_spire/help_desk/models.py +2 -0
  281. django_spire/help_desk/querysets.py +4 -1
  282. django_spire/help_desk/services/notification_service.py +26 -27
  283. django_spire/help_desk/services/service.py +2 -3
  284. django_spire/help_desk/tests/factories.py +8 -3
  285. django_spire/help_desk/tests/test_admin.py +41 -0
  286. django_spire/help_desk/tests/test_apps.py +41 -0
  287. django_spire/help_desk/tests/test_choices.py +50 -0
  288. django_spire/help_desk/tests/test_controller.py +87 -0
  289. django_spire/help_desk/tests/test_enums.py +18 -0
  290. django_spire/help_desk/tests/test_exceptions.py +37 -0
  291. django_spire/help_desk/tests/test_forms.py +89 -0
  292. django_spire/help_desk/tests/test_models.py +59 -0
  293. django_spire/help_desk/tests/test_querysets.py +38 -0
  294. django_spire/help_desk/tests/test_services/test_notification_service.py +15 -8
  295. django_spire/help_desk/tests/test_services/test_service.py +92 -0
  296. django_spire/help_desk/tests/test_urls/test_form_urls.py +6 -6
  297. django_spire/help_desk/tests/test_urls/test_page_urls.py +8 -9
  298. django_spire/help_desk/tests/test_views/test_form_views.py +46 -19
  299. django_spire/help_desk/tests/test_views/test_page_views.py +32 -9
  300. django_spire/help_desk/urls/__init__.py +4 -1
  301. django_spire/help_desk/urls/form_urls.py +3 -0
  302. django_spire/help_desk/urls/page_urls.py +3 -0
  303. django_spire/help_desk/views/form_views.py +13 -5
  304. django_spire/help_desk/views/page_views.py +11 -3
  305. django_spire/history/activity/admin.py +2 -0
  306. django_spire/history/activity/apps.py +3 -1
  307. django_spire/history/activity/mixins.py +13 -7
  308. django_spire/history/activity/models.py +6 -5
  309. django_spire/history/activity/querysets.py +2 -0
  310. django_spire/history/activity/tests/__init__.py +0 -0
  311. django_spire/history/activity/tests/test_activity.py +176 -0
  312. django_spire/history/admin.py +9 -2
  313. django_spire/history/choices.py +3 -0
  314. django_spire/history/models.py +5 -5
  315. django_spire/history/tests/test_admin.py +93 -0
  316. django_spire/history/tests/test_history.py +101 -0
  317. django_spire/history/tests/test_mixins.py +84 -0
  318. django_spire/history/viewed/admin.py +3 -1
  319. django_spire/history/viewed/apps.py +3 -1
  320. django_spire/history/viewed/models.py +2 -0
  321. django_spire/history/viewed/tests/__init__.py +0 -0
  322. django_spire/history/viewed/tests/test_viewed.py +46 -0
  323. django_spire/knowledge/auth/tests/__init__.py +0 -0
  324. django_spire/knowledge/auth/tests/test_controller.py +116 -0
  325. django_spire/knowledge/collection/admin.py +5 -1
  326. django_spire/knowledge/collection/models.py +3 -1
  327. django_spire/knowledge/collection/seeding/seed.py +1 -0
  328. django_spire/knowledge/collection/services/factory_service.py +10 -11
  329. django_spire/knowledge/collection/services/ordering_service.py +1 -2
  330. django_spire/knowledge/collection/services/service.py +5 -10
  331. django_spire/knowledge/collection/services/tag_service.py +5 -2
  332. django_spire/knowledge/collection/tests/factories.py +28 -1
  333. django_spire/knowledge/collection/tests/test_models.py +48 -0
  334. django_spire/knowledge/collection/tests/test_querysets.py +93 -0
  335. django_spire/knowledge/collection/tests/test_services/test_factory_service.py +100 -0
  336. django_spire/knowledge/collection/tests/test_services/test_services.py +160 -0
  337. django_spire/knowledge/collection/tests/test_urls/test_form_urls.py +21 -3
  338. django_spire/knowledge/collection/tests/test_urls/test_json_urls.py +39 -1
  339. django_spire/knowledge/collection/tests/test_urls/test_page_urls.py +12 -4
  340. django_spire/knowledge/collection/urls/__init__.py +3 -0
  341. django_spire/knowledge/collection/urls/form_urls.py +2 -0
  342. django_spire/knowledge/collection/urls/json_urls.py +2 -0
  343. django_spire/knowledge/collection/urls/page_urls.py +2 -0
  344. django_spire/knowledge/collection/views/form_views.py +4 -4
  345. django_spire/knowledge/collection/views/json_views.py +5 -1
  346. django_spire/knowledge/collection/views/page_views.py +5 -2
  347. django_spire/knowledge/entry/admin.py +7 -1
  348. django_spire/knowledge/entry/forms.py +2 -0
  349. django_spire/knowledge/entry/models.py +2 -0
  350. django_spire/knowledge/entry/seeding/seed.py +3 -0
  351. django_spire/knowledge/entry/services/automation_service.py +5 -4
  352. django_spire/knowledge/entry/services/factory_service.py +7 -5
  353. django_spire/knowledge/entry/services/service.py +4 -7
  354. django_spire/knowledge/entry/services/tag_service.py +0 -1
  355. django_spire/knowledge/entry/services/tool_service.py +1 -0
  356. django_spire/knowledge/entry/services/transformation_services.py +1 -5
  357. django_spire/knowledge/entry/tests/factories.py +1 -2
  358. django_spire/knowledge/entry/tests/test_factory_service.py +20 -0
  359. django_spire/knowledge/entry/tests/test_models.py +41 -0
  360. django_spire/knowledge/entry/tests/test_querysets.py +71 -0
  361. django_spire/knowledge/entry/tests/test_services.py +94 -0
  362. django_spire/knowledge/entry/tests/test_urls/test_form_urls.py +9 -14
  363. django_spire/knowledge/entry/tests/test_urls/test_json_urls.py +48 -5
  364. django_spire/knowledge/entry/tests/test_urls/test_page_urls.py +6 -8
  365. django_spire/knowledge/entry/tests/test_urls/test_template_urls.py +40 -0
  366. django_spire/knowledge/entry/urls/form_urls.py +2 -0
  367. django_spire/knowledge/entry/urls/json_urls.py +2 -0
  368. django_spire/knowledge/entry/urls/page_urls.py +2 -0
  369. django_spire/knowledge/entry/urls/template_urls.py +2 -0
  370. django_spire/knowledge/entry/version/block/choices.py +2 -0
  371. django_spire/knowledge/entry/version/block/data/data.py +1 -0
  372. django_spire/knowledge/entry/version/block/data/list/data.py +8 -13
  373. django_spire/knowledge/entry/version/block/data/list/maps.py +3 -0
  374. django_spire/knowledge/entry/version/block/data/list/meta.py +1 -2
  375. django_spire/knowledge/entry/version/block/data/list/tests/__init__.py +0 -0
  376. django_spire/knowledge/entry/version/block/data/list/tests/test_maps.py +32 -0
  377. django_spire/knowledge/entry/version/block/data/list/tests/test_meta.py +58 -0
  378. django_spire/knowledge/entry/version/block/data/maps.py +3 -6
  379. django_spire/knowledge/entry/version/block/models.py +7 -5
  380. django_spire/knowledge/entry/version/block/seeding/constants.py +5 -4
  381. django_spire/knowledge/entry/version/block/services/service.py +2 -3
  382. django_spire/knowledge/entry/version/block/tests/factories.py +4 -10
  383. django_spire/knowledge/entry/version/block/tests/test_choices.py +56 -0
  384. django_spire/knowledge/entry/version/block/tests/test_data.py +90 -0
  385. django_spire/knowledge/entry/version/block/tests/test_maps.py +37 -0
  386. django_spire/knowledge/entry/version/block/tests/test_models.py +55 -0
  387. django_spire/knowledge/entry/version/block/tests/test_querysets.py +35 -0
  388. django_spire/knowledge/entry/version/block/tests/test_services.py +65 -0
  389. django_spire/knowledge/entry/version/choices.py +2 -0
  390. django_spire/knowledge/entry/version/converters/converter.py +1 -1
  391. django_spire/knowledge/entry/version/converters/docx_converter.py +4 -7
  392. django_spire/knowledge/entry/version/converters/markdown_converter.py +20 -20
  393. django_spire/knowledge/entry/version/maps.py +4 -5
  394. django_spire/knowledge/entry/version/querysets.py +1 -1
  395. django_spire/knowledge/entry/version/seeding/seeder.py +1 -2
  396. django_spire/knowledge/entry/version/services/processor_service.py +5 -4
  397. django_spire/knowledge/entry/version/services/service.py +1 -2
  398. django_spire/knowledge/entry/version/tests/factories.py +2 -2
  399. django_spire/knowledge/entry/version/tests/test_choices.py +18 -0
  400. django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +56 -8
  401. django_spire/knowledge/entry/version/tests/test_converters/test_markdown_converter.py +78 -0
  402. django_spire/knowledge/entry/version/tests/test_maps.py +58 -0
  403. django_spire/knowledge/entry/version/tests/test_models.py +23 -0
  404. django_spire/knowledge/entry/version/tests/test_querysets.py +26 -0
  405. django_spire/knowledge/entry/version/tests/test_services.py +62 -0
  406. django_spire/knowledge/entry/version/tests/test_urls/test_json_urls.py +27 -8
  407. django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +15 -8
  408. django_spire/knowledge/entry/version/tests/test_urls/test_redirect_urls.py +38 -0
  409. django_spire/knowledge/entry/version/urls/__init__.py +3 -0
  410. django_spire/knowledge/entry/version/urls/json_urls.py +2 -1
  411. django_spire/knowledge/entry/version/urls/page_urls.py +2 -0
  412. django_spire/knowledge/entry/version/urls/redirect_urls.py +2 -0
  413. django_spire/knowledge/entry/version/views/json_views.py +5 -1
  414. django_spire/knowledge/entry/version/views/page_views.py +10 -3
  415. django_spire/knowledge/entry/version/views/redirect_views.py +5 -1
  416. django_spire/knowledge/entry/views/form_views.py +16 -8
  417. django_spire/knowledge/entry/views/json_views.py +3 -1
  418. django_spire/knowledge/entry/views/page_views.py +8 -2
  419. django_spire/knowledge/entry/views/template_views.py +7 -1
  420. django_spire/knowledge/exceptions.py +2 -1
  421. django_spire/knowledge/intelligence/intel/answer_intel.py +2 -1
  422. django_spire/knowledge/intelligence/intel/entry_intel.py +0 -1
  423. django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +4 -5
  424. django_spire/knowledge/models.py +1 -2
  425. django_spire/knowledge/tests/__init__.py +0 -0
  426. django_spire/knowledge/tests/test_templatetags.py +40 -0
  427. django_spire/knowledge/tests/test_urls/__init__.py +0 -0
  428. django_spire/knowledge/tests/test_urls/test_page_urls.py +24 -0
  429. django_spire/knowledge/urls/__init__.py +2 -0
  430. django_spire/knowledge/urls/page_urls.py +2 -0
  431. django_spire/knowledge/views/page_views.py +8 -3
  432. django_spire/notification/admin.py +3 -1
  433. django_spire/notification/app/admin.py +2 -0
  434. django_spire/notification/app/apps.py +3 -1
  435. django_spire/notification/app/exceptions.py +9 -2
  436. django_spire/notification/app/models.py +8 -4
  437. django_spire/notification/app/processor.py +22 -26
  438. django_spire/notification/app/querysets.py +2 -0
  439. django_spire/notification/app/tests/__init__.py +0 -0
  440. django_spire/notification/app/tests/factories.py +34 -0
  441. django_spire/notification/app/tests/test_apps.py +24 -0
  442. django_spire/notification/app/tests/test_models.py +72 -0
  443. django_spire/notification/app/tests/test_processor.py +111 -0
  444. django_spire/notification/app/tests/test_querysets.py +90 -0
  445. django_spire/notification/app/tests/test_views/__init__.py +0 -0
  446. django_spire/notification/app/tests/test_views/test_json_views.py +48 -0
  447. django_spire/notification/app/tests/test_views/test_page_views.py +19 -0
  448. django_spire/notification/app/urls/__init__.py +3 -1
  449. django_spire/notification/app/urls/json_urls.py +6 -4
  450. django_spire/notification/app/urls/page_urls.py +4 -3
  451. django_spire/notification/app/urls/template_urls.py +4 -2
  452. django_spire/notification/apps.py +4 -1
  453. django_spire/notification/email/admin.py +5 -1
  454. django_spire/notification/email/apps.py +3 -1
  455. django_spire/notification/email/exceptions.py +4 -2
  456. django_spire/notification/email/helper.py +5 -3
  457. django_spire/notification/email/models.py +4 -0
  458. django_spire/notification/email/processor.py +19 -15
  459. django_spire/notification/email/querysets.py +3 -0
  460. django_spire/notification/email/tests/__init__.py +0 -0
  461. django_spire/notification/email/tests/factories.py +35 -0
  462. django_spire/notification/email/tests/test_apps.py +24 -0
  463. django_spire/notification/email/tests/test_models.py +52 -0
  464. django_spire/notification/email/tests/test_processor.py +92 -0
  465. django_spire/notification/email/tests/test_querysets.py +43 -0
  466. django_spire/notification/exceptions.py +17 -2
  467. django_spire/notification/managers.py +7 -1
  468. django_spire/notification/maps.py +4 -1
  469. django_spire/notification/mixins.py +2 -0
  470. django_spire/notification/models.py +3 -1
  471. django_spire/notification/processors/notification.py +12 -5
  472. django_spire/notification/processors/processor.py +2 -0
  473. django_spire/notification/processors/tests/__init__.py +0 -0
  474. django_spire/notification/processors/tests/test_notification.py +106 -0
  475. django_spire/notification/push/admin.py +10 -1
  476. django_spire/notification/push/apps.py +3 -1
  477. django_spire/notification/push/models.py +2 -3
  478. django_spire/notification/push/tests/__init__.py +0 -0
  479. django_spire/notification/push/tests/test_apps.py +24 -0
  480. django_spire/notification/push/tests/test_models.py +28 -0
  481. django_spire/notification/querysets.py +7 -1
  482. django_spire/notification/sms/admin.py +2 -0
  483. django_spire/notification/sms/apps.py +4 -1
  484. django_spire/notification/sms/automations.py +2 -0
  485. django_spire/notification/sms/choices.py +2 -0
  486. django_spire/notification/sms/exceptions.py +19 -5
  487. django_spire/notification/sms/helper.py +33 -23
  488. django_spire/notification/sms/models.py +5 -1
  489. django_spire/notification/sms/processor.py +20 -20
  490. django_spire/notification/sms/querysets.py +2 -0
  491. django_spire/notification/sms/tests/factories.py +33 -0
  492. django_spire/notification/sms/tests/test_apps.py +24 -0
  493. django_spire/notification/sms/tests/test_automation.py +38 -0
  494. django_spire/notification/sms/tests/test_choices.py +15 -0
  495. django_spire/notification/sms/tests/test_consts.py +17 -0
  496. django_spire/notification/sms/tests/test_exceptions.py +27 -0
  497. django_spire/notification/sms/tests/test_helper.py +50 -0
  498. django_spire/notification/sms/tests/test_models.py +81 -0
  499. django_spire/notification/sms/tests/test_processor.py +107 -0
  500. django_spire/notification/sms/tests/test_tools.py +25 -11
  501. django_spire/notification/sms/tools.py +16 -5
  502. django_spire/notification/sms/urls/__init__.py +3 -1
  503. django_spire/notification/sms/urls/media_urls.py +2 -0
  504. django_spire/notification/sms/views/media_views.py +14 -4
  505. django_spire/notification/tests/__init__.py +0 -0
  506. django_spire/notification/tests/factories.py +26 -0
  507. django_spire/notification/tests/test_admin.py +55 -0
  508. django_spire/notification/tests/test_apps.py +30 -0
  509. django_spire/notification/tests/test_automation.py +18 -0
  510. django_spire/notification/tests/test_choices.py +59 -0
  511. django_spire/notification/tests/test_exceptions.py +58 -0
  512. django_spire/notification/tests/test_managers.py +100 -0
  513. django_spire/notification/tests/test_maps.py +31 -0
  514. django_spire/notification/tests/test_models.py +76 -0
  515. django_spire/notification/tests/test_querysets.py +184 -0
  516. django_spire/notification/tests/test_utils.py +23 -0
  517. django_spire/notification/urls.py +3 -1
  518. django_spire/notification/utils.py +3 -1
  519. django_spire/settings.py +3 -0
  520. django_spire/theme/tests/test_context_processor.py +15 -13
  521. django_spire/theme/tests/test_enums.py +2 -2
  522. django_spire/theme/tests/test_filesystem.py +2 -5
  523. django_spire/theme/tests/test_integration.py +12 -12
  524. django_spire/theme/tests/test_model.py +40 -38
  525. django_spire/theme/tests/test_views/test_json_views.py +33 -33
  526. django_spire/theme/urls/json_urls.py +3 -0
  527. django_spire/theme/urls/page_urls.py +3 -0
  528. django_spire/urls.py +19 -15
  529. django_spire/utils.py +13 -4
  530. {django_spire-0.23.7.dist-info → django_spire-0.23.9.dist-info}/METADATA +2 -2
  531. {django_spire-0.23.7.dist-info → django_spire-0.23.9.dist-info}/RECORD +534 -362
  532. {django_spire-0.23.7.dist-info → django_spire-0.23.9.dist-info}/licenses/LICENSE.md +1 -1
  533. django_spire/contrib/options/tests/test_unit.py +0 -148
  534. django_spire/contrib/seeding/tests/test_seeding.py +0 -25
  535. django_spire/core/tests/test_templatetags.py +0 -117
  536. django_spire/core/tests/tests_shortcuts.py +0 -73
  537. django_spire/history/activity/tests.py +0 -3
  538. django_spire/history/activity/views.py +0 -3
  539. django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +0 -71
  540. django_spire/notification/app/tests.py +0 -3
  541. {django_spire-0.23.7.dist-info → django_spire-0.23.9.dist-info}/WHEEL +0 -0
  542. {django_spire-0.23.7.dist-info → django_spire-0.23.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,160 @@
1
+ from __future__ import annotations
2
+
3
+ # import json
4
+
5
+ from django.contrib.sites.models import Site
6
+ # from django.conf import settings
7
+ # from django.test import RequestFactory
8
+
9
+ from django_spire.core.tests.test_cases import BaseTestCase
10
+ from django_spire.knowledge.collection.models import Collection
11
+ from django_spire.knowledge.collection.tests.factories import create_test_collection
12
+
13
+
14
+ class CollectionServiceTests(BaseTestCase):
15
+ def setUp(self):
16
+ super().setUp()
17
+ self.collection = create_test_collection()
18
+
19
+ def test_save_model_obj_creates_new(self):
20
+ collection, created = Collection.services.save_model_obj(
21
+ name='New Collection',
22
+ description='A new collection'
23
+ )
24
+ assert created is True
25
+ assert collection.name == 'New Collection'
26
+
27
+ def test_save_model_obj_updates_existing(self):
28
+ self.collection.services.obj = self.collection
29
+ updated_collection, created = self.collection.services.save_model_obj(
30
+ name='Updated Name'
31
+ )
32
+ assert created is False
33
+ assert updated_collection.name == 'Updated Name'
34
+
35
+
36
+ class CollectionOrderingServiceTests(BaseTestCase):
37
+ def setUp(self):
38
+ super().setUp()
39
+ self.parent = create_test_collection(name='Parent')
40
+ self.child1 = create_test_collection(parent=self.parent, name='Child 1')
41
+ self.child2 = create_test_collection(parent=self.parent, name='Child 2')
42
+
43
+ def test_reorder_within_same_parent(self):
44
+ self.child2.services.ordering.reorder(order=0, new_parent_pk=self.parent.pk)
45
+ self.child1.refresh_from_db()
46
+ self.child2.refresh_from_db()
47
+ assert self.child2.order <= self.child1.order
48
+
49
+ def test_reorder_to_new_parent(self):
50
+ new_parent = create_test_collection(name='New Parent')
51
+ self.child1.services.ordering.reorder(order=0, new_parent_pk=new_parent.pk)
52
+ self.child1.refresh_from_db()
53
+ assert self.child1.parent_id == new_parent.pk
54
+
55
+ def test_reorder_to_root(self):
56
+ self.child1.services.ordering.reorder(order=0, new_parent_pk=None)
57
+ self.child1.refresh_from_db()
58
+ assert self.child1.parent_id is None
59
+
60
+
61
+ class CollectionProcessorServiceTests(BaseTestCase):
62
+ def setUp(self):
63
+ super().setUp()
64
+ self.parent = create_test_collection(name='Parent')
65
+ self.child = create_test_collection(parent=self.parent, name='Child')
66
+
67
+ def test_set_deleted(self):
68
+ self.parent.services.processor.set_deleted()
69
+ self.parent.refresh_from_db()
70
+ assert self.parent.is_deleted is True
71
+
72
+ def test_set_deleted_cascades_to_children(self):
73
+ self.parent.services.processor.set_deleted()
74
+ self.child.refresh_from_db()
75
+ assert self.child.is_deleted is True
76
+
77
+
78
+ class CollectionToolServiceTests(BaseTestCase):
79
+ def setUp(self):
80
+ super().setUp()
81
+ self.parent = create_test_collection(name='Parent')
82
+ self.child = create_test_collection(parent=self.parent, name='Child')
83
+ self.grandchild = create_test_collection(parent=self.child, name='Grandchild')
84
+
85
+ def test_get_children_ids(self):
86
+ children_ids = Collection.services.tool.get_children_ids(parent_id=self.parent.pk)
87
+ assert self.child.pk in children_ids
88
+ assert self.grandchild.pk in children_ids
89
+ assert self.parent.pk not in children_ids
90
+
91
+ def test_get_root_collection_pk(self):
92
+ self.grandchild.services.tool.obj = self.grandchild
93
+ root_pk = self.grandchild.services.tool.get_root_collection_pk()
94
+ assert root_pk == self.parent.pk
95
+
96
+ def test_get_root_collection_pk_when_already_root(self):
97
+ self.parent.services.tool.obj = self.parent
98
+ root_pk = self.parent.services.tool.get_root_collection_pk()
99
+ assert root_pk == self.parent.pk
100
+
101
+
102
+ class TestCollectionTransformationService(BaseTestCase):
103
+ def setUp(self):
104
+ super().setUp()
105
+ self.site = Site.objects.create(domain='', name='')
106
+
107
+ def _test_collection_urls_json(self, collection_json: dict):
108
+ response = self.client.get(collection_json['delete_url'].replace(' ', ''))
109
+ assert response.status_code == 200
110
+
111
+ response = self.client.get(collection_json['create_entry_url'].replace(' ', ''))
112
+ assert response.status_code == 200
113
+
114
+ response = self.client.get(collection_json['import_entry_url'].replace(' ', ''))
115
+ assert response.status_code == 200
116
+
117
+ # # TODO(Tyrell): Talk to Chase about this
118
+ # def test_to_hierarchy_json(self):
119
+ # settings.SITE_ID = self.site.id
120
+
121
+ # self.test_collection_1 = Collection.objects.create(name='Grand Parent A', id=1, parent_id=None)
122
+ # self.test_collection_2 = Collection.objects.create(name='Parent A1', id=2, parent_id=1)
123
+ # self.test_collection_3 = Collection.objects.create(name='Child A1a', id=3, parent_id=2)
124
+
125
+ # request = RequestFactory().get('/')
126
+ # request.user = self.super_user
127
+
128
+ # family_tree = Collection.services.transformation.to_hierarchy_json(
129
+ # request=request
130
+ # )
131
+
132
+ # for collection_json in json.loads(family_tree):
133
+ # assert collection_json['id'] is not None
134
+ # assert collection_json['name'] == 'Grand Parent A'
135
+
136
+ # assert len(collection_json['entries']) == 0
137
+
138
+ # self._test_collection_urls_json(collection_json=collection_json)
139
+
140
+ # assert len(collection_json['children']) == 1
141
+
142
+ # for child_json in collection_json['children']:
143
+ # assert child_json['id'] is not None
144
+ # assert child_json['name'] == 'Parent A1'
145
+
146
+ # assert len(child_json['entries']) == 0
147
+
148
+ # self._test_collection_urls_json(collection_json=child_json)
149
+
150
+ # assert len(child_json['children']) == 1
151
+
152
+ # for grand_child_json in child_json['children']:
153
+ # assert grand_child_json['id'] is not None
154
+ # assert grand_child_json['name'] == 'Child A1a'
155
+
156
+ # assert len(grand_child_json['entries']) == 0
157
+
158
+ # self._test_collection_urls_json(collection_json=grand_child_json)
159
+
160
+ # assert len(grand_child_json['children']) == 0
@@ -3,17 +3,35 @@ 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
 
7
8
 
8
9
  class CollectionFormUrlsTests(BaseTestCase):
9
10
  def setUp(self):
10
11
  super().setUp()
11
12
 
12
- def test_form_view_url_path(self):
13
+ self.collection = create_test_collection()
14
+
15
+ def test_create_form_view_url_path(self):
16
+ response = self.client.get(
17
+ reverse('django_spire:knowledge:collection:form:create')
18
+ )
19
+ assert response.status_code == 200
20
+
21
+ def test_create_with_parent_form_view_url_path(self):
13
22
  response = self.client.get(
14
23
  reverse(
15
- 'django_spire:knowledge:collection:form:create',
24
+ 'django_spire:knowledge:collection:form:create_with_parent',
25
+ kwargs={'parent_pk': self.collection.pk}
16
26
  )
17
27
  )
28
+ assert response.status_code == 200
18
29
 
19
- self.assertEqual(response.status_code, 200)
30
+ def test_update_form_view_url_path(self):
31
+ response = self.client.get(
32
+ reverse(
33
+ 'django_spire:knowledge:collection:form:update',
34
+ kwargs={'pk': self.collection.pk}
35
+ )
36
+ )
37
+ assert response.status_code == 200
@@ -21,5 +21,43 @@ class CollectionJsonUrlsTests(BaseTestCase):
21
21
  },
22
22
  content_type='application/json',
23
23
  )
24
+ assert response.status_code == 200
24
25
 
25
- self.assertEqual(response.status_code, 200)
26
+ def test_reorder_view_with_parent(self):
27
+ child_collection = create_test_collection(
28
+ parent=self.test_collection,
29
+ name='Child Collection'
30
+ )
31
+ response = self.client.post(
32
+ reverse('django_spire:knowledge:collection:json:reorder'),
33
+ data={
34
+ 'collection_id': child_collection.pk,
35
+ 'order': 0,
36
+ 'parent': self.test_collection.pk
37
+ },
38
+ content_type='application/json',
39
+ )
40
+ assert response.status_code == 200
41
+
42
+ def test_reorder_view_invalid_collection(self):
43
+ response = self.client.post(
44
+ reverse('django_spire:knowledge:collection:json:reorder'),
45
+ data={
46
+ 'collection_id': 99999,
47
+ 'order': 0
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_missing_order(self):
55
+ response = self.client.post(
56
+ reverse('django_spire:knowledge:collection:json:reorder'),
57
+ data={
58
+ 'collection_id': self.test_collection.pk,
59
+ },
60
+ content_type='application/json',
61
+ )
62
+ assert response.status_code == 200
63
+ assert response.json()['type'] == 'error'
@@ -9,8 +9,18 @@ from django_spire.knowledge.collection.tests.factories import create_test_collec
9
9
  class CollectionPageUrlsTests(BaseTestCase):
10
10
  def setUp(self):
11
11
  super().setUp()
12
+
12
13
  self.test_collection = create_test_collection()
13
14
 
15
+ def test_top_level_view_url_path(self):
16
+ response = self.client.get(
17
+ reverse(
18
+ 'django_spire:knowledge:collection:page:top_level',
19
+ kwargs={'pk': self.test_collection.pk}
20
+ )
21
+ )
22
+ assert response.status_code == 200
23
+
14
24
  def test_delete_view_url_path(self):
15
25
  response = self.client.get(
16
26
  reverse(
@@ -18,12 +28,10 @@ class CollectionPageUrlsTests(BaseTestCase):
18
28
  kwargs={'pk': self.test_collection.pk}
19
29
  )
20
30
  )
21
-
22
- self.assertEqual(response.status_code, 200)
31
+ assert response.status_code == 200
23
32
 
24
33
  def test_list_view_url_path(self):
25
34
  response = self.client.get(
26
35
  reverse('django_spire:knowledge:page:home')
27
36
  )
28
-
29
- self.assertEqual(response.status_code, 200)
37
+ assert response.status_code == 200
@@ -1,7 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import include, path
2
4
 
3
5
  from django_spire.knowledge.collection import views
4
6
 
7
+
5
8
  app_name = 'collection'
6
9
 
7
10
  urlpatterns = [
@@ -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.collection.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.collection.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.collection.views import page_views
@@ -22,9 +22,9 @@ if TYPE_CHECKING:
22
22
 
23
23
  @AppAuthController('knowledge').permission_required('can_add')
24
24
  def form_view(
25
- request: WSGIRequest,
26
- pk: int = 0,
27
- parent_pk: int = None,
25
+ request: WSGIRequest,
26
+ pk: int = 0,
27
+ parent_pk: int = None
28
28
  ) -> TemplateResponse | HttpResponseRedirect:
29
29
  collection = get_object_or_null_obj(Collection, pk=pk)
30
30
 
@@ -55,7 +55,7 @@ def form_view(
55
55
  if form.is_valid():
56
56
  collection, _ = collection.services.save_model_obj(**form.cleaned_data)
57
57
 
58
- _ = CollectionGroup.services.factory.replace_groups(
58
+ CollectionGroup.services.factory.replace_groups(
59
59
  request=request,
60
60
  group_pks=dict(request.POST).get('groups'),
61
61
  collection=collection,
@@ -2,13 +2,17 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
 
5
- from django.core.handlers.wsgi import WSGIRequest
5
+ from typing import TYPE_CHECKING
6
+
6
7
  from django.http import JsonResponse
7
8
 
8
9
  from django_spire.core.decorators import valid_ajax_request_required
9
10
  from django_spire.core.shortcuts import get_object_or_null_obj
10
11
  from django_spire.knowledge.collection.models import Collection
11
12
 
13
+ if TYPE_CHECKING:
14
+ from django.core.handlers.wsgi import WSGIRequest
15
+
12
16
 
13
17
  @valid_ajax_request_required
14
18
  def reorder_view(request: WSGIRequest) -> JsonResponse:
@@ -1,14 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- from django.core.handlers.wsgi import WSGIRequest
4
3
  from django.shortcuts import get_object_or_404
5
- from django.template.response import TemplateResponse
6
4
  from django.urls import reverse
7
5
 
8
6
  from django_spire.auth.controller.controller import AppAuthController
9
7
  from django_spire.contrib import Breadcrumbs
10
8
  from django_spire.contrib.generic_views import portal_views
11
9
  from django_spire.knowledge.collection.models import Collection
10
+ from typing import TYPE_CHECKING
11
+
12
+ if TYPE_CHECKING:
13
+ from django.core.handlers.wsgi import WSGIRequest
14
+ from django.template.response import TemplateResponse
12
15
 
13
16
 
14
17
  @AppAuthController('knowledge').permission_required('can_view')
@@ -1,11 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
1
5
  from django.contrib import admin, messages
2
- from django.db.models import QuerySet
3
6
  from django.urls import reverse
4
7
  from django.utils.html import format_html
5
8
  from django.utils.http import urlencode
6
9
 
7
10
  from django_spire.knowledge.entry.models import Entry
8
11
 
12
+ if TYPE_CHECKING:
13
+ from django.db.models import QuerySet
14
+
9
15
 
10
16
  @admin.register(Entry)
11
17
  class EntryAdmin(admin.ModelAdmin):
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django import forms
2
4
 
3
5
  from django_spire.knowledge.entry.models import Entry
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.db import models
2
4
  from django.urls import reverse
3
5
 
@@ -1,3 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.entry.seeding.seeder import EntrySeeder
2
4
 
5
+
3
6
  EntrySeeder.seed_database(count=50)
@@ -1,14 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import traceback
4
- from typing import TYPE_CHECKING
5
4
 
6
- import json
5
+ from typing import TYPE_CHECKING
7
6
 
8
7
  from django_spire.contrib.service import BaseDjangoModelService
9
8
  from django_spire.core.decorators import close_db_connections
10
9
  from django_spire.knowledge.entry.version.block.models import EntryVersionBlock
11
- from django_spire.knowledge.exceptions import KnowledgeBaseConversionException
10
+ from django_spire.knowledge.exceptions import KnowledgeBaseConversionError
12
11
 
13
12
  if TYPE_CHECKING:
14
13
  from django_spire.knowledge.entry.models import Entry
@@ -41,11 +40,13 @@ class EntryAutomationService(BaseDjangoModelService['Entry']):
41
40
  file_object.set_deleted()
42
41
 
43
42
  message = f'Files Converted: {len(file_objects) - len(errored)}'
43
+
44
44
  if errored:
45
45
  error_string = f'\n{message}\nFiles Errored:'
46
+
46
47
  for error in errored:
47
48
  error_string += f' File Name: {error["file"]}\n Error: {error["error"]}'
48
49
 
49
- raise KnowledgeBaseConversionException(error_string)
50
+ raise KnowledgeBaseConversionError(error_string)
50
51
 
51
52
  return message
@@ -4,11 +4,11 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from django.contrib.contenttypes.models import ContentType
6
6
 
7
- from django_spire.auth.user.models import AuthUser
8
7
  from django_spire.contrib.service import BaseDjangoModelService
9
8
  from django_spire.file.models import File
10
9
 
11
10
  if TYPE_CHECKING:
11
+ from django_spire.auth.user.models import AuthUser
12
12
  from django_spire.knowledge.entry.models import Entry
13
13
  from django_spire.knowledge.collection.models import Collection
14
14
 
@@ -17,18 +17,20 @@ class EntryFactoryService(BaseDjangoModelService['Entry']):
17
17
  obj: Entry
18
18
 
19
19
  def create_from_files(
20
- self,
21
- author: AuthUser,
22
- collection: Collection,
23
- files: list[File],
20
+ self,
21
+ author: AuthUser,
22
+ collection: Collection,
23
+ files: list[File]
24
24
  ) -> list[Entry]:
25
25
  entries = []
26
+
26
27
  for file in files:
27
28
  entry, _ = self.obj_class.services.save_model_obj(
28
29
  name=file.name,
29
30
  author=author,
30
31
  collection=collection
31
32
  )
33
+
32
34
  entries.append(entry)
33
35
 
34
36
  file.content_type = ContentType.objects.get_for_model(entry.__class__)
@@ -2,21 +2,18 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from django_spire.auth.user.models import AuthUser
6
5
  from django_spire.contrib.ordering.services.service import OrderingService
7
6
  from django_spire.contrib.service import BaseDjangoModelService
8
- from django_spire.knowledge.entry.services.automation_service import \
9
- EntryAutomationService
7
+ from django_spire.knowledge.entry.services.automation_service import EntryAutomationService
10
8
  from django_spire.knowledge.entry.services.factory_service import EntryFactoryService
11
- from django_spire.knowledge.entry.services.processor_service import \
12
- EntryProcessorService
9
+ from django_spire.knowledge.entry.services.processor_service import EntryProcessorService
13
10
  from django_spire.knowledge.entry.services.tag_service import EntryTagService
14
11
  from django_spire.knowledge.entry.services.tool_service import EntryToolService
15
- from django_spire.knowledge.entry.services.transformation_services import \
16
- EntryTransformationService
12
+ from django_spire.knowledge.entry.services.transformation_services import EntryTransformationService
17
13
  from django_spire.knowledge.entry.version.models import EntryVersion
18
14
 
19
15
  if TYPE_CHECKING:
16
+ from django_spire.auth.user.models import AuthUser
20
17
  from django_spire.knowledge.entry.models import Entry
21
18
 
22
19
 
@@ -11,7 +11,6 @@ if TYPE_CHECKING:
11
11
  from django_spire.knowledge.entry.models import Entry
12
12
 
13
13
 
14
-
15
14
  class EntryTagService(BaseTagService['Entry']):
16
15
  obj: Entry
17
16
 
@@ -11,6 +11,7 @@ from django_spire.file.models import File
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from django.db.models import QuerySet
14
+
14
15
  from django_spire.knowledge.entry.models import Entry
15
16
 
16
17
 
@@ -18,11 +18,7 @@ class EntryTransformationService(BaseDjangoModelService['Entry']):
18
18
 
19
19
  @staticmethod
20
20
  def queryset_to_navigation_list(queryset: QuerySet[Entry]) -> list[dict[str, str]]:
21
- json_list = []
22
- for entry in queryset:
23
- json_list.append(entry.services.transformation.to_dict())
24
-
25
- return json_list
21
+ return [entry.services.transformation.to_dict() for entry in queryset]
26
22
 
27
23
  def to_dict(self):
28
24
  site = Site.objects.get_current() if not settings.DEBUG else ''
@@ -6,11 +6,10 @@ from django_spire.knowledge.entry.models import Entry
6
6
 
7
7
  def create_test_entry(**kwargs) -> Entry:
8
8
  data = {
9
- 'collection': create_test_collection(),
9
+ 'collection': kwargs.pop('collection', None) or create_test_collection(),
10
10
  'name': 'Video Game Cheat Codes',
11
11
  'is_deleted': False,
12
12
  'is_active': True
13
13
  }
14
-
15
14
  data.update(kwargs)
16
15
  return Entry.objects.create(**data)
@@ -0,0 +1,20 @@
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
+
7
+
8
+ class EntryFactoryServiceTests(BaseTestCase):
9
+ def setUp(self):
10
+ super().setUp()
11
+
12
+ self.collection = create_test_collection()
13
+
14
+ def test_create_from_files_empty_list(self):
15
+ entries = Entry.services.factory.create_from_files(
16
+ author=self.super_user,
17
+ collection=self.collection,
18
+ files=[]
19
+ )
20
+ assert entries == []
@@ -0,0 +1,41 @@
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.tests.factories import create_test_entry
6
+
7
+
8
+ class EntryModelTests(BaseTestCase):
9
+ def setUp(self):
10
+ super().setUp()
11
+
12
+ self.collection = create_test_collection()
13
+ self.entry = create_test_entry(collection=self.collection)
14
+
15
+ def test_str(self):
16
+ assert str(self.entry) == self.entry.name
17
+
18
+ def test_name_short_truncates(self):
19
+ long_name = 'A' * 100
20
+ entry = create_test_entry(name=long_name, collection=self.collection)
21
+ assert len(entry.name_short) <= 35
22
+
23
+ def test_name_short_no_truncate(self):
24
+ short_name = 'Short'
25
+ entry = create_test_entry(name=short_name, collection=self.collection)
26
+ assert entry.name_short == short_name
27
+
28
+ def test_top_level_collection(self):
29
+ child_collection = create_test_collection(
30
+ parent=self.collection,
31
+ name='Child Collection'
32
+ )
33
+ entry = create_test_entry(collection=child_collection)
34
+ assert entry.top_level_collection == self.collection
35
+
36
+ def test_top_level_collection_when_already_top(self):
37
+ assert self.entry.top_level_collection == self.collection
38
+
39
+ def test_base_breadcrumb(self):
40
+ breadcrumbs = self.entry.base_breadcrumb()
41
+ assert breadcrumbs is not None