wbcore 1.59.9__py2.py3-none-any.whl → 1.59.11__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.
Files changed (31) hide show
  1. wbcore/configs/registry.py +15 -13
  2. wbcore/configs/views.py +2 -2
  3. wbcore/contrib/authentication/migrations/0007_alter_token_unique_together_token_unique_token.py +21 -0
  4. wbcore/contrib/authentication/models/tokens.py +1 -1
  5. wbcore/contrib/authentication/tests/test_configs.py +2 -2
  6. wbcore/contrib/authentication/viewsets/users.py +2 -2
  7. wbcore/contrib/currency/migrations/0002_alter_currencyfxrates_unique_together_and_more.py +22 -0
  8. wbcore/contrib/currency/models.py +1 -1
  9. wbcore/contrib/directory/configurations.py +9 -10
  10. wbcore/contrib/directory/tests/test_configs.py +2 -2
  11. wbcore/contrib/documents/serializers/documents.py +1 -0
  12. wbcore/contrib/documents/viewsets/display/documents.py +6 -15
  13. wbcore/contrib/gleap/tests/tests.py +2 -2
  14. wbcore/contrib/guardian/filters.py +6 -2
  15. wbcore/contrib/icons/icons.py +2 -3
  16. wbcore/contrib/io/import_export/parsers/resources.py +2 -2
  17. wbcore/contrib/io/migrations/0009_alter_importedobjectproviderrelationship_unique_together_and_more.py +34 -0
  18. wbcore/contrib/io/models.py +21 -9
  19. wbcore/contrib/io/resources.py +2 -2
  20. wbcore/contrib/notifications/tests/test_configs.py +2 -2
  21. wbcore/contrib/tags/migrations/0002_alter_tag_unique_together_tag_unique_tag.py +22 -0
  22. wbcore/contrib/tags/models/tags.py +1 -1
  23. wbcore/contrib/workflow/tests/test_configs.py +2 -2
  24. wbcore/metadata/configs/buttons/view_config.py +7 -2
  25. wbcore/permissions/registry.py +2 -2
  26. wbcore/tests/conftest.py +4 -2
  27. wbcore/tests/test_configs.py +12 -12
  28. wbcore/utils/importlib.py +0 -9
  29. {wbcore-1.59.9.dist-info → wbcore-1.59.11.dist-info}/METADATA +1 -1
  30. {wbcore-1.59.9.dist-info → wbcore-1.59.11.dist-info}/RECORD +31 -27
  31. {wbcore-1.59.9.dist-info → wbcore-1.59.11.dist-info}/WHEEL +0 -0
@@ -1,7 +1,6 @@
1
1
  from contextlib import suppress
2
2
  from importlib import import_module
3
3
  from inspect import getmembers
4
- from types import ModuleType
5
4
  from typing import Any, Iterable
6
5
 
7
6
  from django.conf import settings
@@ -15,21 +14,24 @@ class ConfigRegistry:
15
14
  in the APIView of this module.
16
15
  """
17
16
 
18
- def __init__(self, request: Request, *args, **kwargs):
19
- self.request = request
20
- super().__init__(*args, **kwargs)
17
+ def __init__(self, *args, **kwargs):
18
+ self.config_members = []
19
+ self._load_configs()
21
20
 
22
- def discover_configs(self) -> Iterable[ModuleType]:
21
+ def _load_configs(self):
23
22
  for app in settings.INSTALLED_APPS:
24
23
  with suppress(ModuleNotFoundError):
25
24
  module = import_module(f"{app}.configs")
26
- yield module
25
+ for member in getmembers(module, lambda member: hasattr(member, "_is_config")):
26
+ self.config_members.append(member[1])
27
27
 
28
- def get_configs(self) -> Iterable[tuple[str, Any]]:
29
- for module in self.discover_configs():
30
- for member in getmembers(module, lambda member: hasattr(member, "_is_config")):
31
- if res := member[1](request=self.request):
32
- yield res
28
+ def get_configs(self, request: Request) -> Iterable[tuple[str, Any]]:
29
+ for member in self.config_members:
30
+ if res := member(request=request):
31
+ yield res
33
32
 
34
- def get_config_dict(self) -> dict[str, Any]:
35
- return dict(self.get_configs())
33
+ def get_config_dict(self, request: Request) -> dict[str, Any]:
34
+ return dict(self.get_configs(request))
35
+
36
+
37
+ config_registry = ConfigRegistry()
wbcore/configs/views.py CHANGED
@@ -2,11 +2,11 @@ from rest_framework.request import Request
2
2
  from rest_framework.response import Response
3
3
  from rest_framework.views import APIView
4
4
 
5
- from wbcore.configs.registry import ConfigRegistry
5
+ from wbcore.configs.registry import config_registry
6
6
 
7
7
 
8
8
  class ConfigAPIView(APIView):
9
9
  permission_classes = []
10
10
 
11
11
  def get(self, request: Request) -> Response:
12
- return Response(ConfigRegistry(request=request).get_config_dict())
12
+ return Response(config_registry.get_config_dict(request))
@@ -0,0 +1,21 @@
1
+ # Generated by Django 5.2.9 on 2025-12-16 15:26
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('authentication', '0006_auto_20231206_1422'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterUniqueTogether(
14
+ name='token',
15
+ unique_together=set(),
16
+ ),
17
+ migrations.AddConstraint(
18
+ model_name='token',
19
+ constraint=models.UniqueConstraint(fields=('user', 'protected_view_name'), name='unique_token'),
20
+ ),
21
+ ]
@@ -137,4 +137,4 @@ class Token(DRFToken):
137
137
  class Meta:
138
138
  verbose_name = _("Token")
139
139
  verbose_name_plural = _("Tokens")
140
- unique_together = [("user", "protected_view_name")]
140
+ constraints = (models.UniqueConstraint(name="unique_token", fields=("user", "protected_view_name")),)
@@ -1,6 +1,6 @@
1
1
  from wbcore.configs.registry import ConfigRegistry
2
2
 
3
3
 
4
- def test_authentication_config(config_registry: ConfigRegistry):
5
- authentication = config_registry.get_config_dict()["authentication"]
4
+ def test_authentication_config(config_registry: ConfigRegistry, api_request):
5
+ authentication = config_registry.get_config_dict(api_request)["authentication"]
6
6
  assert authentication
@@ -72,7 +72,7 @@ def reset_password_email(request):
72
72
  try:
73
73
  user.reset_password(request)
74
74
  except Exception as e:
75
- logger.error(f"While user {user} try to reset password, we encounter the error {e}")
75
+ logger.error("While user try to reset password, we encounter the error", extra={"user": user, "detail": e})
76
76
  return Response(
77
77
  {
78
78
  "status": "ok",
@@ -122,7 +122,7 @@ def register_user(request):
122
122
  query_params["error_redirect_url"] = error_redirect_url
123
123
 
124
124
  token = user.generate_temporary_token()
125
- url = f'{reverse("wbcore:authentication:activate", args=[user.uuid, token], request=request)}?{urlencode(query_params)}'
125
+ url = f"{reverse('wbcore:authentication:activate', args=[user.uuid, token], request=request)}?{urlencode(query_params)}"
126
126
 
127
127
  # Construct registration mail and send
128
128
  rendered_message = render_to_string("user_registration_email.html", {"user": user, "url": url})
@@ -0,0 +1,22 @@
1
+ # Generated by Django 5.2.9 on 2025-12-16 15:26
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('currency', '0001_initial'),
10
+ ('io', '0008_importsource_resource_kwargs'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterUniqueTogether(
15
+ name='currencyfxrates',
16
+ unique_together=set(),
17
+ ),
18
+ migrations.AddConstraint(
19
+ model_name='currencyfxrates',
20
+ constraint=models.UniqueConstraint(fields=('date', 'currency'), name='unique_currency'),
21
+ ),
22
+ ]
@@ -114,7 +114,7 @@ class CurrencyFXRates(ImportMixin, models.Model):
114
114
  class Meta:
115
115
  verbose_name = "FX Rate"
116
116
  verbose_name_plural = "FX Rates"
117
- unique_together = ("date", "currency")
117
+ constraints = (models.UniqueConstraint(name="unique_currency", fields=("date", "currency")),)
118
118
  indexes = [
119
119
  models.Index(
120
120
  name="currency_fx_rate_idx",
@@ -1,8 +1,7 @@
1
+ from django.utils.module_loading import import_string
1
2
  from django.utils.translation import gettext_lazy
2
3
  from rest_framework.reverse import reverse
3
4
 
4
- from wbcore.utils.importlib import import_from_dotted_path
5
-
6
5
 
7
6
  class ConfigurationRegistry:
8
7
  DEFAULT_COMPANY_MODEL_VIEWSET = "wbcore.contrib.directory.viewsets.entries.CompanyModelViewSet"
@@ -20,35 +19,35 @@ class ConfigurationRegistry:
20
19
 
21
20
  @property
22
21
  def company_model_viewset(self):
23
- return import_from_dotted_path(self.DEFAULT_COMPANY_MODEL_VIEWSET)
22
+ return import_string(self.DEFAULT_COMPANY_MODEL_VIEWSET)
24
23
 
25
24
  @property
26
25
  def company_representation_viewset(self):
27
- return import_from_dotted_path(self.DEFAULT_COMPANY_REPRESENTATION_VIEWSET)
26
+ return import_string(self.DEFAULT_COMPANY_REPRESENTATION_VIEWSET)
28
27
 
29
28
  @property
30
29
  def company_model_serializer(self):
31
- return import_from_dotted_path(self.DEFAULT_COMPANY_MODEL_SERIALIZER)
30
+ return import_string(self.DEFAULT_COMPANY_MODEL_SERIALIZER)
32
31
 
33
32
  @property
34
33
  def company_representation_serializer(self):
35
- return import_from_dotted_path(self.DEFAULT_COMPANY_REPRESENTATION_SERIALIZER)
34
+ return import_string(self.DEFAULT_COMPANY_REPRESENTATION_SERIALIZER)
36
35
 
37
36
  @property
38
37
  def person_model_viewset(self):
39
- return import_from_dotted_path(self.DEFAULT_PERSON_MODEL_VIEWSET)
38
+ return import_string(self.DEFAULT_PERSON_MODEL_VIEWSET)
40
39
 
41
40
  @property
42
41
  def person_representation_viewset(self):
43
- return import_from_dotted_path(self.DEFAULT_PERSON_REPRESENTATION_VIEWSET)
42
+ return import_string(self.DEFAULT_PERSON_REPRESENTATION_VIEWSET)
44
43
 
45
44
  @property
46
45
  def person_model_serializer(self):
47
- return import_from_dotted_path(self.DEFAULT_PERSON_MODEL_SERIALIZER)
46
+ return import_string(self.DEFAULT_PERSON_MODEL_SERIALIZER)
48
47
 
49
48
  @property
50
49
  def person_representation_serializer(self):
51
- return import_from_dotted_path(self.DEFAULT_PERSON_REPRESENTATION_SERIALIZER)
50
+ return import_string(self.DEFAULT_PERSON_REPRESENTATION_SERIALIZER)
52
51
 
53
52
 
54
53
  class DirectoryConfigurationMixin:
@@ -1,6 +1,6 @@
1
1
  from wbcore.configs.registry import ConfigRegistry
2
2
 
3
3
 
4
- def test_profile_config(config_registry: ConfigRegistry):
5
- profile = config_registry.get_config_dict()["profile"]
4
+ def test_profile_config(config_registry: ConfigRegistry, api_request):
5
+ profile = config_registry.get_config_dict(api_request)["profile"]
6
6
  assert profile
@@ -46,6 +46,7 @@ class DocumentModelSerializer(serializers.ModelSerializer):
46
46
  "created",
47
47
  "valid_from",
48
48
  "valid_until",
49
+ "permission_type",
49
50
  "_additional_resources",
50
51
  )
51
52
 
@@ -15,6 +15,7 @@ class DocumentModelDisplay(DisplayViewConfig):
15
15
  fields=[
16
16
  dp.Field(key="name", label=_("Name")),
17
17
  dp.Field(key="document_type", label=_("Type")),
18
+ dp.Field(key="permission_type", label=_("Permission")),
18
19
  dp.Field(key="valid_from", label=_("Valid From")),
19
20
  dp.Field(key="valid_until", label=_("Valid Until")),
20
21
  dp.Field(key="updated", label=_("Updated")),
@@ -52,27 +53,17 @@ class DocumentModelDisplay(DisplayViewConfig):
52
53
  layouts={
53
54
  dp.default(): dp.Layout(
54
55
  grid_template_areas=[
55
- ["file", "file", "file", "file", "file", "file"],
56
- ["name", "name", "name", "document_type", "document_type", "document_type"],
57
- ["created", "created", "updated", "updated", "system_created", "system_created"],
56
+ ["file", "file", "file"],
57
+ ["name", "document_type", "permission_type"],
58
+ ["created", "updated", "system_created"],
59
+ ["valid_from", "valid_until", "."],
58
60
  [
59
- "valid_from",
60
- "valid_from",
61
- "valid_from",
62
- "valid_until",
63
- "valid_until",
64
- "valid_until",
65
- ],
66
- [
67
- "description",
68
- "description",
69
- "description",
70
61
  "description",
71
62
  "description",
72
63
  "description",
73
64
  ],
74
65
  ],
75
- grid_template_columns=[dp.repeat_field(6, "1fr")],
66
+ grid_template_columns=[dp.repeat_field(3, "1fr")],
76
67
  )
77
68
  },
78
69
  ),
@@ -23,7 +23,7 @@ def test_different_secret():
23
23
  assert hash1 != hash2
24
24
 
25
25
 
26
- def test_gleap_config(config_registry: ConfigRegistry):
27
- gleap = config_registry.get_config_dict()["gleap"]
26
+ def test_gleap_config(config_registry: ConfigRegistry, api_request):
27
+ gleap = config_registry.get_config_dict(api_request)["gleap"]
28
28
  assert gleap["user_identity_endpoint"]
29
29
  assert gleap["api_token"]
@@ -1,3 +1,4 @@
1
+ from django.db.models import Q
1
2
  from rest_framework.filters import BaseFilterBackend
2
3
 
3
4
 
@@ -14,8 +15,11 @@ class ObjectPermissionsFilter(BaseFilterBackend):
14
15
  model_class = queryset.model
15
16
  if issubclass(model_class, PermissionObjectModelMixin):
16
17
  user = request.user
17
-
18
- return get_objects_for_user(
18
+ protected_objects = get_objects_for_user(
19
19
  user, [model_class.view_perm_str], queryset, **model_class.guardian_shortcut_kwargs
20
20
  )
21
+ public_objects = queryset.filter(permission_type=PermissionObjectModelMixin.PermissionType.PUBLIC)
22
+ return queryset.filter(
23
+ Q(id__in=public_objects.values("id")) | Q(id__in=protected_objects.values("id"))
24
+ ).distinct()
21
25
  return queryset
@@ -5,8 +5,7 @@ from types import DynamicClassAttribute
5
5
  from django.conf import settings
6
6
  from django.db.models import TextChoices
7
7
  from django.db.models.enums import ChoicesType
8
-
9
- from wbcore.utils.importlib import import_from_dotted_path
8
+ from django.utils.module_loading import import_string
10
9
 
11
10
  DEFAULT_ICON_BACKEND = "wbcore.contrib.icons.backends.material.IconBackend"
12
11
  FALLBACK_ICON_VALUE = "FALLBACK_ICON"
@@ -21,7 +20,7 @@ class WBIconMeta(ChoicesType):
21
20
  ) # add a default member that represent the fallback in case it's not yet implement in the imported backend
22
21
  cls = super().__new__(cls, classname, bases, classdict, **kwds)
23
22
  with suppress(ModuleNotFoundError):
24
- cls.icon_backend = import_from_dotted_path(getattr(settings, "WBCORE_ICON_BACKEND", DEFAULT_ICON_BACKEND))
23
+ cls.icon_backend = import_string(getattr(settings, "WBCORE_ICON_BACKEND", DEFAULT_ICON_BACKEND))
25
24
  icon_backend = cls.icon_backend
26
25
  # For each enumeration values, attached an "icon" property to its members
27
26
  for member, value in zip(cls.__members__.values(), cls.values, strict=False):
@@ -1,16 +1,16 @@
1
1
  import magic
2
2
  from django.apps import apps
3
3
  from django.conf import settings
4
+ from django.utils.module_loading import import_string
4
5
  from import_export.formats.base_formats import CSV
5
6
  from import_export.results import RowResult
6
7
  from import_export.signals import post_import
7
- from wbcore.utils.importlib import import_from_dotted_path
8
8
 
9
9
 
10
10
  def default_import_parse(import_source):
11
11
  resource_path = import_source.resource_kwargs["resource_path"]
12
12
  resource_kwargs = import_source.resource_kwargs["resource_kwargs"]
13
- resource_class = import_from_dotted_path(resource_path)
13
+ resource_class = import_string(resource_path)
14
14
  resource = resource_class(**resource_kwargs)
15
15
  input_format = CSV(encoding="utf-8-sig")
16
16
 
@@ -0,0 +1,34 @@
1
+ # Generated by Django 5.2.9 on 2025-12-16 15:26
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('contenttypes', '0002_remove_content_type_name'),
10
+ ('io', '0008_importsource_resource_kwargs'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterUniqueTogether(
15
+ name='importedobjectproviderrelationship',
16
+ unique_together=set(),
17
+ ),
18
+ migrations.AlterUniqueTogether(
19
+ name='parserhandler',
20
+ unique_together=set(),
21
+ ),
22
+ migrations.AddConstraint(
23
+ model_name='importedobjectproviderrelationship',
24
+ constraint=models.UniqueConstraint(fields=('content_type', 'object_id', 'provider'), name='unique_contentobjectprovideridentifierrelationship'),
25
+ ),
26
+ migrations.AddConstraint(
27
+ model_name='importedobjectproviderrelationship',
28
+ constraint=models.UniqueConstraint(fields=('content_type', 'provider_identifier', 'provider'), name='unique_contentobjectprovideridentifier'),
29
+ ),
30
+ migrations.AddConstraint(
31
+ model_name='parserhandler',
32
+ constraint=models.UniqueConstraint(fields=('parser', 'handler'), name='unique_parserhandler'),
33
+ ),
34
+ ]
@@ -28,6 +28,7 @@ from django.db.utils import IntegrityError
28
28
  from django.dispatch import receiver
29
29
  from django.utils import timezone
30
30
  from django.utils.functional import cached_property
31
+ from django.utils.module_loading import import_string
31
32
  from django.utils.translation import gettext_lazy as _
32
33
  from django_celery_beat.models import CrontabSchedule, PeriodicTask, cronexp
33
34
  from import_export.resources import Resource
@@ -37,7 +38,6 @@ from tqdm import tqdm
37
38
 
38
39
  from wbcore.contrib.notifications.dispatch import send_notification
39
40
  from wbcore.contrib.notifications.utils import create_notification_type
40
- from wbcore.utils.importlib import import_from_dotted_path
41
41
  from wbcore.utils.models import ComplexToStringMixin
42
42
 
43
43
  from ...workers import Queue
@@ -91,7 +91,7 @@ class ParserHandler(models.Model):
91
91
  handler.process(parsed_data, **kwargs)
92
92
 
93
93
  class Meta:
94
- unique_together = ("parser", "handler")
94
+ constraints = (models.UniqueConstraint(name="unique_parserhandler", fields=("parser", "handler")),)
95
95
  verbose_name = _("Parser-Handler")
96
96
  verbose_name_plural = _("Parsers-Handlers")
97
97
 
@@ -132,10 +132,16 @@ class ImportedObjectProviderRelationship(ComplexToStringMixin):
132
132
  class Meta:
133
133
  verbose_name = _("Content object Provider Identifier relationship")
134
134
  verbose_name_plural = _("Content object Provider Identifier relationships")
135
- unique_together = [
136
- ("content_type", "object_id", "provider"),
137
- ("content_type", "provider_identifier", "provider"),
138
- ]
135
+ constraints = (
136
+ models.UniqueConstraint(
137
+ name="unique_contentobjectprovideridentifierrelationship",
138
+ fields=("content_type", "object_id", "provider"),
139
+ ),
140
+ models.UniqueConstraint(
141
+ name="unique_contentobjectprovideridentifier",
142
+ fields=("content_type", "provider_identifier", "provider"),
143
+ ),
144
+ )
139
145
  indexes = [
140
146
  models.Index(fields=["content_type", "object_id", "provider"]),
141
147
  models.Index(fields=["content_type", "provider_identifier", "provider"]),
@@ -728,7 +734,7 @@ class ExportSource(ImportExportSource):
728
734
  """
729
735
  Load into an attribute the instantiated resource loaded from the resource path
730
736
  """
731
- resource_class = import_from_dotted_path(self.resource_path)
737
+ resource_class = import_string(self.resource_path)
732
738
  return resource_class(**self.resource_kwargs)
733
739
 
734
740
  @property
@@ -796,7 +802,10 @@ class ExportSource(ImportExportSource):
796
802
  self.log = f"{ex_type}: {ex_value}\n"
797
803
  self.log += traceback.format_exc()
798
804
  self.save()
799
- logger.error(f"Export source {self.id} error: {e}")
805
+ logger.error(
806
+ "Data source export failed: Processing error during file generation.",
807
+ extra={"export_source": self, "parser_handler": self.parser_handler, "detail": e},
808
+ )
800
809
 
801
810
 
802
811
  class ImportSource(ImportExportSource):
@@ -902,7 +911,10 @@ class ImportSource(ImportExportSource):
902
911
  if debug:
903
912
  raise e
904
913
  elif not self.creator: # if a creator is set in this import source, they will receive a proper notification with feedback. No need then to pollute the logger
905
- logger.error(f"Could not import file {self.file.name} (parser/handler: {self.parser_handler})")
914
+ logger.error(
915
+ "Data import failed: Processing error during file parsing and handling.",
916
+ extra={"import_source": self, "parser_handler": self.parser_handler, "detail": e},
917
+ )
906
918
 
907
919
  self.notify()
908
920
 
@@ -4,11 +4,11 @@ from inspect import isfunction
4
4
 
5
5
  import tablib
6
6
  from django.template import Context, Template
7
+ from django.utils.module_loading import import_string
7
8
  from import_export import resources
8
9
 
9
10
  from wbcore.serializers import ListSerializer
10
11
  from wbcore.serializers.fields.related import ListSerializer as RelatedListSerializer
11
- from wbcore.utils.importlib import import_from_dotted_path
12
12
 
13
13
 
14
14
  class ExportResourceMixin:
@@ -84,7 +84,7 @@ class ViewResource(ExportResourceMixin, resources.Resource):
84
84
  super().__init__(**kwargs)
85
85
  # in that case, serializer_class is lazy loaded,
86
86
  if serializer_class_path:
87
- serializer_class = import_from_dotted_path(serializer_class_path)
87
+ serializer_class = import_string(serializer_class_path)
88
88
  if isfunction(serializer_class):
89
89
  serializer_class = serializer_class(*serializer_class_method_args)
90
90
  if not serializer_class:
@@ -1,7 +1,7 @@
1
1
  from wbcore.configs.registry import ConfigRegistry
2
2
 
3
3
 
4
- def test_notifications_config(config_registry: ConfigRegistry):
5
- notifications = config_registry.get_config_dict()["notifications"]
4
+ def test_notifications_config(config_registry: ConfigRegistry, api_request):
5
+ notifications = config_registry.get_config_dict(api_request)["notifications"]
6
6
  assert notifications["endpoint"]
7
7
  assert notifications["token"]
@@ -0,0 +1,22 @@
1
+ # Generated by Django 5.2.9 on 2025-12-16 15:26
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('contenttypes', '0002_remove_content_type_name'),
10
+ ('tags', '0001_initial'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterUniqueTogether(
15
+ name='tag',
16
+ unique_together=set(),
17
+ ),
18
+ migrations.AddConstraint(
19
+ model_name='tag',
20
+ constraint=models.UniqueConstraint(fields=('slug', 'content_type'), name='unique_tag'),
21
+ ),
22
+ ]
@@ -31,7 +31,7 @@ class Tag(ComplexToStringMixin, ManagedMixin):
31
31
  )
32
32
 
33
33
  class Meta:
34
- unique_together = [("slug", "content_type")]
34
+ constraints = (models.UniqueConstraint(name="unique_tag", fields=("slug", "content_type")),)
35
35
  verbose_name = "Tag"
36
36
  verbose_name_plural = "Tags"
37
37
 
@@ -1,6 +1,6 @@
1
1
  from wbcore.configs.registry import ConfigRegistry
2
2
 
3
3
 
4
- def test_workflow_config(config_registry: ConfigRegistry):
5
- workflow = config_registry.get_config_dict()["workflow"]
4
+ def test_workflow_config(config_registry: ConfigRegistry, api_request):
5
+ workflow = config_registry.get_config_dict(api_request)["workflow"]
6
6
  assert workflow["endpoint"]
@@ -69,12 +69,17 @@ class ButtonViewConfig(WBCoreViewConfig):
69
69
  return getattr(self.view, "FSM_BUTTONS", set())
70
70
 
71
71
  # Create Button Configuration
72
- CREATE_BUTTONS = frozenset({Button.SAVE.value})
72
+ CREATE_BUTTONS = frozenset(
73
+ {
74
+ Button.SAVE.value,
75
+ Button.SAVE_AND_CLOSE.value,
76
+ Button.SAVE_AND_NEW.value,
77
+ }
78
+ )
73
79
  CREATE_BUTTONS_ORDERING = [
74
80
  Button.SAVE.value,
75
81
  Button.SAVE_AND_CLOSE.value,
76
82
  Button.SAVE_AND_NEW.value,
77
- Button.RESET.value,
78
83
  ]
79
84
 
80
85
  def get_create_buttons(self) -> Iterable:
@@ -4,15 +4,15 @@ from django.conf import settings
4
4
  from django.contrib.auth.models import Group
5
5
  from django.db.models import QuerySet
6
6
  from django.utils.functional import cached_property
7
+ from django.utils.module_loading import import_string
7
8
 
8
9
  from wbcore.contrib.authentication.models import User
9
- from wbcore.utils.importlib import import_from_dotted_path
10
10
 
11
11
 
12
12
  class UserBackendRegistry:
13
13
  def __init__(self):
14
14
  internal_users_backend_path = getattr(settings, "USER_BACKEND", "wbcore.permissions.backend.UserBackend")
15
- internal_users_backend_class = import_from_dotted_path(internal_users_backend_path)
15
+ internal_users_backend_class = import_string(internal_users_backend_path)
16
16
  self.backend = internal_users_backend_class()
17
17
 
18
18
  @cached_property
wbcore/tests/conftest.py CHANGED
@@ -43,10 +43,12 @@ pre_migrate.connect(app_pre_migration)
43
43
 
44
44
  @pytest.fixture()
45
45
  def config_registry():
46
- request = APIRequestFactory().get("/")
47
- registry = ConfigRegistry(request)
46
+ registry = ConfigRegistry()
48
47
  return registry
49
48
 
49
+ @pytest.fixture()
50
+ def api_request():
51
+ return APIRequestFactory().get("/")
50
52
 
51
53
  @pytest.fixture
52
54
  def chrome_options(chrome_options):
@@ -6,37 +6,37 @@ from wbcore.configs.registry import ConfigRegistry
6
6
  from wbcore.configs.views import ConfigAPIView
7
7
 
8
8
 
9
- def test_registry(config_registry: ConfigRegistry):
10
- configs = config_registry.get_config_dict()
9
+ def test_registry(config_registry: ConfigRegistry, api_request):
10
+ configs = config_registry.get_config_dict(api_request)
11
11
  assert configs.keys()
12
12
 
13
13
 
14
- def test_release_note_config(config_registry: ConfigRegistry):
15
- release_notes = config_registry.get_config_dict()["release_notes"]
14
+ def test_release_note_config(config_registry: ConfigRegistry, api_request):
15
+ release_notes = config_registry.get_config_dict(api_request)["release_notes"]
16
16
  assert release_notes["endpoint"]
17
17
  assert release_notes["unread_release_notes"]
18
18
 
19
19
 
20
- def test_menu_config(config_registry: ConfigRegistry):
21
- menu = config_registry.get_config_dict()["menu"]
20
+ def test_menu_config(config_registry: ConfigRegistry, api_request):
21
+ menu = config_registry.get_config_dict(api_request)["menu"]
22
22
  assert menu
23
23
 
24
24
 
25
- def test_share_config(config_registry: ConfigRegistry):
26
- share = config_registry.get_config_dict()["share"]
25
+ def test_share_config(config_registry: ConfigRegistry, api_request):
26
+ share = config_registry.get_config_dict(api_request)["share"]
27
27
  assert share
28
28
 
29
29
 
30
- def test_menu_calendar_config(config_registry: ConfigRegistry):
31
- menu_calendar = config_registry.get_config_dict()["menu_calendar"]
30
+ def test_menu_calendar_config(config_registry: ConfigRegistry, api_request):
31
+ menu_calendar = config_registry.get_config_dict(api_request)["menu_calendar"]
32
32
  assert menu_calendar
33
33
 
34
34
 
35
35
  @pytest.mark.parametrize("text, version", [("Foo bar", "Foo")])
36
- def test_beta_button_config(config_registry: ConfigRegistry, text, version):
36
+ def test_beta_button_config(config_registry: ConfigRegistry, text, version, api_request):
37
37
  settings.BETA_BUTTON_VERSION = version
38
38
  settings.BETA_BUTTON_TEXT = text
39
- beta_calendar = config_registry.get_config_dict()["beta_button"]
39
+ beta_calendar = config_registry.get_config_dict(api_request)["beta_button"]
40
40
  assert beta_calendar["url"] == f"{settings.CDN_BASE_ENDPOINT_URL}/{version}/main.js"
41
41
  assert beta_calendar["text"] == text
42
42
 
wbcore/utils/importlib.py CHANGED
@@ -1,12 +1,3 @@
1
- from importlib import import_module
2
- from typing import Callable, Type, Union
3
-
4
-
5
- def import_from_dotted_path(path: str) -> Union[Type, Callable]:
6
- *module_path, name = path.split(".")
7
- return getattr(import_module(".".join(module_path)), name)
8
-
9
-
10
1
  def parse_signal_received_for_module(receiver_response) -> tuple[str, any]:
11
2
  for receiver, response in receiver_response:
12
3
  if response:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbcore
3
- Version: 1.59.9
3
+ Version: 1.59.11
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  Requires-Dist: celery[redis]==5.*
6
6
  Requires-Dist: croniter==2.*
@@ -24,8 +24,8 @@ wbcore/cache/views.py,sha256=Ehwglwlug2Z4285BPvTE5623sCAlHrDD3np1oZkw_gc,630
24
24
  wbcore/configs/__init__.py,sha256=icE1l0NI-0vGErpIyCUx48l-Fys4OCJxK0Wi781Wdek,238
25
25
  wbcore/configs/configs.py,sha256=QDgKfNUMFfVYXBvmh_yk_2oFikmAspiSKxuhjePAyd0,1882
26
26
  wbcore/configs/decorators.py,sha256=5kdwENMaiw6rzjqTj-D7ezx-9gj2FVg1P5NsFrO-fnc,387
27
- wbcore/configs/registry.py,sha256=mBOETXfDdGPW7tpXRTyvvEzn4IvAWtPegN13-ml6Jy4,1287
28
- wbcore/configs/views.py,sha256=GCf8jPF0hAgQ8oIle4jJMliWlWoXj4yBPsZAe7MZS1s,366
27
+ wbcore/configs/registry.py,sha256=9WM_CUSgItFAE5sno5ssEH6qrmyyhX2wZz3SNWB__Ds,1295
28
+ wbcore/configs/views.py,sha256=QVmgyeB4pFZMmtkzv-JlRmyT-b6OwuUVuKOKMXxpOL4,358
29
29
  wbcore/configurations/__init__.py,sha256=H-vQTsjryzvwQ7FN4kGLywoGFV_VrPkbuNV4VRx1WHU,68
30
30
  wbcore/configurations/base.py,sha256=woxAbHfAU6vMHu6oZp5eDJB97j-PjUVkA6UdItXNc8Q,1550
31
31
  wbcore/configurations/configurations/__init__.py,sha256=mni_MM6rOHK1YwOC9i4xlrITumInHJuKCngc4k-pdpo,574
@@ -148,9 +148,10 @@ wbcore/contrib/authentication/migrations/0003_alter_user_profile.py,sha256=WW8PW
148
148
  wbcore/contrib/authentication/migrations/0004_token.py,sha256=rD5Tpby4iUb4Vje-IejhJW1PWIZTmMPW4QGtIQtYpos,1971
149
149
  wbcore/contrib/authentication/migrations/0005_user_external_calendar_settings.py,sha256=BegFBiGbtbNWoGGATBbfHn9GcDkmdqKhLdf8VeLvwYc,386
150
150
  wbcore/contrib/authentication/migrations/0006_auto_20231206_1422.py,sha256=jetLcssq55i2KKc8TV1YGHgv3aLB1d63GfC3q7G8cmQ,259
151
+ wbcore/contrib/authentication/migrations/0007_alter_token_unique_together_token_unique_token.py,sha256=wNrKthi0VzNzfMyjx-umfbAPp5PArKIf6OEl3RgXdDM,538
151
152
  wbcore/contrib/authentication/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
153
  wbcore/contrib/authentication/models/__init__.py,sha256=GhtPxWgZEUcbFQt2ArdB6OPjyEYav3F_XddlKnht0_w,125
153
- wbcore/contrib/authentication/models/tokens.py,sha256=QGNz4Tejy6KqxOnrIGIGC4PPbKsP-CbGQ3AXNsN-zW4,5415
154
+ wbcore/contrib/authentication/models/tokens.py,sha256=03m0BiU1U3EPohNOagyEKqGSzKEBpPm2GkoazqwmuTA,5465
154
155
  wbcore/contrib/authentication/models/users.py,sha256=ShQjVpEKHCgwH1IajrYXMlDef13xinf2WqfV68aQf-A,7826
155
156
  wbcore/contrib/authentication/models/users_activities.py,sha256=uyr1FLNNCC9YDBN7hKnVGDjc9DmonY-BjPqtrUUA8o8,4289
156
157
  wbcore/contrib/authentication/release_notes/1_0_0.md,sha256=pZ6rgeR5mTB3vabX3eaEJXMSfs7m4a1SEbYdpAmXwyI,170
@@ -171,7 +172,7 @@ wbcore/contrib/authentication/templates/user_registration_email.html,sha256=_hmZ
171
172
  wbcore/contrib/authentication/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
173
  wbcore/contrib/authentication/tests/conftest.py,sha256=_Ib93zJ2oygjPME_v38N8v_2P0geVGgvLLJgQ7JDQ7Y,485
173
174
  wbcore/contrib/authentication/tests/signals.py,sha256=3Vrb_z4u_XMI-pfcGAbO4aBwhUdu7MPfPZDe07iqiAg,571
174
- wbcore/contrib/authentication/tests/test_configs.py,sha256=AJ2LmSgenIjG_9dp0bzPZj6mMG7hB_B3x2imXL7nFOY,217
175
+ wbcore/contrib/authentication/tests/test_configs.py,sha256=BX2u3r2lbfMMvKo8JpaaNYLJslOPzhsezXy64pQdTO4,241
175
176
  wbcore/contrib/authentication/tests/test_serializers.py,sha256=yiF6x5IRbWKwndlZkVlFwQd-zCebAJVbqmfDbpI87dE,79
176
177
  wbcore/contrib/authentication/tests/test_tasks.py,sha256=yiqt4U2yxh2uslu0l-nA2Zldoh-yjG5LYeg2jUWKu00,1355
177
178
  wbcore/contrib/authentication/tests/test_tokens.py,sha256=MtLW2BDElaWFpiZIRmDc_MTLd3TedjJcjOR6G1DYNbE,6129
@@ -182,7 +183,7 @@ wbcore/contrib/authentication/tests/e2e/__init__.py,sha256=0QhVTsjMlR1BTGlRiaO5i
182
183
  wbcore/contrib/authentication/tests/e2e/e2e_auth_utility.py,sha256=DNCAiaLGVZ964oGmdp1CYc1oU2AEDZdA_W1kLZv5Zn0,564
183
184
  wbcore/contrib/authentication/viewsets/__init__.py,sha256=Kvt5ikqkg0_4P-DXvRBOpfQcUMHwDIE7vyGpGQ5uSbg,479
184
185
  wbcore/contrib/authentication/viewsets/user_activities.py,sha256=aJVtAnVYdbhc8iPOIMHcVripDJ2s0lU1lTQWSX_IyrI,8324
185
- wbcore/contrib/authentication/viewsets/users.py,sha256=8oX0EY126o5FWiiBUHiUHbk2g1bEUTR9naWbQlLiUVs,12442
186
+ wbcore/contrib/authentication/viewsets/users.py,sha256=PG0tmCQXq6UaTq8OaSl8GAKEaYGPslrddjZllh4a7uU,12465
186
187
  wbcore/contrib/authentication/viewsets/buttons/__init__.py,sha256=H2DLTgMil7mRmj-NtnBfJa-DrbMxT4lv8GbZNhe_76w,66
187
188
  wbcore/contrib/authentication/viewsets/buttons/users.py,sha256=OHtuM4M-Um85-bXXnKNA0PZQEZVB51BCiXsoOjfFLIs,2359
188
189
  wbcore/contrib/authentication/viewsets/display/__init__.py,sha256=iOKARtlVqcaMB80CZqFpCPbyjz4bKaOdjYqEmGYlIBs,222
@@ -215,7 +216,7 @@ wbcore/contrib/currency/admin.py,sha256=40IS_gMyIXjYYUka35Olk3aYI3cLLb5NXpC_rWds
215
216
  wbcore/contrib/currency/apps.py,sha256=10grJHw9gyBLDfbVJ-gGGUFcU5AgTaH7uBFr8j0bshE,106
216
217
  wbcore/contrib/currency/dynamic_preferences_registry.py,sha256=1f4tPjAf1OYyp4FPUZ9WCdh8cEcM_1OD_y5GWRCa6NA,1074
217
218
  wbcore/contrib/currency/factories.py,sha256=DTFzyceTewYzj3IFyI3roJCwF1VWKZOZKLcsJg829mA,1211
218
- wbcore/contrib/currency/models.py,sha256=Qxa_d-6oNL4VtCoAgXVvXqe9nO1IOeAb3f2aCnYASJg,6961
219
+ wbcore/contrib/currency/models.py,sha256=kyHwsLmhxrtbGNBDENuMVMRLKBd93xJ2N2nrvgicqck,7016
219
220
  wbcore/contrib/currency/serializers.py,sha256=v9y5ldcxe9cm2rabwEI9yHIj2Sp0QKnVAs9eX6F60fY,1448
220
221
  wbcore/contrib/currency/urls.py,sha256=kyM6mM-1wQtsdc58r7MsSgAGhVS-4U-xLPeC3-XPNys,685
221
222
  wbcore/contrib/currency/fixtures/currency.yaml,sha256=lB0DyTrfSt96fym_fc8_13qsWIk09h-6jfVnjHIhVQs,17225
@@ -232,6 +233,7 @@ wbcore/contrib/currency/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_T
232
233
  wbcore/contrib/currency/import_export/parsers/fixerio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
234
  wbcore/contrib/currency/import_export/parsers/fixerio/currency_fx_rates.py,sha256=pGO36qKVqdhwWjJpuQqa-UO0i_UWIVtQF3-jAUvoyV4,1242
234
235
  wbcore/contrib/currency/migrations/0001_initial.py,sha256=v1bMEVABzqAHn6D9jdBzbj4j5wTrUYDc7_fONdEQ7Jw,3063
236
+ wbcore/contrib/currency/migrations/0002_alter_currencyfxrates_unique_together_and_more.py,sha256=lrID4O3GDJodjWUL5bnIlNA0Qo1FBHbT2y5gcypPGuY,586
235
237
  wbcore/contrib/currency/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
236
238
  wbcore/contrib/currency/release_notes/1_0_0.md,sha256=Hm_Jt3S7nv30s3-Hl_ie0xkHgrRsZLuiBpOXkIDj2UE,164
237
239
  wbcore/contrib/currency/release_notes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -280,7 +282,7 @@ wbcore/contrib/dataloader/tests/test/dataloaders/proxies.py,sha256=AL7CunsWJW8G7
280
282
  wbcore/contrib/directory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
281
283
  wbcore/contrib/directory/apps.py,sha256=X-Cl9KtrSMSQIl4gejtQmjDX56BOCHS6K8qZLKqXu9I,165
282
284
  wbcore/contrib/directory/configs.py,sha256=wFGQi3WO2L_xfeQ0MG8FxVaozR9vBAvISHjedlHw6fs,282
283
- wbcore/contrib/directory/configurations.py,sha256=x-4Eh-T76Xi82IVefdsEOvKzzf-OKrmrJ3qW-jqSjwM,2801
285
+ wbcore/contrib/directory/configurations.py,sha256=SwcphDsxt8vz9UTqMVMJe-ORnxAo2viupwv3-6uJiGQ,2715
284
286
  wbcore/contrib/directory/dynamic_preferences_registry.py,sha256=ejEzrt-gqmvI3q1NbndsUtbfpeLC7tzKiGrhVtwY4w0,2098
285
287
  wbcore/contrib/directory/permissions.py,sha256=3i1n4AzGzHAx0L0H00KZKd4AHo90OHRdYk34opPYIjo,248
286
288
  wbcore/contrib/directory/preferences.py,sha256=B6J1Y5jqEPW6VrnbuxdA9Sq94XFdrwP68wnBdYoaRjs,423
@@ -358,7 +360,7 @@ wbcore/contrib/directory/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
358
360
  wbcore/contrib/directory/tests/conftest.py,sha256=54xK711IfBc6Cj7MweNOGNdkP-ojjMcfqjP1G2XrSn0,1826
359
361
  wbcore/contrib/directory/tests/disable_signals.py,sha256=kgVeTtzItEtLJ7MOVo9KdnRABsMvKBTub-vhHIMKO_M,1727
360
362
  wbcore/contrib/directory/tests/signals.py,sha256=DqQkJWnq2Y0wTTLh3ICY3qZJLUpGJqiTTSV6YypqsDQ,3217
361
- wbcore/contrib/directory/tests/test_configs.py,sha256=VouLg3TpDuxi_ljh8MtJGMhtW_h8OzCo15GyyApW16c,189
363
+ wbcore/contrib/directory/tests/test_configs.py,sha256=dXICPQOfKqloya9X8OxhVmdbeCOMCgHKDbgLzgpNTu8,213
362
364
  wbcore/contrib/directory/tests/test_filters.py,sha256=tc4G0XoUoDoiisECXtaftYCG69fdE42-EmkmLcjbN78,2492
363
365
  wbcore/contrib/directory/tests/test_models.py,sha256=L2029y7pTUznRYHXJOKFpy_jdTBZvvbx3KwHMEcNSAM,19304
364
366
  wbcore/contrib/directory/tests/test_permissions.py,sha256=lmGAiE0wtIDJkHEfNk_8NDwqN71FdPuu2qXvSMm0FbM,4231
@@ -426,7 +428,7 @@ wbcore/contrib/documents/release_notes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
426
428
  wbcore/contrib/documents/serializers/__init__.py,sha256=JQBjKbR6-rG5eIy4K0eSlH55vtdwqqztpqmhxC7yJa0,503
427
429
  wbcore/contrib/documents/serializers/document_model_relationships.py,sha256=AvtHk3OGePZc3dXfqZjBtQrJhd_hx-2eUVsZZFfHKK4,962
428
430
  wbcore/contrib/documents/serializers/document_types.py,sha256=Dtaq_EKOXbUU_x3cpuszbOHUFhY7_M_ehwDugV66BfE,1507
429
- wbcore/contrib/documents/serializers/documents.py,sha256=JxsWrMyCKF52jothUGQZG2kYR1H2mynhBU7CGRQoxvo,2407
431
+ wbcore/contrib/documents/serializers/documents.py,sha256=Mkcwn-J9pFyUk0HO7eaAXO6AWI0cgwMbDi6wzyOGXss,2438
430
432
  wbcore/contrib/documents/serializers/shareable_links.py,sha256=FbKWkDa8XZVbKcXh4ICTKMG0TQT3drSDlbnLlnegVBo,3319
431
433
  wbcore/contrib/documents/static/documents/markdown/documentation/document_types.md,sha256=MebPHN-xP_gt58fKJQ6AgLKpIwE_7EPHytXdSrZ-okc,921
432
434
  wbcore/contrib/documents/static/documents/markdown/documentation/documents.md,sha256=dbUB93mTQ-lSTXghaJYY51v58I-q9aAFtgg-XDY-Hds,768
@@ -446,7 +448,7 @@ wbcore/contrib/documents/viewsets/buttons/signals.py,sha256=6p7dtvJwyTE_OGknKbg6
446
448
  wbcore/contrib/documents/viewsets/display/__init__.py,sha256=j_anyJOMU-oxc6CIj9arJe9asOMDkuVYHw2X6bGWPa8,263
447
449
  wbcore/contrib/documents/viewsets/display/document_model_relationships.py,sha256=_gJtBB9u7MU2mKNVjrLvRhxMcgeQiYDBsKWYtIGi4vE,679
448
450
  wbcore/contrib/documents/viewsets/display/document_types.py,sha256=iZFtRDjDd2ir4vCdKdGZKjmxEYUHV-tRy9unkAjC6K4,810
449
- wbcore/contrib/documents/viewsets/display/documents.py,sha256=-aBdAk9w6M3ORZYLIinlq3GT0b1y_IgOuyMChPjfwto,4277
451
+ wbcore/contrib/documents/viewsets/display/documents.py,sha256=O5HbHKxhE1rbIksFirbstE4wiQuOhH2sjFCnAIbmR3Y,3797
450
452
  wbcore/contrib/documents/viewsets/display/shareable_links.py,sha256=p8ZYt1N1HoapYEFj1vVQvPE7tLoIUhT7m2e6m4eE-N4,2367
451
453
  wbcore/contrib/documents/viewsets/endpoints/__init__.py,sha256=S-14SZ88A8-JGIi_rF4es5ngJ6GrivIUUkplqZkbKeE,151
452
454
  wbcore/contrib/documents/viewsets/endpoints/documents.py,sha256=Yoee84rx1g35L8vCKZkn41Bvf_-QIfO3IZX3WXigpi0,790
@@ -622,10 +624,10 @@ wbcore/contrib/gleap/urls.py,sha256=0g0EfJO90ketG8dCp3sUOfFuOjqOma_XDTqKoU8b4C0,
622
624
  wbcore/contrib/gleap/views.py,sha256=8UthTu7LRRW_pi8muUDWzXVtBaQhwCRNox9JSriF5lQ,1088
623
625
  wbcore/contrib/gleap/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
624
626
  wbcore/contrib/gleap/tests/conftest.py,sha256=q9RKC6JpBsW4ZlgtnuB_V1uHtKUys4Zn0BGu3m4NbRI,36
625
- wbcore/contrib/gleap/tests/tests.py,sha256=jtPqW_ATh8OFIEb4R8RMMrhAbcNrB0FamOj1L3slT4E,714
627
+ wbcore/contrib/gleap/tests/tests.py,sha256=7m2BdJ1r34lUn8waMN_TqiS2u40f9sA2byUz0H8NZPU,738
626
628
  wbcore/contrib/guardian/apps.py,sha256=dHE4YM4uk92w5Xsmk_P1agutR_1jQytTq9dRDaj-BAU,139
627
629
  wbcore/contrib/guardian/configurations.py,sha256=rzSTs_4zbADDSnmqgqRHYd83gKdPAGyrHdegQtnH-qQ,168
628
- wbcore/contrib/guardian/filters.py,sha256=36dXy8IaSyPDKc7QkAip4d_12U1luCOKH3ujXgjBHqg,752
630
+ wbcore/contrib/guardian/filters.py,sha256=IQicKFbEtSAQ9TwwyxG-0FTbJjK53RY7qfYsibZ21L8,1064
629
631
  wbcore/contrib/guardian/tasks.py,sha256=hCUKRkcASTnSjLIQTOgU5C6pNDCL2soyij-JzTjLU08,588
630
632
  wbcore/contrib/guardian/urls.py,sha256=UCUiYxALnbEH7ZNKs4jp_xBx6vHClsVi9Hd_NR1_0Wg,412
631
633
  wbcore/contrib/guardian/utils.py,sha256=3CP48t9r8puWQ1lFCmoPTVLnrXQc02h7bwEthnWQMCo,5198
@@ -659,7 +661,7 @@ wbcore/contrib/i18n/tests/conftest.py,sha256=S0kfCoA_Aq-05_75AXfPod0oWitji1un8_w
659
661
  wbcore/contrib/i18n/tests/test_viewsets.py,sha256=cWDwIdVwEmVMbidU6fLVxjFFJH8FF8VuiM-sp4d7slE,2060
660
662
  wbcore/contrib/icons/__init__.py,sha256=zMehywxDfn8IvNcMW-6TSai6FpXE7Dd4m6X2GI5l4Bk,26
661
663
  wbcore/contrib/icons/apps.py,sha256=CbfoZkSePdV9nlUwxtNk0qMiWIR8XtBSNCmUbH1Clg8,102
662
- wbcore/contrib/icons/icons.py,sha256=IcC6zxyWGELr8qJWY2Obb_R1wJPdcxOZ56h1r2ElESo,6715
664
+ wbcore/contrib/icons/icons.py,sha256=R4K8R202H8pWgMuoTHn7grGi4XJaozHDXuakzNYFCe0,6699
663
665
  wbcore/contrib/icons/models.py,sha256=CaLITnSbltSJTKd_kieT1FAK0vrvKURVElilzqFF4wE,304
664
666
  wbcore/contrib/icons/serializers.py,sha256=C08Gr43K3dv2jB7DcAqnBz-RD9r6O9t2E_JIV8k-P-Q,582
665
667
  wbcore/contrib/icons/backends/__init__.py,sha256=GrA72d_857UivZzBmLkqgqLEqccF0L2pjpAcDTsPWls,118
@@ -674,8 +676,8 @@ wbcore/contrib/io/exceptions.py,sha256=-9pTtBr4oj7qBpKwnsN7sabu5S6gpDkWTXkA4ZaW9
674
676
  wbcore/contrib/io/factories.py,sha256=VVtUf_YPJOkT0YmJ0M09bKz1RINd98yb-ZJKwu5F5R0,7133
675
677
  wbcore/contrib/io/imports.py,sha256=Hu8ppai06SQ_CDQ2oUbFcwduAhekCp1l1DB89kTn2nQ,13087
676
678
  wbcore/contrib/io/mixins.py,sha256=Sy_1mfdJzrIODCRcbfiA6miU8EqKEaJhL7mEjsRhOvY,1297
677
- wbcore/contrib/io/models.py,sha256=X5zb00EkpiOaAALAoXV4JmtSwn6QApGYWbIMCPwVFJk,40536
678
- wbcore/contrib/io/resources.py,sha256=eGEpmyrtkB3DgFKV6m57OFzyu6jBZUIXkn5Jopeus9M,6953
679
+ wbcore/contrib/io/models.py,sha256=HzsHglQBQM1a4tf8Ga3hhVhi_iK2K4dQwvsHyGjcvJw,41147
680
+ wbcore/contrib/io/resources.py,sha256=igablmQh-4brM4f5ew_lmUwXgOeLoRqqXjik__kzbqc,6938
679
681
  wbcore/contrib/io/serializers.py,sha256=oS5od8ni8wUZml1zM_RAdW9VWrw226Ru4v3RBifOnFY,4639
680
682
  wbcore/contrib/io/signals.py,sha256=jCGHjt5Qg2T1aIi4BzWYzWYb2YZT82gUMhG68v2rx58,145
681
683
  wbcore/contrib/io/tasks.py,sha256=auozEPYqu_R7pjwr_1QSS5csGAYIEEWIVqNjSLzZhkw,859
@@ -698,7 +700,7 @@ wbcore/contrib/io/import_export/backends/sftp.py,sha256=va27MF_naWE2horVOGkrqBKf
698
700
  wbcore/contrib/io/import_export/backends/stream.py,sha256=ywSZCm8ccC1kxB9CBt0PypshdZooAxo5eHZboPwzcnY,3090
699
701
  wbcore/contrib/io/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
700
702
  wbcore/contrib/io/import_export/parsers/base_csv.py,sha256=6CPeV5j8VBeFOothav42kJEkY1F5d_ucVTRfnX8boiM,1250
701
- wbcore/contrib/io/import_export/parsers/resources.py,sha256=pTLGDf23S4Q5iNQE782a9Zgxep_WrziMX8mWO3z3SbY,1886
703
+ wbcore/contrib/io/import_export/parsers/resources.py,sha256=4bEEwmx3rtBtOJdtKo5-KqHRFg70LhRIhTfh13bE1YQ,1871
702
704
  wbcore/contrib/io/locale/de/LC_MESSAGES/django.po,sha256=98w3QBX3Evo7W8kRGx7fdedT3jJX_vF5go0c0TguNqU,3235
703
705
  wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated,sha256=KSVtjDxjCHfWg4Hq-sbkIKvGsOusXuOMFhEmOYkKFF4,2558
704
706
  wbcore/contrib/io/locale/en/LC_MESSAGES/django.po,sha256=8QyjmE4MJoz10z3k6tLXpW-mF8988Uh0CEndIvtLSTw,2920
@@ -712,6 +714,7 @@ wbcore/contrib/io/migrations/0005_exportsource_data_alter_exportsource_query_str
712
714
  wbcore/contrib/io/migrations/0006_alter_exportsource_query_params.py,sha256=JHnzz6C1Mr2kVcD5bBJMO6eNvqSFfvw6c0NoGL7pcqs,578
713
715
  wbcore/contrib/io/migrations/0007_alter_exportsource_query_params.py,sha256=xHVM23caWAPjo1eTrfTm37G20j8r_AxapoEgb685c2Q,617
714
716
  wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py,sha256=dZx4LUedW8I1Sf0JBMvWgauFbJlzw6HBT6WjhQUW72c,419
717
+ wbcore/contrib/io/migrations/0009_alter_importedobjectproviderrelationship_unique_together_and_more.py,sha256=QWtL5kTQhV0ThhNTj-ERu56kUkokUX7LBaGiMjSL1W4,1274
715
718
  wbcore/contrib/io/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
716
719
  wbcore/contrib/io/release_notes/1_0_0.md,sha256=1nJ-vnOKk4l5-gU8GTyKrvoz-YUKSGyX96KBoFDlKQc,238
717
720
  wbcore/contrib/io/release_notes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -769,7 +772,7 @@ wbcore/contrib/notifications/static/notifications/service-worker.js,sha256=4_yl6
769
772
  wbcore/contrib/notifications/templates/notifications/notification_template.html,sha256=k-o9ieU6z6c0SKAw43_iLEleJTIZK43Y8jrRCwbKPCc,1441
770
773
  wbcore/contrib/notifications/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
771
774
  wbcore/contrib/notifications/tests/conftest.py,sha256=QthEmk6WnvMsvo9Rdva7RGGT8grNlGvSLdD9Ggj4480,1486
772
- wbcore/contrib/notifications/tests/test_configs.py,sha256=I9rYEKXe0zLAOu8CrF5NzKQ7EYXj4qJUywT27Uj8fr0,259
775
+ wbcore/contrib/notifications/tests/test_configs.py,sha256=2V3m8EurnV7FlnVpexawfgR5fsOUSSe9RDZMzWqWowk,283
773
776
  wbcore/contrib/notifications/tests/test_tasks.py,sha256=d8EtXHNPZFU_JwTiVDqpdjBsxbZuRZ-NruEuaqt306M,2338
774
777
  wbcore/contrib/notifications/tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
775
778
  wbcore/contrib/notifications/tests/test_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -813,10 +816,11 @@ wbcore/contrib/tags/serializers.py,sha256=H5pxHrXd7nOiZU67zIKgp3_HCb5ARyluywpnb4
813
816
  wbcore/contrib/tags/signals.py,sha256=4WDNS2wL-JqSQPaSNDUDnxUEUMmNIs5lnJ7S1H05ydw,726
814
817
  wbcore/contrib/tags/urls.py,sha256=y_QatHkx9hyIUfdYnBX4zfMQkKtTVdztQ8FQmpDV4cE,727
815
818
  wbcore/contrib/tags/migrations/0001_initial.py,sha256=6dswzuzzubfzx5cJ69Njz7ZtDBCf0UwAbUrctTsNE00,2301
819
+ wbcore/contrib/tags/migrations/0002_alter_tag_unique_together_tag_unique_tag.py,sha256=3A45U-LPzs5vTnPmlCGKPw8S8hXIHNJ4ly7K7acJNec,563
816
820
  wbcore/contrib/tags/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
817
821
  wbcore/contrib/tags/models/__init__.py,sha256=o5Oqc0SJ5kZWQ466Z5Wgj8J9Ppsv1E3JcuLHWM5p9Zw,66
818
822
  wbcore/contrib/tags/models/mixins.py,sha256=B3UhUsU3veuGsh_cx6-VASxvUMVPKanaOknkYp0SmFg,950
819
- wbcore/contrib/tags/models/tags.py,sha256=IV1dmqRKLD9Ka7yvqnPmmX8rPBn0HfW8Xokb8sdmRgo,3237
823
+ wbcore/contrib/tags/models/tags.py,sha256=DjItYIoB2065lEbx9qDoEEdx03WkZveauYYj-e46f1M,3285
820
824
  wbcore/contrib/tags/release_notes/1_0_0.md,sha256=jG3JupsX-qW0P8UN2ktJJce_7mCMCc1fAL-nbiCJJnE,160
821
825
  wbcore/contrib/tags/release_notes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
822
826
  wbcore/contrib/tags/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -902,7 +906,7 @@ wbcore/contrib/workflow/static/workflow/markdown/documentation/workflow.md,sha25
902
906
  wbcore/contrib/workflow/templates/Test_Templates.txt,sha256=TPyYY95ZVlOPsdH_XPaDgz11RpB6tZH-PUu6BKutJhE,764
903
907
  wbcore/contrib/workflow/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
904
908
  wbcore/contrib/workflow/tests/conftest.py,sha256=5jS-R4lpLOu0VhNENaKPI1O_62qbltHzcSowRHN3Md0,6471
905
- wbcore/contrib/workflow/tests/test_configs.py,sha256=LIGgRTM9l6Fj-RHLG08fM9OdutJVEE63x-0XZ2M7oWQ,205
909
+ wbcore/contrib/workflow/tests/test_configs.py,sha256=Ir2YnjDPhpzbxtrEM_JX6SmUADw6w0W_66pcOOEQJzY,229
906
910
  wbcore/contrib/workflow/tests/test_dispatch.py,sha256=xW8EHv6yV88893R1O41ytEIaC_GY0GFLGYsdOVOF5-w,4133
907
911
  wbcore/contrib/workflow/tests/test_displays.py,sha256=Do1lD5OvnMTEW0bnjI7MV0BjKToaMUB2knvyncyfQw4,1526
908
912
  wbcore/contrib/workflow/tests/test_filters.py,sha256=tHDn1DxAIgLlcWIDQPV_vFB6FG3VGbfCfOg1KFybQPo,4146
@@ -1029,7 +1033,7 @@ wbcore/metadata/configs/buttons/bases.py,sha256=rAw5Te9V5y6tCCKOTbZXz-uln0vT7io2
1029
1033
  wbcore/metadata/configs/buttons/buttons.py,sha256=0dKPokHYMis_SZhFZ1gTHayFTMQk5nVAvyDetTNdQ6o,5033
1030
1034
  wbcore/metadata/configs/buttons/enums.py,sha256=vkJBfNFPTIIFvYrDGxrugqgRe22_KcqFRU39jo8ZvFw,1472
1031
1035
  wbcore/metadata/configs/buttons/metadata.py,sha256=OhSkW18R6B_uJrtcGjN8VEkNCPlXD2DxuYWCqZXQbD0,348
1032
- wbcore/metadata/configs/buttons/view_config.py,sha256=31fFJFeV9iM24FQY7I6XaPthokJdCuzSeCBdAB1xGnE,5308
1036
+ wbcore/metadata/configs/buttons/view_config.py,sha256=j-ydilvH0zK2AzhtBi-JaQalJOZc8I4dUItoZUHqOR8,5397
1033
1037
  wbcore/metadata/configs/display/__init__.py,sha256=K3CdAUuC-YbowUusZ9F6vGfepppSqE8cfvazczEGePo,272
1034
1038
  wbcore/metadata/configs/display/configs.py,sha256=T_jJaryQf7hMqgJ_m2b685ynBxTQgsb526Zw4maBcsI,654
1035
1039
  wbcore/metadata/configs/display/display.py,sha256=WszWJutDuE_95RBlIxj7FkR2WxGhRuQ4fUcwYmGlfY8,6236
@@ -1073,7 +1077,7 @@ wbcore/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
1073
1077
  wbcore/permissions/backend.py,sha256=pLK_Hpk_2O4pMXEnUkw_dDYG2Jagm4vK0ER9eZt80MY,1368
1074
1078
  wbcore/permissions/mixins.py,sha256=LfuFM-RcB83_-ChFPvwsoL5SbY4in7gEgaqDQ2LRyTQ,1795
1075
1079
  wbcore/permissions/permissions.py,sha256=cIj7NWhG5ws_4JHYOLYmlxQt72ygq_eAPBNWMG-wkgU,1801
1076
- wbcore/permissions/registry.py,sha256=gC9YPjinpi_B3o-qFzBy4mAmavZWLfZF2aToqT6yD74,1100
1080
+ wbcore/permissions/registry.py,sha256=fS4tbLF_5IIrHXqeZRlsqZ7XRUaqln4Oz86enjX83tg,1085
1077
1081
  wbcore/permissions/shortcuts.py,sha256=xCtU-CCfW3bCHQG5H94SxrHDLm6TStsDpqKu7nDv188,1137
1078
1082
  wbcore/permissions/utils.py,sha256=Bn7Gj4kabzEwCdz-lnqtJlH-1Zy1MRJdDdBPXKszmdQ,935
1079
1083
  wbcore/release_notes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1151,9 +1155,9 @@ wbcore/test/utils.py,sha256=-PNuj4UjeoX2FdRCPObedTQAgUDsmiO672BCwIZtKwE,8406
1151
1155
  wbcore/test/e2e_helpers_methods/e2e_checks.py,sha256=teyYS5OQGSy2r7VvhfxkaskPOrQ_jLBNPN64CRUKmzQ,4266
1152
1156
  wbcore/test/e2e_helpers_methods/e2e_helper_methods.py,sha256=Uo61TfEwYOP_u9N84gz-asZ4VwK80cWhdlnhJpnw8U8,17654
1153
1157
  wbcore/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1154
- wbcore/tests/conftest.py,sha256=XWVhrLuyY80o_-qMx4HQu0-k2h-GKw-xXnNMyUIcbjQ,1425
1158
+ wbcore/tests/conftest.py,sha256=mIDICLGEZNz-fluDsu_qRdqv-KIVMvC_3uHduww5FNI,1452
1155
1159
  wbcore/tests/models.py,sha256=QYJRhVMJZ6nENYuO-ktieiKvw3clxy57n3Is5h0tcmg,207
1156
- wbcore/tests/test_configs.py,sha256=NYJrozsPE_ZW1uNqC_wrMpajbGTiHkIy3bono2Lvkos,1766
1160
+ wbcore/tests/test_configs.py,sha256=PQ-VKV-fHN4bcS0naflpO6VMKMW0fw1_K9i0n05DYZo,1910
1157
1161
  wbcore/tests/test_enums.py,sha256=KwnEznR6PdWN9AHFMY1qx0krOqAoT7QZF8x-BPsOanM,1741
1158
1162
  wbcore/tests/test_list_display.py,sha256=9zX8grPa0lie65vxDAzJUBTjwVIep2mItbu0voSwhHs,721
1159
1163
  wbcore/tests/test_pagination.py,sha256=JRdmhLNrBkg_r7Cg1tug-jxjt0hJg4k8m-xcjpsyKMY,1078
@@ -1209,7 +1213,7 @@ wbcore/utils/deprecations.py,sha256=ju1h3-icVlJnItZkugdOdeX4sY3QJIeFxXxAo9TG_rM,
1209
1213
  wbcore/utils/enum.py,sha256=eTTMt03iCMaNEoB5xsq5IGxkCi8X3xfIRjJNI0ygzWs,533
1210
1214
  wbcore/utils/figures.py,sha256=Z7EsJ-pSWk2UExahKhO7OnPYTJltMFV6LJp8DbLptiI,9199
1211
1215
  wbcore/utils/html.py,sha256=Ir_bX4l3EgaWf7bv3ymlt836ekoCVDHedMMu8TzXyj4,157
1212
- wbcore/utils/importlib.py,sha256=6_-m6YuGdg-iKQU_MU1yCDS0_nhOTAG6UNIQYeAYTiI,461
1216
+ wbcore/utils/importlib.py,sha256=uWxesC-A0sgmjEWEVjCXOb3GuOxG_xs2Bfd4dzhAJxw,211
1213
1217
  wbcore/utils/itertools.py,sha256=tgmDS9FMzq3oy5PzAMcBreNAN8EjpoC6waRt738dcW8,1410
1214
1218
  wbcore/utils/models.py,sha256=fCYU6OUuWzBA0JzTtkTZr9jw-XPNQZaCDxAh6tBdJ_g,9490
1215
1219
  wbcore/utils/numbers.py,sha256=KaC2yNmaVMwe05uRvGvC_ayWJW_1dOgjswlqsB-QeoM,2289
@@ -1234,6 +1238,6 @@ wbcore/viewsets/generics.py,sha256=lKDq9UY_Tyc56u1bqaIEvHGgoaXwXxpZ1c3fLVteptI,1
1234
1238
  wbcore/viewsets/mixins.py,sha256=IdHd_uixOv3ExKoHxTgL5Bt8OELIwfYwhBZm0nsvZfc,12054
1235
1239
  wbcore/viewsets/utils.py,sha256=4520Ij3ASM8lOa8QZkCqbBfOexVRiZu688eW-PGqMOA,882
1236
1240
  wbcore/viewsets/viewsets.py,sha256=FPPESunEjlunDr5VFsjTfsquTS3iDSQkw0H6QjMKPqk,6574
1237
- wbcore-1.59.9.dist-info/METADATA,sha256=QnMgZcMPLWlUbAHLh-_O3uWcRmffAohcoLsrIrnuTrU,2316
1238
- wbcore-1.59.9.dist-info/WHEEL,sha256=aha0VrrYvgDJ3Xxl3db_g_MDIW-ZexDdrc_m-Hk8YY4,105
1239
- wbcore-1.59.9.dist-info/RECORD,,
1241
+ wbcore-1.59.11.dist-info/METADATA,sha256=BDSGN09DBIVVwXIZpQGQB-A7noYzZtdRjPR04DxdhiA,2317
1242
+ wbcore-1.59.11.dist-info/WHEEL,sha256=aha0VrrYvgDJ3Xxl3db_g_MDIW-ZexDdrc_m-Hk8YY4,105
1243
+ wbcore-1.59.11.dist-info/RECORD,,