wbcore 1.46.0__py2.py3-none-any.whl → 1.58.2__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/cache/decorators.py +5 -3
- wbcore/cache/registry.py +14 -7
- wbcore/configs/__init__.py +1 -0
- wbcore/configs/configs.py +5 -0
- wbcore/configs/decorators.py +1 -1
- wbcore/configurations/configurations/apps.py +3 -2
- wbcore/configurations/configurations/authentication.py +1 -1
- wbcore/configurations/configurations/base.py +1 -1
- wbcore/configurations/configurations/cache.py +1 -1
- wbcore/configurations/configurations/i18nl10n.py +2 -1
- wbcore/configurations/configurations/maintenance.py +1 -1
- wbcore/configurations/configurations/media.py +1 -1
- wbcore/configurations/configurations/middleware.py +1 -1
- wbcore/configurations/configurations/rest_framework.py +1 -1
- wbcore/configurations/configurations/static.py +3 -3
- wbcore/configurations/configurations/wbcore.py +1 -1
- wbcore/content_type/serializers.py +13 -5
- wbcore/content_type/utils.py +3 -3
- wbcore/content_type/viewsets.py +2 -2
- wbcore/contrib/agenda/filters/calendar_item.py +5 -4
- wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +145 -52
- wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
- wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
- wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
- wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
- wbcore/contrib/agenda/viewsets/menu/calendar_items.py +0 -6
- wbcore/contrib/ai/exceptions.py +5 -5
- wbcore/contrib/ai/llm/config.py +76 -27
- wbcore/contrib/ai/llm/mixins.py +5 -8
- wbcore/contrib/ai/llm/utils.py +50 -26
- wbcore/contrib/authentication/admin.py +2 -2
- wbcore/contrib/authentication/factories/__init__.py +8 -1
- wbcore/contrib/authentication/factories/users.py +19 -0
- wbcore/contrib/authentication/filters.py +1 -2
- wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +209 -187
- wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
- wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
- wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
- wbcore/contrib/authentication/models/users.py +3 -3
- wbcore/contrib/authentication/models/users_activities.py +1 -1
- wbcore/contrib/authentication/serializers/users.py +2 -2
- wbcore/contrib/authentication/tests/test_tokens.py +3 -3
- wbcore/contrib/authentication/tests/test_users.py +0 -1
- wbcore/contrib/authentication/urls.py +0 -4
- wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +2 -11
- wbcore/contrib/authentication/viewsets/endpoints/users.py +0 -3
- wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
- wbcore/contrib/authentication/viewsets/users.py +6 -4
- wbcore/contrib/color/models.py +2 -1
- wbcore/contrib/currency/factories.py +1 -1
- wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
- wbcore/contrib/currency/models.py +30 -8
- wbcore/contrib/currency/serializers.py +5 -1
- wbcore/contrib/currency/tests/test_serializers.py +7 -3
- wbcore/contrib/currency/tests/test_viewsets.py +1 -1
- wbcore/contrib/currency/viewsets/currency.py +2 -2
- wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +0 -9
- wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +1 -2
- wbcore/contrib/dataloader/utils.py +2 -2
- wbcore/contrib/directory/factories/__init__.py +1 -1
- wbcore/contrib/directory/factories/entries.py +2 -1
- wbcore/contrib/directory/filters/entries.py +9 -0
- wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +728 -714
- wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
- wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
- wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
- wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
- wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
- wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
- wbcore/contrib/directory/models/contacts.py +2 -2
- wbcore/contrib/directory/models/entries.py +31 -5
- wbcore/contrib/directory/models/relationships.py +31 -35
- wbcore/contrib/directory/permissions.py +6 -0
- wbcore/contrib/directory/serializers/companies.py +16 -8
- wbcore/contrib/directory/serializers/contacts.py +8 -8
- wbcore/contrib/directory/serializers/entries.py +26 -15
- wbcore/contrib/directory/serializers/entry_representations.py +4 -2
- wbcore/contrib/directory/serializers/persons.py +12 -10
- wbcore/contrib/directory/serializers/relationships.py +2 -2
- wbcore/contrib/directory/tests/conftest.py +2 -0
- wbcore/contrib/directory/tests/disable_signals.py +11 -1
- wbcore/contrib/directory/tests/signals.py +2 -2
- wbcore/contrib/directory/tests/test_models.py +88 -66
- wbcore/contrib/directory/tests/test_serializers.py +1 -1
- wbcore/contrib/directory/tests/test_viewsets.py +8 -8
- wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
- wbcore/contrib/directory/viewsets/contacts.py +6 -6
- wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/display/contacts.py +1 -14
- wbcore/contrib/directory/viewsets/display/entries.py +68 -38
- wbcore/contrib/directory/viewsets/display/relationships.py +26 -50
- wbcore/contrib/directory/viewsets/endpoints/relationships.py +1 -26
- wbcore/contrib/directory/viewsets/entries.py +8 -6
- wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
- wbcore/contrib/directory/viewsets/relationships.py +16 -2
- wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
- wbcore/contrib/documents/filters.py +0 -2
- wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +103 -94
- wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
- wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
- wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
- wbcore/contrib/documents/tests/test_models.py +32 -28
- wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +2 -21
- wbcore/contrib/dynamic_preferences/types.py +108 -0
- wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
- wbcore/contrib/example_app/filters/event.py +3 -1
- wbcore/contrib/example_app/filters/match.py +1 -1
- wbcore/contrib/example_app/models.py +91 -22
- wbcore/contrib/example_app/serializers/person_team.py +4 -4
- wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
- wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
- wbcore/contrib/example_app/tests/test_models/test_match.py +17 -7
- wbcore/contrib/example_app/urls.py +2 -0
- wbcore/contrib/example_app/views.py +7 -0
- wbcore/contrib/example_app/viewsets/displays/team.py +23 -4
- wbcore/contrib/example_app/viewsets/menu/menus.py +1 -1
- wbcore/contrib/example_app/viewsets/menus.py +1 -1
- wbcore/contrib/geography/tests/conftest.py +14 -0
- wbcore/contrib/geography/tests/test_models.py +23 -8
- wbcore/contrib/geography/tests/test_viewsets.py +96 -2
- wbcore/contrib/guardian/tests/test_model_mixins.py +3 -4
- wbcore/contrib/guardian/tests/test_tasks.py +9 -9
- wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
- wbcore/contrib/guardian/viewsets/configs/__init__.py +1 -1
- wbcore/contrib/guardian/viewsets/configs/buttons.py +9 -0
- wbcore/contrib/guardian/viewsets/configs/endpoints.py +7 -0
- wbcore/contrib/guardian/viewsets/viewsets.py +2 -0
- wbcore/contrib/i18n/__init__.py +2 -0
- wbcore/contrib/i18n/buttons.py +33 -0
- wbcore/contrib/i18n/serializers/__init__.py +0 -0
- wbcore/contrib/i18n/serializers/fields.py +20 -0
- wbcore/contrib/i18n/serializers/mixins.py +13 -0
- wbcore/contrib/i18n/tests/conftest.py +11 -0
- wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
- wbcore/contrib/i18n/translation.py +140 -0
- wbcore/contrib/i18n/viewsets.py +36 -0
- wbcore/contrib/icons/backends/default.py +1 -0
- wbcore/contrib/icons/backends/material.py +1 -0
- wbcore/contrib/icons/icons.py +5 -8
- wbcore/contrib/io/admin.py +1 -0
- wbcore/contrib/io/backends/mail.py +3 -2
- wbcore/contrib/io/backends/utils.py +14 -17
- wbcore/contrib/io/exceptions.py +8 -0
- wbcore/contrib/io/factories.py +1 -1
- wbcore/contrib/io/import_export/backends/mail.py +1 -0
- wbcore/contrib/io/import_export/backends/sftp.py +29 -20
- wbcore/contrib/io/import_export/backends/stream.py +2 -2
- wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
- wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
- wbcore/contrib/io/import_export/parsers/resources.py +50 -0
- wbcore/contrib/io/imports.py +33 -25
- wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +114 -22
- wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
- wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
- wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
- wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
- wbcore/contrib/io/models.py +65 -45
- wbcore/contrib/io/resources.py +0 -6
- wbcore/contrib/io/serializers.py +2 -2
- wbcore/contrib/io/signals.py +4 -0
- wbcore/contrib/io/tests/test_backends.py +19 -13
- wbcore/contrib/io/tests/test_exports.py +1 -1
- wbcore/contrib/io/tests/test_imports.py +1 -1
- wbcore/contrib/io/tests/test_models.py +47 -14
- wbcore/contrib/io/tests/test_viewsets.py +271 -0
- wbcore/contrib/io/viewset_mixins.py +41 -54
- wbcore/contrib/notifications/admin.py +1 -0
- wbcore/contrib/notifications/apps.py +2 -1
- wbcore/contrib/notifications/backends/abstract_backend.py +2 -4
- wbcore/contrib/notifications/backends/firebase/backends.py +5 -2
- wbcore/contrib/notifications/dispatch.py +18 -7
- wbcore/contrib/notifications/factories/notification_types.py +1 -0
- wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +25 -19
- wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
- wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
- wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
- wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
- wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
- wbcore/contrib/notifications/models/notification_types.py +67 -24
- wbcore/contrib/notifications/serializers/notification_types.py +16 -1
- wbcore/contrib/notifications/tests/test_models/test_tokens.py +8 -0
- wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +5 -0
- wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +3 -5
- wbcore/contrib/notifications/utils.py +3 -2
- wbcore/contrib/notifications/viewsets/configs/notification_types.py +28 -6
- wbcore/contrib/notifications/viewsets/menus.py +1 -1
- wbcore/contrib/notifications/viewsets/notification_types.py +12 -2
- wbcore/contrib/pandas/fields.py +38 -10
- wbcore/contrib/pandas/filters.py +4 -1
- wbcore/contrib/pandas/filterset.py +8 -7
- wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +2 -7
- wbcore/contrib/pandas/utils.py +1 -1
- wbcore/contrib/pandas/views.py +14 -13
- wbcore/contrib/tags/models/tags.py +4 -1
- wbcore/contrib/workflow/factories/display.py +2 -2
- wbcore/contrib/workflow/factories/transition.py +16 -15
- wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +457 -566
- wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
- wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
- wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
- wbcore/contrib/workflow/models/data.py +7 -4
- wbcore/contrib/workflow/models/process.py +2 -2
- wbcore/contrib/workflow/models/step.py +57 -15
- wbcore/contrib/workflow/serializers/data.py +8 -8
- wbcore/contrib/workflow/serializers/process.py +3 -2
- wbcore/contrib/workflow/tests/conftest.py +224 -0
- wbcore/contrib/workflow/tests/test_dispatch.py +82 -77
- wbcore/contrib/workflow/tests/test_displays.py +10 -88
- wbcore/contrib/workflow/tests/test_filters.py +57 -40
- wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +71 -68
- wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +78 -38
- wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +152 -90
- wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +100 -110
- wbcore/contrib/workflow/tests/test_models/step/test_step.py +168 -33
- wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
- wbcore/contrib/workflow/tests/test_models/test_workflow.py +3 -3
- wbcore/contrib/workflow/tests/test_serializers.py +172 -150
- wbcore/contrib/workflow/tests/test_viewsets.py +264 -323
- wbcore/contrib/workflow/tests/test_workflow_assignees.py +215 -205
- wbcore/contrib/workflow/viewsets/process.py +4 -1
- wbcore/contrib/workflow/workflows/assignees.py +12 -7
- wbcore/dynamic_preferences_registry.py +102 -0
- wbcore/enums.py +2 -51
- wbcore/filters/fields/choices.py +4 -6
- wbcore/filters/fields/content_type.py +15 -4
- wbcore/filters/fields/datetime.py +50 -25
- wbcore/filters/fields/models.py +18 -9
- wbcore/filters/fields/numbers.py +9 -8
- wbcore/filters/filterset.py +27 -6
- wbcore/filters/mixins.py +41 -42
- wbcore/forms.py +6 -6
- wbcore/fsm/markdown_extensions.py +1 -1
- wbcore/fsm/mixins.py +20 -6
- wbcore/locale/de/LC_MESSAGES/django.po +982 -397
- wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
- wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
- wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
- wbcore/markdown/models.py +8 -5
- wbcore/markdown/views.py +1 -1
- wbcore/menus/menus.py +2 -2
- wbcore/metadata/configs/buttons/bases.py +10 -7
- wbcore/metadata/configs/buttons/buttons.py +2 -1
- wbcore/metadata/configs/buttons/enums.py +50 -0
- wbcore/metadata/configs/buttons/view_config.py +13 -46
- wbcore/metadata/configs/display/display.py +2 -2
- wbcore/metadata/configs/display/formatting.py +6 -9
- wbcore/metadata/configs/display/instance_display/display.py +5 -2
- wbcore/metadata/configs/display/instance_display/pages.py +1 -1
- wbcore/metadata/configs/display/instance_display/shortcuts.py +1 -1
- wbcore/metadata/configs/display/list_display.py +54 -40
- wbcore/metadata/configs/display/models.py +6 -0
- wbcore/metadata/configs/display/view_config.py +11 -9
- wbcore/metadata/configs/endpoints.py +11 -4
- wbcore/metadata/configs/fields.py +6 -1
- wbcore/metadata/configs/filter_fields.py +12 -13
- wbcore/metadata/configs/identifiers.py +3 -1
- wbcore/metadata/tests/test_buttons.py +13 -16
- wbcore/models/fields.py +2 -2
- wbcore/pagination.py +1 -2
- wbcore/permissions/permissions.py +2 -2
- wbcore/permissions/utils.py +2 -2
- wbcore/release_notes/display.py +2 -8
- wbcore/release_notes/serializers.py +2 -9
- wbcore/release_notes/viewsets.py +8 -2
- wbcore/reversion/viewsets/titles.py +4 -3
- wbcore/serializers/__init__.py +2 -0
- wbcore/serializers/fields/__init__.py +2 -1
- wbcore/serializers/fields/boolean.py +1 -1
- wbcore/serializers/fields/choice.py +28 -4
- wbcore/serializers/fields/datetime.py +45 -36
- wbcore/serializers/fields/fields.py +1 -1
- wbcore/serializers/fields/fsm.py +1 -1
- wbcore/serializers/fields/list.py +2 -5
- wbcore/serializers/fields/mixins.py +24 -11
- wbcore/serializers/fields/number.py +6 -23
- wbcore/serializers/fields/other.py +2 -10
- wbcore/serializers/fields/related.py +4 -6
- wbcore/serializers/fields/text.py +1 -1
- wbcore/serializers/fields/types.py +2 -0
- wbcore/serializers/serializers.py +12 -3
- wbcore/signals/__init__.py +1 -0
- wbcore/signals/clone.py +4 -0
- wbcore/signals/models.py +2 -6
- wbcore/tasks.py +2 -2
- wbcore/templates/wbcore/email_base_template.html +3 -3
- wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
- wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
- wbcore/test/mixins.py +52 -102
- wbcore/test/tests.py +6 -9
- wbcore/test/utils.py +3 -4
- wbcore/tests/e2e/test_e2e.py +2 -2
- wbcore/tests/test_cache/test_decorators.py +4 -7
- wbcore/tests/test_configs.py +2 -5
- wbcore/tests/test_enums.py +2 -1
- wbcore/tests/test_fields/test_choice_fields.py +9 -1
- wbcore/tests/test_fields/test_number_fields.py +7 -15
- wbcore/tests/test_fields/test_other_fields.py +1 -2
- wbcore/tests/test_filters/test_mixins.py +35 -35
- wbcore/tests/test_list_display.py +0 -2
- wbcore/tests/test_models/test_mixins.py +1 -1
- wbcore/tests/test_utils/test_date.py +1 -1
- wbcore/tests/test_utils/test_date_builder.py +25 -1
- wbcore/tests/test_utils/test_primary.py +1 -1
- wbcore/urls.py +4 -0
- wbcore/utils/date.py +18 -2
- wbcore/utils/figures.py +2 -2
- wbcore/utils/models.py +21 -4
- wbcore/utils/reportlab.py +7 -0
- wbcore/utils/rrules.py +3 -1
- wbcore/utils/string_loader.py +1 -1
- wbcore/utils/strings.py +3 -3
- wbcore/utils/views.py +8 -3
- wbcore/viewsets/mixins.py +9 -4
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/METADATA +9 -5
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/RECORD +317 -271
- wbcore/contrib/geography/tests/test_serializers.py +0 -7
- wbcore/contrib/geography/tests/tests.py +0 -13
- wbcore/contrib/io/tests/tests.py +0 -19
- wbcore/contrib/workflow/tests/tests.py +0 -25
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/WHEEL +0 -0
|
@@ -1,4 +1,112 @@
|
|
|
1
|
+
from django.forms import fields as form_fields
|
|
2
|
+
from dynamic_preferences.types import BooleanPreference as BaseBooleanPreference
|
|
3
|
+
from dynamic_preferences.types import ChoicePreference as BaseChoicePreference
|
|
4
|
+
from dynamic_preferences.types import DatePreference as BaseDatePreference
|
|
5
|
+
from dynamic_preferences.types import DateTimePreference as BaseDateTimePreference
|
|
6
|
+
from dynamic_preferences.types import DecimalPreference as BaseDecimalPreference
|
|
7
|
+
from dynamic_preferences.types import DurationPreference as BaseDurationPreference
|
|
8
|
+
from dynamic_preferences.types import FilePreference as BaseFilePreference
|
|
9
|
+
from dynamic_preferences.types import FloatPreference as BaseFloatPreference
|
|
10
|
+
from dynamic_preferences.types import IntegerPreference as BaseIntegerPreference
|
|
11
|
+
from dynamic_preferences.types import LongStringPreference as BaseLongStringPreference
|
|
1
12
|
from dynamic_preferences.types import ModelChoicePreference
|
|
13
|
+
from dynamic_preferences.types import MultipleChoicePreference as BaseMultipleChoicePreference
|
|
14
|
+
from dynamic_preferences.types import StringPreference as BaseStringPreference
|
|
15
|
+
from dynamic_preferences.types import TimePreference as BaseTimePreference
|
|
16
|
+
|
|
17
|
+
from wbcore.serializers import fields
|
|
18
|
+
from wbcore.serializers.fields import LanguageChoiceField
|
|
19
|
+
|
|
20
|
+
FIELD_MAPPING = {
|
|
21
|
+
form_fields.BooleanField: fields.BooleanField,
|
|
22
|
+
form_fields.IntegerField: fields.IntegerField,
|
|
23
|
+
form_fields.FloatField: fields.FloatField,
|
|
24
|
+
form_fields.DecimalField: fields.DecimalField,
|
|
25
|
+
form_fields.CharField: fields.CharField,
|
|
26
|
+
form_fields.ChoiceField: fields.ChoiceField,
|
|
27
|
+
form_fields.FileField: fields.FileField,
|
|
28
|
+
form_fields.DurationField: fields.DurationField,
|
|
29
|
+
form_fields.DateField: fields.DateField,
|
|
30
|
+
form_fields.DateTimeField: fields.DateTimeField,
|
|
31
|
+
form_fields.TimeField: fields.TimeField,
|
|
32
|
+
form_fields.MultipleChoiceField: fields.MultipleChoiceField,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class PreferenceMixin:
|
|
37
|
+
weight: int = 0
|
|
38
|
+
|
|
39
|
+
def get_api_additional_data(self):
|
|
40
|
+
return {}
|
|
41
|
+
|
|
42
|
+
def get_api_field_data(self):
|
|
43
|
+
field_class = FIELD_MAPPING[self.field_class]
|
|
44
|
+
kwargs = self.get_field_kwargs()
|
|
45
|
+
del kwargs["widget"]
|
|
46
|
+
rep = field_class(**kwargs, default=kwargs.get("initial")).get_representation(None, self.name)[1]
|
|
47
|
+
rep["required"] = True
|
|
48
|
+
return rep
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BooleanPreference(PreferenceMixin, BaseBooleanPreference):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class IntegerPreference(PreferenceMixin, BaseIntegerPreference):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class DecimalPreference(PreferenceMixin, BaseDecimalPreference):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class FloatPreference(PreferenceMixin, BaseFloatPreference):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class StringPreference(PreferenceMixin, BaseStringPreference):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class LongStringPreference(PreferenceMixin, BaseLongStringPreference):
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ChoicePreference(PreferenceMixin, BaseChoicePreference):
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FilePreference(PreferenceMixin, BaseFilePreference):
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class DurationPreference(PreferenceMixin, BaseDurationPreference):
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class DatePreference(PreferenceMixin, BaseDatePreference):
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class DateTimePreference(PreferenceMixin, BaseDateTimePreference):
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class TimePreference(PreferenceMixin, BaseTimePreference):
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class MultipleChoicePreference(PreferenceMixin, BaseMultipleChoicePreference):
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class LanguageChoicePreference(PreferenceMixin, BaseChoicePreference):
|
|
104
|
+
def get_api_field_data(self):
|
|
105
|
+
kwargs = self.get_field_kwargs()
|
|
106
|
+
del kwargs["widget"]
|
|
107
|
+
rep = LanguageChoiceField(**kwargs, default=kwargs.get("initial")).get_representation(None, self.name)[1]
|
|
108
|
+
rep["required"] = True
|
|
109
|
+
return rep
|
|
2
110
|
|
|
3
111
|
|
|
4
112
|
class CallableDefaultModelChoicePreference(ModelChoicePreference):
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from django.db.models import Case, Value, When
|
|
2
|
+
from dynamic_preferences.users.registries import user_preferences_registry
|
|
3
|
+
from dynamic_preferences.users.viewsets import UserPreferencesViewSet as BaseUserPreferencesViewSet
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UserPreferencesViewSet(BaseUserPreferencesViewSet):
|
|
7
|
+
def get_queryset(self):
|
|
8
|
+
obsolete_expressions = []
|
|
9
|
+
weight_expressions = []
|
|
10
|
+
# we mount a when statement dynamically from the static user preference registry
|
|
11
|
+
# if the condition is matched, we assume the preference is not obsolete.
|
|
12
|
+
for section_name, preferences in user_preferences_registry.items():
|
|
13
|
+
for pref in preferences.values():
|
|
14
|
+
obsolete_expressions.append(When(section=section_name, name=pref.name, then=Value(False)))
|
|
15
|
+
weight_expressions.append(
|
|
16
|
+
When(section=section_name, name=pref.name, then=Value(getattr(pref, "weight", 0)))
|
|
17
|
+
)
|
|
18
|
+
return (
|
|
19
|
+
super()
|
|
20
|
+
.get_queryset()
|
|
21
|
+
.annotate(
|
|
22
|
+
is_obsolete=Case(*obsolete_expressions, default=Value(True)),
|
|
23
|
+
weight=Case(*weight_expressions, default=Value(0)),
|
|
24
|
+
)
|
|
25
|
+
.exclude(is_obsolete=True)
|
|
26
|
+
.order_by("weight", "name")
|
|
27
|
+
)
|
|
@@ -71,7 +71,9 @@ class EventTypeFilter(EventTypeSportFilter):
|
|
|
71
71
|
class PlayerStatisticsChartFilter(filters.FilterSet):
|
|
72
72
|
minute__gte = filters.NumberFilter(label=_("Minute"), lookup_expr="gte", field_name="minute")
|
|
73
73
|
minute__lte = filters.NumberFilter(label=_("Minute"), lookup_expr="lte", field_name="minute")
|
|
74
|
-
period = filters.DateRangeFilter(
|
|
74
|
+
period = filters.DateRangeFilter(
|
|
75
|
+
label=_("Period"), method="filter_by_period", initial=current_year_date_range, required=True
|
|
76
|
+
)
|
|
75
77
|
|
|
76
78
|
def filter_by_period(self, queryset: QuerySet[Event], name, value: DateRange) -> QuerySet[Event]:
|
|
77
79
|
return queryset.filter(match__date_time__contained_by=TimestamptzRange(value.lower, value.upper))
|
|
@@ -48,7 +48,7 @@ class MatchBaseFilter(filters.FilterSet):
|
|
|
48
48
|
label_key=SportPerson.get_representation_label_key(),
|
|
49
49
|
)
|
|
50
50
|
status = filters.ChoiceFilter(
|
|
51
|
-
label=_("Status"), choices=Match.MatchStatus.choices,
|
|
51
|
+
label=_("Status"), choices=Match.MatchStatus.choices, initial=Match.MatchStatus.ONGOING
|
|
52
52
|
)
|
|
53
53
|
sport = filters.ModelMultipleChoiceFilter(
|
|
54
54
|
label=_("Sports"),
|
|
@@ -69,7 +69,7 @@ class Role(models.Model):
|
|
|
69
69
|
verbose_name_plural = _("Roles")
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
class SportPerson(ComplexToStringMixin
|
|
72
|
+
class SportPerson(ComplexToStringMixin):
|
|
73
73
|
roles = models.ManyToManyField(to=Role, blank=True, related_name="sport_persons", verbose_name=_("Roles"))
|
|
74
74
|
first_name = models.CharField(max_length=255, verbose_name=_("First Name"))
|
|
75
75
|
last_name = models.CharField(max_length=255, verbose_name=_("Last Name"))
|
|
@@ -175,7 +175,12 @@ def post_save_sport(sender, instance: Sport, created: bool, raw: bool, **kwargs)
|
|
|
175
175
|
|
|
176
176
|
class League(ComplexToStringMixin, models.Model):
|
|
177
177
|
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
|
178
|
-
sport = models.ForeignKey(
|
|
178
|
+
sport = models.ForeignKey(
|
|
179
|
+
to=Sport,
|
|
180
|
+
on_delete=models.PROTECT,
|
|
181
|
+
related_name="leagues",
|
|
182
|
+
verbose_name=_("Sport"),
|
|
183
|
+
)
|
|
179
184
|
country = models.ForeignKey(
|
|
180
185
|
to=Geography,
|
|
181
186
|
limit_choices_to={"level": 1},
|
|
@@ -314,7 +319,9 @@ class Stadium(models.Model):
|
|
|
314
319
|
standing_capacity = models.PositiveIntegerField(default=0, verbose_name=_("Standing Capacity"))
|
|
315
320
|
seating_capacity = models.PositiveIntegerField(default=0, verbose_name=_("Seating Capacity"))
|
|
316
321
|
guest_rating = models.IntegerField(
|
|
317
|
-
validators=[MinValueValidator(0), MaxValueValidator(4)],
|
|
322
|
+
validators=[MinValueValidator(0), MaxValueValidator(4)],
|
|
323
|
+
default=3,
|
|
324
|
+
verbose_name=_("Guest Rating"),
|
|
318
325
|
)
|
|
319
326
|
|
|
320
327
|
teams_playing: models.QuerySet[Team]
|
|
@@ -365,30 +372,67 @@ class Match(ComplexToStringMixin, CalendarItem):
|
|
|
365
372
|
WBColor.BLUE_LIGHT.value,
|
|
366
373
|
WBColor.GREEN_LIGHT.value,
|
|
367
374
|
]
|
|
368
|
-
return [status for status in zip(cls, colors)]
|
|
375
|
+
return [status for status in zip(cls, colors, strict=False)]
|
|
369
376
|
|
|
370
|
-
home = models.ForeignKey(
|
|
371
|
-
|
|
377
|
+
home = models.ForeignKey(
|
|
378
|
+
to="Team",
|
|
379
|
+
related_name="home_matches",
|
|
380
|
+
on_delete=models.CASCADE,
|
|
381
|
+
verbose_name=_("Home"),
|
|
382
|
+
)
|
|
383
|
+
away = models.ForeignKey(
|
|
384
|
+
to="Team",
|
|
385
|
+
related_name="away_matches",
|
|
386
|
+
on_delete=models.CASCADE,
|
|
387
|
+
verbose_name=_("Away"),
|
|
388
|
+
)
|
|
372
389
|
date_time = models.DateTimeField(verbose_name=_("Date Time"))
|
|
373
390
|
stadium = models.ForeignKey(
|
|
374
|
-
to=Stadium,
|
|
391
|
+
to=Stadium,
|
|
392
|
+
related_name="matches",
|
|
393
|
+
on_delete=models.CASCADE,
|
|
394
|
+
verbose_name=_("Stadium"),
|
|
395
|
+
)
|
|
396
|
+
status = FSMField(
|
|
397
|
+
choices=MatchStatus.choices,
|
|
398
|
+
verbose_name=_("Status"),
|
|
399
|
+
default=MatchStatus.SCHEDULED,
|
|
375
400
|
)
|
|
376
|
-
status = FSMField(choices=MatchStatus.choices, verbose_name=_("Status"), default=MatchStatus.SCHEDULED)
|
|
377
401
|
score_home = models.PositiveIntegerField(verbose_name=_("Home Score"), default=0, editable=False)
|
|
378
402
|
score_away = models.PositiveIntegerField(verbose_name=_("Away Score"), default=0, editable=False)
|
|
379
403
|
referee = models.ForeignKey(
|
|
380
|
-
to=SportPerson,
|
|
404
|
+
to=SportPerson,
|
|
405
|
+
null=True,
|
|
406
|
+
blank=True,
|
|
407
|
+
related_name="refereed_matches",
|
|
408
|
+
on_delete=models.SET_NULL,
|
|
381
409
|
)
|
|
382
410
|
league = models.ForeignKey(
|
|
383
|
-
to=League,
|
|
411
|
+
to=League,
|
|
412
|
+
on_delete=models.SET_NULL,
|
|
413
|
+
null=True,
|
|
414
|
+
blank=True,
|
|
415
|
+
related_name="matches",
|
|
416
|
+
verbose_name=_("League"),
|
|
417
|
+
)
|
|
418
|
+
winner = models.ForeignKey(
|
|
419
|
+
"Team",
|
|
420
|
+
on_delete=models.SET_NULL,
|
|
421
|
+
null=True,
|
|
422
|
+
blank=True,
|
|
423
|
+
related_name="won_matches",
|
|
424
|
+
)
|
|
425
|
+
sport = models.ForeignKey(
|
|
426
|
+
to=Sport,
|
|
427
|
+
on_delete=models.PROTECT,
|
|
428
|
+
related_name="matches",
|
|
429
|
+
verbose_name=_("Sport"),
|
|
384
430
|
)
|
|
385
|
-
winner = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, related_name="won_matches")
|
|
386
|
-
sport = models.ForeignKey(to=Sport, on_delete=models.PROTECT, related_name="matches", verbose_name=_("Sport"))
|
|
387
431
|
task_id = models.CharField(blank=True, editable=False, max_length=50)
|
|
388
432
|
|
|
389
433
|
events: models.QuerySet[Event]
|
|
390
434
|
|
|
391
|
-
def has_permissions(
|
|
435
|
+
def has_permissions(self: Match, user: User) -> bool:
|
|
392
436
|
if user.is_superuser or user.has_perm("wbcore.change_match_status"):
|
|
393
437
|
return True
|
|
394
438
|
return False
|
|
@@ -629,7 +673,11 @@ class Team(OrderableModel, Company):
|
|
|
629
673
|
verbose_name=_("Home Stadium"),
|
|
630
674
|
)
|
|
631
675
|
opponents = models.ManyToManyField(
|
|
632
|
-
to="self",
|
|
676
|
+
to="self",
|
|
677
|
+
blank=True,
|
|
678
|
+
through=Match,
|
|
679
|
+
through_fields=("home", "away"),
|
|
680
|
+
verbose_name=_("Opponents"),
|
|
633
681
|
)
|
|
634
682
|
duration_since_last_win = models.DurationField(
|
|
635
683
|
blank=True,
|
|
@@ -693,7 +741,7 @@ def post_save_team(sender, instance: Team, created: bool, raw: bool, **kwargs):
|
|
|
693
741
|
away_match.recompute_computed_str()
|
|
694
742
|
|
|
695
743
|
|
|
696
|
-
class Player(OrderableModel, SportPerson):
|
|
744
|
+
class Player(OrderableModel, SportPerson): # noqa
|
|
697
745
|
PARTITION_BY = PARENT_FK = "current_team"
|
|
698
746
|
|
|
699
747
|
position = models.CharField(max_length=50, null=True, blank=True, verbose_name=_("Position"))
|
|
@@ -706,15 +754,23 @@ class Player(OrderableModel, SportPerson):
|
|
|
706
754
|
verbose_name=_("Current Team"),
|
|
707
755
|
)
|
|
708
756
|
former_teams = models.ManyToManyField(
|
|
709
|
-
to=Team,
|
|
757
|
+
to=Team,
|
|
758
|
+
related_name="former_players",
|
|
759
|
+
blank=True,
|
|
760
|
+
verbose_name=_("Former Teams"),
|
|
710
761
|
)
|
|
711
762
|
transfer_value = models.DecimalField(
|
|
712
|
-
max_digits=10,
|
|
763
|
+
max_digits=10,
|
|
764
|
+
decimal_places=2,
|
|
765
|
+
default=Decimal(0),
|
|
766
|
+
verbose_name=_("Market Value"),
|
|
713
767
|
)
|
|
714
768
|
is_active = models.BooleanField(default=True, verbose_name=_("Is Active"))
|
|
715
769
|
is_injured = models.BooleanField(default=False, verbose_name=_("Is Injured"))
|
|
716
770
|
player_strength = models.IntegerField(
|
|
717
|
-
validators=[MinValueValidator(0), MaxValueValidator(5)],
|
|
771
|
+
validators=[MinValueValidator(0), MaxValueValidator(5)],
|
|
772
|
+
default=3,
|
|
773
|
+
verbose_name=_("Player Strength"),
|
|
718
774
|
)
|
|
719
775
|
game_activity = models.FloatField(
|
|
720
776
|
validators=[MinValueValidator(0), MaxValueValidator(1)],
|
|
@@ -815,7 +871,8 @@ class Event(models.Model):
|
|
|
815
871
|
verbose_name_plural = _("Events")
|
|
816
872
|
constraints = [
|
|
817
873
|
models.UniqueConstraint(
|
|
818
|
-
fields=["person", "match", "minute", "event_type"],
|
|
874
|
+
fields=["person", "match", "minute", "event_type"],
|
|
875
|
+
name="event_person_match_minute_event_type",
|
|
819
876
|
),
|
|
820
877
|
]
|
|
821
878
|
|
|
@@ -823,7 +880,9 @@ class Event(models.Model):
|
|
|
823
880
|
class EventType(models.Model):
|
|
824
881
|
name = models.CharField(max_length=100, verbose_name=_("Name"))
|
|
825
882
|
points = models.PositiveIntegerField(
|
|
826
|
-
verbose_name=_("Points"),
|
|
883
|
+
verbose_name=_("Points"),
|
|
884
|
+
help_text=_("Number of points awarded to a player's team per event"),
|
|
885
|
+
default=1,
|
|
827
886
|
)
|
|
828
887
|
sport = models.ForeignKey(
|
|
829
888
|
to=Sport,
|
|
@@ -872,9 +931,19 @@ class Season(models.Model):
|
|
|
872
931
|
date_range = DateRangeField()
|
|
873
932
|
name = models.CharField(max_length=255, blank=True)
|
|
874
933
|
file = models.FileField(upload_to="season_files/", blank=True, null=True)
|
|
875
|
-
winner = models.ForeignKey(
|
|
934
|
+
winner = models.ForeignKey(
|
|
935
|
+
"Team",
|
|
936
|
+
on_delete=models.SET_NULL,
|
|
937
|
+
blank=True,
|
|
938
|
+
null=True,
|
|
939
|
+
related_name="won_seasons",
|
|
940
|
+
)
|
|
876
941
|
top_scorer = models.ForeignKey(
|
|
877
|
-
"Player",
|
|
942
|
+
"Player",
|
|
943
|
+
on_delete=models.SET_NULL,
|
|
944
|
+
blank=True,
|
|
945
|
+
null=True,
|
|
946
|
+
related_name="top_scorer_seasons",
|
|
878
947
|
)
|
|
879
948
|
|
|
880
949
|
def __str__(self):
|
|
@@ -108,8 +108,8 @@ class TeamModelSerializer(serializers.ModelSerializer):
|
|
|
108
108
|
if email:
|
|
109
109
|
try:
|
|
110
110
|
validate_email(email)
|
|
111
|
-
except ValidationError:
|
|
112
|
-
raise ValidationError({"email": _("Invalid e-mail address")})
|
|
111
|
+
except ValidationError as e:
|
|
112
|
+
raise ValidationError({"email": _("Invalid e-mail address")}) from e
|
|
113
113
|
if phone_number:
|
|
114
114
|
try:
|
|
115
115
|
if phone_number.startswith("00"):
|
|
@@ -120,8 +120,8 @@ class TeamModelSerializer(serializers.ModelSerializer):
|
|
|
120
120
|
if parser_number:
|
|
121
121
|
formatted_number = phonenumbers.format_number(parser_number, phonenumbers.PhoneNumberFormat.E164)
|
|
122
122
|
data["phone_number"] = formatted_number
|
|
123
|
-
except Exception:
|
|
124
|
-
raise ValidationError({"phone_number": _("Invalid phone number format")})
|
|
123
|
+
except Exception as e:
|
|
124
|
+
raise ValidationError({"phone_number": _("Invalid phone number format")}) from e
|
|
125
125
|
|
|
126
126
|
return super().validate(data)
|
|
127
127
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<link rel="stylesheet" href="https://stainly-cdn.fra1.cdn.digitaloceanspaces.com/static/{{ version }}/embedded/main.css">
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<h1>Embedded View Example</h1>
|
|
7
|
+
<div style="display: flex; flex-direction: row;">
|
|
8
|
+
<div style="width: 70%; height: 750px;" data-wb-endpoint="{% url 'example_app:player-list' %}" data-wb-hide-control-bar data-wb-lazy-load></div>
|
|
9
|
+
<div style="width: 30%; height: 750px;" data-wb-endpoint="{% url 'example_app:player-detail' 37 %}" data-wb-hide-control-bar></div>
|
|
10
|
+
</div>
|
|
11
|
+
<div style="height: 750px;" data-wb-endpoint="{% url 'example_app:player-statistics-list' 37 %}" data-wb-hide-control-bar></div>
|
|
12
|
+
<div style="height: 750px;" data-wb-endpoint="{% url 'example_app:team-list' %}" data-wb-lazy-load></div>
|
|
13
|
+
<div style="height: 750px;" data-wb-endpoint="{% url 'example_app:stadium-list' %}" data-wb-hide-control-bar data-wb-lazy-load data-wb-lazy-load-threshold="500"></div>
|
|
14
|
+
<script>window.wbcore_config_url = 'https://staging.atonra.stainly-bench.com/wbcore/config/'</script>
|
|
15
|
+
<script src="https://cdn.plot.ly/plotly-3.0.0.min.js" charset="utf-8"></script>
|
|
16
|
+
<script src="https://stainly-cdn.fra1.cdn.digitaloceanspaces.com/static/{{ version }}/embedded/embeddedWbView-runtime.umd.js" type="module"></script>
|
|
17
|
+
<script src="https://stainly-cdn.fra1.cdn.digitaloceanspaces.com/static/{{ version }}/embedded/embeddedWbView-main.umd.js" type="module"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -25,7 +25,7 @@ USER_PASSWORD = "User_Password"
|
|
|
25
25
|
class TestTeam:
|
|
26
26
|
def test_create_edit_delete_team(self, live_server, selenium):
|
|
27
27
|
# Creating a test user and login to the WB
|
|
28
|
-
user: User = SuperUserFactory(plaintext_password=USER_PASSWORD)
|
|
28
|
+
user: User = SuperUserFactory(plaintext_password=USER_PASSWORD) # noqa
|
|
29
29
|
actions = ActionChains(selenium, 1000)
|
|
30
30
|
set_up(selenium, live_server, user.email, USER_PASSWORD)
|
|
31
31
|
|
|
@@ -28,10 +28,11 @@ class TestMatch:
|
|
|
28
28
|
match = MatchFactory()
|
|
29
29
|
assert match.has_permissions(user) is True
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
# TODO This tests need some fixing
|
|
32
|
+
# def test_has_permissions_custom_perm(self):
|
|
33
|
+
# match = MatchFactory()
|
|
34
|
+
# user = UserFactory(user_permissions=["wbcore.change_match_status"])
|
|
35
|
+
# assert match.has_permissions(user) is True
|
|
35
36
|
|
|
36
37
|
def test_str(self):
|
|
37
38
|
match = MatchFactory(home__name="Home Team", away__name="Away Team")
|
|
@@ -48,7 +49,10 @@ class TestMatch:
|
|
|
48
49
|
match.reschedule_task()
|
|
49
50
|
assert mock_revoke.call_args.args == (old_task_id,)
|
|
50
51
|
assert mock_revoke.call_args.kwargs == {"terminate": True}
|
|
51
|
-
assert mock_start.call_args.kwargs == {
|
|
52
|
+
assert mock_start.call_args.kwargs == {
|
|
53
|
+
"eta": match.date_time,
|
|
54
|
+
"args": [match.pk],
|
|
55
|
+
}
|
|
52
56
|
assert match.task_id == user.pk
|
|
53
57
|
|
|
54
58
|
@patch("wbcore.contrib.example_app.models.start_match.apply_async")
|
|
@@ -61,7 +65,10 @@ class TestMatch:
|
|
|
61
65
|
match.task_id = None
|
|
62
66
|
match.reschedule_task()
|
|
63
67
|
assert mock_revoke.call_count == 1
|
|
64
|
-
assert mock_start.call_args.kwargs == {
|
|
68
|
+
assert mock_start.call_args.kwargs == {
|
|
69
|
+
"eta": match.date_time,
|
|
70
|
+
"args": [match.pk],
|
|
71
|
+
}
|
|
65
72
|
assert match.task_id == user.pk
|
|
66
73
|
|
|
67
74
|
def test_save_calendar_item(self):
|
|
@@ -111,7 +118,10 @@ class TestMatch:
|
|
|
111
118
|
score_away=1,
|
|
112
119
|
league=league,
|
|
113
120
|
)
|
|
114
|
-
assert set(TeamResults.objects.values_list("team__name", flat=True)) == {
|
|
121
|
+
assert set(TeamResults.objects.values_list("team__name", flat=True)) == {
|
|
122
|
+
home_team.name,
|
|
123
|
+
away_team.name,
|
|
124
|
+
}
|
|
115
125
|
home_results = TeamResults.objects.get(team=home_team)
|
|
116
126
|
away_results = TeamResults.objects.get(team=away_team)
|
|
117
127
|
assert home_results.wins == 1
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.urls import include, path
|
|
2
2
|
|
|
3
|
+
from wbcore.contrib.example_app.views import embedded_view_example
|
|
3
4
|
from wbcore.routers import WBCoreRouter
|
|
4
5
|
|
|
5
6
|
from . import viewsets
|
|
@@ -77,4 +78,5 @@ urlpatterns = [
|
|
|
77
78
|
path("league/<int:league_id>/", include(league_router.urls)),
|
|
78
79
|
path("league/<int:league_id>/event_type/<int:event_type_id>/", include(league_event_type_router.urls)),
|
|
79
80
|
path("player/<int:player_id>/", include(player_router.urls)),
|
|
81
|
+
path("embedded/", embedded_view_example),
|
|
80
82
|
]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.http import HttpRequest, HttpResponse
|
|
3
|
+
from django.shortcuts import render
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def embedded_view_example(request: HttpRequest) -> HttpResponse:
|
|
7
|
+
return render(request, "example_app/embedded_view.html", {"version": settings.FRONTEND_VERSION})
|
|
@@ -19,6 +19,11 @@ TEAM_FIELDS = [
|
|
|
19
19
|
dp.Field(key="founded_date", label=_("Founded Date")),
|
|
20
20
|
dp.Field(key="coach", label=_("Coach"), tooltip=dp.Tooltip(key="coach_tooltip")),
|
|
21
21
|
dp.Field(key="home_stadium", label=_("Home Stadium")),
|
|
22
|
+
dp.Field(
|
|
23
|
+
key="computed_str",
|
|
24
|
+
label=_("Name"),
|
|
25
|
+
formatting_rules=[dp.FormattingRule(style={"fontWeight": "bold"}, condition=("==", "Altona 93"))],
|
|
26
|
+
),
|
|
22
27
|
]
|
|
23
28
|
|
|
24
29
|
|
|
@@ -28,7 +33,6 @@ class TeamDisplayConfig(DisplayViewConfig):
|
|
|
28
33
|
fields=TEAM_FIELDS,
|
|
29
34
|
tree=True,
|
|
30
35
|
tree_group_field="computed_str",
|
|
31
|
-
tree_group_label=_("Name"),
|
|
32
36
|
tree_group_level_options=[
|
|
33
37
|
dp.TreeGroupLevelOption(
|
|
34
38
|
filter_depth=1,
|
|
@@ -99,10 +103,25 @@ class TeamDisplayConfig(DisplayViewConfig):
|
|
|
99
103
|
default(): Layout(
|
|
100
104
|
grid_template_areas=(
|
|
101
105
|
[
|
|
102
|
-
[
|
|
103
|
-
|
|
106
|
+
[
|
|
107
|
+
"name",
|
|
108
|
+
"coach",
|
|
109
|
+
"matches_section",
|
|
110
|
+
"matches_section",
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
"home_stadium",
|
|
114
|
+
".",
|
|
115
|
+
"matches_section",
|
|
116
|
+
"matches_section",
|
|
117
|
+
],
|
|
104
118
|
[".", ".", "matches_section", "matches_section"],
|
|
105
|
-
[
|
|
119
|
+
[
|
|
120
|
+
"players_section",
|
|
121
|
+
"players_section",
|
|
122
|
+
"players_section",
|
|
123
|
+
"players_section",
|
|
124
|
+
],
|
|
106
125
|
]
|
|
107
126
|
if not is_create_display
|
|
108
127
|
else [
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
1
3
|
from django.apps import apps
|
|
2
4
|
from django.db import connection
|
|
3
5
|
from django.db.models.signals import pre_migrate
|
|
4
6
|
from pytest_factoryboy import register
|
|
7
|
+
from rest_framework.test import APIRequestFactory, APIClient
|
|
8
|
+
from wbcore.contrib.authentication.factories import UserFactory
|
|
5
9
|
|
|
6
10
|
from ..factories import ContinentFactory
|
|
7
11
|
from .signals import app_pre_migration
|
|
@@ -10,3 +14,13 @@ register(ContinentFactory)
|
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
pre_migrate.connect(app_pre_migration, sender=apps.get_app_config("geography"))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.fixture()
|
|
20
|
+
def request_factory():
|
|
21
|
+
return APIRequestFactory()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture()
|
|
25
|
+
def super_user():
|
|
26
|
+
return UserFactory(is_superuser=True)
|
|
@@ -1,12 +1,27 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
|
|
5
|
+
from wbcore.contrib.geography.models import Geography
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestModels:
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def geography(self):
|
|
11
|
+
return Geography(name="Test Geography")
|
|
12
|
+
|
|
13
|
+
def test_endpoint_basename(self, geography):
|
|
14
|
+
assert isinstance(geography.get_endpoint_basename, Callable)
|
|
15
|
+
|
|
16
|
+
def test_representation_endpoint(self, geography):
|
|
17
|
+
assert isinstance(geography.get_representation_endpoint, Callable)
|
|
18
|
+
|
|
19
|
+
def test_representation_value_key(self, geography):
|
|
20
|
+
assert geography.get_representation_value_key() == "id"
|
|
3
21
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
pass
|
|
22
|
+
def test_representation_label_key(self, geography):
|
|
23
|
+
assert geography.get_representation_label_key is not None
|
|
7
24
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# result = Geography.objects.get_by_natural_key(obj.code_2)
|
|
12
|
-
# assert obj == result
|
|
25
|
+
def test_str(self, geography):
|
|
26
|
+
assert isinstance(str(geography), str)
|
|
27
|
+
assert str(geography) == geography.name
|