wbcore 2.2.1__py2.py3-none-any.whl → 2.2.4__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 (143) hide show
  1. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +113 -0
  2. wbcore/contrib/agenda/static/agenda/markdown/documentation/building.md +11 -0
  3. wbcore/contrib/agenda/static/agenda/markdown/documentation/conferenceroom.md +20 -0
  4. wbcore/contrib/authentication/fixtures/authentication.json +62 -0
  5. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +610 -0
  6. wbcore/contrib/authentication/templates/activate_confirm.html +12 -0
  7. wbcore/contrib/authentication/templates/base.html +135 -0
  8. wbcore/contrib/authentication/templates/email_base_template.html +335 -0
  9. wbcore/contrib/authentication/templates/password_reset_done.html +13 -0
  10. wbcore/contrib/authentication/templates/password_reset_email.html +11 -0
  11. wbcore/contrib/authentication/templates/password_reset_email_html.html +43 -0
  12. wbcore/contrib/authentication/templates/password_reset_form.html +23 -0
  13. wbcore/contrib/authentication/templates/password_reset_sent.html +11 -0
  14. wbcore/contrib/authentication/templates/reset_password.html +15 -0
  15. wbcore/contrib/authentication/templates/user_registration_email.html +37 -0
  16. wbcore/contrib/color/admin.py +28 -0
  17. wbcore/contrib/color/apps.py +5 -0
  18. wbcore/contrib/color/enums.py +17 -0
  19. wbcore/contrib/color/factories.py +10 -0
  20. wbcore/contrib/color/fields.py +29 -0
  21. wbcore/contrib/color/forms.py +13 -0
  22. wbcore/contrib/color/models.py +62 -0
  23. wbcore/contrib/color/tests/conftest.py +10 -0
  24. wbcore/contrib/color/tests/test_color_models.py +61 -0
  25. wbcore/contrib/color/tests/test_fields.py +25 -0
  26. wbcore/contrib/currency/fixtures/currency.yaml +1014 -0
  27. wbcore/contrib/currency/fixtures/currency_fx_rate.yaml +73585 -0
  28. wbcore/contrib/directory/fixtures/directory.json +3924 -0
  29. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +1686 -0
  30. wbcore/contrib/directory/static/directory/markdown/documentation/address.md +38 -0
  31. wbcore/contrib/directory/static/directory/markdown/documentation/banking.md +54 -0
  32. wbcore/contrib/directory/static/directory/markdown/documentation/bankingentry.md +38 -0
  33. wbcore/contrib/directory/static/directory/markdown/documentation/clientmanagerrelationship.md +42 -0
  34. wbcore/contrib/directory/static/directory/markdown/documentation/company.md +52 -0
  35. wbcore/contrib/directory/static/directory/markdown/documentation/companytype.md +2 -0
  36. wbcore/contrib/directory/static/directory/markdown/documentation/customerstatus.md +2 -0
  37. wbcore/contrib/directory/static/directory/markdown/documentation/email.md +20 -0
  38. wbcore/contrib/directory/static/directory/markdown/documentation/employeecompany.md +34 -0
  39. wbcore/contrib/directory/static/directory/markdown/documentation/employerperson.md +43 -0
  40. wbcore/contrib/directory/static/directory/markdown/documentation/person.md +61 -0
  41. wbcore/contrib/directory/static/directory/markdown/documentation/position.md +2 -0
  42. wbcore/contrib/directory/static/directory/markdown/documentation/relationshiptype.md +2 -0
  43. wbcore/contrib/directory/static/directory/markdown/documentation/socialmedia.md +23 -0
  44. wbcore/contrib/directory/static/directory/markdown/documentation/specialization.md +2 -0
  45. wbcore/contrib/directory/static/directory/markdown/documentation/systememployee.md +31 -0
  46. wbcore/contrib/directory/static/directory/markdown/documentation/telephone.md +23 -0
  47. wbcore/contrib/directory/static/directory/markdown/documentation/telephonesearch.md +26 -0
  48. wbcore/contrib/directory/static/directory/markdown/documentation/userisclient.md +14 -0
  49. wbcore/contrib/directory/static/directory/markdown/documentation/userismanager.md +28 -0
  50. wbcore/contrib/directory/static/directory/markdown/documentation/website.md +20 -0
  51. wbcore/contrib/documents/fixtures/docments.json +135 -0
  52. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +272 -0
  53. wbcore/contrib/documents/static/documents/markdown/documentation/document_types.md +21 -0
  54. wbcore/contrib/documents/static/documents/markdown/documentation/documents.md +18 -0
  55. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelink.md +28 -0
  56. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelinkaccess.md +20 -0
  57. wbcore/contrib/documents/tests/conftest.py +30 -0
  58. wbcore/contrib/documents/tests/test_models.py +144 -0
  59. wbcore/contrib/example_app/fixtures/example_app.json +7425 -0
  60. wbcore/contrib/example_app/tests/test_models/test_event.py +87 -0
  61. wbcore/contrib/example_app/tests/test_models/test_match.py +210 -0
  62. wbcore/contrib/example_app/tests/test_models/test_others.py +159 -0
  63. wbcore/contrib/example_app/tests/test_serializers/test_league_serializer.py +34 -0
  64. wbcore/contrib/example_app/tests/test_serializers/test_match_serializer.py +134 -0
  65. wbcore/contrib/example_app/tests/test_serializers/test_role_serializer.py +13 -0
  66. wbcore/contrib/example_app/tests/test_serializers/test_sport_serializer.py +14 -0
  67. wbcore/contrib/example_app/tests/test_serializers/test_stadium_serializer.py +14 -0
  68. wbcore/contrib/example_app/tests/test_serializers/test_team_result_serializer.py +30 -0
  69. wbcore/contrib/example_app/tests/test_serializers/test_team_serializer.py +70 -0
  70. wbcore/contrib/example_app/tests/test_viewsets/test_event_viewset.py +162 -0
  71. wbcore/contrib/example_app/tests/test_viewsets/test_league_viewset.py +84 -0
  72. wbcore/contrib/example_app/tests/test_viewsets/test_match_viewset.py +65 -0
  73. wbcore/contrib/example_app/tests/test_viewsets/test_person_viewset.py +166 -0
  74. wbcore/contrib/example_app/tests/test_viewsets/test_role_viewset.py +75 -0
  75. wbcore/contrib/example_app/tests/test_viewsets/test_sport_viewset.py +75 -0
  76. wbcore/contrib/example_app/tests/test_viewsets/test_stadium_viewset.py +75 -0
  77. wbcore/contrib/example_app/tests/test_viewsets/test_team_viewset.py +92 -0
  78. wbcore/contrib/example_app/tests/test_viewsets/test_teamresult_viewset.py +58 -0
  79. wbcore/contrib/example_app/tests/test_viewsets/test_utils_viewsets.py +124 -0
  80. wbcore/contrib/geography/fixtures/geography.json +13454 -0
  81. wbcore/contrib/geography/static/geography/markdown/documentation/geography.md +16 -0
  82. wbcore/contrib/guardian/apps.py +6 -0
  83. wbcore/contrib/guardian/configurations.py +3 -0
  84. wbcore/contrib/guardian/filters.py +21 -0
  85. wbcore/contrib/guardian/tasks.py +10 -0
  86. wbcore/contrib/guardian/urls.py +12 -0
  87. wbcore/contrib/guardian/utils.py +124 -0
  88. wbcore/contrib/io/fixtures/io.json +145 -0
  89. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +52 -0
  90. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +60 -0
  91. wbcore/contrib/notifications/static/notifications/service-worker.js +1 -0
  92. wbcore/contrib/notifications/templates/notifications/notification_template.html +43 -0
  93. wbcore/contrib/notifications/viewsets/configs/notification_types.py +27 -0
  94. wbcore/contrib/notifications/viewsets/configs/notifications.py +85 -0
  95. wbcore/contrib/workflow/fixtures/workflow.json +612 -0
  96. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +1289 -0
  97. wbcore/contrib/workflow/static/workflow/markdown/documentation/assignedprocessstep.md +33 -0
  98. wbcore/contrib/workflow/static/workflow/markdown/documentation/condition.md +24 -0
  99. wbcore/contrib/workflow/static/workflow/markdown/documentation/decisionstep.md +30 -0
  100. wbcore/contrib/workflow/static/workflow/markdown/documentation/emailstep.md +45 -0
  101. wbcore/contrib/workflow/static/workflow/markdown/documentation/finishstep.md +33 -0
  102. wbcore/contrib/workflow/static/workflow/markdown/documentation/joinstep.md +33 -0
  103. wbcore/contrib/workflow/static/workflow/markdown/documentation/process.md +33 -0
  104. wbcore/contrib/workflow/static/workflow/markdown/documentation/processstep.md +51 -0
  105. wbcore/contrib/workflow/static/workflow/markdown/documentation/scriptstep.md +33 -0
  106. wbcore/contrib/workflow/static/workflow/markdown/documentation/splitstep.md +30 -0
  107. wbcore/contrib/workflow/static/workflow/markdown/documentation/startstep.md +27 -0
  108. wbcore/contrib/workflow/static/workflow/markdown/documentation/transition.md +27 -0
  109. wbcore/contrib/workflow/static/workflow/markdown/documentation/userstep.md +42 -0
  110. wbcore/contrib/workflow/static/workflow/markdown/documentation/workflow.md +32 -0
  111. wbcore/contrib/workflow/templates/Test_Templates.txt +25 -0
  112. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +79 -0
  113. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +45 -0
  114. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +105 -0
  115. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +127 -0
  116. wbcore/contrib/workflow/tests/test_models/step/test_script_step.py +24 -0
  117. wbcore/contrib/workflow/tests/test_models/step/test_split_step.py +49 -0
  118. wbcore/contrib/workflow/tests/test_models/step/test_step.py +621 -0
  119. wbcore/contrib/workflow/tests/test_models/step/test_user_step.py +225 -0
  120. wbcore/contrib/workflow/tests/test_models/test_condition.py +103 -0
  121. wbcore/contrib/workflow/tests/test_models/test_data.py +134 -0
  122. wbcore/contrib/workflow/tests/test_models/test_process.py +98 -0
  123. wbcore/contrib/workflow/tests/test_models/test_transition.py +128 -0
  124. wbcore/contrib/workflow/tests/test_models/test_workflow.py +358 -0
  125. wbcore/locale/de/LC_MESSAGES/django.po +667 -0
  126. wbcore/templates/errors/404.html +134 -0
  127. wbcore/templates/errors/500.html +138 -0
  128. wbcore/templates/errors/503.html +132 -0
  129. wbcore/templates/errors/custom.html +132 -0
  130. wbcore/templates/forms.py +0 -0
  131. wbcore/templates/notifications/email_template.html +43 -0
  132. wbcore/templates/wbcore/admin/change_list.html +8 -0
  133. wbcore/templates/wbcore/admin/csv_form.html +15 -0
  134. wbcore/templates/wbcore/dynamic_color_array.html +29 -0
  135. wbcore/templates/wbcore/email_base_template.html +335 -0
  136. wbcore/templates/wbcore/email_notification_template.html +10 -0
  137. wbcore/templates/wbcore/frontend.html +51 -0
  138. wbcore/test/e2e_helpers_methods/e2e_checks.py +121 -0
  139. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +395 -0
  140. wbcore/tests/test_permissions/test_backend.py +29 -0
  141. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/METADATA +1 -1
  142. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/RECORD +143 -3
  143. {wbcore-2.2.1.dist-info → wbcore-2.2.4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,16 @@
1
+ # Geographies
2
+ A list of every geography object saved in the database.
3
+
4
+ ## Columns:
5
+ Each column title has three lines on the right if you hover over it. Click on them to show options for that column. The second tab of the options menu will allow you to filter the column, the third to completely hide entire columns. Click on anywhere else on the column to order it, cycling between ascending, descending and no ordering. Hold shift while clicking to order multiple columns with individual weights.
6
+ ### Name:
7
+ A representation name for the selected geography. Consists of its geography type (continent, country, state or city), the geography's name (e.g. Hamburg) and in the case of states and cities the alpha 3 code of its parent country in brackets (e.g. DEU).
8
+ ### Parent:
9
+ The representation name of the geography's parent. Geography objects are ordered like this: Continent > Country > State > City. As a result, continents have no parent. Hover over the name to display the parent's name, their parent object and alpha 3 country code. Column can be ordered by (non-representation-) name.
10
+ ### Alpha 2 Country Code:
11
+ The alpha 2 country code for the geography object's parent country. Thus, continents have no country codes.
12
+ ### Alpha 3 Country Code:
13
+ The alpha 3 country code for the geography object's parent country.
14
+
15
+ ## Search Field:
16
+ Typing in the search field allows to filter the geography objects by name.
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class GuardianAppConfig(AppConfig):
5
+ name = "wbcore.contrib.guardian"
6
+ label = "wbcore_guardian"
@@ -0,0 +1,3 @@
1
+ class Guardian:
2
+ GUARDIAN_USER_OBJ_PERMS_MODEL = "wbcore_guardian.UserObjectPermission"
3
+ GUARDIAN_GROUP_OBJ_PERMS_MODEL = "wbcore_guardian.GroupObjectPermission"
@@ -0,0 +1,21 @@
1
+ from rest_framework.filters import BaseFilterBackend
2
+
3
+
4
+ class ObjectPermissionsFilter(BaseFilterBackend):
5
+ """
6
+ A filter backend that limits results to those where the requesting user
7
+ has read object level permissions.
8
+ """
9
+
10
+ def filter_queryset(self, request, queryset, view):
11
+ from guardian.shortcuts import get_objects_for_user
12
+ from wbcore.contrib.guardian.models.mixins import PermissionObjectModelMixin
13
+
14
+ model_class = queryset.model
15
+ if issubclass(model_class, PermissionObjectModelMixin):
16
+ user = request.user
17
+
18
+ return get_objects_for_user(
19
+ user, [model_class.view_perm_str], queryset, **model_class.guardian_shortcut_kwargs
20
+ )
21
+ return queryset
@@ -0,0 +1,10 @@
1
+ from celery import shared_task
2
+ from wbcore.contrib.guardian.models.mixins import PermissionObjectModelMixin
3
+ from wbcore.utils.itertools import get_inheriting_subclasses
4
+
5
+
6
+ @shared_task
7
+ def reload_permissions_as_task(prune_existing: bool | None = True, force_pruning: bool | None = False):
8
+ for subclass in get_inheriting_subclasses(PermissionObjectModelMixin):
9
+ for instance in subclass.objects.iterator():
10
+ instance.reload_permissions(prune_existing=prune_existing, force_pruning=force_pruning)
@@ -0,0 +1,12 @@
1
+ from django.urls import include, path
2
+ from wbcore.contrib.guardian.viewsets import PivotUserObjectPermissionModelViewSet
3
+ from wbcore.routers import WBCoreRouter
4
+
5
+ router = WBCoreRouter()
6
+ router.register(
7
+ r"pivoteduserobjectpermission", PivotUserObjectPermissionModelViewSet, basename="pivoteduserobjectpermission"
8
+ )
9
+
10
+ urlpatterns = [
11
+ path("<int:content_type_id>/<int:object_pk>/", include(router.urls)),
12
+ ]
@@ -0,0 +1,124 @@
1
+ from contextlib import suppress
2
+ from datetime import datetime
3
+ from typing import TYPE_CHECKING, Iterable, Iterator
4
+
5
+ from django.contrib.contenttypes.models import ContentType
6
+ from django.db import ProgrammingError
7
+ from django.db.models import Model, Q, QuerySet
8
+ from django.utils import timezone
9
+ from guardian.shortcuts import assign_perm, get_anonymous_user
10
+ from psycopg.errors import InvalidCursorName
11
+ from wbcore.contrib.authentication.models import User
12
+ from wbcore.contrib.guardian.models.models import UserObjectPermission
13
+ from wbcore.permissions.shortcuts import get_internal_users
14
+
15
+ if TYPE_CHECKING:
16
+ from wbcore.contrib.guardian.models.mixins import PermissionObjectModelMixin
17
+
18
+
19
+ def assign_permissions(permissions_map: Iterable[tuple[str, Model, User, bool]]):
20
+ """
21
+ Assigns object-level permissions to users based on the provided permissions map.
22
+
23
+ This method iterates through the permissions_map, assigns the specified permission
24
+ to the user for the model instance, sets the 'editable' flag for the permission,
25
+ and saves the object permission.
26
+ """
27
+ for permission, instance, user, editable in permissions_map:
28
+ object_permissions = assign_perm(permission, user, instance)
29
+
30
+ if object_permissions is None:
31
+ continue
32
+
33
+ if isinstance(object_permissions, Model):
34
+ object_permissions = [object_permissions]
35
+
36
+ for object_permission in object_permissions:
37
+ object_permission.editable = editable # type: ignore -- We have our custom Permission class here
38
+ object_permission.save()
39
+
40
+
41
+ def get_public_user_or_group(only_internal: bool = False) -> QuerySet[User]:
42
+ """
43
+ Retrieves a queryset of active users, optionally filtering to internal users only.
44
+
45
+ This method fetches users based on the `only_internal` flag.
46
+ If set, it filters for internal users, otherwise returns all users.
47
+ The queryset includes active users or the anonymous user and excludes superusers
48
+ from the main set, while later ensuring their inclusion through a union operation.
49
+ """
50
+ users = User.objects.filter(is_active=True)
51
+ if only_internal:
52
+ users = users.filter(
53
+ Q(is_superuser=True) | Q(id=get_anonymous_user().pk) | Q(id__in=get_internal_users().values("id"))
54
+ )
55
+ return users
56
+
57
+
58
+ def get_permission_matrix(
59
+ queryset: QuerySet,
60
+ created: datetime | None = None,
61
+ instance: Model | None = None,
62
+ user: User | None = None,
63
+ ) -> Iterator[tuple[str, Model, User, bool]]:
64
+ """
65
+ Retrieves the permission matrix for all (user, object) pairs
66
+
67
+ If an instance is provided, the queryset is filtered to that specific object. The method determines the
68
+ appropriate set of users based on the permission type of the object (private or public).
69
+
70
+ For each user, the function yields a tuple containing the permission string, the object instance,
71
+ the user, and whether the permission is editable.
72
+ """
73
+
74
+ if instance:
75
+ queryset = queryset.filter(id=instance.id) # type: ignore
76
+
77
+ for _instance in queryset.all():
78
+ if _instance.permission_type is _instance.PermissionType.PUBLIC:
79
+ users = get_public_user_or_group()
80
+ else:
81
+ users = get_public_user_or_group(only_internal=True)
82
+ if user:
83
+ users = users.filter(id=user.id)
84
+ for user in users:
85
+ for permission, editable in _instance.get_permissions_for_user(user, created=created).items():
86
+ yield permission, _instance, user, editable
87
+
88
+
89
+ def prune_permissions(instance: "PermissionObjectModelMixin", force: bool | None = False):
90
+ queryset = UserObjectPermission.objects.filter(
91
+ content_type=ContentType.objects.get_for_model(instance), object_pk=instance.id
92
+ )
93
+ if not force:
94
+ queryset = queryset.exclude(editable=True)
95
+ for permission in queryset:
96
+ permission.delete()
97
+
98
+
99
+ def reload_permissions(
100
+ queryset: QuerySet,
101
+ created: datetime | None = None,
102
+ user: User | None = None,
103
+ instance: "PermissionObjectModelMixin | None" = None,
104
+ prune_existing: bool = True,
105
+ force_pruning: bool = False,
106
+ ):
107
+ """
108
+ Assigns permissions based on a given queryset, with options to prune existing permissions and
109
+ specify the creation timestamp. If no creation time is provided, the current time is used.
110
+
111
+ The function first checks if existing permissions should be pruned, which happens if both
112
+ `prune_existing` and `instance` are provided. It then retrieves the permission matrix
113
+ using `get_permission_matrix()` and assigns the appropriate permissions.
114
+
115
+ Error handling is in place to suppress database-related errors, such as `ProgrammingError`
116
+ and `InvalidCursorName`, which can occur due to unmanaged tables.
117
+ """
118
+ if not created:
119
+ created = timezone.now()
120
+ with suppress(ProgrammingError, InvalidCursorName): # We check this to catch error trigger by unmanaged table
121
+ if prune_existing and instance:
122
+ prune_permissions(instance, force=force_pruning)
123
+ permission_matrix = get_permission_matrix(queryset, created=created, instance=instance, user=user)
124
+ assign_permissions(permission_matrix)
@@ -0,0 +1,145 @@
1
+ [
2
+ {
3
+ "model": "wbcore.contrib.io.source",
4
+ "pk": 59,
5
+ "fields": {
6
+ "title": "UBS API (Instrument price)",
7
+ "is_active": true,
8
+ "is_default": false,
9
+ "save_data_in_import_source": true,
10
+ "connection_parameters": {},
11
+ "import_parameters": {
12
+ "ubs_bank": 3044
13
+ },
14
+ "data_backend": "wbportfolio.import_export.backend.ubs.instrument_price.DataBackend",
15
+ "crontab": null,
16
+ "periodic_task": null,
17
+ "import_timedelta_interval": 1,
18
+ "parser_handler": [
19
+ 46
20
+ ],
21
+ "credentials": [
22
+ 4
23
+ ]
24
+ }
25
+ },
26
+ {
27
+ "model": "wbcore.contrib.io.source",
28
+ "pk": 60,
29
+ "fields": {
30
+ "title": "UBS API (Asset Position)",
31
+ "is_active": true,
32
+ "is_default": false,
33
+ "save_data_in_import_source": true,
34
+ "connection_parameters": {},
35
+ "import_parameters": {
36
+ "ubs_bank": 3044
37
+ },
38
+ "data_backend": "wbportfolio.import_export.backend.ubs.asset_position.DataBackend",
39
+ "crontab": null,
40
+ "periodic_task": null,
41
+ "import_timedelta_interval": 1,
42
+ "parser_handler": [
43
+ 44
44
+ ],
45
+ "credentials": [
46
+ 4
47
+ ]
48
+ }
49
+ },
50
+ {
51
+ "model": "wbcore.contrib.io.source",
52
+ "pk": 61,
53
+ "fields": {
54
+ "title": "UBS API (fees)",
55
+ "is_active": true,
56
+ "is_default": false,
57
+ "save_data_in_import_source": true,
58
+ "connection_parameters": {},
59
+ "import_parameters": {
60
+ "ubs_bank": 3044
61
+ },
62
+ "data_backend": "wbportfolio.import_export.backend.ubs.fees.DataBackend",
63
+ "crontab": null,
64
+ "periodic_task": null,
65
+ "import_timedelta_interval": 1,
66
+ "parser_handler": [
67
+ 45
68
+ ],
69
+ "credentials": [
70
+ 4
71
+ ]
72
+ }
73
+ },
74
+ {
75
+ "model": "wbcore.contrib.io.source",
76
+ "pk": 66,
77
+ "fields": {
78
+ "title": "Natixis Dividend",
79
+ "is_active": true,
80
+ "is_default": false,
81
+ "save_data_in_import_source": true,
82
+ "connection_parameters": {},
83
+ "import_parameters": {
84
+ "sftp_folder": "Production",
85
+ "file_name_regex": ".*Corporate Actions.*"
86
+ },
87
+ "data_backend": "wbcore.contrib.io.backends.sftp.DataBackend",
88
+ "crontab": null,
89
+ "periodic_task": null,
90
+ "import_timedelta_interval": 0,
91
+ "parser_handler": [
92
+ 47
93
+ ],
94
+ "credentials": []
95
+ }
96
+ },
97
+ {
98
+ "model": "wbcore.contrib.io.parserhandler",
99
+ "pk": 44,
100
+ "fields": {
101
+ "parser": "wbportfolio.import_export.parsers.ubs.api.asset_position",
102
+ "handler": "wbportfolio.AssetPosition"
103
+ }
104
+ },
105
+ {
106
+ "model": "wbcore.contrib.io.parserhandler",
107
+ "pk": 45,
108
+ "fields": {
109
+ "parser": "wbportfolio.import_export.parsers.ubs.api.fees",
110
+ "handler": "wbportfolio.Fees"
111
+ }
112
+ },
113
+ {
114
+ "model": "wbcore.contrib.io.parserhandler",
115
+ "pk": 46,
116
+ "fields": {
117
+ "parser": "wbportfolio.import_export.parsers.ubs.api.instrument_price",
118
+ "handler": "wbportfolio.InstrumentPrice"
119
+ }
120
+ },
121
+ {
122
+ "model": "wbcore.contrib.io.parserhandler",
123
+ "pk": 47,
124
+ "fields": {
125
+ "parser": "wbportfolio.import_export.parsers.natixis.dividend",
126
+ "handler": "wbportfolio.DividendTransaction"
127
+ }
128
+ },
129
+ {
130
+ "model": "wbcore.contrib.io.importcredential",
131
+ "pk": 4,
132
+ "fields": {
133
+ "key": "api ubs",
134
+ "type": "AUTHENTICATION_TOKEN",
135
+ "username": null,
136
+ "password": null,
137
+ "authentication_token": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIvZ2VkLWFtYy9leHRlcm5hbCIsInN1YiI6IlRDQ2Q3MDEwYmEyZjc4MTQ3OGI5NDAzMzEzNWE0ZWI3MjczIiwiaXNzIjoiTmVvIFBsYXRmb3JtIEpXVCBBdXRob3JpemF0aW9uIFNlcnZpY2UiLCJleHAiOjE2NTM2OTYwMDAsImlhdCI6MTY0NjA1OTQ2MiwianRpIjoiM2FkYzlhOTItNzE5ZC00ODIwLWEzNzctNjZjZDU4OTNkNDViIn0.DCzVeWojN_k2_1dvk6fIWwXyBQ49VH6qQ9RB-BVjg8kBSNqoPX5WdPrQBctuy3u5pHa2fL6VEV9G5zdSUaa40yBSqSJFKrzJE4WZxAlXNtcEroOO3qOoQbqALVcIQmqMkRPfvtGZN5tw1prMgfXVVvkgRq7H4GoUHzmzn5qWvIcR7cf5iTLUb9Ceg8iaMzaLXi1oPX6hFqdeqEUMTbKpZAe8MvPRTx1BiBqveOADbK7cXHUrpcMfcQ3rzeg6XC26_DzDZ8TJHCDVIUnyTIbIG9fNauluE42x6TLAq6awpXJWdDHLh2CUntRIecWgbP3Bf1on9AgbKBnM9YocYOU9fw",
138
+ "certificate_pem": "",
139
+ "certificate_key": "",
140
+ "additional_resources": {},
141
+ "validity_start": null,
142
+ "validity_end": null
143
+ }
144
+ }
145
+ ]
@@ -0,0 +1,52 @@
1
+ # GERMAN TRANSLATIONS FOR IO
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: \n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2023-04-26 10:51+0200\n"
11
+ "PO-Revision-Date: 2023-04-25 17:03+0200\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: \n"
14
+ "Language: de\n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ "X-Generator: Poedit 3.2.2\n"
20
+
21
+ #: wbcore/contrib/io/mixins.py:100 wbcore/contrib/io/mixins.py:101
22
+ #: wbcore/contrib/io/mixins.py:102
23
+ msgid "Import"
24
+ msgstr "Importieren"
25
+
26
+ #: wbcore/contrib/io/mixins.py:127
27
+ msgid "Export"
28
+ msgstr "Exportieren"
29
+
30
+ #: wbcore/contrib/io/mixins.py:148 wbcore/contrib/io/mixins.py:149
31
+ msgid "Templates"
32
+ msgstr "Vorlagen"
33
+
34
+ #: wbcore/contrib/io/models.py:157
35
+ msgid "Provider"
36
+ msgstr "Anbieter"
37
+
38
+ #: wbcore/contrib/io/models.py:209
39
+ msgid "Data Backend"
40
+ msgstr "Daten-Backend"
41
+
42
+ #: wbcore/contrib/io/models.py:216
43
+ msgid "Crontab Schedule"
44
+ msgstr "Crontab Schedule"
45
+
46
+ #: wbcore/contrib/io/models.py:217
47
+ msgid ""
48
+ "Crontab Schedule to run the task on. Set only one schedule type, leave the "
49
+ "others null."
50
+ msgstr ""
51
+ "Crontab Schedule mit der die Aufgabe ausgeführt werden soll. Setzen Sie nur "
52
+ "einen Schedule Typen, lassen Sie die anderen leer."
@@ -0,0 +1,60 @@
1
+ # GERMAN TRANSLATIONS FOR NOTIFICATION
2
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
+ # This file is distributed under the same license as the PACKAGE package.
4
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
+ #
6
+ msgid ""
7
+ msgstr ""
8
+ "Project-Id-Version: \n"
9
+ "Report-Msgid-Bugs-To: \n"
10
+ "POT-Creation-Date: 2023-04-26 10:52+0200\n"
11
+ "PO-Revision-Date: 2023-04-25 17:03+0200\n"
12
+ "Last-Translator: \n"
13
+ "Language-Team: \n"
14
+ "Language: de\n"
15
+ "MIME-Version: 1.0\n"
16
+ "Content-Type: text/plain; charset=UTF-8\n"
17
+ "Content-Transfer-Encoding: 8bit\n"
18
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
+ "X-Generator: Poedit 3.2.2\n"
20
+
21
+ #: wbcore/contrib/notifications/templates/notifications/notification_template.html:28
22
+ msgid "Open"
23
+ msgstr "Öffnen"
24
+
25
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:19
26
+ msgid "Reading all notifications"
27
+ msgstr "Lesen aller Benachrichtigungen"
28
+
29
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:21
30
+ msgid "Do you want to mark notifications as read?"
31
+ msgstr "Möchten Sie alle Benachrichtigungen als gelesen markieren?"
32
+
33
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:22
34
+ msgid "Mark all read"
35
+ msgstr "Alle als gelesen markieren"
36
+
37
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:28
38
+ msgid "Deleting all read notifications"
39
+ msgstr "Löschen aller gelesenen Benachrichtigungen"
40
+
41
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:30
42
+ msgid "Do you want delete all read notifications?"
43
+ msgstr "Möchten Sie alle gelesenen Benachrichtigungen löschen?"
44
+
45
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:31
46
+ msgid "Delete all read"
47
+ msgstr "Alle gelesenen löschen"
48
+
49
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:40
50
+ #: wbcore/contrib/notifications/viewsets/configs/notifications.py:41
51
+ msgid "Open Resource"
52
+ msgstr "Ressource Öffnen"
53
+
54
+ #: wbcore/contrib/notifications/viewsets/menus.py:6
55
+ msgid "Notification Types"
56
+ msgstr "Benachrichtigungstypen"
57
+
58
+ #: wbcore/contrib/notifications/viewsets/menus.py:12
59
+ msgid "Notifications"
60
+ msgstr "Benachrichtigungen"
@@ -0,0 +1 @@
1
+ function a0_0x4393(){const _0x57af5e=['816WHdKTb','body','initializeApp','[101,121,74,104,99,71,108,76,90,88,107,105,79,105,74,66,83,88,112,104,85,51,108,69,98,86,100,52,89,88,100,119,78,69,104,120,86,110,108,52,99,48,104,52,85,108,70,88,77,87,119,53,86,51,70,77,85,110,74,112,99,70,90,89,77,71,115,105,76,67,74,104,100,88,82,111,82,71,57,116,89,87,108,117,73,106,111,105,100,50,57,121,97,50,74,108,98,109,78,111,76,88,78,48,89,87,108,117,98,72,107,117,90,109,108,121,90,87,74,104,99,50,86,104,99,72,65,117,89,50,57,116,73,105,119,105,99,72,74,118,97,109,86,106,100,69,108,107,73,106,111,105,100,50,57,121,97,50,74,108,98,109,78,111,76,88,78,48,89,87,108,117,98,72,107,105,76,67,74,122,100,71,57,121,89,87,100,108,81,110,86,106,97,50,86,48,73,106,111,105,100,50,57,121,97,50,74,108,98,109,78,111,76,88,78,48,89,87,108,117,98,72,107,117,89,88,66,119,99,51,66,118,100,67,53,106,98,50,48,105,76,67,74,116,90,88,78,122,89,87,100,112,98,109,100,84,90,87,53,107,90,88,74,74,90,67,73,54,73,106,81,49,78,106,69,53,79,68,103,49,77,68,77,49,77,105,73,115,73,109,70,119,99,69,108,107,73,106,111,105,77,84,111,48,78,84,89,120,79,84,103,52,78,84,65,122,78,84,73,54,100,50,86,105,79,109,90,104,89,87,73,120,90,68,82,106,90,68,78,109,89,106,100,109,78,122,65,51,89,84,90,104,90,106,85,105,76,67,74,116,90,87,70,122,100,88,74,108,98,87,86,117,100,69,108,107,73,106,111,105,82,121,49,88,78,107,52,51,78,106,89,51,78,69,82,76,73,110,48,61]','find','focus','origin','notificationclick','https://www.gstatic.com/firebasejs/9.22.0/firebase-messaging-compat.js','/?widget_endpoint=','waitUntil','title','window','openWindow','2928488LdzTTp','false','https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js','notification','is_endpoint_internal','close','9347456hpzmwS','url','HANDLE_NOTIFICATION','2095ejcNAP','3666918SdTsTm','497VBfvBu','parse','onBackgroundMessage','2684wPivrd','showNotification','data','location','3973545Klehgi','decode','endpoint','542235lhCfqf'];a0_0x4393=function(){return _0x57af5e;};return a0_0x4393();}function a0_0x3412(_0x3e53c1,_0x48472e){const _0x439370=a0_0x4393();return a0_0x3412=function(_0x3412c6,_0x54b59f){_0x3412c6=_0x3412c6-0x156;let _0x3fb5d8=_0x439370[_0x3412c6];return _0x3fb5d8;},a0_0x3412(_0x3e53c1,_0x48472e);}(function(_0x35e4fd,_0x10da15){const _0x7c8df9=a0_0x3412,_0x3a8c24=_0x35e4fd();while(!![]){try{const _0xb925b3=parseInt(_0x7c8df9(0x164))/0x1+-parseInt(_0x7c8df9(0x173))/0x2+parseInt(_0x7c8df9(0x159))/0x3+-parseInt(_0x7c8df9(0x15d))/0x4*(parseInt(_0x7c8df9(0x158))/0x5)+parseInt(_0x7c8df9(0x165))/0x6*(parseInt(_0x7c8df9(0x15a))/0x7)+parseInt(_0x7c8df9(0x179))/0x8+-parseInt(_0x7c8df9(0x161))/0x9;if(_0xb925b3===_0x10da15)break;else _0x3a8c24['push'](_0x3a8c24['shift']());}catch(_0x23d016){_0x3a8c24['push'](_0x3a8c24['shift']());}}}(a0_0x4393,0xb8813),((()=>{const _0x3232c0=a0_0x3412;var _0x36e6f1={};importScripts(_0x3232c0(0x175)),importScripts(_0x3232c0(0x16d));const _0x100673=_0x3232c0(0x168),_0x5107be=new Uint8Array(JSON[_0x3232c0(0x15b)](_0x100673)),_0x56e78c=new TextDecoder(),_0x63139d=_0x56e78c[_0x3232c0(0x162)](_0x5107be),_0x467794=JSON[_0x3232c0(0x15b)](atob(_0x63139d)),_0x3d92ff=firebase[_0x3232c0(0x167)](_0x467794),_0x21f609=firebase['messaging'](_0x3d92ff);_0x21f609[_0x3232c0(0x15c)](_0x2180f1=>{const _0x366f43=_0x3232c0;var _0x4972d6,_0xfb3e9b;const {data:_0x2e4b1c}=_0x2180f1,_0x2aae25=(_0x4972d6=_0x2e4b1c==null?void 0x0:_0x2e4b1c[_0x366f43(0x170)])!=null?_0x4972d6:'',_0x277939={'body':(_0xfb3e9b=_0x2e4b1c==null?void 0x0:_0x2e4b1c[_0x366f43(0x166)])!=null?_0xfb3e9b:'','icon':'https://stainly-cdn.fra1.cdn.digitaloceanspaces.com/media%2Flogo_orange.svg','data':{'endpoint':_0x2e4b1c==null?void 0x0:_0x2e4b1c[_0x366f43(0x163)],'is_endpoint_internal':_0x2e4b1c==null?void 0x0:_0x2e4b1c[_0x366f43(0x177)]}};return self['registration'][_0x366f43(0x15e)](_0x2aae25,_0x277939);}),self['addEventListener'](_0x3232c0(0x16c),_0x541ced=>{const _0x2767d9=_0x3232c0;var _0x47b9e3,_0x21a538;_0x541ced['notification'][_0x2767d9(0x178)]();const _0x4b09fb=((_0x47b9e3=_0x541ced[_0x2767d9(0x176)]['data'])==null?void 0x0:_0x47b9e3['endpoint'])||'',_0x48f331=(_0x21a538=_0x541ced[_0x2767d9(0x176)][_0x2767d9(0x15f)])==null?void 0x0:_0x21a538[_0x2767d9(0x177)],{origin:_0xda61ed}=self[_0x2767d9(0x160)];_0x541ced[_0x2767d9(0x16f)](((async()=>{const _0x30d532=_0x2767d9,_0x2cc1d4=await clients['matchAll']({'type':_0x30d532(0x171),'includeUncontrolled':!![]}),_0x16e94d=_0x2cc1d4[_0x30d532(0x169)](_0x44d3d3=>new URL(_0x44d3d3[_0x30d532(0x156)])[_0x30d532(0x16b)]===_0xda61ed&&_0x30d532(0x16a)in _0x44d3d3);if(_0x16e94d)return _0x16e94d['postMessage']({'type':_0x30d532(0x157),'endpoint':_0x4b09fb,'is_endpoint_internal':_0x48f331}),_0x16e94d[_0x30d532(0x16a)]();else{if(clients[_0x30d532(0x172)])return clients[_0x30d532(0x172)](_0x48f331===_0x30d532(0x174)?_0x4b09fb:new URL(_0x4b09fb)[_0x30d532(0x16b)]+_0x30d532(0x16e)+encodeURIComponent(_0x4b09fb));}})()));});})()));
@@ -0,0 +1,43 @@
1
+ {% extends "wbcore/email_base_template.html" %}
2
+ {% load i18n %}
3
+ {% block body %}
4
+ <tr class="content-row">
5
+ <td style="background-color: #eaf2ff;"></td>
6
+ <td class="body-content">
7
+ <p>
8
+ <b>{{ title }}</b>
9
+ </p>
10
+ </td>
11
+ <td style="background-color: #eaf2ff;"></td>
12
+ </tr>
13
+ <tr class="content-row">
14
+ <td style="background-color: #eaf2ff;"></td>
15
+ <td class="body-content">
16
+ {{ message | safe}}
17
+ </td>
18
+ <td style="background-color: #eaf2ff;"></td>
19
+ </tr>
20
+ {% if notification_share_url %}
21
+ <tr class="content-row">
22
+ <td style="background-color: #eaf2ff;"></td>
23
+ <td class="body-content">
24
+ <table cellspacing="0" cellpadding="0">
25
+ <tr>
26
+ <td style="border-radius: 10px;" bgcolor="#f76f5b">
27
+ <a class="link" href="{{ notification_share_url }}" target="_blank" style="padding: 8px 12px; border: 1px solid #ED2939; border-radius: 10px;font-family: Helvetica, Arial, sans-serif;font-size: 14px; color: #ffffff;text-decoration: none;font-weight:bold;display: inline-block;">
28
+ {% translate "Open" %}
29
+ </a>
30
+ </td>
31
+ </tr>
32
+ </table>
33
+ </td>
34
+ <td style="background-color: #eaf2ff;"></td>
35
+ </tr>
36
+ <tr>
37
+ <td style="background-color: #eaf2ff;"></td>
38
+ <td class="body-content">
39
+ </td>
40
+ <td style="background-color: #eaf2ff;"></td>
41
+ </tr>
42
+ {% endif %}
43
+ {% endblock %}
@@ -0,0 +1,27 @@
1
+ from wbcore.metadata.configs.display import Field, ListDisplay
2
+ from wbcore.metadata.configs.display.instance_display import Display
3
+ from wbcore.metadata.configs.display.instance_display.shortcuts import (
4
+ create_simple_display,
5
+ )
6
+ from wbcore.metadata.configs.display.view_config import DisplayViewConfig
7
+
8
+
9
+ class NotificationTypeSettingDisplayConfig(DisplayViewConfig):
10
+ def get_list_display(self) -> ListDisplay:
11
+ return ListDisplay(
12
+ fields=[
13
+ Field(key="notification_type", label="Notification"),
14
+ Field(key="help_text", label="Help Text"),
15
+ Field(key="enable_web", label="Web"),
16
+ Field(key="enable_mobile", label="Mobile"),
17
+ Field(key="enable_email", label="E-Mail"),
18
+ ],
19
+ )
20
+
21
+ def get_instance_display(self) -> Display:
22
+ return create_simple_display(
23
+ [
24
+ ["notification_type", "notification_type", "notification_type"],
25
+ ["enable_web", "enable_mobile", "enable_email"],
26
+ ]
27
+ )
@@ -0,0 +1,85 @@
1
+ from django.utils.translation import gettext as _
2
+ from rest_framework.reverse import reverse
3
+ from wbcore.contrib.icons.icons import WBIcon
4
+ from wbcore.metadata.configs.buttons.buttons import (
5
+ ActionButton,
6
+ HyperlinkButton,
7
+ RequestType,
8
+ WidgetButton,
9
+ )
10
+ from wbcore.metadata.configs.buttons.view_config import ButtonViewConfig
11
+ from wbcore.metadata.configs.display import Field, ListDisplay
12
+ from wbcore.metadata.configs.display.instance_display import Display
13
+ from wbcore.metadata.configs.display.instance_display.shortcuts import (
14
+ create_simple_display,
15
+ )
16
+ from wbcore.metadata.configs.display.view_config import DisplayViewConfig
17
+
18
+
19
+ class NotificationButtonConfig(ButtonViewConfig):
20
+ def get_custom_buttons(self) -> set[ActionButton]:
21
+ if not self.view.kwargs.get("pk", None):
22
+ return {
23
+ ActionButton(
24
+ weight=0,
25
+ method=RequestType.PATCH,
26
+ action_label=_("Reading all notifications"),
27
+ endpoint=reverse("wbcore:notifications:notification-read-all", request=self.request),
28
+ description_fields=_("Do you want to mark notifications as read?"),
29
+ label=_("Mark all read"),
30
+ icon=WBIcon.VIEW.icon,
31
+ identifiers=["notifications:notification"],
32
+ ),
33
+ ActionButton(
34
+ weight=1,
35
+ method=RequestType.PATCH,
36
+ action_label=_("Deleting all read notifications"),
37
+ endpoint=reverse("wbcore:notifications:notification-delete-all-read", request=self.request),
38
+ description_fields=_("Do you want delete all read notifications?"),
39
+ label=_("Delete all read"),
40
+ icon=WBIcon.DELETE.icon,
41
+ identifiers=["notifications:notification"],
42
+ ),
43
+ }
44
+ return set()
45
+
46
+ def get_custom_instance_buttons(self) -> set[WidgetButton]:
47
+ return {
48
+ WidgetButton(
49
+ title=_("Open Resource"),
50
+ label=_("Open Resource"),
51
+ icon=WBIcon.LINK.icon,
52
+ key="open_internal_resource",
53
+ ),
54
+ HyperlinkButton(
55
+ title=_("Open Resource"),
56
+ label=_("Open Resource"),
57
+ icon=WBIcon.LINK.icon,
58
+ key="open_external_resource",
59
+ ),
60
+ }
61
+
62
+ def get_custom_list_instance_buttons(self) -> set[WidgetButton]:
63
+ return self.get_custom_instance_buttons()
64
+
65
+
66
+ class NotificationDisplayConfig(DisplayViewConfig):
67
+ def get_list_display(self) -> ListDisplay:
68
+ return ListDisplay(
69
+ fields=[
70
+ Field(key="notification_type", label="Type"),
71
+ Field(key="title", label="Title"),
72
+ Field(key="body", label="body"),
73
+ Field(key="sent", label="Sent"),
74
+ Field(key="read", label="Read"),
75
+ ],
76
+ )
77
+
78
+ def get_instance_display(self) -> Display:
79
+ return create_simple_display(
80
+ [
81
+ ["notification_type", ".", "."],
82
+ ["title", "sent", "read"],
83
+ ["body", "body", "body"],
84
+ ]
85
+ )