wbcore 2.2.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wbcore/__init__.py +1 -0
- wbcore/admin.py +197 -0
- wbcore/apps.py +17 -0
- wbcore/cache/__init__.py +0 -0
- wbcore/cache/buttons.py +22 -0
- wbcore/cache/decorators.py +29 -0
- wbcore/cache/mixins.py +48 -0
- wbcore/cache/registry.py +90 -0
- wbcore/cache/views.py +18 -0
- wbcore/configs/__init__.py +11 -0
- wbcore/configs/configs.py +51 -0
- wbcore/configs/decorators.py +11 -0
- wbcore/configs/registry.py +35 -0
- wbcore/configs/views.py +11 -0
- wbcore/configurations/__init__.py +1 -0
- wbcore/configurations/base.py +45 -0
- wbcore/configurations/configurations/__init__.py +16 -0
- wbcore/configurations/configurations/apps.py +54 -0
- wbcore/configurations/configurations/authentication.py +43 -0
- wbcore/configurations/configurations/base.py +15 -0
- wbcore/configurations/configurations/cache.py +20 -0
- wbcore/configurations/configurations/celery.py +26 -0
- wbcore/configurations/configurations/i18nl10n.py +10 -0
- wbcore/configurations/configurations/mail.py +2 -0
- wbcore/configurations/configurations/maintenance.py +53 -0
- wbcore/configurations/configurations/media.py +22 -0
- wbcore/configurations/configurations/middleware.py +27 -0
- wbcore/configurations/configurations/network.py +19 -0
- wbcore/configurations/configurations/rest_framework.py +42 -0
- wbcore/configurations/configurations/static.py +28 -0
- wbcore/configurations/configurations/templates.py +17 -0
- wbcore/configurations/configurations/uvicorn.py +9 -0
- wbcore/configurations/configurations/wbcore.py +68 -0
- wbcore/content_type/__init__.py +0 -0
- wbcore/content_type/admin.py +8 -0
- wbcore/content_type/filters.py +19 -0
- wbcore/content_type/serializers.py +89 -0
- wbcore/content_type/utils.py +30 -0
- wbcore/content_type/viewsets.py +80 -0
- wbcore/contrib/__init__.py +0 -0
- wbcore/contrib/agenda/__init__.py +0 -0
- wbcore/contrib/agenda/admin/__init__.py +2 -0
- wbcore/contrib/agenda/admin/calendar_item.py +13 -0
- wbcore/contrib/agenda/admin/conference_room.py +18 -0
- wbcore/contrib/agenda/apps.py +6 -0
- wbcore/contrib/agenda/configurations.py +11 -0
- wbcore/contrib/agenda/factories/__init__.py +2 -0
- wbcore/contrib/agenda/factories/calendar_item.py +47 -0
- wbcore/contrib/agenda/factories/conference_room.py +19 -0
- wbcore/contrib/agenda/filters/__init__.py +2 -0
- wbcore/contrib/agenda/filters/calendar_item.py +64 -0
- wbcore/contrib/agenda/filters/conference_room.py +41 -0
- wbcore/contrib/agenda/migrations/0001_initial.py +84 -0
- wbcore/contrib/agenda/migrations/0002_initial.py +26 -0
- wbcore/contrib/agenda/migrations/0003_calendaritem_endpoint_basename.py +42 -0
- wbcore/contrib/agenda/migrations/0004_alter_calendaritem_item_type.py +17 -0
- wbcore/contrib/agenda/migrations/0005_building_and_more.py +94 -0
- wbcore/contrib/agenda/migrations/0006_calendaritem_is_deletable.py +17 -0
- wbcore/contrib/agenda/migrations/0007_alter_calendaritem_options.py +21 -0
- wbcore/contrib/agenda/migrations/0008_alter_calendaritem_item_type.py +17 -0
- wbcore/contrib/agenda/migrations/0009_alter_calendaritem_icon.py +18 -0
- wbcore/contrib/agenda/migrations/__init__.py +0 -0
- wbcore/contrib/agenda/models/__init__.py +2 -0
- wbcore/contrib/agenda/models/calendar_item.py +238 -0
- wbcore/contrib/agenda/models/conference_room.py +95 -0
- wbcore/contrib/agenda/release_notes/1_0_0.md +13 -0
- wbcore/contrib/agenda/release_notes/__init__.py +0 -0
- wbcore/contrib/agenda/serializers/__init__.py +10 -0
- wbcore/contrib/agenda/serializers/calendar_item.py +76 -0
- wbcore/contrib/agenda/serializers/conference_room.py +98 -0
- wbcore/contrib/agenda/signals.py +8 -0
- wbcore/contrib/agenda/tests/__init__.py +0 -0
- wbcore/contrib/agenda/tests/conftest.py +14 -0
- wbcore/contrib/agenda/tests/signals.py +16 -0
- wbcore/contrib/agenda/tests/test_models.py +34 -0
- wbcore/contrib/agenda/tests/test_viewsets.py +171 -0
- wbcore/contrib/agenda/tests/tests.py +25 -0
- wbcore/contrib/agenda/typings.py +19 -0
- wbcore/contrib/agenda/urls.py +25 -0
- wbcore/contrib/agenda/viewsets/__init__.py +13 -0
- wbcore/contrib/agenda/viewsets/buttons/__init__.py +1 -0
- wbcore/contrib/agenda/viewsets/buttons/conference_room.py +20 -0
- wbcore/contrib/agenda/viewsets/calendar_items.py +168 -0
- wbcore/contrib/agenda/viewsets/conference_room.py +48 -0
- wbcore/contrib/agenda/viewsets/display/__init__.py +2 -0
- wbcore/contrib/agenda/viewsets/display/calendar_items.py +17 -0
- wbcore/contrib/agenda/viewsets/display/conference_room.py +41 -0
- wbcore/contrib/agenda/viewsets/endpoints/__init__.py +1 -0
- wbcore/contrib/agenda/viewsets/endpoints/calendar_items.py +18 -0
- wbcore/contrib/agenda/viewsets/menu/__init__.py +2 -0
- wbcore/contrib/agenda/viewsets/menu/calendar_items.py +17 -0
- wbcore/contrib/agenda/viewsets/menu/conference_room.py +37 -0
- wbcore/contrib/agenda/viewsets/titles/__init__.py +2 -0
- wbcore/contrib/agenda/viewsets/titles/calendar_items.py +7 -0
- wbcore/contrib/agenda/viewsets/titles/conference_room.py +24 -0
- wbcore/contrib/ai/__init__.py +0 -0
- wbcore/contrib/ai/apps.py +5 -0
- wbcore/contrib/ai/exceptions.py +42 -0
- wbcore/contrib/ai/llm/__init__.py +0 -0
- wbcore/contrib/ai/llm/config.py +107 -0
- wbcore/contrib/ai/llm/decorators.py +10 -0
- wbcore/contrib/ai/llm/mixins.py +35 -0
- wbcore/contrib/ai/llm/utils.py +45 -0
- wbcore/contrib/authentication/__init__.py +9 -0
- wbcore/contrib/authentication/admin.py +247 -0
- wbcore/contrib/authentication/apps.py +14 -0
- wbcore/contrib/authentication/authentication.py +162 -0
- wbcore/contrib/authentication/configs.py +9 -0
- wbcore/contrib/authentication/configurations.py +53 -0
- wbcore/contrib/authentication/dynamic_preferences_registry.py +26 -0
- wbcore/contrib/authentication/factories/__init__.py +3 -0
- wbcore/contrib/authentication/factories/tokens.py +15 -0
- wbcore/contrib/authentication/factories/users.py +82 -0
- wbcore/contrib/authentication/factories/users_activities.py +19 -0
- wbcore/contrib/authentication/filters.py +18 -0
- wbcore/contrib/authentication/management/__init__.py +14 -0
- wbcore/contrib/authentication/migrations/0001_initial_squashed.py +174 -0
- wbcore/contrib/authentication/migrations/0002_profile.py +26 -0
- wbcore/contrib/authentication/migrations/0003_alter_user_profile.py +34 -0
- wbcore/contrib/authentication/migrations/0004_token.py +51 -0
- wbcore/contrib/authentication/migrations/0005_user_external_calendar_settings.py +17 -0
- wbcore/contrib/authentication/migrations/0006_auto_20231206_1422.py +13 -0
- wbcore/contrib/authentication/migrations/__init__.py +0 -0
- wbcore/contrib/authentication/models/__init__.py +3 -0
- wbcore/contrib/authentication/models/tokens.py +140 -0
- wbcore/contrib/authentication/models/users.py +225 -0
- wbcore/contrib/authentication/models/users_activities.py +112 -0
- wbcore/contrib/authentication/release_notes/1_0_0.md +13 -0
- wbcore/contrib/authentication/release_notes/__init__.py +0 -0
- wbcore/contrib/authentication/serializers/__init__.py +14 -0
- wbcore/contrib/authentication/serializers/users.py +350 -0
- wbcore/contrib/authentication/serializers/users_activites.py +37 -0
- wbcore/contrib/authentication/tasks.py +29 -0
- wbcore/contrib/authentication/tests/__init__.py +0 -0
- wbcore/contrib/authentication/tests/conftest.py +18 -0
- wbcore/contrib/authentication/tests/e2e/__init__.py +1 -0
- wbcore/contrib/authentication/tests/e2e/e2e_auth_utility.py +20 -0
- wbcore/contrib/authentication/tests/signals.py +17 -0
- wbcore/contrib/authentication/tests/test_configs.py +6 -0
- wbcore/contrib/authentication/tests/test_serializers.py +6 -0
- wbcore/contrib/authentication/tests/test_tasks.py +33 -0
- wbcore/contrib/authentication/tests/test_tokens.py +126 -0
- wbcore/contrib/authentication/tests/test_users.py +338 -0
- wbcore/contrib/authentication/tests/test_viewsets.py +6 -0
- wbcore/contrib/authentication/tests/tests.py +15 -0
- wbcore/contrib/authentication/urls.py +97 -0
- wbcore/contrib/authentication/utils.py +10 -0
- wbcore/contrib/authentication/viewsets/__init__.py +19 -0
- wbcore/contrib/authentication/viewsets/buttons/__init__.py +1 -0
- wbcore/contrib/authentication/viewsets/buttons/users.py +55 -0
- wbcore/contrib/authentication/viewsets/display/__init__.py +6 -0
- wbcore/contrib/authentication/viewsets/display/user_activities.py +85 -0
- wbcore/contrib/authentication/viewsets/display/users.py +72 -0
- wbcore/contrib/authentication/viewsets/endpoints/__init__.py +6 -0
- wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +22 -0
- wbcore/contrib/authentication/viewsets/endpoints/users.py +20 -0
- wbcore/contrib/authentication/viewsets/menu/__init__.py +6 -0
- wbcore/contrib/authentication/viewsets/menu/user_activities.py +39 -0
- wbcore/contrib/authentication/viewsets/menu/users.py +16 -0
- wbcore/contrib/authentication/viewsets/titles/__init__.py +12 -0
- wbcore/contrib/authentication/viewsets/titles/user_activities.py +31 -0
- wbcore/contrib/authentication/viewsets/titles/users.py +26 -0
- wbcore/contrib/authentication/viewsets/user_activities.py +222 -0
- wbcore/contrib/authentication/viewsets/users.py +328 -0
- wbcore/contrib/color/migrations/0001_initial.py +33 -0
- wbcore/contrib/color/migrations/0002_alter_colorgradient_colors.py +25 -0
- wbcore/contrib/color/migrations/__init__.py +0 -0
- wbcore/contrib/currency/__init__.py +0 -0
- wbcore/contrib/currency/admin.py +32 -0
- wbcore/contrib/currency/apps.py +5 -0
- wbcore/contrib/currency/dynamic_preferences_registry.py +39 -0
- wbcore/contrib/currency/factories.py +39 -0
- wbcore/contrib/currency/import_export/__init__.py +0 -0
- wbcore/contrib/currency/import_export/backends/__init__.py +1 -0
- wbcore/contrib/currency/import_export/backends/fixerio/__init__.py +1 -0
- wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +66 -0
- wbcore/contrib/currency/import_export/backends/utils.py +5 -0
- wbcore/contrib/currency/import_export/handlers/__init__.py +2 -0
- wbcore/contrib/currency/import_export/handlers/currency.py +24 -0
- wbcore/contrib/currency/import_export/handlers/currency_fx_rates.py +28 -0
- wbcore/contrib/currency/import_export/parsers/__init__.py +0 -0
- wbcore/contrib/currency/import_export/parsers/fixerio/__init__.py +0 -0
- wbcore/contrib/currency/import_export/parsers/fixerio/currency_fx_rates.py +34 -0
- wbcore/contrib/currency/migrations/0001_initial.py +89 -0
- wbcore/contrib/currency/migrations/__init__.py +0 -0
- wbcore/contrib/currency/models.py +176 -0
- wbcore/contrib/currency/release_notes/1_0_0.md +13 -0
- wbcore/contrib/currency/release_notes/__init__.py +0 -0
- wbcore/contrib/currency/serializers.py +40 -0
- wbcore/contrib/currency/tests/__init__.py +0 -0
- wbcore/contrib/currency/tests/conftest.py +7 -0
- wbcore/contrib/currency/tests/test_models.py +104 -0
- wbcore/contrib/currency/tests/test_serializers.py +62 -0
- wbcore/contrib/currency/tests/test_viewsets.py +197 -0
- wbcore/contrib/currency/urls.py +19 -0
- wbcore/contrib/currency/viewsets/__init__.py +2 -0
- wbcore/contrib/currency/viewsets/buttons/__init__.py +0 -0
- wbcore/contrib/currency/viewsets/currency.py +56 -0
- wbcore/contrib/currency/viewsets/currency_fx_rates.py +32 -0
- wbcore/contrib/currency/viewsets/display/__init__.py +2 -0
- wbcore/contrib/currency/viewsets/display/currency.py +37 -0
- wbcore/contrib/currency/viewsets/display/currency_fx_rates.py +9 -0
- wbcore/contrib/currency/viewsets/endpoints/__init__.py +1 -0
- wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +14 -0
- wbcore/contrib/currency/viewsets/menu/__init__.py +1 -0
- wbcore/contrib/currency/viewsets/menu/currency.py +8 -0
- wbcore/contrib/currency/viewsets/preview/__init__.py +1 -0
- wbcore/contrib/currency/viewsets/preview/currency.py +10 -0
- wbcore/contrib/currency/viewsets/titles/__init__.py +2 -0
- wbcore/contrib/currency/viewsets/titles/currency.py +6 -0
- wbcore/contrib/currency/viewsets/titles/currency_fx_rates.py +8 -0
- wbcore/contrib/dataloader/__init__.py +1 -0
- wbcore/contrib/dataloader/apps.py +5 -0
- wbcore/contrib/dataloader/dataloaders/__init__.py +2 -0
- wbcore/contrib/dataloader/dataloaders/dataloaders.py +24 -0
- wbcore/contrib/dataloader/dataloaders/proxies.py +81 -0
- wbcore/contrib/dataloader/models/__init__.py +1 -0
- wbcore/contrib/dataloader/models/entities.py +29 -0
- wbcore/contrib/dataloader/models/querysets/__init__.py +1 -0
- wbcore/contrib/dataloader/models/querysets/entities.py +27 -0
- wbcore/contrib/dataloader/tests/__init__.py +0 -0
- wbcore/contrib/dataloader/tests/conftest.py +26 -0
- wbcore/contrib/dataloader/tests/test/__init__.py +0 -0
- wbcore/contrib/dataloader/tests/test/dataloaders/__init__.py +0 -0
- wbcore/contrib/dataloader/tests/test/dataloaders/dataloaders.py +18 -0
- wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +6 -0
- wbcore/contrib/dataloader/tests/test/dataloaders/proxies.py +11 -0
- wbcore/contrib/dataloader/tests/test/factories.py +13 -0
- wbcore/contrib/dataloader/tests/test/models.py +10 -0
- wbcore/contrib/dataloader/tests/test_dataloaders.py +37 -0
- wbcore/contrib/dataloader/tests/test_entities.py +12 -0
- wbcore/contrib/dataloader/utils.py +17 -0
- wbcore/contrib/directory/__init__.py +0 -0
- wbcore/contrib/directory/admin/__init__.py +14 -0
- wbcore/contrib/directory/admin/contacts.py +54 -0
- wbcore/contrib/directory/admin/entries.py +230 -0
- wbcore/contrib/directory/admin/relationships.py +73 -0
- wbcore/contrib/directory/apps.py +6 -0
- wbcore/contrib/directory/configs.py +8 -0
- wbcore/contrib/directory/configurations.py +69 -0
- wbcore/contrib/directory/dynamic_preferences_registry.py +61 -0
- wbcore/contrib/directory/factories/__init__.py +34 -0
- wbcore/contrib/directory/factories/contacts.py +71 -0
- wbcore/contrib/directory/factories/entries.py +169 -0
- wbcore/contrib/directory/factories/relationships.py +77 -0
- wbcore/contrib/directory/filters/__init__.py +22 -0
- wbcore/contrib/directory/filters/contacts.py +233 -0
- wbcore/contrib/directory/filters/entries.py +247 -0
- wbcore/contrib/directory/filters/relationships.py +89 -0
- wbcore/contrib/directory/migrations/0001_initial.py +871 -0
- wbcore/contrib/directory/migrations/0002_auto_20230414_1553.py +42 -0
- wbcore/contrib/directory/migrations/0003_remove_entry_last_event.py +16 -0
- wbcore/contrib/directory/migrations/0004_entry_is_draft_entry.py +21 -0
- wbcore/contrib/directory/migrations/0005_entry_salutation.py +17 -0
- wbcore/contrib/directory/migrations/0006_employeremployeerelationship_position_name.py +23 -0
- wbcore/contrib/directory/migrations/0007_alter_bankingcontact_options.py +20 -0
- wbcore/contrib/directory/migrations/0008_bankingcontact_access.py +17 -0
- wbcore/contrib/directory/migrations/0009_remove_entry_external_identfier_and_more.py +22 -0
- wbcore/contrib/directory/migrations/__init__.py +0 -0
- wbcore/contrib/directory/models/__init__.py +27 -0
- wbcore/contrib/directory/models/contacts.py +554 -0
- wbcore/contrib/directory/models/entries.py +889 -0
- wbcore/contrib/directory/models/relationships.py +634 -0
- wbcore/contrib/directory/preferences.py +10 -0
- wbcore/contrib/directory/release_notes/1_0_0.md +13 -0
- wbcore/contrib/directory/release_notes/1_0_1.md +13 -0
- wbcore/contrib/directory/release_notes/__init__.py +0 -0
- wbcore/contrib/directory/serializers/__init__.py +63 -0
- wbcore/contrib/directory/serializers/companies.py +158 -0
- wbcore/contrib/directory/serializers/contacts.py +404 -0
- wbcore/contrib/directory/serializers/entries.py +344 -0
- wbcore/contrib/directory/serializers/entry_representations.py +35 -0
- wbcore/contrib/directory/serializers/persons.py +209 -0
- wbcore/contrib/directory/serializers/relationships.py +332 -0
- wbcore/contrib/directory/signals.py +3 -0
- wbcore/contrib/directory/tests/__init__.py +0 -0
- wbcore/contrib/directory/tests/conftest.py +60 -0
- wbcore/contrib/directory/tests/disable_signals.py +52 -0
- wbcore/contrib/directory/tests/e2e/__init__.py +7 -0
- wbcore/contrib/directory/tests/e2e/e2e_directory_utility.py +162 -0
- wbcore/contrib/directory/tests/signals.py +90 -0
- wbcore/contrib/directory/tests/test_configs.py +6 -0
- wbcore/contrib/directory/tests/test_filters.py +59 -0
- wbcore/contrib/directory/tests/test_models.py +285 -0
- wbcore/contrib/directory/tests/test_permissions.py +122 -0
- wbcore/contrib/directory/tests/test_serializers.py +201 -0
- wbcore/contrib/directory/tests/test_viewsets.py +677 -0
- wbcore/contrib/directory/tests/tests.py +130 -0
- wbcore/contrib/directory/typings.py +17 -0
- wbcore/contrib/directory/urls.py +135 -0
- wbcore/contrib/directory/viewsets/__init__.py +58 -0
- wbcore/contrib/directory/viewsets/buttons/__init__.py +7 -0
- wbcore/contrib/directory/viewsets/buttons/contacts.py +16 -0
- wbcore/contrib/directory/viewsets/buttons/entries.py +133 -0
- wbcore/contrib/directory/viewsets/buttons/relationships.py +31 -0
- wbcore/contrib/directory/viewsets/contacts.py +393 -0
- wbcore/contrib/directory/viewsets/display/__init__.py +36 -0
- wbcore/contrib/directory/viewsets/display/contacts.py +380 -0
- wbcore/contrib/directory/viewsets/display/entries.py +501 -0
- wbcore/contrib/directory/viewsets/display/relationships.py +315 -0
- wbcore/contrib/directory/viewsets/display/utils.py +33 -0
- wbcore/contrib/directory/viewsets/endpoints/__init__.py +22 -0
- wbcore/contrib/directory/viewsets/endpoints/contacts.py +54 -0
- wbcore/contrib/directory/viewsets/endpoints/entries.py +30 -0
- wbcore/contrib/directory/viewsets/endpoints/relationships.py +105 -0
- wbcore/contrib/directory/viewsets/entries.py +212 -0
- wbcore/contrib/directory/viewsets/menu/__init__.py +16 -0
- wbcore/contrib/directory/viewsets/menu/contacts.py +25 -0
- wbcore/contrib/directory/viewsets/menu/entries.py +61 -0
- wbcore/contrib/directory/viewsets/menu/relationships.py +31 -0
- wbcore/contrib/directory/viewsets/menu/utils.py +72 -0
- wbcore/contrib/directory/viewsets/mixins.py +11 -0
- wbcore/contrib/directory/viewsets/previews/__init__.py +2 -0
- wbcore/contrib/directory/viewsets/previews/contacts.py +18 -0
- wbcore/contrib/directory/viewsets/previews/entries.py +31 -0
- wbcore/contrib/directory/viewsets/relationships.py +241 -0
- wbcore/contrib/directory/viewsets/titles/__init__.py +30 -0
- wbcore/contrib/directory/viewsets/titles/contacts.py +122 -0
- wbcore/contrib/directory/viewsets/titles/entries.py +29 -0
- wbcore/contrib/directory/viewsets/titles/relationships.py +86 -0
- wbcore/contrib/directory/viewsets/titles/utils.py +46 -0
- wbcore/contrib/directory/viewsets/utils.py +101 -0
- wbcore/contrib/documents/__init__.py +0 -0
- wbcore/contrib/documents/admin.py +79 -0
- wbcore/contrib/documents/apps.py +6 -0
- wbcore/contrib/documents/factories.py +43 -0
- wbcore/contrib/documents/filters.py +82 -0
- wbcore/contrib/documents/migrations/0001_initial.py +189 -0
- wbcore/contrib/documents/migrations/0002_documentmodelrelationship_primary_and_more.py +22 -0
- wbcore/contrib/documents/migrations/0003_alter_documentmodelrelationship_unique_together_and_more.py +30 -0
- wbcore/contrib/documents/migrations/0004_auto_20240103_0958.py +44 -0
- wbcore/contrib/documents/migrations/0005_document_valid_from_document_valid_until_and_more.py +32 -0
- wbcore/contrib/documents/migrations/__init__.py +0 -0
- wbcore/contrib/documents/models/__init__.py +4 -0
- wbcore/contrib/documents/models/document_model_relationships.py +57 -0
- wbcore/contrib/documents/models/document_types.py +35 -0
- wbcore/contrib/documents/models/documents.py +309 -0
- wbcore/contrib/documents/models/mixins.py +10 -0
- wbcore/contrib/documents/models/shareable_links.py +90 -0
- wbcore/contrib/documents/release_notes/1_0_0.md +13 -0
- wbcore/contrib/documents/release_notes/__init__.py +0 -0
- wbcore/contrib/documents/serializers/__init__.py +12 -0
- wbcore/contrib/documents/serializers/document_model_relationships.py +31 -0
- wbcore/contrib/documents/serializers/document_types.py +40 -0
- wbcore/contrib/documents/serializers/documents.py +64 -0
- wbcore/contrib/documents/serializers/shareable_links.py +90 -0
- wbcore/contrib/documents/urls.py +42 -0
- wbcore/contrib/documents/viewsets/__init__.py +10 -0
- wbcore/contrib/documents/viewsets/buttons/__init__.py +3 -0
- wbcore/contrib/documents/viewsets/buttons/documents.py +53 -0
- wbcore/contrib/documents/viewsets/buttons/shareable_links.py +20 -0
- wbcore/contrib/documents/viewsets/buttons/signals.py +13 -0
- wbcore/contrib/documents/viewsets/display/__init__.py +4 -0
- wbcore/contrib/documents/viewsets/display/document_model_relationships.py +18 -0
- wbcore/contrib/documents/viewsets/display/document_types.py +23 -0
- wbcore/contrib/documents/viewsets/display/documents.py +101 -0
- wbcore/contrib/documents/viewsets/display/shareable_links.py +65 -0
- wbcore/contrib/documents/viewsets/document_model_relationships.py +25 -0
- wbcore/contrib/documents/viewsets/document_types.py +37 -0
- wbcore/contrib/documents/viewsets/documents.py +107 -0
- wbcore/contrib/documents/viewsets/endpoints/__init__.py +5 -0
- wbcore/contrib/documents/viewsets/endpoints/documents.py +19 -0
- wbcore/contrib/documents/viewsets/endpoints/documents_model_relationships.py +13 -0
- wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +45 -0
- wbcore/contrib/documents/viewsets/menu/__init__.py +1 -0
- wbcore/contrib/documents/viewsets/menu/documents.py +24 -0
- wbcore/contrib/documents/viewsets/previews/__init__.py +1 -0
- wbcore/contrib/documents/viewsets/previews/documents.py +10 -0
- wbcore/contrib/documents/viewsets/shareable_links.py +109 -0
- wbcore/contrib/documents/viewsets/titles/__init__.py +3 -0
- wbcore/contrib/documents/viewsets/titles/document_types.py +13 -0
- wbcore/contrib/documents/viewsets/titles/documents.py +26 -0
- wbcore/contrib/documents/viewsets/titles/shareable_links.py +13 -0
- wbcore/contrib/dynamic_preferences/__init__.py +0 -0
- wbcore/contrib/dynamic_preferences/types.py +19 -0
- wbcore/contrib/example_app/__init__.py +0 -0
- wbcore/contrib/example_app/admin.py +117 -0
- wbcore/contrib/example_app/apps.py +6 -0
- wbcore/contrib/example_app/factories/__init__.py +8 -0
- wbcore/contrib/example_app/factories/event.py +26 -0
- wbcore/contrib/example_app/factories/league.py +15 -0
- wbcore/contrib/example_app/factories/match.py +25 -0
- wbcore/contrib/example_app/factories/person.py +32 -0
- wbcore/contrib/example_app/factories/role.py +9 -0
- wbcore/contrib/example_app/factories/sport.py +12 -0
- wbcore/contrib/example_app/factories/stadium.py +12 -0
- wbcore/contrib/example_app/factories/team.py +35 -0
- wbcore/contrib/example_app/filters/__init__.py +9 -0
- wbcore/contrib/example_app/filters/event.py +80 -0
- wbcore/contrib/example_app/filters/league.py +74 -0
- wbcore/contrib/example_app/filters/match.py +92 -0
- wbcore/contrib/example_app/filters/person.py +77 -0
- wbcore/contrib/example_app/filters/role.py +17 -0
- wbcore/contrib/example_app/filters/sport.py +26 -0
- wbcore/contrib/example_app/filters/stadium.py +30 -0
- wbcore/contrib/example_app/filters/team.py +77 -0
- wbcore/contrib/example_app/filters/teamresult.py +47 -0
- wbcore/contrib/example_app/migrations/0001_initial.py +498 -0
- wbcore/contrib/example_app/migrations/0002_sportperson_profile.py +49 -0
- wbcore/contrib/example_app/migrations/0003_change_stadium_capacity.py +31 -0
- wbcore/contrib/example_app/migrations/0004_alter_player_transfer_value.py +21 -0
- wbcore/contrib/example_app/migrations/0005_sportperson_profile_image.py +23 -0
- wbcore/contrib/example_app/migrations/0006_league_season_period_player_is_active_and_more.py +116 -0
- wbcore/contrib/example_app/migrations/0007_alter_player_options_alter_team_options_and_more.py +40 -0
- wbcore/contrib/example_app/migrations/__init__.py +0 -0
- wbcore/contrib/example_app/models.py +906 -0
- wbcore/contrib/example_app/serializers/__init__.py +31 -0
- wbcore/contrib/example_app/serializers/league.py +111 -0
- wbcore/contrib/example_app/serializers/match_event.py +304 -0
- wbcore/contrib/example_app/serializers/person_team.py +280 -0
- wbcore/contrib/example_app/serializers/role.py +16 -0
- wbcore/contrib/example_app/serializers/season.py +53 -0
- wbcore/contrib/example_app/serializers/sport.py +37 -0
- wbcore/contrib/example_app/serializers/stadium.py +58 -0
- wbcore/contrib/example_app/serializers/teamresult.py +43 -0
- wbcore/contrib/example_app/tests/__init__.py +0 -0
- wbcore/contrib/example_app/tests/conftest.py +13 -0
- wbcore/contrib/example_app/tests/e2e/__init__.py +1 -0
- wbcore/contrib/example_app/tests/e2e/e2e_example_app_utility.py +51 -0
- wbcore/contrib/example_app/tests/e2e/test_league.py +69 -0
- wbcore/contrib/example_app/tests/e2e/test_person.py +67 -0
- wbcore/contrib/example_app/tests/e2e/test_teams.py +56 -0
- wbcore/contrib/example_app/tests/signals.py +7 -0
- wbcore/contrib/example_app/tests/test_displays.py +40 -0
- wbcore/contrib/example_app/tests/test_filters.py +70 -0
- wbcore/contrib/example_app/tests/test_utils.py +25 -0
- wbcore/contrib/example_app/urls.py +79 -0
- wbcore/contrib/example_app/utils.py +20 -0
- wbcore/contrib/example_app/viewsets/__init__.py +29 -0
- wbcore/contrib/example_app/viewsets/buttons/__init__.py +2 -0
- wbcore/contrib/example_app/viewsets/buttons/person.py +18 -0
- wbcore/contrib/example_app/viewsets/buttons/team.py +23 -0
- wbcore/contrib/example_app/viewsets/displays/__init__.py +23 -0
- wbcore/contrib/example_app/viewsets/displays/event.py +186 -0
- wbcore/contrib/example_app/viewsets/displays/league.py +390 -0
- wbcore/contrib/example_app/viewsets/displays/match.py +264 -0
- wbcore/contrib/example_app/viewsets/displays/person.py +251 -0
- wbcore/contrib/example_app/viewsets/displays/role.py +16 -0
- wbcore/contrib/example_app/viewsets/displays/season.py +65 -0
- wbcore/contrib/example_app/viewsets/displays/sport.py +115 -0
- wbcore/contrib/example_app/viewsets/displays/stadium.py +149 -0
- wbcore/contrib/example_app/viewsets/displays/team.py +230 -0
- wbcore/contrib/example_app/viewsets/displays/teamresult.py +30 -0
- wbcore/contrib/example_app/viewsets/endpoints/__init__.py +12 -0
- wbcore/contrib/example_app/viewsets/endpoints/endpoints.py +79 -0
- wbcore/contrib/example_app/viewsets/event.py +287 -0
- wbcore/contrib/example_app/viewsets/league.py +72 -0
- wbcore/contrib/example_app/viewsets/match.py +119 -0
- wbcore/contrib/example_app/viewsets/menu/__init__.py +1 -0
- wbcore/contrib/example_app/viewsets/menu/menus.py +102 -0
- wbcore/contrib/example_app/viewsets/menus.py +63 -0
- wbcore/contrib/example_app/viewsets/person.py +133 -0
- wbcore/contrib/example_app/viewsets/role.py +25 -0
- wbcore/contrib/example_app/viewsets/season.py +23 -0
- wbcore/contrib/example_app/viewsets/sport.py +26 -0
- wbcore/contrib/example_app/viewsets/stadium.py +30 -0
- wbcore/contrib/example_app/viewsets/team.py +68 -0
- wbcore/contrib/example_app/viewsets/teamresult.py +106 -0
- wbcore/contrib/example_app/viewsets/titles/__init__.py +9 -0
- wbcore/contrib/example_app/viewsets/titles/event.py +41 -0
- wbcore/contrib/example_app/viewsets/titles/league.py +24 -0
- wbcore/contrib/example_app/viewsets/titles/match.py +34 -0
- wbcore/contrib/example_app/viewsets/titles/person.py +35 -0
- wbcore/contrib/example_app/viewsets/titles/role.py +13 -0
- wbcore/contrib/example_app/viewsets/titles/sport.py +13 -0
- wbcore/contrib/example_app/viewsets/titles/stadium.py +13 -0
- wbcore/contrib/example_app/viewsets/titles/team.py +24 -0
- wbcore/contrib/example_app/viewsets/titles/teamresult.py +12 -0
- wbcore/contrib/geography/__init__.py +0 -0
- wbcore/contrib/geography/admin.py +30 -0
- wbcore/contrib/geography/apps.py +5 -0
- wbcore/contrib/geography/factories.py +46 -0
- wbcore/contrib/geography/import_export/__init__.py +0 -0
- wbcore/contrib/geography/import_export/resources/__init__.py +0 -0
- wbcore/contrib/geography/import_export/resources/geography.py +10 -0
- wbcore/contrib/geography/migrations/0001_initial.py +110 -0
- wbcore/contrib/geography/migrations/__init__.py +0 -0
- wbcore/contrib/geography/models.py +147 -0
- wbcore/contrib/geography/release_notes/1_0_0.md +13 -0
- wbcore/contrib/geography/release_notes/__init__.py +0 -0
- wbcore/contrib/geography/serializers.py +32 -0
- wbcore/contrib/geography/tests/__init__.py +0 -0
- wbcore/contrib/geography/tests/conftest.py +12 -0
- wbcore/contrib/geography/tests/signals.py +7 -0
- wbcore/contrib/geography/tests/test_models.py +12 -0
- wbcore/contrib/geography/tests/test_serializers.py +7 -0
- wbcore/contrib/geography/tests/test_viewsets.py +6 -0
- wbcore/contrib/geography/tests/tests.py +12 -0
- wbcore/contrib/geography/urls.py +12 -0
- wbcore/contrib/geography/viewsets/__init__.py +1 -0
- wbcore/contrib/geography/viewsets/buttons/__init__.py +0 -0
- wbcore/contrib/geography/viewsets/display/__init__.py +1 -0
- wbcore/contrib/geography/viewsets/display/geography.py +32 -0
- wbcore/contrib/geography/viewsets/endpoints/__init__.py +0 -0
- wbcore/contrib/geography/viewsets/geography.py +57 -0
- wbcore/contrib/geography/viewsets/menu/__init__.py +1 -0
- wbcore/contrib/geography/viewsets/menu/geography.py +8 -0
- wbcore/contrib/geography/viewsets/preview/__init__.py +1 -0
- wbcore/contrib/geography/viewsets/preview/geography.py +19 -0
- wbcore/contrib/geography/viewsets/titles/__init__.py +0 -0
- wbcore/contrib/geography/viewsets/titles/geography.py +14 -0
- wbcore/contrib/gleap/__init__.py +0 -0
- wbcore/contrib/gleap/apps.py +5 -0
- wbcore/contrib/gleap/configs.py +11 -0
- wbcore/contrib/gleap/configurations.py +6 -0
- wbcore/contrib/gleap/hashes.py +13 -0
- wbcore/contrib/gleap/tests/__init__.py +0 -0
- wbcore/contrib/gleap/tests/conftest.py +1 -0
- wbcore/contrib/gleap/tests/tests.py +29 -0
- wbcore/contrib/gleap/urls.py +7 -0
- wbcore/contrib/gleap/views.py +31 -0
- wbcore/contrib/guardian/migrations/0001_initial.py +103 -0
- wbcore/contrib/guardian/migrations/__init__.py +0 -0
- wbcore/contrib/guardian/models/__init__.py +1 -0
- wbcore/contrib/guardian/models/mixins.py +138 -0
- wbcore/contrib/guardian/models/models.py +29 -0
- wbcore/contrib/guardian/tests/__init__.py +0 -0
- wbcore/contrib/guardian/tests/conftest.py +1 -0
- wbcore/contrib/guardian/tests/test_model_mixins.py +93 -0
- wbcore/contrib/guardian/tests/test_tasks.py +77 -0
- wbcore/contrib/guardian/tests/test_utils.py +196 -0
- wbcore/contrib/guardian/tests/test_viewsets.py +48 -0
- wbcore/contrib/guardian/viewsets/__init__.py +1 -0
- wbcore/contrib/guardian/viewsets/configs/__init__.py +4 -0
- wbcore/contrib/guardian/viewsets/configs/buttons.py +27 -0
- wbcore/contrib/guardian/viewsets/configs/displays.py +43 -0
- wbcore/contrib/guardian/viewsets/configs/endpoints.py +18 -0
- wbcore/contrib/guardian/viewsets/configs/titles.py +16 -0
- wbcore/contrib/guardian/viewsets/mixins.py +6 -0
- wbcore/contrib/guardian/viewsets/viewsets.py +139 -0
- wbcore/contrib/icons/__init__.py +1 -0
- wbcore/contrib/icons/apps.py +5 -0
- wbcore/contrib/icons/backends/__init__.py +5 -0
- wbcore/contrib/icons/backends/default.py +374 -0
- wbcore/contrib/icons/backends/material.py +135 -0
- wbcore/contrib/icons/icons.py +169 -0
- wbcore/contrib/icons/models.py +11 -0
- wbcore/contrib/icons/serializers.py +18 -0
- wbcore/contrib/io/__init__.py +0 -0
- wbcore/contrib/io/admin.py +150 -0
- wbcore/contrib/io/apps.py +27 -0
- wbcore/contrib/io/backends/__init__.py +5 -0
- wbcore/contrib/io/backends/abstract.py +60 -0
- wbcore/contrib/io/backends/mail.py +85 -0
- wbcore/contrib/io/backends/sftp.py +63 -0
- wbcore/contrib/io/backends/stream.py +92 -0
- wbcore/contrib/io/backends/utils.py +42 -0
- wbcore/contrib/io/configs/__init__.py +0 -0
- wbcore/contrib/io/configs/endpoints.py +12 -0
- wbcore/contrib/io/configurations/__init__.py +1 -0
- wbcore/contrib/io/configurations/base.py +7 -0
- wbcore/contrib/io/dynamic_preferences_registry.py +15 -0
- wbcore/contrib/io/enums.py +15 -0
- wbcore/contrib/io/exceptions.py +16 -0
- wbcore/contrib/io/factories.py +202 -0
- wbcore/contrib/io/imports.py +305 -0
- wbcore/contrib/io/management/__init__.py +13 -0
- wbcore/contrib/io/migrations/0001_initial_squashed.py +319 -0
- wbcore/contrib/io/migrations/0002_importsource_creator.py +26 -0
- wbcore/contrib/io/migrations/0003_auto_20240103_1000.py +46 -0
- wbcore/contrib/io/migrations/0004_alter_importsource_status_exportsource.py +134 -0
- wbcore/contrib/io/migrations/0005_exportsource_data_alter_exportsource_query_str_and_more.py +67 -0
- wbcore/contrib/io/migrations/0006_alter_exportsource_query_params.py +20 -0
- wbcore/contrib/io/migrations/0007_alter_exportsource_query_params.py +23 -0
- wbcore/contrib/io/migrations/__init__.py +0 -0
- wbcore/contrib/io/mixins.py +37 -0
- wbcore/contrib/io/models.py +1005 -0
- wbcore/contrib/io/release_notes/1_0_0.md +13 -0
- wbcore/contrib/io/release_notes/__init__.py +0 -0
- wbcore/contrib/io/resources.py +177 -0
- wbcore/contrib/io/serializers.py +136 -0
- wbcore/contrib/io/tests/__init__.py +0 -0
- wbcore/contrib/io/tests/conftest.py +42 -0
- wbcore/contrib/io/tests/test_backends.py +128 -0
- wbcore/contrib/io/tests/test_exports.py +130 -0
- wbcore/contrib/io/tests/test_imports.py +167 -0
- wbcore/contrib/io/tests/test_models.py +363 -0
- wbcore/contrib/io/tests/tests.py +18 -0
- wbcore/contrib/io/urls.py +28 -0
- wbcore/contrib/io/utils.py +44 -0
- wbcore/contrib/io/viewset_mixins.py +301 -0
- wbcore/contrib/io/viewsets.py +138 -0
- wbcore/contrib/notifications/__init__.py +0 -0
- wbcore/contrib/notifications/admin.py +61 -0
- wbcore/contrib/notifications/apps.py +38 -0
- wbcore/contrib/notifications/backends/__init__.py +0 -0
- wbcore/contrib/notifications/backends/abstract_backend.py +13 -0
- wbcore/contrib/notifications/backends/console/__init__.py +1 -0
- wbcore/contrib/notifications/backends/console/backends.py +25 -0
- wbcore/contrib/notifications/backends/firebase/__init__.py +1 -0
- wbcore/contrib/notifications/backends/firebase/backends.py +102 -0
- wbcore/contrib/notifications/configs.py +12 -0
- wbcore/contrib/notifications/configurations.py +9 -0
- wbcore/contrib/notifications/dispatch.py +71 -0
- wbcore/contrib/notifications/factories/__init__.py +0 -0
- wbcore/contrib/notifications/factories/notification_types.py +22 -0
- wbcore/contrib/notifications/factories/notifications.py +16 -0
- wbcore/contrib/notifications/factories/tokens.py +11 -0
- wbcore/contrib/notifications/migrations/0001_initial.py +116 -0
- wbcore/contrib/notifications/migrations/0002_notificationusertoken_unique_user_token_device.py +18 -0
- wbcore/contrib/notifications/migrations/0003_notificationusertoken_updated.py +17 -0
- wbcore/contrib/notifications/migrations/0004_alter_notification_body.py +17 -0
- wbcore/contrib/notifications/migrations/0005_alter_notification_endpoint.py +17 -0
- wbcore/contrib/notifications/migrations/0006_notification_created.py +25 -0
- wbcore/contrib/notifications/migrations/__init__.py +0 -0
- wbcore/contrib/notifications/models/__init__.py +3 -0
- wbcore/contrib/notifications/models/notification_types.py +112 -0
- wbcore/contrib/notifications/models/notifications.py +81 -0
- wbcore/contrib/notifications/models/tokens.py +45 -0
- wbcore/contrib/notifications/release_notes/1_0_0.md +13 -0
- wbcore/contrib/notifications/release_notes/__init__.py +0 -0
- wbcore/contrib/notifications/serializers/__init__.py +5 -0
- wbcore/contrib/notifications/serializers/notification_types.py +36 -0
- wbcore/contrib/notifications/serializers/notifications.py +33 -0
- wbcore/contrib/notifications/tasks.py +55 -0
- wbcore/contrib/notifications/tests/__init__.py +0 -0
- wbcore/contrib/notifications/tests/conftest.py +47 -0
- wbcore/contrib/notifications/tests/test_backends/__init__.py +0 -0
- wbcore/contrib/notifications/tests/test_backends/test_firebase.py +78 -0
- wbcore/contrib/notifications/tests/test_configs.py +7 -0
- wbcore/contrib/notifications/tests/test_models/__init__.py +0 -0
- wbcore/contrib/notifications/tests/test_models/test_notification_types.py +84 -0
- wbcore/contrib/notifications/tests/test_models/test_notifications.py +45 -0
- wbcore/contrib/notifications/tests/test_models/test_tokens.py +21 -0
- wbcore/contrib/notifications/tests/test_serializers/__init__.py +0 -0
- wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +53 -0
- wbcore/contrib/notifications/tests/test_serializers/test_notifications.py +23 -0
- wbcore/contrib/notifications/tests/test_tasks.py +71 -0
- wbcore/contrib/notifications/tests/test_utils.py +0 -0
- wbcore/contrib/notifications/tests/test_viewsets/__init__.py +0 -0
- wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +121 -0
- wbcore/contrib/notifications/tests/test_viewsets/test_notifications.py +120 -0
- wbcore/contrib/notifications/urls.py +26 -0
- wbcore/contrib/notifications/utils.py +20 -0
- wbcore/contrib/notifications/views.py +62 -0
- wbcore/contrib/notifications/viewsets/__init__.py +5 -0
- wbcore/contrib/notifications/viewsets/menus.py +14 -0
- wbcore/contrib/notifications/viewsets/notification_types.py +40 -0
- wbcore/contrib/notifications/viewsets/notifications.py +57 -0
- wbcore/contrib/tags/__init__.py +0 -0
- wbcore/contrib/tags/admin.py +17 -0
- wbcore/contrib/tags/apps.py +9 -0
- wbcore/contrib/tags/factories.py +27 -0
- wbcore/contrib/tags/filters.py +42 -0
- wbcore/contrib/tags/migrations/0001_initial.py +62 -0
- wbcore/contrib/tags/migrations/__init__.py +0 -0
- wbcore/contrib/tags/models/__init__.py +2 -0
- wbcore/contrib/tags/models/mixins.py +27 -0
- wbcore/contrib/tags/models/tags.py +103 -0
- wbcore/contrib/tags/release_notes/1_0_0.md +13 -0
- wbcore/contrib/tags/release_notes/__init__.py +0 -0
- wbcore/contrib/tags/serializers.py +87 -0
- wbcore/contrib/tags/signals.py +17 -0
- wbcore/contrib/tags/tests/__init__.py +0 -0
- wbcore/contrib/tags/tests/conftest.py +7 -0
- wbcore/contrib/tags/tests/tests.py +17 -0
- wbcore/contrib/tags/urls.py +14 -0
- wbcore/contrib/tags/viewsets/__init__.py +8 -0
- wbcore/contrib/tags/viewsets/display.py +50 -0
- wbcore/contrib/tags/viewsets/menu.py +15 -0
- wbcore/contrib/tags/viewsets/viewsets.py +58 -0
- wbcore/contrib/workflow/__init__.py +1 -0
- wbcore/contrib/workflow/admin/__init__.py +15 -0
- wbcore/contrib/workflow/admin/condition.py +8 -0
- wbcore/contrib/workflow/admin/data.py +14 -0
- wbcore/contrib/workflow/admin/display.py +8 -0
- wbcore/contrib/workflow/admin/process.py +36 -0
- wbcore/contrib/workflow/admin/step.py +91 -0
- wbcore/contrib/workflow/admin/transition.py +8 -0
- wbcore/contrib/workflow/admin/workflow.py +8 -0
- wbcore/contrib/workflow/apps.py +26 -0
- wbcore/contrib/workflow/configs.py +10 -0
- wbcore/contrib/workflow/decorators.py +25 -0
- wbcore/contrib/workflow/dispatch.py +23 -0
- wbcore/contrib/workflow/factories/__init__.py +18 -0
- wbcore/contrib/workflow/factories/condition.py +15 -0
- wbcore/contrib/workflow/factories/data.py +22 -0
- wbcore/contrib/workflow/factories/display.py +27 -0
- wbcore/contrib/workflow/factories/process.py +69 -0
- wbcore/contrib/workflow/factories/step.py +155 -0
- wbcore/contrib/workflow/factories/transition.py +25 -0
- wbcore/contrib/workflow/factories/workflow.py +19 -0
- wbcore/contrib/workflow/filters/__init__.py +24 -0
- wbcore/contrib/workflow/filters/condition.py +23 -0
- wbcore/contrib/workflow/filters/data.py +24 -0
- wbcore/contrib/workflow/filters/process.py +164 -0
- wbcore/contrib/workflow/filters/step.py +226 -0
- wbcore/contrib/workflow/filters/transition.py +41 -0
- wbcore/contrib/workflow/filters/workflow.py +43 -0
- wbcore/contrib/workflow/migrations/0001_initial.py +788 -0
- wbcore/contrib/workflow/migrations/0002_alter_step_step_type.py +31 -0
- wbcore/contrib/workflow/migrations/0003_alter_condition_attribute_name_and_more.py +75 -0
- wbcore/contrib/workflow/migrations/0004_alter_userstep_assignee_method.py +27 -0
- wbcore/contrib/workflow/migrations/0005_alter_userstep_assignee_method.py +17 -0
- wbcore/contrib/workflow/migrations/__init__.py +0 -0
- wbcore/contrib/workflow/models/__init__.py +19 -0
- wbcore/contrib/workflow/models/condition.py +123 -0
- wbcore/contrib/workflow/models/data.py +238 -0
- wbcore/contrib/workflow/models/display.py +33 -0
- wbcore/contrib/workflow/models/process.py +243 -0
- wbcore/contrib/workflow/models/step.py +735 -0
- wbcore/contrib/workflow/models/transition.py +70 -0
- wbcore/contrib/workflow/models/workflow.py +307 -0
- wbcore/contrib/workflow/serializers/__init__.py +37 -0
- wbcore/contrib/workflow/serializers/condition.py +64 -0
- wbcore/contrib/workflow/serializers/data.py +135 -0
- wbcore/contrib/workflow/serializers/display.py +25 -0
- wbcore/contrib/workflow/serializers/process.py +182 -0
- wbcore/contrib/workflow/serializers/signals.py +25 -0
- wbcore/contrib/workflow/serializers/step.py +364 -0
- wbcore/contrib/workflow/serializers/transition.py +80 -0
- wbcore/contrib/workflow/serializers/workflow.py +124 -0
- wbcore/contrib/workflow/sites.py +43 -0
- wbcore/contrib/workflow/tests/__init__.py +0 -0
- wbcore/contrib/workflow/tests/conftest.py +57 -0
- wbcore/contrib/workflow/tests/test_configs.py +6 -0
- wbcore/contrib/workflow/tests/test_dispatch.py +88 -0
- wbcore/contrib/workflow/tests/test_displays.py +119 -0
- wbcore/contrib/workflow/tests/test_filters.py +86 -0
- wbcore/contrib/workflow/tests/test_serializers.py +177 -0
- wbcore/contrib/workflow/tests/test_viewsets.py +358 -0
- wbcore/contrib/workflow/tests/test_workflow_assignees.py +225 -0
- wbcore/contrib/workflow/tests/tests.py +24 -0
- wbcore/contrib/workflow/urls.py +66 -0
- wbcore/contrib/workflow/utils.py +13 -0
- wbcore/contrib/workflow/viewsets/__init__.py +17 -0
- wbcore/contrib/workflow/viewsets/buttons/__init__.py +1 -0
- wbcore/contrib/workflow/viewsets/buttons/step.py +67 -0
- wbcore/contrib/workflow/viewsets/condition.py +32 -0
- wbcore/contrib/workflow/viewsets/data.py +33 -0
- wbcore/contrib/workflow/viewsets/display/__init__.py +15 -0
- wbcore/contrib/workflow/viewsets/display/condition.py +50 -0
- wbcore/contrib/workflow/viewsets/display/data.py +50 -0
- wbcore/contrib/workflow/viewsets/display/process.py +185 -0
- wbcore/contrib/workflow/viewsets/display/step.py +453 -0
- wbcore/contrib/workflow/viewsets/display/transition.py +75 -0
- wbcore/contrib/workflow/viewsets/display/workflow.py +167 -0
- wbcore/contrib/workflow/viewsets/endpoints/__init__.py +5 -0
- wbcore/contrib/workflow/viewsets/endpoints/condition.py +9 -0
- wbcore/contrib/workflow/viewsets/endpoints/data.py +9 -0
- wbcore/contrib/workflow/viewsets/endpoints/process.py +11 -0
- wbcore/contrib/workflow/viewsets/endpoints/step.py +24 -0
- wbcore/contrib/workflow/viewsets/endpoints/transition.py +18 -0
- wbcore/contrib/workflow/viewsets/menu/__init__.py +15 -0
- wbcore/contrib/workflow/viewsets/menu/condition.py +18 -0
- wbcore/contrib/workflow/viewsets/menu/data.py +18 -0
- wbcore/contrib/workflow/viewsets/menu/process.py +18 -0
- wbcore/contrib/workflow/viewsets/menu/step.py +123 -0
- wbcore/contrib/workflow/viewsets/menu/transition.py +18 -0
- wbcore/contrib/workflow/viewsets/menu/workflow.py +18 -0
- wbcore/contrib/workflow/viewsets/process.py +171 -0
- wbcore/contrib/workflow/viewsets/step.py +229 -0
- wbcore/contrib/workflow/viewsets/titles/__init__.py +16 -0
- wbcore/contrib/workflow/viewsets/titles/condition.py +13 -0
- wbcore/contrib/workflow/viewsets/titles/data.py +13 -0
- wbcore/contrib/workflow/viewsets/titles/process.py +26 -0
- wbcore/contrib/workflow/viewsets/titles/step.py +101 -0
- wbcore/contrib/workflow/viewsets/titles/transition.py +13 -0
- wbcore/contrib/workflow/viewsets/titles/workflow.py +13 -0
- wbcore/contrib/workflow/viewsets/transition.py +57 -0
- wbcore/contrib/workflow/viewsets/workflow.py +36 -0
- wbcore/contrib/workflow/workflows/__init__.py +1 -0
- wbcore/contrib/workflow/workflows/assignees.py +82 -0
- wbcore/crontab/__init__.py +0 -0
- wbcore/crontab/serializers.py +23 -0
- wbcore/crontab/viewsets.py +9 -0
- wbcore/dispatch.py +55 -0
- wbcore/docs/__init__.py +25 -0
- wbcore/docs/orderable.md +29 -0
- wbcore/docs/reparent.md +13 -0
- wbcore/dynamic_preferences_registry.py +29 -0
- wbcore/enums.py +98 -0
- wbcore/filters/__init__.py +21 -0
- wbcore/filters/backends.py +19 -0
- wbcore/filters/defaults.py +69 -0
- wbcore/filters/fields/__init__.py +15 -0
- wbcore/filters/fields/booleans.py +6 -0
- wbcore/filters/fields/choices.py +61 -0
- wbcore/filters/fields/content_type.py +33 -0
- wbcore/filters/fields/datetime.py +91 -0
- wbcore/filters/fields/models.py +113 -0
- wbcore/filters/fields/multiple_lookups.py +19 -0
- wbcore/filters/fields/numbers.py +46 -0
- wbcore/filters/fields/text.py +6 -0
- wbcore/filters/filterset.py +217 -0
- wbcore/filters/lookups.py +41 -0
- wbcore/filters/mixins.py +112 -0
- wbcore/filters/utils.py +21 -0
- wbcore/forms.py +125 -0
- wbcore/frontend.py +23 -0
- wbcore/frontend_user_configuration.py +96 -0
- wbcore/fsm/__init__.py +0 -0
- wbcore/fsm/markdown_extensions.py +31 -0
- wbcore/fsm/mixins.py +114 -0
- wbcore/management/__init__.py +88 -0
- wbcore/management/commands/__init__.py +0 -0
- wbcore/management/commands/bootstrap.py +18 -0
- wbcore/management/commands/clean_obsolete_object.py +21 -0
- wbcore/management/commands/handle_release_notes.py +53 -0
- wbcore/markdown/__init__.py +1 -0
- wbcore/markdown/admin.py +9 -0
- wbcore/markdown/dynamic_preferences_registry.py +16 -0
- wbcore/markdown/models.py +38 -0
- wbcore/markdown/template.py +38 -0
- wbcore/markdown/utils.py +36 -0
- wbcore/markdown/views.py +67 -0
- wbcore/menus/__init__.py +2 -0
- wbcore/menus/menus.py +96 -0
- wbcore/menus/registry.py +28 -0
- wbcore/menus/views.py +41 -0
- wbcore/messages.py +51 -0
- wbcore/metadata/__init__.py +0 -0
- wbcore/metadata/configs/__init__.py +0 -0
- wbcore/metadata/configs/base.py +86 -0
- wbcore/metadata/configs/buttons/__init__.py +4 -0
- wbcore/metadata/configs/buttons/bases.py +91 -0
- wbcore/metadata/configs/buttons/buttons.py +142 -0
- wbcore/metadata/configs/buttons/enums.py +25 -0
- wbcore/metadata/configs/buttons/metadata.py +8 -0
- wbcore/metadata/configs/buttons/view_config.py +176 -0
- wbcore/metadata/configs/display/__init__.py +4 -0
- wbcore/metadata/configs/display/configs.py +15 -0
- wbcore/metadata/configs/display/display.py +234 -0
- wbcore/metadata/configs/display/formatting.py +50 -0
- wbcore/metadata/configs/display/instance_display/__init__.py +15 -0
- wbcore/metadata/configs/display/instance_display/display.py +37 -0
- wbcore/metadata/configs/display/instance_display/enums.py +7 -0
- wbcore/metadata/configs/display/instance_display/layouts/__init__.py +3 -0
- wbcore/metadata/configs/display/instance_display/layouts/inlines.py +58 -0
- wbcore/metadata/configs/display/instance_display/layouts/layouts.py +77 -0
- wbcore/metadata/configs/display/instance_display/layouts/sections.py +43 -0
- wbcore/metadata/configs/display/instance_display/operators.py +22 -0
- wbcore/metadata/configs/display/instance_display/pages.py +40 -0
- wbcore/metadata/configs/display/instance_display/shortcuts.py +70 -0
- wbcore/metadata/configs/display/instance_display/signals.py +3 -0
- wbcore/metadata/configs/display/instance_display/styles.py +42 -0
- wbcore/metadata/configs/display/instance_display/utils.py +74 -0
- wbcore/metadata/configs/display/list_display.py +230 -0
- wbcore/metadata/configs/display/models.py +20 -0
- wbcore/metadata/configs/display/view_config.py +82 -0
- wbcore/metadata/configs/display/views.py +48 -0
- wbcore/metadata/configs/display/windows.py +28 -0
- wbcore/metadata/configs/documentations.py +11 -0
- wbcore/metadata/configs/endpoints.py +176 -0
- wbcore/metadata/configs/fields.py +17 -0
- wbcore/metadata/configs/filter_fields.py +42 -0
- wbcore/metadata/configs/identifiers.py +25 -0
- wbcore/metadata/configs/ordering_fields.py +24 -0
- wbcore/metadata/configs/paginations.py +11 -0
- wbcore/metadata/configs/preview.py +41 -0
- wbcore/metadata/configs/primary_keys.py +9 -0
- wbcore/metadata/configs/search_fields.py +9 -0
- wbcore/metadata/configs/titles.py +48 -0
- wbcore/metadata/configs/window_types.py +13 -0
- wbcore/metadata/exceptions.py +0 -0
- wbcore/metadata/metadata.py +33 -0
- wbcore/metadata/mixins.py +105 -0
- wbcore/metadata/tests/__init__.py +0 -0
- wbcore/metadata/tests/test_buttons.py +179 -0
- wbcore/metadata/utils.py +4 -0
- wbcore/migrations/0001_initial_squashed_squashed_0010_preset_appliedpreset.py +398 -0
- wbcore/migrations/0011_genericmodel.py +22 -0
- wbcore/migrations/0012_delete_notification.py +15 -0
- wbcore/migrations/0013_delete_colorgradient.py +14 -0
- wbcore/migrations/0014_biguserobjectpermission_system.py +44 -0
- wbcore/migrations/__init__.py +0 -0
- wbcore/models/__init__.py +6 -0
- wbcore/models/base.py +182 -0
- wbcore/models/fields.py +29 -0
- wbcore/models/orderable.py +6 -0
- wbcore/pagination.py +65 -0
- wbcore/pandas/__init__.py +0 -0
- wbcore/pandas/fields.py +136 -0
- wbcore/pandas/filters.py +113 -0
- wbcore/pandas/filterset.py +26 -0
- wbcore/pandas/metadata.py +14 -0
- wbcore/pandas/utils.py +129 -0
- wbcore/pandas/views.py +157 -0
- wbcore/permissions/__init__.py +0 -0
- wbcore/permissions/backend.py +35 -0
- wbcore/permissions/mixins.py +72 -0
- wbcore/permissions/permissions.py +50 -0
- wbcore/permissions/registry.py +32 -0
- wbcore/permissions/shortcuts.py +37 -0
- wbcore/permissions/utils.py +26 -0
- wbcore/release_notes/__init__.py +0 -0
- wbcore/release_notes/admin.py +30 -0
- wbcore/release_notes/buttons.py +25 -0
- wbcore/release_notes/display.py +57 -0
- wbcore/release_notes/filters.py +35 -0
- wbcore/release_notes/models.py +65 -0
- wbcore/release_notes/serializers.py +19 -0
- wbcore/release_notes/utils.py +14 -0
- wbcore/release_notes/viewsets.py +45 -0
- wbcore/reversion/__init__.py +0 -0
- wbcore/reversion/filters.py +38 -0
- wbcore/reversion/serializers.py +80 -0
- wbcore/reversion/viewsets/__init__.py +6 -0
- wbcore/reversion/viewsets/buttons.py +94 -0
- wbcore/reversion/viewsets/displays.py +44 -0
- wbcore/reversion/viewsets/endpoints.py +29 -0
- wbcore/reversion/viewsets/titles.py +17 -0
- wbcore/reversion/viewsets/viewsets.py +111 -0
- wbcore/routers.py +63 -0
- wbcore/search/__init__.py +62 -0
- wbcore/serializers/__init__.py +66 -0
- wbcore/serializers/fields/__init__.py +58 -0
- wbcore/serializers/fields/boolean.py +51 -0
- wbcore/serializers/fields/choice.py +36 -0
- wbcore/serializers/fields/datetime.py +143 -0
- wbcore/serializers/fields/fields.py +190 -0
- wbcore/serializers/fields/file.py +20 -0
- wbcore/serializers/fields/fsm.py +20 -0
- wbcore/serializers/fields/json.py +56 -0
- wbcore/serializers/fields/list.py +105 -0
- wbcore/serializers/fields/mixins.py +175 -0
- wbcore/serializers/fields/number.py +103 -0
- wbcore/serializers/fields/other.py +42 -0
- wbcore/serializers/fields/primary_key.py +22 -0
- wbcore/serializers/fields/related.py +152 -0
- wbcore/serializers/fields/text.py +136 -0
- wbcore/serializers/fields/types.py +41 -0
- wbcore/serializers/mixins.py +24 -0
- wbcore/serializers/serializers.py +415 -0
- wbcore/serializers/utils.py +142 -0
- wbcore/shares/__init__.py +1 -0
- wbcore/shares/config.py +63 -0
- wbcore/shares/decorator.py +13 -0
- wbcore/shares/signals.py +3 -0
- wbcore/shares/sites.py +28 -0
- wbcore/shares/views.py +24 -0
- wbcore/signals/__init__.py +6 -0
- wbcore/signals/filters.py +3 -0
- wbcore/signals/instance_buttons.py +5 -0
- wbcore/signals/merge.py +4 -0
- wbcore/signals/models.py +8 -0
- wbcore/signals/permissions.py +3 -0
- wbcore/signals/serializers.py +5 -0
- wbcore/tasks.py +83 -0
- wbcore/templates/reversion/__init__.py +0 -0
- wbcore/templates/reversion/compare_detail.html +19 -0
- wbcore/test/__init__.py +30 -0
- wbcore/test/mixins.py +709 -0
- wbcore/test/signals.py +6 -0
- wbcore/test/tests.py +131 -0
- wbcore/test/utils.py +227 -0
- wbcore/tests/__init__.py +0 -0
- wbcore/tests/conftest.py +55 -0
- wbcore/tests/e2e/__init__.py +0 -0
- wbcore/tests/e2e/test_e2e.py +24 -0
- wbcore/tests/models.py +6 -0
- wbcore/tests/test_cache/__init__.py +0 -0
- wbcore/tests/test_cache/test_decorators.py +30 -0
- wbcore/tests/test_cache/test_mixins.py +29 -0
- wbcore/tests/test_cache/test_registry.py +57 -0
- wbcore/tests/test_configs.py +65 -0
- wbcore/tests/test_enums.py +54 -0
- wbcore/tests/test_fields/__init__.py +0 -0
- wbcore/tests/test_fields/test_boolean_fields.py +48 -0
- wbcore/tests/test_fields/test_choice_fields.py +48 -0
- wbcore/tests/test_fields/test_datetime_fields.py +151 -0
- wbcore/tests/test_fields/test_fields.py +23 -0
- wbcore/tests/test_fields/test_file_fields.py +52 -0
- wbcore/tests/test_fields/test_json_fields.py +28 -0
- wbcore/tests/test_fields/test_list_fields.py +27 -0
- wbcore/tests/test_fields/test_mixins.py +111 -0
- wbcore/tests/test_fields/test_number_fields.py +190 -0
- wbcore/tests/test_fields/test_other_fields.py +61 -0
- wbcore/tests/test_fields/test_primary_key_fields.py +52 -0
- wbcore/tests/test_fields/test_related.py +80 -0
- wbcore/tests/test_fields/test_text_fields.py +117 -0
- wbcore/tests/test_filters/__init__.py +0 -0
- wbcore/tests/test_filters/test_mixins.py +108 -0
- wbcore/tests/test_filters/test_pandas.py +114 -0
- wbcore/tests/test_list_display.py +31 -0
- wbcore/tests/test_models/__init__.py +0 -0
- wbcore/tests/test_models/test_fields.py +25 -0
- wbcore/tests/test_models/test_mixins.py +31 -0
- wbcore/tests/test_new_display/__init__.py +0 -0
- wbcore/tests/test_new_display/test_inlines.py +13 -0
- wbcore/tests/test_new_display/test_layouts.py +15 -0
- wbcore/tests/test_new_display/test_operators.py +15 -0
- wbcore/tests/test_new_display/test_pages.py +8 -0
- wbcore/tests/test_new_display/test_sections.py +0 -0
- wbcore/tests/test_new_display/test_shortcuts.py +38 -0
- wbcore/tests/test_new_display/test_utils.py +48 -0
- wbcore/tests/test_pagination.py +31 -0
- wbcore/tests/test_serializers/__init__.py +0 -0
- wbcore/tests/test_serializers/test_fields.py +140 -0
- wbcore/tests/test_serializers/test_mixins.py +53 -0
- wbcore/tests/test_serializers/test_related.py +77 -0
- wbcore/tests/test_something.py +39 -0
- wbcore/tests/test_utils/__init__.py +0 -0
- wbcore/tests/test_utils/test_date.py +49 -0
- wbcore/tests/test_utils/test_date_builder.py +99 -0
- wbcore/tests/test_utils/test_primary.py +79 -0
- wbcore/tests/test_utils/test_signals.py +38 -0
- wbcore/tests/test_viewsets.py +20 -0
- wbcore/urls.py +114 -0
- wbcore/utils/__init__.py +13 -0
- wbcore/utils/cache.py +8 -0
- wbcore/utils/date.py +220 -0
- wbcore/utils/date_builder/__init__.py +18 -0
- wbcore/utils/date_builder/components.py +42 -0
- wbcore/utils/date_builder/offsets.py +27 -0
- wbcore/utils/deprecations.py +11 -0
- wbcore/utils/enum.py +23 -0
- wbcore/utils/figures.py +290 -0
- wbcore/utils/html.py +8 -0
- wbcore/utils/importlib.py +13 -0
- wbcore/utils/itertools.py +40 -0
- wbcore/utils/models.py +275 -0
- wbcore/utils/numbers.py +69 -0
- wbcore/utils/prettytable.py +35 -0
- wbcore/utils/print.py +29 -0
- wbcore/utils/renderers.py +13 -0
- wbcore/utils/rrules.py +37 -0
- wbcore/utils/serializers.py +8 -0
- wbcore/utils/settings.py +5 -0
- wbcore/utils/signals.py +36 -0
- wbcore/utils/string_loader.py +42 -0
- wbcore/utils/strings.py +77 -0
- wbcore/utils/task.py +6 -0
- wbcore/utils/urls.py +70 -0
- wbcore/utils/views.py +201 -0
- wbcore/views.py +26 -0
- wbcore/viewsets/__init__.py +10 -0
- wbcore/viewsets/encoders.py +18 -0
- wbcore/viewsets/generics.py +5 -0
- wbcore/viewsets/mixins.py +290 -0
- wbcore/viewsets/utils.py +26 -0
- wbcore/viewsets/viewsets.py +142 -0
- wbcore-2.2.1.dist-info/METADATA +62 -0
- wbcore-2.2.1.dist-info/RECORD +1035 -0
- wbcore-2.2.1.dist-info/WHEEL +5 -0
wbcore/utils/urls.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import urllib.parse
|
|
2
|
+
from typing import Dict, Tuple
|
|
3
|
+
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.contrib.sites.models import Site
|
|
6
|
+
from django.http.request import QueryDict
|
|
7
|
+
from django.utils.http import urlencode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def clean_shareable_url(url):
|
|
11
|
+
endpoint = url.split("?widget_endpoint=")[-1]
|
|
12
|
+
parse_url = urllib.parse.urlsplit(urllib.parse.unquote(endpoint))
|
|
13
|
+
endpoint = parse_url.path
|
|
14
|
+
if params := dict(urllib.parse.parse_qsl(parse_url.query)):
|
|
15
|
+
params_repr = "&".join([f"{k}={v}" for k, v in params.items()])
|
|
16
|
+
endpoint += f"?{params_repr}"
|
|
17
|
+
return endpoint
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_parse_endpoint(endpoint: str) -> Tuple[str, Dict[str, str]]:
|
|
21
|
+
"""
|
|
22
|
+
Takes a URL endpoint and outputs the path and the params separately.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
endpoint: The endpoint string
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
Returns a tuple in the form of (path: str, params: dict[str, str]). Where path is the url and params are the parameters of the endpoint.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
path = urllib.parse.urljoin(endpoint, urllib.parse.urlparse(endpoint).path)
|
|
34
|
+
params = dict(urllib.parse.parse_qsl(urllib.parse.urlsplit(endpoint).query))
|
|
35
|
+
return path, params
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_urlencode_endpoint(endpoint: str, params: Dict[str, str]) -> str:
|
|
39
|
+
"""
|
|
40
|
+
Takes a URL path and params and creates an endpoint from it.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
endpoint: The URL string
|
|
45
|
+
params: The params dictonary
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
Returns an endpoint string with the params attached.
|
|
50
|
+
"""
|
|
51
|
+
if isinstance(params, QueryDict):
|
|
52
|
+
params = params.dict()
|
|
53
|
+
return f"{endpoint}?{urlencode(params)}"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def base_domain() -> str:
|
|
57
|
+
"""A utility method that assembles the current domain. Utilizes the site app from django
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
A string containing the current domain as noted in the curret `Site` prefixed with the http scheme
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
scheme = "https" if settings.SECURE_SSL_REDIRECT else "http"
|
|
64
|
+
base_domain = Site.objects.get_current().domain
|
|
65
|
+
return f"{scheme}://{base_domain}"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def new_mode(url: str) -> str:
|
|
69
|
+
operator = "&" if "?" in url else "?"
|
|
70
|
+
return url + f"{operator}new_mode=true"
|
wbcore/utils/views.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import re
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
|
|
5
|
+
from django.conf import settings
|
|
6
|
+
from django.contrib.contenttypes.models import ContentType
|
|
7
|
+
from django.dispatch import receiver
|
|
8
|
+
from django.shortcuts import get_object_or_404
|
|
9
|
+
from django.urls import resolve
|
|
10
|
+
from django.urls.exceptions import NoReverseMatch
|
|
11
|
+
from django.utils.translation import gettext as _
|
|
12
|
+
from rest_framework import status
|
|
13
|
+
from rest_framework.decorators import action, api_view, permission_classes
|
|
14
|
+
from rest_framework.permissions import IsAuthenticated
|
|
15
|
+
from rest_framework.response import Response
|
|
16
|
+
from rest_framework.reverse import reverse
|
|
17
|
+
from wbcore import serializers as wb_serializer
|
|
18
|
+
from wbcore.contrib.icons import WBIcon
|
|
19
|
+
from wbcore.enums import RequestType
|
|
20
|
+
from wbcore.metadata.configs import buttons as bt
|
|
21
|
+
from wbcore.metadata.configs.display.instance_display import Display
|
|
22
|
+
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
23
|
+
create_simple_display,
|
|
24
|
+
)
|
|
25
|
+
from wbcore.models.base import merge_as_task
|
|
26
|
+
from wbcore.signals.instance_buttons import add_extra_button
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_query_parameters_list(list_str):
|
|
30
|
+
try:
|
|
31
|
+
return list(set(map(lambda x: int(x), filter(None, list_str.split(",")))))
|
|
32
|
+
except ValueError:
|
|
33
|
+
return ""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def set_identifier(identifier):
|
|
37
|
+
def decorator(func):
|
|
38
|
+
func.identifier = identifier
|
|
39
|
+
return func
|
|
40
|
+
|
|
41
|
+
return decorator
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@api_view(["GET"])
|
|
45
|
+
@permission_classes([IsAuthenticated])
|
|
46
|
+
def api_endpoints_root(request, format=None):
|
|
47
|
+
try:
|
|
48
|
+
endpoints = dict()
|
|
49
|
+
for wb_endpoint in settings.WB_ENDPOINTS:
|
|
50
|
+
try:
|
|
51
|
+
endpoints[wb_endpoint] = reverse(f"{wb_endpoint}:api-root", request=request, format=format)
|
|
52
|
+
except NoReverseMatch:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
return Response(endpoints)
|
|
56
|
+
|
|
57
|
+
except AttributeError:
|
|
58
|
+
return Response({"error": "No Endpoints specified."}, status=status.HTTP_400_BAD_REQUEST)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class CloneMixin:
|
|
62
|
+
"""
|
|
63
|
+
This Mixin can be used to inherit the clone functionality out of the box. This mixin will register the additional resources
|
|
64
|
+
and the appropriate button to allow user to clone a given instance
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def get_clone_instance_display(self) -> Display | None:
|
|
68
|
+
"""
|
|
69
|
+
Return the instance display to show in the clone action button. Default to return None (i.e. No form)
|
|
70
|
+
"""
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
@action(methods=["PATCH"], detail=True)
|
|
74
|
+
def clone(self, request, pk=None):
|
|
75
|
+
instance = get_object_or_404(self.queryset.model, pk=pk)
|
|
76
|
+
if (clone_fct := getattr(instance, "clone", None)) and callable(clone_fct):
|
|
77
|
+
kwargs = {}
|
|
78
|
+
if request.data:
|
|
79
|
+
serializer = self.get_serializer_class()(data=request.data)
|
|
80
|
+
serializer.is_valid(raise_exception=False)
|
|
81
|
+
kwargs = serializer.data
|
|
82
|
+
cloned_obj = clone_fct(user=request.user, **kwargs)
|
|
83
|
+
if (
|
|
84
|
+
cloned_obj
|
|
85
|
+
and (clone_id := getattr(cloned_obj, "id", None))
|
|
86
|
+
and (endpoint_config_class := getattr(self, "endpoint_config_class", None))
|
|
87
|
+
):
|
|
88
|
+
endpoint_config = endpoint_config_class(self, request, cloned_obj)
|
|
89
|
+
if endpoint := endpoint_config.get_instance_endpoint():
|
|
90
|
+
return Response(
|
|
91
|
+
{
|
|
92
|
+
"endpoint": re.sub(
|
|
93
|
+
pattern=r"[^\/]+(?=\/$|$)",
|
|
94
|
+
repl=str(clone_id),
|
|
95
|
+
string=endpoint,
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
return Response({})
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@receiver(add_extra_button)
|
|
103
|
+
def add_clone_extra_button(sender, instance, request, view, pk=None, **kwargs):
|
|
104
|
+
if instance and pk and issubclass(view.__class__, CloneMixin):
|
|
105
|
+
object = view.get_object()
|
|
106
|
+
if getattr(object, "is_cloneable", True) and (endpoint_basename := object.get_endpoint_basename()):
|
|
107
|
+
endpoint = reverse(f"{endpoint_basename}-clone", args=[pk], request=request)
|
|
108
|
+
identifier = getattr(view, "IDENTIFIER", "{0.app_label}:{0.model}".format(view.get_content_type()))
|
|
109
|
+
return bt.ActionButton(
|
|
110
|
+
method=RequestType.PATCH,
|
|
111
|
+
identifiers=(identifier,),
|
|
112
|
+
endpoint=endpoint,
|
|
113
|
+
action_label=_("Clone"),
|
|
114
|
+
title=_("Clone"),
|
|
115
|
+
label=_("Clone"),
|
|
116
|
+
icon=WBIcon.COPY.icon,
|
|
117
|
+
instance_display=view.get_clone_instance_display(),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class MergeMixin:
|
|
122
|
+
"""
|
|
123
|
+
This Mixin can be used to inherit the clone functionality out of the box. This mixin will register the additional resources
|
|
124
|
+
and the appropriate button to allow user to merge a given instance
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
@cached_property
|
|
128
|
+
def model(self):
|
|
129
|
+
return self.queryset.model
|
|
130
|
+
|
|
131
|
+
@cached_property
|
|
132
|
+
def has_user_merge_permission(self) -> bool:
|
|
133
|
+
return getattr(self, "MERGE_PERMISSION", f"administrate_{self.model._meta.model_name}")
|
|
134
|
+
|
|
135
|
+
@cached_property
|
|
136
|
+
def can_merge(self):
|
|
137
|
+
return hasattr(self.queryset.model, "merge") and self.has_user_merge_permission
|
|
138
|
+
|
|
139
|
+
def get_merged_object_representation_serializer(self):
|
|
140
|
+
"""
|
|
141
|
+
Return the representation serializer used for the action button merged object field. Default to the model representation endpoint serializer
|
|
142
|
+
"""
|
|
143
|
+
view_func = resolve(reverse(self.model.get_representation_endpoint())).func
|
|
144
|
+
module = importlib.import_module(view_func.__module__)
|
|
145
|
+
view = getattr(module, view_func.__name__)
|
|
146
|
+
return view.serializer_class
|
|
147
|
+
|
|
148
|
+
def get_merged_object_representation_serializer_filter_params(self) -> dict[str, str]:
|
|
149
|
+
"""
|
|
150
|
+
Return the representation serializer filter kwargs. Default to an empty dict
|
|
151
|
+
"""
|
|
152
|
+
return dict()
|
|
153
|
+
|
|
154
|
+
@action(methods=["PATCH"], detail=True)
|
|
155
|
+
def merge(self, request, pk=None):
|
|
156
|
+
instance = get_object_or_404(self.queryset.model, pk=pk)
|
|
157
|
+
merged_instance = get_object_or_404(self.queryset.model, pk=request.POST.get("merged_object", None))
|
|
158
|
+
try:
|
|
159
|
+
content_type = ContentType.objects.get_for_model(self.model)
|
|
160
|
+
except ContentType.DoesNotExist:
|
|
161
|
+
content_type = None
|
|
162
|
+
if content_type and self.has_user_merge_permission and hasattr(instance, "merge"):
|
|
163
|
+
merge_as_task.delay(content_type.id, instance.id, merged_instance.id)
|
|
164
|
+
return Response({"status": "Merged with success"})
|
|
165
|
+
return Response({}, status=400)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@receiver(add_extra_button)
|
|
169
|
+
def add_merge_extra_button(sender, instance, request, view, pk=None, **kwargs):
|
|
170
|
+
if instance and pk and issubclass(view.__class__, CloneMixin) and getattr(view, "can_merge", False):
|
|
171
|
+
object = view.get_object()
|
|
172
|
+
if getattr(object, "is_mergeable", True) and (endpoint_basename := object.get_endpoint_basename()):
|
|
173
|
+
endpoint = reverse(f"{endpoint_basename}-merge", args=[pk], request=request)
|
|
174
|
+
identifier = getattr(view, "IDENTIFIER", "{0.app_label}:{0.model}".format(view.get_content_type()))
|
|
175
|
+
|
|
176
|
+
class MergeSerializer(wb_serializer.ModelSerializer):
|
|
177
|
+
merged_object = wb_serializer.PrimaryKeyRelatedField(queryset=view.model.objects.all())
|
|
178
|
+
_merged_object = view.get_merged_object_representation_serializer()(
|
|
179
|
+
source="merged_object",
|
|
180
|
+
filter_params=view.get_merged_object_representation_serializer_filter_params(),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
class Meta:
|
|
184
|
+
model = view.model
|
|
185
|
+
fields = [
|
|
186
|
+
"id",
|
|
187
|
+
"merged_object",
|
|
188
|
+
"_merged_object",
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
return bt.ActionButton(
|
|
192
|
+
method=RequestType.PATCH,
|
|
193
|
+
identifiers=(identifier,),
|
|
194
|
+
endpoint=endpoint,
|
|
195
|
+
action_label=_("Merge"),
|
|
196
|
+
title=_("Merge"),
|
|
197
|
+
label=_("Merge"),
|
|
198
|
+
icon=WBIcon.MERGE.icon,
|
|
199
|
+
serializer=MergeSerializer,
|
|
200
|
+
instance_display=create_simple_display([["merged_object"]]),
|
|
201
|
+
)
|
wbcore/views.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.utils.module_loading import import_string
|
|
3
|
+
from rest_framework.permissions import IsAuthenticated
|
|
4
|
+
from rest_framework.request import Request
|
|
5
|
+
from rest_framework.response import Response
|
|
6
|
+
from rest_framework.reverse import reverse
|
|
7
|
+
from rest_framework.views import APIView
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Profile(APIView):
|
|
11
|
+
"""Profile view to get the default user name, email and profile
|
|
12
|
+
|
|
13
|
+
This view should be substituted by one from the authentication module
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
permission_classes = [IsAuthenticated]
|
|
17
|
+
|
|
18
|
+
def get(self, request: Request) -> Response:
|
|
19
|
+
return Response(
|
|
20
|
+
{
|
|
21
|
+
"config": reverse("wbcore:frontenduserconfiguration-list", request=request),
|
|
22
|
+
"name": import_string(settings.WBCORE_DEFAULT_USER_NAME)(request.user),
|
|
23
|
+
"email": request.user.email,
|
|
24
|
+
"profile": import_string(settings.WBCORE_PROFILE)(request),
|
|
25
|
+
}
|
|
26
|
+
)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import types
|
|
3
|
+
|
|
4
|
+
from django.core.serializers.json import DjangoJSONEncoder
|
|
5
|
+
from rest_framework.renderers import JSONRenderer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PandasDataCustomEncoder(json.JSONEncoder):
|
|
9
|
+
def default(self, obj):
|
|
10
|
+
# We need to handle generator for option request that sometime contains generator as values
|
|
11
|
+
if isinstance(obj, types.GeneratorType):
|
|
12
|
+
return list(obj)
|
|
13
|
+
return DjangoJSONEncoder().default(obj)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PandasDataCustomRenderer(JSONRenderer):
|
|
17
|
+
encoder_class = PandasDataCustomEncoder
|
|
18
|
+
strict = False
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
from django.contrib.messages import get_messages
|
|
4
|
+
from django.contrib.staticfiles import finders
|
|
5
|
+
from django.db import IntegrityError
|
|
6
|
+
from django.db.models import F, Model, QuerySet
|
|
7
|
+
from django.db.models.expressions import OrderBy
|
|
8
|
+
from django.http import Http404
|
|
9
|
+
from django.shortcuts import get_object_or_404
|
|
10
|
+
from django.templatetags.static import static
|
|
11
|
+
from django.utils.functional import cached_property
|
|
12
|
+
from rest_framework.decorators import action
|
|
13
|
+
from rest_framework.filters import OrderingFilter, SearchFilter
|
|
14
|
+
from rest_framework.mixins import CreateModelMixin as OriginalCreateModelMixin
|
|
15
|
+
from rest_framework.mixins import DestroyModelMixin as OriginalDestroyModelMixin
|
|
16
|
+
from rest_framework.mixins import ListModelMixin as OriginalListModelMixin
|
|
17
|
+
from rest_framework.mixins import RetrieveModelMixin as OriginalRetrieveModelMixin
|
|
18
|
+
from rest_framework.mixins import UpdateModelMixin as OriginalUpdateModelMixin
|
|
19
|
+
from rest_framework.pagination import BasePagination
|
|
20
|
+
from rest_framework.request import Request
|
|
21
|
+
from rest_framework.response import Response
|
|
22
|
+
from rest_framework.status import (
|
|
23
|
+
HTTP_200_OK,
|
|
24
|
+
HTTP_204_NO_CONTENT,
|
|
25
|
+
HTTP_400_BAD_REQUEST,
|
|
26
|
+
HTTP_405_METHOD_NOT_ALLOWED,
|
|
27
|
+
HTTP_409_CONFLICT,
|
|
28
|
+
)
|
|
29
|
+
from wbcore.filters import DjangoFilterBackend
|
|
30
|
+
from wbcore.messages import InMemoryMessageStorage
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def map_ordering(order_str: str) -> OrderBy:
|
|
34
|
+
asc_desc = "desc" if order_str[0] == "-" else "asc"
|
|
35
|
+
remove_strings = ["-", "__nulls_last", "__nulls_first"]
|
|
36
|
+
clean_order_str = order_str
|
|
37
|
+
for string in remove_strings:
|
|
38
|
+
clean_order_str = clean_order_str.replace(string, "")
|
|
39
|
+
asc_desc_function = getattr(F(clean_order_str), asc_desc)
|
|
40
|
+
if "__nulls_last" in order_str:
|
|
41
|
+
return asc_desc_function(nulls_last=True)
|
|
42
|
+
elif "__nulls_first" in order_str:
|
|
43
|
+
return asc_desc_function(nulls_first=True)
|
|
44
|
+
return asc_desc_function()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class WBCoreOrderingFilter(OrderingFilter):
|
|
48
|
+
def get_mandatory_ordering_fields(self, queryset, view) -> list[str]:
|
|
49
|
+
"""
|
|
50
|
+
Given the queryset and the view, extract the mandatory field for the final ordering. Default to ["id"]
|
|
51
|
+
|
|
52
|
+
To keep it simple, we assume that all view have a id field defined in the serializer. If this is not the case, we expect the dev to override this method and return an empty list.
|
|
53
|
+
"""
|
|
54
|
+
if (fct := getattr(view, "get_mandatory_ordering_fields", None)) and callable(fct):
|
|
55
|
+
fields = fct()
|
|
56
|
+
else:
|
|
57
|
+
fields = ["id"]
|
|
58
|
+
return fields
|
|
59
|
+
|
|
60
|
+
def filter_queryset(self, request, queryset, view):
|
|
61
|
+
ordering = self.get_ordering(request, queryset, view)
|
|
62
|
+
mandatory_ordering_fields = self.get_mandatory_ordering_fields(queryset, view)
|
|
63
|
+
if ordering or mandatory_ordering_fields:
|
|
64
|
+
return queryset.order_by(*map(map_ordering, ordering), *mandatory_ordering_fields)
|
|
65
|
+
|
|
66
|
+
return queryset
|
|
67
|
+
|
|
68
|
+
def get_valid_fields(self, queryset, view, context={}):
|
|
69
|
+
valid_fields = view.get_ordering_fields()
|
|
70
|
+
if valid_fields is None:
|
|
71
|
+
# Default to allowing filtering on serializer fields
|
|
72
|
+
return self.get_default_valid_fields(queryset, view, context)
|
|
73
|
+
|
|
74
|
+
elif valid_fields == "__all__":
|
|
75
|
+
# View explicitly allows filtering on any model field
|
|
76
|
+
valid_fields = [(field.name, field.verbose_name) for field in queryset.model._meta.fields]
|
|
77
|
+
valid_fields += [(key, key.title().split("__")) for key in queryset.query.annotations]
|
|
78
|
+
else:
|
|
79
|
+
valid_fields = [(item, item) if isinstance(item, str) else item for item in valid_fields]
|
|
80
|
+
return valid_fields
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class FilterMixin:
|
|
84
|
+
filter_backends = (DjangoFilterBackend, SearchFilter, WBCoreOrderingFilter)
|
|
85
|
+
filterset_fields = {}
|
|
86
|
+
search_fields = []
|
|
87
|
+
ordering_fields = ordering = ("id",)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DocumentationMixin:
|
|
91
|
+
def _get_documentation_url(self, detail):
|
|
92
|
+
INSTANCE_DOCUMENTATION = getattr(self, "INSTANCE_DOCUMENTATION", None)
|
|
93
|
+
LIST_DOCUMENTATION = getattr(self, "LIST_DOCUMENTATION", None)
|
|
94
|
+
doc = INSTANCE_DOCUMENTATION if detail else LIST_DOCUMENTATION
|
|
95
|
+
|
|
96
|
+
if doc and finders.find(doc):
|
|
97
|
+
return static(doc)
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ActionMixin:
|
|
102
|
+
kwargs: dict
|
|
103
|
+
request: Request
|
|
104
|
+
action: str
|
|
105
|
+
|
|
106
|
+
def get_action(self) -> str:
|
|
107
|
+
if self.action == "metadata":
|
|
108
|
+
if bool(self.request.GET.get("new_mode")):
|
|
109
|
+
return "create-metadata"
|
|
110
|
+
if bool(self.kwargs.get("pk")):
|
|
111
|
+
return "retrieve-metadata"
|
|
112
|
+
else:
|
|
113
|
+
return "list-metadata"
|
|
114
|
+
return self.action
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class MessageMixin:
|
|
118
|
+
def add_messages(
|
|
119
|
+
self,
|
|
120
|
+
request: Request,
|
|
121
|
+
queryset: QuerySet | None = None,
|
|
122
|
+
paginated_queryset: BasePagination | None = None,
|
|
123
|
+
instance: Model | None = None,
|
|
124
|
+
initial: bool = False,
|
|
125
|
+
):
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
def _get_messages(
|
|
129
|
+
self,
|
|
130
|
+
request: Request,
|
|
131
|
+
queryset: QuerySet | None = None,
|
|
132
|
+
paginated_queryset: BasePagination | None = None,
|
|
133
|
+
instance: Model | None = None,
|
|
134
|
+
initial: bool = False,
|
|
135
|
+
) -> Iterable[dict[str, str]]:
|
|
136
|
+
# We call add_messages to collect messages from the view which weren't created at other places
|
|
137
|
+
# because they might need some more information under which circumstances they are being called
|
|
138
|
+
self.add_messages(
|
|
139
|
+
request=request,
|
|
140
|
+
queryset=queryset,
|
|
141
|
+
paginated_queryset=paginated_queryset,
|
|
142
|
+
instance=instance,
|
|
143
|
+
initial=initial,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# We get the storage backend and yield all messages in a serialized form
|
|
147
|
+
# This only works if the storage backend is our custom InMemoryMessageStorage
|
|
148
|
+
# We inject request._request purely for typing, as request will defer attribute
|
|
149
|
+
# lookup to its internal getattribute method. But the get_messages method only
|
|
150
|
+
# accepts a HttpRequest object which is DRF request simply wraps
|
|
151
|
+
storage = get_messages(request._request)
|
|
152
|
+
if isinstance(storage, InMemoryMessageStorage):
|
|
153
|
+
yield from storage.serialize_messages()
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class ListModelMixin(MessageMixin, OriginalListModelMixin):
|
|
157
|
+
def list(self, request, *args, **kwargs):
|
|
158
|
+
queryset = self.get_queryset()
|
|
159
|
+
if queryset.exists():
|
|
160
|
+
queryset = self.filter_queryset(queryset)
|
|
161
|
+
|
|
162
|
+
page = self.paginate_queryset(queryset)
|
|
163
|
+
if page is not None:
|
|
164
|
+
serializer = self.get_serializer(page, many=True)
|
|
165
|
+
response = self.get_paginated_response(serializer.data)
|
|
166
|
+
response.data["messages"] = list(
|
|
167
|
+
self._get_messages(
|
|
168
|
+
request, queryset=queryset, paginated_queryset=page, initial=self._paginator.is_initial()
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if hasattr(self, "get_aggregates"):
|
|
173
|
+
response.data["aggregates"] = self.get_aggregates(queryset=queryset, paginated_queryset=page)
|
|
174
|
+
else:
|
|
175
|
+
serializer = self.get_serializer(queryset, many=True)
|
|
176
|
+
response = Response(serializer.data)
|
|
177
|
+
response.data = {"results": response.data}
|
|
178
|
+
|
|
179
|
+
response.data["messages"] = list(self._get_messages(request, queryset=queryset, initial=True))
|
|
180
|
+
|
|
181
|
+
if hasattr(self, "get_aggregates"):
|
|
182
|
+
response.data["aggregates"] = self.get_aggregates(queryset=queryset, paginated_queryset=queryset)
|
|
183
|
+
|
|
184
|
+
return response
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class RetrieveModelMixin(MessageMixin, OriginalRetrieveModelMixin):
|
|
188
|
+
def retrieve(self, request, *args, **kwargs):
|
|
189
|
+
response = super().retrieve(request, *args, **kwargs)
|
|
190
|
+
response.data = {"instance": response.data}
|
|
191
|
+
try:
|
|
192
|
+
instance = self.get_object()
|
|
193
|
+
except Http404:
|
|
194
|
+
instance = None
|
|
195
|
+
response.data["messages"] = list(self._get_messages(request, instance=instance))
|
|
196
|
+
return response
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class CreateModelMixin(OriginalCreateModelMixin):
|
|
200
|
+
def create(self, request, *args, **kwargs):
|
|
201
|
+
# If not create endpoint is defined then raise 405
|
|
202
|
+
if self.endpoint_config_class(view=self, request=self.request, instance=False)._get_create_endpoint() is None:
|
|
203
|
+
return Response(status=HTTP_405_METHOD_NOT_ALLOWED)
|
|
204
|
+
|
|
205
|
+
response = super().create(request, *args, **kwargs)
|
|
206
|
+
response.data = {"instance": response.data, "messages": list(self._get_messages(request))}
|
|
207
|
+
return response
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class UpdateModelMixin(OriginalUpdateModelMixin):
|
|
211
|
+
def update(self, request, *args, **kwargs):
|
|
212
|
+
# If no instance endpoint is defined, then raise 405
|
|
213
|
+
if self.endpoint_config_class(view=self, request=self.request, instance=True)._get_update_endpoint() is None:
|
|
214
|
+
return Response(status=HTTP_405_METHOD_NOT_ALLOWED)
|
|
215
|
+
|
|
216
|
+
response = super().update(request, *args, **kwargs)
|
|
217
|
+
response.data = {"instance": response.data}
|
|
218
|
+
try:
|
|
219
|
+
instance = self.get_object()
|
|
220
|
+
except Http404:
|
|
221
|
+
instance = None
|
|
222
|
+
response.data["messages"] = list(self._get_messages(request, instance=instance))
|
|
223
|
+
return response
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class DestroyModelMixin(OriginalDestroyModelMixin):
|
|
227
|
+
def destroy(self, request, *args, **kwargs):
|
|
228
|
+
# If no delete endpoint is defined, then raise 405
|
|
229
|
+
if self.endpoint_config_class(view=self, request=self.request, instance=True)._get_delete_endpoint() is None:
|
|
230
|
+
return Response(status=HTTP_405_METHOD_NOT_ALLOWED)
|
|
231
|
+
|
|
232
|
+
return super().destroy(request, *args, **kwargs)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class DestroyMultipleModelMixin:
|
|
236
|
+
def destroy_multiple(self, request, *args, **kwargs):
|
|
237
|
+
# If no delete endpoint is defined, then raise 405
|
|
238
|
+
if self.endpoint_config_class(view=self, request=self.request, instance=False)._get_delete_endpoint() is None:
|
|
239
|
+
return Response(status=HTTP_405_METHOD_NOT_ALLOWED)
|
|
240
|
+
|
|
241
|
+
model = self.get_serializer_class().Meta.model
|
|
242
|
+
app_label = model._meta.app_label
|
|
243
|
+
|
|
244
|
+
queryset = model.objects.filter(id__in=request.data)
|
|
245
|
+
destroyed = self.perform_destroy_multiple(queryset)
|
|
246
|
+
return Response({"count": destroyed[1].get(f"{app_label}.{model.__name__}", 0)}, status=HTTP_204_NO_CONTENT)
|
|
247
|
+
|
|
248
|
+
def perform_destroy_multiple(self, queryset):
|
|
249
|
+
return queryset.delete()
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class OrderableMixin:
|
|
253
|
+
# This mixin will not work if the viewset model does not inherit from ordered_model.models.OrderedModel
|
|
254
|
+
|
|
255
|
+
ordering = ("order",)
|
|
256
|
+
|
|
257
|
+
@action(methods=["PATCH"], detail=True)
|
|
258
|
+
def reorder(self, request: Request, pk=None, **kwargs) -> Response:
|
|
259
|
+
instance = self.get_object()
|
|
260
|
+
order = request.data.get("order")
|
|
261
|
+
if order is None:
|
|
262
|
+
return Response("No order received", status=HTTP_400_BAD_REQUEST)
|
|
263
|
+
instance.to(order)
|
|
264
|
+
return Response("Reordering Successful", status=HTTP_200_OK)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class ReparentMixin:
|
|
268
|
+
PARENT_FIELD: str
|
|
269
|
+
PARENT_MODEL: type[Model]
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def parent_field(self) -> str:
|
|
273
|
+
return self.PARENT_FIELD
|
|
274
|
+
|
|
275
|
+
@cached_property
|
|
276
|
+
def model(self):
|
|
277
|
+
return self.queryset.model
|
|
278
|
+
|
|
279
|
+
@action(methods=["PATCH"], detail=True)
|
|
280
|
+
def reparent(self, request: Request, pk=None, **kwargs) -> Response:
|
|
281
|
+
instance = self.get_object()
|
|
282
|
+
new_parent = get_object_or_404(self.PARENT_MODEL, pk=request.data.get("new_parent"))
|
|
283
|
+
old_parent = getattr(instance, self.parent_field)
|
|
284
|
+
if old_parent != new_parent:
|
|
285
|
+
setattr(instance, self.parent_field, new_parent)
|
|
286
|
+
try:
|
|
287
|
+
instance.save()
|
|
288
|
+
except IntegrityError:
|
|
289
|
+
return Response("Cannot reparent due to conflict", status=HTTP_409_CONFLICT)
|
|
290
|
+
return Response("Reparenting Successful", status=HTTP_200_OK)
|
wbcore/viewsets/utils.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from django.utils.translation import gettext as _
|
|
4
|
+
from rest_framework.response import Response
|
|
5
|
+
from wbcore.metadata.configs.buttons import ButtonConfig
|
|
6
|
+
from wbcore.metadata.configs.display.instance_display import Display
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class PreAction:
|
|
11
|
+
message: str
|
|
12
|
+
instance_display: Display | None = None
|
|
13
|
+
confirm_config: ButtonConfig = ButtonConfig(label=_("Confirm"), title=_("Confirm"))
|
|
14
|
+
cancel_config: ButtonConfig = ButtonConfig(label=_("Cancel"), title=_("Cancel"))
|
|
15
|
+
|
|
16
|
+
def to_response(self):
|
|
17
|
+
response_dict = {
|
|
18
|
+
"message": self.message,
|
|
19
|
+
"confirm_config": dict(self.confirm_config),
|
|
20
|
+
"cancel_config": dict(self.cancel_config),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if self.instance_display:
|
|
24
|
+
response_dict["display"] = self.instance_display.serialize()
|
|
25
|
+
|
|
26
|
+
return Response(response_dict)
|