django-spire 0.23.6__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.
- django_spire/ai/admin.py +11 -11
- django_spire/ai/chat/apps.py +1 -0
- django_spire/ai/chat/templates/django_spire/ai/chat/widget/dialog_widget.html +1 -1
- django_spire/ai/chat/tests/factories.py +15 -0
- django_spire/ai/chat/tests/test_controller.py +45 -0
- django_spire/ai/chat/tests/test_models.py +301 -0
- django_spire/ai/chat/tests/test_prompts.py +48 -0
- django_spire/ai/chat/tests/test_responses.py +208 -0
- django_spire/ai/chat/tests/test_router/test_base_chat_router.py +66 -6
- django_spire/ai/chat/tests/test_router/test_chat_workflow.py +73 -3
- django_spire/ai/chat/tests/test_router/test_integration.py +86 -6
- django_spire/ai/chat/tests/test_router/test_intent_decoder.py +93 -1
- django_spire/ai/chat/tests/test_router/test_message_intel.py +60 -1
- django_spire/ai/chat/tests/test_router/test_spire_chat_router.py +110 -0
- django_spire/ai/chat/tests/test_urls/test_json_urls.py +202 -1
- django_spire/ai/context/tests/__init__.py +0 -0
- django_spire/ai/context/tests/test_context.py +188 -0
- django_spire/ai/decorators.py +7 -6
- django_spire/ai/prompt/tests/test_bots.py +100 -10
- django_spire/ai/prompt/tests/test_prompt_intel.py +83 -0
- django_spire/ai/prompt/tests/test_prompt_tuning.py +126 -0
- django_spire/ai/sms/decorators.py +8 -2
- django_spire/ai/sms/tests/test_sms.py +240 -16
- django_spire/ai/sms/tests/test_sms_intel.py +42 -0
- django_spire/ai/sms/tests/test_webhook.py +155 -7
- django_spire/ai/sms/views.py +23 -24
- django_spire/ai/tests/test_ai.py +131 -7
- django_spire/auth/apps.py +4 -2
- django_spire/auth/controller/controller.py +36 -23
- django_spire/auth/controller/exceptions.py +9 -0
- django_spire/auth/group/admin.py +1 -0
- django_spire/auth/group/apps.py +2 -0
- django_spire/auth/group/factories.py +17 -8
- django_spire/auth/group/forms.py +7 -0
- django_spire/auth/group/tests/test_factories.py +146 -0
- django_spire/auth/group/tests/test_forms.py +282 -0
- django_spire/auth/group/tests/test_models.py +192 -0
- django_spire/auth/group/tests/test_querysets.py +98 -0
- django_spire/auth/group/tests/test_utils.py +341 -0
- django_spire/auth/group/tests/test_views.py +377 -0
- django_spire/auth/group/urls/__init__.py +3 -1
- django_spire/auth/group/urls/form_urls.py +2 -0
- django_spire/auth/group/urls/json_urls.py +3 -0
- django_spire/auth/group/urls/page_urls.py +2 -0
- django_spire/auth/group/utils.py +6 -2
- django_spire/auth/group/views/form_views.py +6 -3
- django_spire/auth/group/views/json_views.py +6 -2
- django_spire/auth/mfa/admin.py +2 -0
- django_spire/auth/mfa/apps.py +2 -0
- django_spire/auth/mfa/forms.py +1 -0
- django_spire/auth/mfa/querysets.py +9 -2
- django_spire/auth/mfa/tests/test_models.py +233 -0
- django_spire/auth/mfa/tests/test_utils.py +106 -0
- django_spire/auth/mfa/urls/__init__.py +2 -0
- django_spire/auth/mfa/urls/page_urls.py +2 -0
- django_spire/auth/mfa/urls/redirect_urls.py +2 -0
- django_spire/auth/mfa/views/page_views.py +2 -1
- django_spire/auth/permissions/consts.py +2 -2
- django_spire/auth/permissions/decorators.py +8 -8
- django_spire/auth/permissions/permissions.py +28 -35
- django_spire/auth/permissions/tests/test_decorators.py +333 -0
- django_spire/auth/permissions/tests/test_permissions.py +337 -0
- django_spire/auth/permissions/tests/test_tools.py +305 -0
- django_spire/auth/permissions/tools.py +21 -15
- django_spire/auth/seeding/seed.py +3 -0
- django_spire/auth/seeding/seeder.py +2 -0
- django_spire/auth/tests/test_controller.py +323 -0
- django_spire/auth/tests/test_url_endpoints.py +9 -9
- django_spire/auth/tests/test_views.py +406 -0
- django_spire/auth/urls/admin_urls.py +2 -0
- django_spire/auth/urls/redirect_urls.py +2 -0
- django_spire/auth/user/apps.py +2 -0
- django_spire/auth/user/forms.py +9 -0
- django_spire/auth/user/models.py +1 -1
- django_spire/auth/user/services/services.py +1 -0
- django_spire/auth/user/tests/factories.py +14 -13
- django_spire/auth/user/tests/test_factories.py +166 -2
- django_spire/auth/user/tests/test_forms.py +573 -0
- django_spire/auth/user/tests/test_models.py +257 -0
- django_spire/auth/user/tests/test_services.py +200 -0
- django_spire/auth/user/tests/test_tools.py +153 -0
- django_spire/auth/user/tests/test_user_factories.py +139 -0
- django_spire/auth/user/tests/test_views.py +363 -0
- django_spire/auth/user/tools.py +7 -1
- django_spire/auth/user/urls/form_urls.py +3 -0
- django_spire/auth/user/urls/page_urls.py +3 -0
- django_spire/auth/user/views/form_views.py +19 -10
- django_spire/auth/user/views/page_views.py +8 -2
- django_spire/auth/views/redirect_views.py +14 -9
- django_spire/comment/admin.py +2 -0
- django_spire/comment/apps.py +2 -0
- django_spire/comment/templatetags/comment_tags.py +1 -0
- django_spire/comment/tests/test_forms.py +27 -0
- django_spire/comment/tests/test_models.py +215 -0
- django_spire/comment/tests/test_querysets.py +101 -0
- django_spire/comment/tests/test_utils.py +90 -0
- django_spire/comment/urls.py +2 -0
- django_spire/comment/utils.py +22 -13
- django_spire/comment/views.py +1 -1
- django_spire/conf.py +8 -6
- django_spire/consts.py +1 -1
- django_spire/contrib/breadcrumb/apps.py +2 -0
- django_spire/contrib/breadcrumb/breadcrumbs.py +18 -18
- django_spire/contrib/breadcrumb/tests/test_breadcrumbs.py +198 -0
- django_spire/contrib/constructor/__init__.py +3 -3
- django_spire/contrib/constructor/constructor.py +15 -15
- django_spire/contrib/constructor/django_model_constructor.py +5 -4
- django_spire/contrib/constructor/exceptions.py +5 -3
- django_spire/contrib/constructor/tests/__init__.py +0 -0
- django_spire/contrib/constructor/tests/test_constructor.py +193 -0
- django_spire/contrib/form/tests/__init__.py +0 -0
- django_spire/contrib/form/tests/test_forms.py +203 -0
- django_spire/contrib/generic_views/modal_views.py +2 -1
- django_spire/contrib/generic_views/portal_views.py +20 -19
- django_spire/contrib/generic_views/tests/__init__.py +0 -0
- django_spire/contrib/generic_views/tests/test_views.py +459 -0
- django_spire/contrib/help/apps.py +2 -0
- django_spire/contrib/help/templatetags/help.py +1 -0
- django_spire/contrib/help/tests/__init__.py +0 -0
- django_spire/contrib/help/tests/test_templatetags.py +100 -0
- django_spire/contrib/options/mixins.py +6 -5
- django_spire/contrib/options/tests/factories.py +5 -1
- django_spire/contrib/options/tests/test_options.py +234 -0
- django_spire/contrib/ordering/exceptions.py +7 -3
- django_spire/contrib/ordering/mixins.py +2 -0
- django_spire/contrib/ordering/querysets.py +3 -1
- django_spire/contrib/ordering/services/processor_service.py +8 -4
- django_spire/contrib/ordering/services/service.py +1 -2
- django_spire/contrib/ordering/tests/__init__.py +0 -0
- django_spire/contrib/ordering/tests/test_ordering.py +165 -0
- django_spire/contrib/ordering/validators.py +6 -6
- django_spire/contrib/pagination/templatetags/pagination_tags.py +12 -5
- django_spire/contrib/pagination/tests/__init__.py +0 -0
- django_spire/contrib/pagination/tests/test_pagination.py +179 -0
- django_spire/contrib/performance/decorators.py +16 -6
- django_spire/contrib/performance/tests/__init__.py +0 -0
- django_spire/contrib/performance/tests/test_performance.py +107 -0
- django_spire/contrib/progress/__init__.py +1 -3
- django_spire/contrib/progress/static/django_spire/js/contrib/progress/progress.js +38 -82
- django_spire/contrib/queryset/enums.py +3 -1
- django_spire/contrib/queryset/filter_tools.py +10 -5
- django_spire/contrib/queryset/mixins.py +16 -16
- django_spire/contrib/queryset/tests/__init__.py +0 -0
- django_spire/contrib/queryset/tests/test_queryset.py +137 -0
- django_spire/contrib/seeding/field/base.py +13 -7
- django_spire/contrib/seeding/field/callable.py +8 -1
- django_spire/contrib/seeding/field/cleaners.py +5 -5
- django_spire/contrib/seeding/field/custom.py +20 -10
- django_spire/contrib/seeding/field/django/seeder.py +8 -6
- django_spire/contrib/seeding/field/enums.py +7 -5
- django_spire/contrib/seeding/field/override.py +16 -6
- django_spire/contrib/seeding/field/static.py +9 -2
- django_spire/contrib/seeding/field/tests/test_base.py +18 -14
- django_spire/contrib/seeding/field/tests/test_callable.py +13 -9
- django_spire/contrib/seeding/field/tests/test_cleaners.py +51 -38
- django_spire/contrib/seeding/field/tests/test_static.py +13 -9
- django_spire/contrib/seeding/intelligence/bots/seeder_generator_bot.py +2 -0
- django_spire/contrib/seeding/intelligence/intel.py +5 -1
- django_spire/contrib/seeding/intelligence/prompts/factory.py +6 -1
- django_spire/contrib/seeding/intelligence/prompts/foreign_key_selection_prompt.py +6 -1
- django_spire/contrib/seeding/intelligence/prompts/generate_django_model_seeder_prompts.py +2 -0
- django_spire/contrib/seeding/intelligence/prompts/generic_relationship_selection_prompt.py +7 -1
- django_spire/contrib/seeding/intelligence/prompts/hierarchical_selection_prompt.py +6 -2
- django_spire/contrib/seeding/intelligence/prompts/model_field_choices_prompt.py +8 -2
- django_spire/contrib/seeding/intelligence/prompts/negation_prompt.py +2 -0
- django_spire/contrib/seeding/intelligence/prompts/objective_prompt.py +6 -1
- django_spire/contrib/seeding/management/commands/seeding.py +9 -3
- django_spire/contrib/seeding/management/example.py +2 -0
- django_spire/contrib/seeding/model/base.py +16 -7
- django_spire/contrib/seeding/model/config.py +31 -15
- django_spire/contrib/seeding/model/django/config.py +13 -13
- django_spire/contrib/seeding/model/django/seeder.py +4 -4
- django_spire/contrib/seeding/model/django/tests/test_seeder.py +34 -23
- django_spire/contrib/seeding/model/enums.py +2 -0
- django_spire/contrib/seeding/tests/test_config.py +71 -0
- django_spire/contrib/seeding/tests/test_custom.py +35 -0
- django_spire/contrib/seeding/tests/test_enums.py +40 -0
- django_spire/contrib/seeding/tests/test_intel.py +32 -0
- django_spire/contrib/seeding/tests/test_override.py +63 -0
- django_spire/contrib/service/__init__.py +2 -2
- django_spire/contrib/service/django_model_service.py +16 -15
- django_spire/contrib/service/exceptions.py +5 -3
- django_spire/contrib/service/tests/__init__.py +0 -0
- django_spire/contrib/service/tests/test_service.py +153 -0
- django_spire/contrib/session/apps.py +2 -0
- django_spire/contrib/session/controller.py +48 -42
- django_spire/contrib/session/templatetags/session_tags.py +11 -2
- django_spire/contrib/session/tests/test_session_controller.py +117 -53
- django_spire/contrib/tests/__init__.py +0 -0
- django_spire/contrib/tests/test_utils.py +37 -0
- django_spire/contrib/utils.py +4 -1
- django_spire/core/apps.py +2 -0
- django_spire/core/converters/tests/test_to_data.py +353 -0
- django_spire/core/converters/tests/test_to_enums.py +61 -41
- django_spire/core/converters/tests/test_to_pydantic.py +138 -109
- django_spire/core/converters/to_data.py +29 -10
- django_spire/core/converters/to_enums.py +4 -2
- django_spire/core/converters/to_pydantic.py +22 -22
- django_spire/core/decorators.py +19 -6
- django_spire/core/forms/widgets.py +4 -0
- django_spire/core/maps.py +3 -1
- django_spire/core/middleware/maintenance.py +3 -3
- django_spire/core/middleware.py +8 -6
- django_spire/core/redirect/__init__.py +5 -0
- django_spire/core/redirect/generic_redirect.py +1 -2
- django_spire/core/redirect/tests/__init__.py +0 -0
- django_spire/core/redirect/tests/test_generic_redirect.py +34 -0
- django_spire/core/{tests/tests_redirect.py → redirect/tests/test_safe_redirect.py} +55 -81
- django_spire/core/shortcuts.py +3 -3
- django_spire/core/static/django_spire/css/app-layout.css +1 -1
- django_spire/core/static/django_spire/css/app-navigation.css +3 -3
- django_spire/core/static/django_spire/css/bootstrap-override.css +4 -0
- django_spire/core/tag/admin.py +12 -0
- django_spire/core/tag/intelligence/tag_set_bot.py +2 -0
- django_spire/core/tag/mixins.py +2 -0
- django_spire/core/tag/models.py +2 -0
- django_spire/core/tag/querysets.py +2 -0
- django_spire/core/tag/service/tag_service.py +6 -3
- django_spire/core/tag/tests/test_intelligence.py +9 -9
- django_spire/core/tag/tests/test_tags.py +44 -54
- django_spire/core/tag/tests/test_tools.py +191 -0
- django_spire/core/tag/tools.py +3 -0
- django_spire/core/templates/django_spire/card/card.html +5 -2
- django_spire/core/templates/django_spire/card/title_card.html +9 -4
- django_spire/core/templates/django_spire/infinite_scroll/base.html +1 -0
- django_spire/core/templates/django_spire/navigation/side_navigation.html +19 -24
- django_spire/core/templates/django_spire/page/full_page.html +46 -16
- django_spire/core/templates/django_spire/table/base.html +4 -2
- django_spire/core/templatetags/json.py +6 -2
- django_spire/core/templatetags/message.py +13 -8
- django_spire/core/templatetags/string_formating.py +8 -5
- django_spire/core/templatetags/tests/__init__.py +0 -0
- django_spire/core/templatetags/tests/test_templatetags.py +427 -0
- django_spire/core/templatetags/variable_types.py +17 -9
- django_spire/core/tests/test_cases.py +1 -1
- django_spire/core/tests/test_conf.py +43 -0
- django_spire/core/tests/test_consts.py +28 -0
- django_spire/core/tests/test_context_processors.py +93 -0
- django_spire/core/tests/test_decorators.py +95 -0
- django_spire/core/tests/test_django_spire_utils.py +56 -0
- django_spire/core/tests/test_exceptions.py +37 -0
- django_spire/core/tests/test_models.py +54 -0
- django_spire/core/tests/test_settings.py +45 -0
- django_spire/core/tests/test_shortcuts.py +74 -0
- django_spire/core/tests/test_urls.py +16 -0
- django_spire/core/tests/test_utils.py +58 -0
- django_spire/core/urls.py +4 -1
- django_spire/core/utils.py +12 -8
- django_spire/exceptions.py +16 -1
- django_spire/file/admin.py +4 -2
- django_spire/file/apps.py +8 -10
- django_spire/file/fields.py +7 -7
- django_spire/file/forms.py +1 -1
- django_spire/file/interfaces.py +15 -15
- django_spire/file/mixins.py +1 -4
- django_spire/file/models.py +3 -5
- django_spire/file/tests/factories.py +59 -0
- django_spire/file/tests/test_admin.py +69 -0
- django_spire/file/tests/test_apps.py +24 -0
- django_spire/file/tests/test_fields.py +114 -0
- django_spire/file/tests/test_forms.py +20 -0
- django_spire/file/tests/test_interfaces.py +183 -0
- django_spire/file/tests/test_models.py +82 -0
- django_spire/file/tests/test_querysets.py +102 -0
- django_spire/file/tests/test_utils.py +32 -0
- django_spire/file/tests/test_views.py +145 -0
- django_spire/file/tests/test_widgets.py +82 -0
- django_spire/file/tools.py +8 -2
- django_spire/file/views.py +7 -3
- django_spire/file/widgets.py +12 -12
- django_spire/help_desk/admin.py +15 -0
- django_spire/help_desk/apps.py +2 -0
- django_spire/help_desk/auth/controller.py +2 -0
- django_spire/help_desk/choices.py +2 -0
- django_spire/help_desk/enums.py +2 -0
- django_spire/help_desk/exceptions.py +31 -3
- django_spire/help_desk/forms.py +2 -0
- django_spire/help_desk/models.py +2 -0
- django_spire/help_desk/querysets.py +4 -1
- django_spire/help_desk/services/notification_service.py +26 -27
- django_spire/help_desk/services/service.py +2 -3
- django_spire/help_desk/tests/factories.py +8 -3
- django_spire/help_desk/tests/test_admin.py +41 -0
- django_spire/help_desk/tests/test_apps.py +41 -0
- django_spire/help_desk/tests/test_choices.py +50 -0
- django_spire/help_desk/tests/test_controller.py +87 -0
- django_spire/help_desk/tests/test_enums.py +18 -0
- django_spire/help_desk/tests/test_exceptions.py +37 -0
- django_spire/help_desk/tests/test_forms.py +89 -0
- django_spire/help_desk/tests/test_models.py +59 -0
- django_spire/help_desk/tests/test_querysets.py +38 -0
- django_spire/help_desk/tests/test_services/test_notification_service.py +15 -8
- django_spire/help_desk/tests/test_services/test_service.py +92 -0
- django_spire/help_desk/tests/test_urls/test_form_urls.py +6 -6
- django_spire/help_desk/tests/test_urls/test_page_urls.py +8 -9
- django_spire/help_desk/tests/test_views/test_form_views.py +46 -19
- django_spire/help_desk/tests/test_views/test_page_views.py +32 -9
- django_spire/help_desk/urls/__init__.py +4 -1
- django_spire/help_desk/urls/form_urls.py +3 -0
- django_spire/help_desk/urls/page_urls.py +3 -0
- django_spire/help_desk/views/form_views.py +13 -5
- django_spire/help_desk/views/page_views.py +11 -3
- django_spire/history/activity/admin.py +2 -0
- django_spire/history/activity/apps.py +3 -1
- django_spire/history/activity/mixins.py +13 -7
- django_spire/history/activity/models.py +6 -5
- django_spire/history/activity/querysets.py +2 -0
- django_spire/history/activity/tests/__init__.py +0 -0
- django_spire/history/activity/tests/test_activity.py +176 -0
- django_spire/history/admin.py +9 -2
- django_spire/history/choices.py +3 -0
- django_spire/history/models.py +5 -5
- django_spire/history/tests/test_admin.py +93 -0
- django_spire/history/tests/test_history.py +101 -0
- django_spire/history/tests/test_mixins.py +84 -0
- django_spire/history/viewed/admin.py +3 -1
- django_spire/history/viewed/apps.py +3 -1
- django_spire/history/viewed/models.py +2 -0
- django_spire/history/viewed/tests/__init__.py +0 -0
- django_spire/history/viewed/tests/test_viewed.py +46 -0
- django_spire/knowledge/auth/tests/__init__.py +0 -0
- django_spire/knowledge/auth/tests/test_controller.py +116 -0
- django_spire/knowledge/collection/admin.py +5 -1
- django_spire/knowledge/collection/models.py +3 -1
- django_spire/knowledge/collection/seeding/seed.py +1 -0
- django_spire/knowledge/collection/services/factory_service.py +10 -11
- django_spire/knowledge/collection/services/ordering_service.py +1 -2
- django_spire/knowledge/collection/services/service.py +5 -10
- django_spire/knowledge/collection/services/tag_service.py +5 -2
- django_spire/knowledge/collection/tests/factories.py +28 -1
- django_spire/knowledge/collection/tests/test_models.py +48 -0
- django_spire/knowledge/collection/tests/test_querysets.py +93 -0
- django_spire/knowledge/collection/tests/test_services/test_factory_service.py +100 -0
- django_spire/knowledge/collection/tests/test_services/test_services.py +160 -0
- django_spire/knowledge/collection/tests/test_urls/test_form_urls.py +21 -3
- django_spire/knowledge/collection/tests/test_urls/test_json_urls.py +39 -1
- django_spire/knowledge/collection/tests/test_urls/test_page_urls.py +12 -4
- django_spire/knowledge/collection/urls/__init__.py +3 -0
- django_spire/knowledge/collection/urls/form_urls.py +2 -0
- django_spire/knowledge/collection/urls/json_urls.py +2 -0
- django_spire/knowledge/collection/urls/page_urls.py +2 -0
- django_spire/knowledge/collection/views/form_views.py +4 -4
- django_spire/knowledge/collection/views/json_views.py +5 -1
- django_spire/knowledge/collection/views/page_views.py +5 -2
- django_spire/knowledge/entry/admin.py +7 -1
- django_spire/knowledge/entry/forms.py +2 -0
- django_spire/knowledge/entry/models.py +2 -0
- django_spire/knowledge/entry/seeding/seed.py +3 -0
- django_spire/knowledge/entry/services/automation_service.py +5 -4
- django_spire/knowledge/entry/services/factory_service.py +7 -5
- django_spire/knowledge/entry/services/service.py +4 -7
- django_spire/knowledge/entry/services/tag_service.py +0 -1
- django_spire/knowledge/entry/services/tool_service.py +1 -0
- django_spire/knowledge/entry/services/transformation_services.py +1 -5
- django_spire/knowledge/entry/tests/factories.py +1 -2
- django_spire/knowledge/entry/tests/test_factory_service.py +20 -0
- django_spire/knowledge/entry/tests/test_models.py +41 -0
- django_spire/knowledge/entry/tests/test_querysets.py +71 -0
- django_spire/knowledge/entry/tests/test_services.py +94 -0
- django_spire/knowledge/entry/tests/test_urls/test_form_urls.py +9 -14
- django_spire/knowledge/entry/tests/test_urls/test_json_urls.py +48 -5
- django_spire/knowledge/entry/tests/test_urls/test_page_urls.py +6 -8
- django_spire/knowledge/entry/tests/test_urls/test_template_urls.py +40 -0
- django_spire/knowledge/entry/urls/form_urls.py +2 -0
- django_spire/knowledge/entry/urls/json_urls.py +2 -0
- django_spire/knowledge/entry/urls/page_urls.py +2 -0
- django_spire/knowledge/entry/urls/template_urls.py +2 -0
- django_spire/knowledge/entry/version/block/choices.py +2 -0
- django_spire/knowledge/entry/version/block/data/data.py +1 -0
- django_spire/knowledge/entry/version/block/data/list/data.py +8 -13
- django_spire/knowledge/entry/version/block/data/list/maps.py +3 -0
- django_spire/knowledge/entry/version/block/data/list/meta.py +1 -2
- django_spire/knowledge/entry/version/block/data/list/tests/__init__.py +0 -0
- django_spire/knowledge/entry/version/block/data/list/tests/test_maps.py +32 -0
- django_spire/knowledge/entry/version/block/data/list/tests/test_meta.py +58 -0
- django_spire/knowledge/entry/version/block/data/maps.py +3 -6
- django_spire/knowledge/entry/version/block/models.py +7 -5
- django_spire/knowledge/entry/version/block/seeding/constants.py +5 -4
- django_spire/knowledge/entry/version/block/services/service.py +2 -3
- django_spire/knowledge/entry/version/block/tests/factories.py +4 -10
- django_spire/knowledge/entry/version/block/tests/test_choices.py +56 -0
- django_spire/knowledge/entry/version/block/tests/test_data.py +90 -0
- django_spire/knowledge/entry/version/block/tests/test_maps.py +37 -0
- django_spire/knowledge/entry/version/block/tests/test_models.py +55 -0
- django_spire/knowledge/entry/version/block/tests/test_querysets.py +35 -0
- django_spire/knowledge/entry/version/block/tests/test_services.py +65 -0
- django_spire/knowledge/entry/version/choices.py +2 -0
- django_spire/knowledge/entry/version/converters/converter.py +1 -1
- django_spire/knowledge/entry/version/converters/docx_converter.py +4 -7
- django_spire/knowledge/entry/version/converters/markdown_converter.py +20 -20
- django_spire/knowledge/entry/version/maps.py +4 -5
- django_spire/knowledge/entry/version/querysets.py +1 -1
- django_spire/knowledge/entry/version/seeding/seeder.py +1 -2
- django_spire/knowledge/entry/version/services/processor_service.py +5 -4
- django_spire/knowledge/entry/version/services/service.py +1 -2
- django_spire/knowledge/entry/version/tests/factories.py +2 -2
- django_spire/knowledge/entry/version/tests/test_choices.py +18 -0
- django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +56 -8
- django_spire/knowledge/entry/version/tests/test_converters/test_markdown_converter.py +78 -0
- django_spire/knowledge/entry/version/tests/test_maps.py +58 -0
- django_spire/knowledge/entry/version/tests/test_models.py +23 -0
- django_spire/knowledge/entry/version/tests/test_querysets.py +26 -0
- django_spire/knowledge/entry/version/tests/test_services.py +62 -0
- django_spire/knowledge/entry/version/tests/test_urls/test_json_urls.py +27 -8
- django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +15 -8
- django_spire/knowledge/entry/version/tests/test_urls/test_redirect_urls.py +38 -0
- django_spire/knowledge/entry/version/urls/__init__.py +3 -0
- django_spire/knowledge/entry/version/urls/json_urls.py +2 -1
- django_spire/knowledge/entry/version/urls/page_urls.py +2 -0
- django_spire/knowledge/entry/version/urls/redirect_urls.py +2 -0
- django_spire/knowledge/entry/version/views/json_views.py +5 -1
- django_spire/knowledge/entry/version/views/page_views.py +10 -3
- django_spire/knowledge/entry/version/views/redirect_views.py +5 -1
- django_spire/knowledge/entry/views/form_views.py +16 -8
- django_spire/knowledge/entry/views/json_views.py +3 -1
- django_spire/knowledge/entry/views/page_views.py +8 -2
- django_spire/knowledge/entry/views/template_views.py +7 -1
- django_spire/knowledge/exceptions.py +2 -1
- django_spire/knowledge/intelligence/intel/answer_intel.py +2 -1
- django_spire/knowledge/intelligence/intel/entry_intel.py +0 -1
- django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +4 -5
- django_spire/knowledge/models.py +1 -2
- django_spire/knowledge/tests/__init__.py +0 -0
- django_spire/knowledge/tests/test_templatetags.py +40 -0
- django_spire/knowledge/tests/test_urls/__init__.py +0 -0
- django_spire/knowledge/tests/test_urls/test_page_urls.py +24 -0
- django_spire/knowledge/urls/__init__.py +2 -0
- django_spire/knowledge/urls/page_urls.py +2 -0
- django_spire/knowledge/views/page_views.py +8 -3
- django_spire/notification/admin.py +3 -1
- django_spire/notification/app/admin.py +2 -0
- django_spire/notification/app/apps.py +3 -1
- django_spire/notification/app/exceptions.py +9 -2
- django_spire/notification/app/models.py +8 -4
- django_spire/notification/app/processor.py +22 -26
- django_spire/notification/app/querysets.py +2 -0
- django_spire/notification/app/tests/__init__.py +0 -0
- django_spire/notification/app/tests/factories.py +34 -0
- django_spire/notification/app/tests/test_apps.py +24 -0
- django_spire/notification/app/tests/test_models.py +72 -0
- django_spire/notification/app/tests/test_processor.py +111 -0
- django_spire/notification/app/tests/test_querysets.py +90 -0
- django_spire/notification/app/tests/test_views/__init__.py +0 -0
- django_spire/notification/app/tests/test_views/test_json_views.py +48 -0
- django_spire/notification/app/tests/test_views/test_page_views.py +19 -0
- django_spire/notification/app/urls/__init__.py +3 -1
- django_spire/notification/app/urls/json_urls.py +6 -4
- django_spire/notification/app/urls/page_urls.py +4 -3
- django_spire/notification/app/urls/template_urls.py +4 -2
- django_spire/notification/apps.py +4 -1
- django_spire/notification/email/admin.py +5 -1
- django_spire/notification/email/apps.py +3 -1
- django_spire/notification/email/exceptions.py +4 -2
- django_spire/notification/email/helper.py +5 -3
- django_spire/notification/email/models.py +4 -0
- django_spire/notification/email/processor.py +19 -15
- django_spire/notification/email/querysets.py +3 -0
- django_spire/notification/email/tests/__init__.py +0 -0
- django_spire/notification/email/tests/factories.py +35 -0
- django_spire/notification/email/tests/test_apps.py +24 -0
- django_spire/notification/email/tests/test_models.py +52 -0
- django_spire/notification/email/tests/test_processor.py +92 -0
- django_spire/notification/email/tests/test_querysets.py +43 -0
- django_spire/notification/exceptions.py +17 -2
- django_spire/notification/managers.py +7 -1
- django_spire/notification/maps.py +4 -1
- django_spire/notification/mixins.py +2 -0
- django_spire/notification/models.py +3 -1
- django_spire/notification/processors/notification.py +12 -5
- django_spire/notification/processors/processor.py +2 -0
- django_spire/notification/processors/tests/__init__.py +0 -0
- django_spire/notification/processors/tests/test_notification.py +106 -0
- django_spire/notification/push/admin.py +10 -1
- django_spire/notification/push/apps.py +3 -1
- django_spire/notification/push/models.py +2 -3
- django_spire/notification/push/tests/__init__.py +0 -0
- django_spire/notification/push/tests/test_apps.py +24 -0
- django_spire/notification/push/tests/test_models.py +28 -0
- django_spire/notification/querysets.py +7 -1
- django_spire/notification/sms/admin.py +2 -0
- django_spire/notification/sms/apps.py +4 -1
- django_spire/notification/sms/automations.py +2 -0
- django_spire/notification/sms/choices.py +2 -0
- django_spire/notification/sms/exceptions.py +19 -5
- django_spire/notification/sms/helper.py +33 -23
- django_spire/notification/sms/models.py +5 -1
- django_spire/notification/sms/processor.py +20 -20
- django_spire/notification/sms/querysets.py +2 -0
- django_spire/notification/sms/tests/factories.py +33 -0
- django_spire/notification/sms/tests/test_apps.py +24 -0
- django_spire/notification/sms/tests/test_automation.py +38 -0
- django_spire/notification/sms/tests/test_choices.py +15 -0
- django_spire/notification/sms/tests/test_consts.py +17 -0
- django_spire/notification/sms/tests/test_exceptions.py +27 -0
- django_spire/notification/sms/tests/test_helper.py +50 -0
- django_spire/notification/sms/tests/test_models.py +81 -0
- django_spire/notification/sms/tests/test_processor.py +107 -0
- django_spire/notification/sms/tests/test_tools.py +25 -11
- django_spire/notification/sms/tools.py +16 -5
- django_spire/notification/sms/urls/__init__.py +3 -1
- django_spire/notification/sms/urls/media_urls.py +2 -0
- django_spire/notification/sms/views/media_views.py +14 -4
- django_spire/notification/tests/__init__.py +0 -0
- django_spire/notification/tests/factories.py +26 -0
- django_spire/notification/tests/test_admin.py +55 -0
- django_spire/notification/tests/test_apps.py +30 -0
- django_spire/notification/tests/test_automation.py +18 -0
- django_spire/notification/tests/test_choices.py +59 -0
- django_spire/notification/tests/test_exceptions.py +58 -0
- django_spire/notification/tests/test_managers.py +100 -0
- django_spire/notification/tests/test_maps.py +31 -0
- django_spire/notification/tests/test_models.py +76 -0
- django_spire/notification/tests/test_querysets.py +184 -0
- django_spire/notification/tests/test_utils.py +23 -0
- django_spire/notification/urls.py +3 -1
- django_spire/notification/utils.py +3 -1
- django_spire/settings.py +3 -0
- django_spire/theme/tests/test_context_processor.py +15 -13
- django_spire/theme/tests/test_enums.py +2 -2
- django_spire/theme/tests/test_filesystem.py +2 -5
- django_spire/theme/tests/test_integration.py +12 -12
- django_spire/theme/tests/test_model.py +40 -38
- django_spire/theme/tests/test_views/test_json_views.py +33 -33
- django_spire/theme/urls/json_urls.py +3 -0
- django_spire/theme/urls/page_urls.py +3 -0
- django_spire/urls.py +19 -15
- django_spire/utils.py +13 -4
- {django_spire-0.23.6.dist-info → django_spire-0.23.8.dist-info}/METADATA +1 -1
- {django_spire-0.23.6.dist-info → django_spire-0.23.8.dist-info}/RECORD +532 -361
- django_spire/contrib/options/tests/test_unit.py +0 -148
- django_spire/contrib/progress/views.py +0 -64
- django_spire/contrib/seeding/tests/test_seeding.py +0 -25
- django_spire/core/tests/test_templatetags.py +0 -117
- django_spire/core/tests/tests_shortcuts.py +0 -73
- django_spire/history/activity/tests.py +0 -3
- django_spire/history/activity/views.py +0 -3
- django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +0 -71
- django_spire/notification/app/tests.py +0 -3
- {django_spire-0.23.6.dist-info → django_spire-0.23.8.dist-info}/WHEEL +0 -0
- {django_spire-0.23.6.dist-info → django_spire-0.23.8.dist-info}/licenses/LICENSE.md +0 -0
- {django_spire-0.23.6.dist-info → django_spire-0.23.8.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.contrib.auth.models import Permission
|
|
4
|
+
from django.contrib.contenttypes.models import ContentType
|
|
5
|
+
from django.test import RequestFactory
|
|
6
|
+
|
|
7
|
+
from django_spire.auth.user.tests.factories import create_user
|
|
8
|
+
from django_spire.core.tests.test_cases import BaseTestCase
|
|
9
|
+
from django_spire.knowledge.auth.controller import BaseKnowledgeAuthController
|
|
10
|
+
from django_spire.knowledge.collection.models import Collection
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseKnowledgeAuthControllerTests(BaseTestCase):
|
|
14
|
+
def setUp(self):
|
|
15
|
+
super().setUp()
|
|
16
|
+
self.factory = RequestFactory()
|
|
17
|
+
self.user = create_user(username='test_auth_user')
|
|
18
|
+
self.request = self.factory.get('/')
|
|
19
|
+
self.request.user = self.user
|
|
20
|
+
|
|
21
|
+
content_type = ContentType.objects.get_for_model(Collection)
|
|
22
|
+
|
|
23
|
+
self.view_permission = Permission.objects.get(
|
|
24
|
+
codename='view_collection',
|
|
25
|
+
content_type=content_type
|
|
26
|
+
)
|
|
27
|
+
self.add_permission = Permission.objects.get(
|
|
28
|
+
codename='add_collection',
|
|
29
|
+
content_type=content_type
|
|
30
|
+
)
|
|
31
|
+
self.change_permission = Permission.objects.get(
|
|
32
|
+
codename='change_collection',
|
|
33
|
+
content_type=content_type
|
|
34
|
+
)
|
|
35
|
+
self.delete_permission = Permission.objects.get(
|
|
36
|
+
codename='delete_collection',
|
|
37
|
+
content_type=content_type
|
|
38
|
+
)
|
|
39
|
+
self.access_all_permission = Permission.objects.get(
|
|
40
|
+
codename='can_access_all_collections',
|
|
41
|
+
content_type=content_type
|
|
42
|
+
)
|
|
43
|
+
self.change_groups_permission = Permission.objects.get(
|
|
44
|
+
codename='can_change_collection_groups',
|
|
45
|
+
content_type=content_type
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def _refresh_user_and_request(self):
|
|
49
|
+
self.user = type(self.user).objects.get(pk=self.user.pk)
|
|
50
|
+
self.request.user = self.user
|
|
51
|
+
|
|
52
|
+
def test_can_view_without_permission(self):
|
|
53
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
54
|
+
assert controller.can_view() is False
|
|
55
|
+
|
|
56
|
+
def test_can_view_with_permission(self):
|
|
57
|
+
self.user.user_permissions.add(self.view_permission)
|
|
58
|
+
self._refresh_user_and_request()
|
|
59
|
+
|
|
60
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
61
|
+
assert controller.can_view() is True
|
|
62
|
+
|
|
63
|
+
def test_can_add_without_permission(self):
|
|
64
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
65
|
+
assert controller.can_add() is False
|
|
66
|
+
|
|
67
|
+
def test_can_add_with_permission(self):
|
|
68
|
+
self.user.user_permissions.add(self.add_permission)
|
|
69
|
+
self._refresh_user_and_request()
|
|
70
|
+
|
|
71
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
72
|
+
assert controller.can_add() is True
|
|
73
|
+
|
|
74
|
+
def test_can_change_without_permission(self):
|
|
75
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
76
|
+
assert controller.can_change() is False
|
|
77
|
+
|
|
78
|
+
def test_can_change_with_permission(self):
|
|
79
|
+
self.user.user_permissions.add(self.change_permission)
|
|
80
|
+
self._refresh_user_and_request()
|
|
81
|
+
|
|
82
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
83
|
+
assert controller.can_change() is True
|
|
84
|
+
|
|
85
|
+
def test_can_delete_without_permission(self):
|
|
86
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
87
|
+
assert controller.can_delete() is False
|
|
88
|
+
|
|
89
|
+
def test_can_delete_with_permission(self):
|
|
90
|
+
self.user.user_permissions.add(self.delete_permission)
|
|
91
|
+
self._refresh_user_and_request()
|
|
92
|
+
|
|
93
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
94
|
+
assert controller.can_delete() is True
|
|
95
|
+
|
|
96
|
+
def test_can_access_all_collections_without_permission(self):
|
|
97
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
98
|
+
assert controller.can_access_all_collections() is False
|
|
99
|
+
|
|
100
|
+
def test_can_access_all_collections_with_permission(self):
|
|
101
|
+
self.user.user_permissions.add(self.access_all_permission)
|
|
102
|
+
self._refresh_user_and_request()
|
|
103
|
+
|
|
104
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
105
|
+
assert controller.can_access_all_collections() is True
|
|
106
|
+
|
|
107
|
+
def test_can_change_collection_groups_without_permission(self):
|
|
108
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
109
|
+
assert controller.can_change_collection_groups() is False
|
|
110
|
+
|
|
111
|
+
def test_can_change_collection_groups_with_permission(self):
|
|
112
|
+
self.user.user_permissions.add(self.change_groups_permission)
|
|
113
|
+
self._refresh_user_and_request()
|
|
114
|
+
|
|
115
|
+
controller = BaseKnowledgeAuthController(self.request)
|
|
116
|
+
assert controller.can_change_collection_groups() is True
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
3
5
|
from django.contrib import admin
|
|
4
|
-
from django.db.models import QuerySet
|
|
5
6
|
from django.contrib import messages
|
|
6
7
|
|
|
7
8
|
from .models import Collection, CollectionGroup
|
|
8
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from django.db.models import QuerySet
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
@admin.register(Collection)
|
|
11
15
|
class CollectionAdmin(admin.ModelAdmin):
|
|
@@ -9,8 +9,10 @@ from django_spire.core.tag.mixins import TagModelMixin
|
|
|
9
9
|
from django_spire.contrib.utils import truncate_string
|
|
10
10
|
from django_spire.history.mixins import HistoryModelMixin
|
|
11
11
|
from django_spire.knowledge.collection.querysets import CollectionQuerySet
|
|
12
|
-
from django_spire.knowledge.collection.services.service import
|
|
12
|
+
from django_spire.knowledge.collection.services.service import (
|
|
13
|
+
CollectionGroupService,
|
|
13
14
|
CollectionService
|
|
15
|
+
)
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class Collection(
|
|
@@ -2,12 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from django.core.handlers.wsgi import WSGIRequest
|
|
6
|
-
|
|
7
5
|
from django_spire.auth.controller.controller import AppAuthController
|
|
8
6
|
from django_spire.contrib.service import BaseDjangoModelService
|
|
9
7
|
|
|
10
8
|
if TYPE_CHECKING:
|
|
9
|
+
from django.core.handlers.wsgi import WSGIRequest
|
|
10
|
+
|
|
11
11
|
from django_spire.knowledge.collection.models import Collection, CollectionGroup
|
|
12
12
|
|
|
13
13
|
|
|
@@ -15,10 +15,10 @@ class CollectionGroupFactoryService(BaseDjangoModelService['CollectionGroup']):
|
|
|
15
15
|
obj: CollectionGroup
|
|
16
16
|
|
|
17
17
|
def replace_groups(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
self,
|
|
19
|
+
request: WSGIRequest,
|
|
20
|
+
group_pks: list[int] | None,
|
|
21
|
+
collection: Collection
|
|
22
22
|
) -> list[CollectionGroup]:
|
|
23
23
|
if not AppAuthController('knowledge', request).can_change_collection_groups():
|
|
24
24
|
return []
|
|
@@ -28,11 +28,10 @@ class CollectionGroupFactoryService(BaseDjangoModelService['CollectionGroup']):
|
|
|
28
28
|
|
|
29
29
|
old_collection_groups = list(collection.groups.all())
|
|
30
30
|
|
|
31
|
-
new_collection_groups = [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
31
|
+
new_collection_groups = [
|
|
32
|
+
self.obj_class(auth_group_id=group_pk, collection=collection)
|
|
33
|
+
for group_pk in group_pks
|
|
34
|
+
]
|
|
36
35
|
|
|
37
36
|
self.obj_class.objects.bulk_create(new_collection_groups)
|
|
38
37
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from django_spire.contrib.service import BaseDjangoModelService
|
|
4
|
-
|
|
5
3
|
from typing import TYPE_CHECKING
|
|
6
4
|
|
|
5
|
+
from django_spire.contrib.service import BaseDjangoModelService
|
|
7
6
|
|
|
8
7
|
if TYPE_CHECKING:
|
|
9
8
|
from django_spire.knowledge.collection.models import Collection
|
|
@@ -4,17 +4,12 @@ from django_spire.contrib.service import BaseDjangoModelService
|
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
from django_spire.knowledge.collection.services.factory_service import
|
|
8
|
-
|
|
9
|
-
from django_spire.knowledge.collection.services.
|
|
10
|
-
CollectionOrderingService
|
|
11
|
-
from django_spire.knowledge.collection.services.processor_service import \
|
|
12
|
-
CollectionProcessorService
|
|
7
|
+
from django_spire.knowledge.collection.services.factory_service import CollectionGroupFactoryService
|
|
8
|
+
from django_spire.knowledge.collection.services.ordering_service import CollectionOrderingService
|
|
9
|
+
from django_spire.knowledge.collection.services.processor_service import CollectionProcessorService
|
|
13
10
|
from django_spire.knowledge.collection.services.tag_service import CollectionTagService
|
|
14
|
-
from django_spire.knowledge.collection.services.tool_services import
|
|
15
|
-
|
|
16
|
-
from django_spire.knowledge.collection.services.transformation_service import \
|
|
17
|
-
CollectionTransformationService
|
|
11
|
+
from django_spire.knowledge.collection.services.tool_services import CollectionToolService
|
|
12
|
+
from django_spire.knowledge.collection.services.transformation_service import CollectionTransformationService
|
|
18
13
|
|
|
19
14
|
if TYPE_CHECKING:
|
|
20
15
|
from django_spire.knowledge.collection.models import Collection, CollectionGroup
|
|
@@ -6,8 +6,11 @@ from dandy import Prompt
|
|
|
6
6
|
|
|
7
7
|
from django_spire.core.tag.intelligence.tag_set_bot import TagSetBot
|
|
8
8
|
from django_spire.core.tag.service.tag_service import BaseTagService
|
|
9
|
-
from django_spire.core.tag.tools import
|
|
10
|
-
get_score_percentage_from_tag_set_weighted
|
|
9
|
+
from django_spire.core.tag.tools import (
|
|
10
|
+
get_score_percentage_from_tag_set_weighted,
|
|
11
|
+
simplify_and_weight_tag_set_to_dict,
|
|
12
|
+
simplify_tag_set
|
|
13
|
+
)
|
|
11
14
|
|
|
12
15
|
if TYPE_CHECKING:
|
|
13
16
|
from django_spire.knowledge.collection.models import Collection
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from django_spire.
|
|
3
|
+
from django_spire.auth.group.models import AuthGroup
|
|
4
|
+
from django_spire.knowledge.collection.models import Collection, CollectionGroup
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_test_auth_group(**kwargs) -> AuthGroup:
|
|
8
|
+
data = {
|
|
9
|
+
'name': 'Test Group',
|
|
10
|
+
}
|
|
11
|
+
data.update(kwargs)
|
|
12
|
+
return AuthGroup.objects.create(**data)
|
|
4
13
|
|
|
5
14
|
|
|
6
15
|
def create_test_collection(**kwargs) -> Collection:
|
|
@@ -13,3 +22,21 @@ def create_test_collection(**kwargs) -> Collection:
|
|
|
13
22
|
}
|
|
14
23
|
data.update(kwargs)
|
|
15
24
|
return Collection.objects.create(**data)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_test_collection_group(
|
|
28
|
+
collection: Collection | None = None,
|
|
29
|
+
auth_group: AuthGroup | None = None,
|
|
30
|
+
**kwargs
|
|
31
|
+
) -> CollectionGroup:
|
|
32
|
+
if collection is None:
|
|
33
|
+
collection = create_test_collection()
|
|
34
|
+
if auth_group is None:
|
|
35
|
+
auth_group = create_test_auth_group()
|
|
36
|
+
|
|
37
|
+
data = {
|
|
38
|
+
'collection': collection,
|
|
39
|
+
'auth_group': auth_group,
|
|
40
|
+
}
|
|
41
|
+
data.update(kwargs)
|
|
42
|
+
return CollectionGroup.objects.create(**data)
|
|
@@ -0,0 +1,48 @@
|
|
|
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 (
|
|
5
|
+
create_test_collection,
|
|
6
|
+
create_test_collection_group,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CollectionModelTests(BaseTestCase):
|
|
11
|
+
def setUp(self):
|
|
12
|
+
super().setUp()
|
|
13
|
+
self.collection = create_test_collection()
|
|
14
|
+
|
|
15
|
+
def test_str(self):
|
|
16
|
+
assert str(self.collection) == self.collection.name
|
|
17
|
+
|
|
18
|
+
def test_name_short_truncates(self):
|
|
19
|
+
long_name = 'A' * 100
|
|
20
|
+
collection = create_test_collection(name=long_name)
|
|
21
|
+
assert len(collection.name_short) <= 35
|
|
22
|
+
|
|
23
|
+
def test_name_short_no_truncate(self):
|
|
24
|
+
short_name = 'Short'
|
|
25
|
+
collection = create_test_collection(name=short_name)
|
|
26
|
+
assert collection.name_short == short_name
|
|
27
|
+
|
|
28
|
+
def test_top_level_parent_returns_self_when_no_parent(self):
|
|
29
|
+
assert self.collection.top_level_parent == self.collection
|
|
30
|
+
|
|
31
|
+
def test_top_level_parent_returns_root(self):
|
|
32
|
+
child = create_test_collection(parent=self.collection, name='Child')
|
|
33
|
+
grandchild = create_test_collection(parent=child, name='Grandchild')
|
|
34
|
+
assert grandchild.top_level_parent == self.collection
|
|
35
|
+
|
|
36
|
+
def test_base_breadcrumb(self):
|
|
37
|
+
breadcrumbs = self.collection.base_breadcrumb()
|
|
38
|
+
assert breadcrumbs is not None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CollectionGroupModelTests(BaseTestCase):
|
|
42
|
+
def setUp(self):
|
|
43
|
+
super().setUp()
|
|
44
|
+
self.collection_group = create_test_collection_group()
|
|
45
|
+
|
|
46
|
+
def test_str(self):
|
|
47
|
+
expected = f'{self.collection_group.collection.name} - {self.collection_group.auth_group.name}'
|
|
48
|
+
assert str(self.collection_group) == expected
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.test import RequestFactory
|
|
4
|
+
|
|
5
|
+
from django_spire.auth.user.tests.factories import create_user
|
|
6
|
+
from django_spire.core.tests.test_cases import BaseTestCase
|
|
7
|
+
from django_spire.knowledge.collection.models import Collection
|
|
8
|
+
from django_spire.knowledge.collection.tests.factories import (
|
|
9
|
+
create_test_auth_group,
|
|
10
|
+
create_test_collection,
|
|
11
|
+
create_test_collection_group,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CollectionQuerySetTests(BaseTestCase):
|
|
16
|
+
def setUp(self):
|
|
17
|
+
super().setUp()
|
|
18
|
+
self.factory = RequestFactory()
|
|
19
|
+
self.user = create_user(username='test_queryset_user')
|
|
20
|
+
self.parent_collection = create_test_collection(name='Parent')
|
|
21
|
+
self.child_collection = create_test_collection(
|
|
22
|
+
parent=self.parent_collection,
|
|
23
|
+
name='Child'
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def test_by_parent(self):
|
|
27
|
+
result = Collection.objects.by_parent(parent=self.parent_collection)
|
|
28
|
+
assert self.child_collection in result
|
|
29
|
+
assert self.parent_collection not in result
|
|
30
|
+
|
|
31
|
+
def test_by_parent_id(self):
|
|
32
|
+
result = Collection.objects.by_parent_id(parent_id=self.parent_collection.id)
|
|
33
|
+
assert self.child_collection in result
|
|
34
|
+
|
|
35
|
+
def test_by_parent_ids(self):
|
|
36
|
+
result = Collection.objects.by_parent_ids(parent_ids=[self.parent_collection.id])
|
|
37
|
+
assert self.child_collection in result
|
|
38
|
+
|
|
39
|
+
def test_parentless(self):
|
|
40
|
+
result = Collection.objects.parentless()
|
|
41
|
+
assert self.parent_collection in result
|
|
42
|
+
assert self.child_collection not in result
|
|
43
|
+
|
|
44
|
+
def test_childless(self):
|
|
45
|
+
grandchild = create_test_collection(
|
|
46
|
+
parent=self.child_collection,
|
|
47
|
+
name='Grandchild'
|
|
48
|
+
)
|
|
49
|
+
result = Collection.objects.childless()
|
|
50
|
+
assert grandchild in result
|
|
51
|
+
assert self.parent_collection not in result
|
|
52
|
+
|
|
53
|
+
def test_children(self):
|
|
54
|
+
grandchild = create_test_collection(
|
|
55
|
+
parent=self.child_collection,
|
|
56
|
+
name='Grandchild'
|
|
57
|
+
)
|
|
58
|
+
result = Collection.objects.children(collection_id=self.parent_collection.id)
|
|
59
|
+
assert self.child_collection in result
|
|
60
|
+
assert grandchild in result
|
|
61
|
+
|
|
62
|
+
def test_exclude_children(self):
|
|
63
|
+
grandchild = create_test_collection(
|
|
64
|
+
parent=self.child_collection,
|
|
65
|
+
name='Grandchild'
|
|
66
|
+
)
|
|
67
|
+
result = Collection.objects.exclude_children(collection_id=self.parent_collection.id)
|
|
68
|
+
assert self.parent_collection in result
|
|
69
|
+
assert self.child_collection not in result
|
|
70
|
+
assert grandchild not in result
|
|
71
|
+
|
|
72
|
+
def test_annotate_entry_count(self):
|
|
73
|
+
result = Collection.objects.annotate_entry_count()
|
|
74
|
+
assert result.first().entry_count == 0
|
|
75
|
+
|
|
76
|
+
def test_request_user_has_access_superuser(self):
|
|
77
|
+
request = self.factory.get('/')
|
|
78
|
+
request.user = self.super_user
|
|
79
|
+
result = Collection.objects.request_user_has_access(request)
|
|
80
|
+
assert self.parent_collection in result
|
|
81
|
+
|
|
82
|
+
def test_request_user_has_access_with_group(self):
|
|
83
|
+
auth_group = create_test_auth_group(name='Access Group')
|
|
84
|
+
self.user.groups.add(auth_group)
|
|
85
|
+
create_test_collection_group(
|
|
86
|
+
collection=self.parent_collection,
|
|
87
|
+
auth_group=auth_group
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
request = self.factory.get('/')
|
|
91
|
+
request.user = self.user
|
|
92
|
+
result = Collection.objects.request_user_has_access(request)
|
|
93
|
+
assert self.parent_collection in result
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.contrib.auth.models import Permission
|
|
4
|
+
from django.contrib.contenttypes.models import ContentType
|
|
5
|
+
from django.test import RequestFactory
|
|
6
|
+
|
|
7
|
+
from django_spire.auth.user.tests.factories import create_user
|
|
8
|
+
from django_spire.core.tests.test_cases import BaseTestCase
|
|
9
|
+
from django_spire.knowledge.collection.models import Collection, CollectionGroup
|
|
10
|
+
from django_spire.knowledge.collection.tests.factories import (
|
|
11
|
+
create_test_auth_group,
|
|
12
|
+
create_test_collection,
|
|
13
|
+
create_test_collection_group,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CollectionGroupFactoryServiceTests(BaseTestCase):
|
|
18
|
+
def setUp(self):
|
|
19
|
+
super().setUp()
|
|
20
|
+
self.factory = RequestFactory()
|
|
21
|
+
self.user = create_user(username='test_factory_user')
|
|
22
|
+
self.collection = create_test_collection()
|
|
23
|
+
self.auth_group1 = create_test_auth_group(name='Group 1')
|
|
24
|
+
self.auth_group2 = create_test_auth_group(name='Group 2')
|
|
25
|
+
|
|
26
|
+
content_type = ContentType.objects.get_for_model(Collection)
|
|
27
|
+
self.change_groups_permission = Permission.objects.get(
|
|
28
|
+
codename='can_change_collection_groups',
|
|
29
|
+
content_type=content_type
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def _refresh_user(self):
|
|
33
|
+
self.user = type(self.user).objects.get(pk=self.user.pk)
|
|
34
|
+
|
|
35
|
+
def test_replace_groups_without_permission(self):
|
|
36
|
+
request = self.factory.get('/')
|
|
37
|
+
request.user = self.user
|
|
38
|
+
|
|
39
|
+
result = CollectionGroup.services.factory.replace_groups(
|
|
40
|
+
request=request,
|
|
41
|
+
group_pks=[self.auth_group1.pk],
|
|
42
|
+
collection=self.collection
|
|
43
|
+
)
|
|
44
|
+
assert result == []
|
|
45
|
+
|
|
46
|
+
def test_replace_groups_with_permission(self):
|
|
47
|
+
self.user.user_permissions.add(self.change_groups_permission)
|
|
48
|
+
self._refresh_user()
|
|
49
|
+
|
|
50
|
+
request = self.factory.get('/')
|
|
51
|
+
request.user = self.user
|
|
52
|
+
|
|
53
|
+
result = CollectionGroup.services.factory.replace_groups(
|
|
54
|
+
request=request,
|
|
55
|
+
group_pks=[self.auth_group1.pk, self.auth_group2.pk],
|
|
56
|
+
collection=self.collection
|
|
57
|
+
)
|
|
58
|
+
assert len(result) == 2
|
|
59
|
+
assert self.collection.groups.count() == 2
|
|
60
|
+
|
|
61
|
+
def test_replace_groups_removes_old(self):
|
|
62
|
+
self.user.user_permissions.add(self.change_groups_permission)
|
|
63
|
+
self._refresh_user()
|
|
64
|
+
|
|
65
|
+
create_test_collection_group(
|
|
66
|
+
collection=self.collection,
|
|
67
|
+
auth_group=self.auth_group1
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
request = self.factory.get('/')
|
|
71
|
+
request.user = self.user
|
|
72
|
+
|
|
73
|
+
CollectionGroup.services.factory.replace_groups(
|
|
74
|
+
request=request,
|
|
75
|
+
group_pks=[self.auth_group2.pk],
|
|
76
|
+
collection=self.collection
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
assert self.collection.groups.count() == 1
|
|
80
|
+
assert self.collection.groups.first().auth_group == self.auth_group2
|
|
81
|
+
|
|
82
|
+
def test_replace_groups_with_none_deletes_all(self):
|
|
83
|
+
self.user.user_permissions.add(self.change_groups_permission)
|
|
84
|
+
self._refresh_user()
|
|
85
|
+
|
|
86
|
+
create_test_collection_group(
|
|
87
|
+
collection=self.collection,
|
|
88
|
+
auth_group=self.auth_group1
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
request = self.factory.get('/')
|
|
92
|
+
request.user = self.user
|
|
93
|
+
|
|
94
|
+
CollectionGroup.services.factory.replace_groups(
|
|
95
|
+
request=request,
|
|
96
|
+
group_pks=None,
|
|
97
|
+
collection=self.collection
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
assert self.collection.groups.count() == 0
|