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.
Files changed (321) hide show
  1. wbcore/cache/decorators.py +5 -3
  2. wbcore/cache/registry.py +14 -7
  3. wbcore/configs/__init__.py +1 -0
  4. wbcore/configs/configs.py +5 -0
  5. wbcore/configs/decorators.py +1 -1
  6. wbcore/configurations/configurations/apps.py +3 -2
  7. wbcore/configurations/configurations/authentication.py +1 -1
  8. wbcore/configurations/configurations/base.py +1 -1
  9. wbcore/configurations/configurations/cache.py +1 -1
  10. wbcore/configurations/configurations/i18nl10n.py +2 -1
  11. wbcore/configurations/configurations/maintenance.py +1 -1
  12. wbcore/configurations/configurations/media.py +1 -1
  13. wbcore/configurations/configurations/middleware.py +1 -1
  14. wbcore/configurations/configurations/rest_framework.py +1 -1
  15. wbcore/configurations/configurations/static.py +3 -3
  16. wbcore/configurations/configurations/wbcore.py +1 -1
  17. wbcore/content_type/serializers.py +13 -5
  18. wbcore/content_type/utils.py +3 -3
  19. wbcore/content_type/viewsets.py +2 -2
  20. wbcore/contrib/agenda/filters/calendar_item.py +5 -4
  21. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +145 -52
  22. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
  23. wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
  24. wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
  25. wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
  26. wbcore/contrib/agenda/viewsets/menu/calendar_items.py +0 -6
  27. wbcore/contrib/ai/exceptions.py +5 -5
  28. wbcore/contrib/ai/llm/config.py +76 -27
  29. wbcore/contrib/ai/llm/mixins.py +5 -8
  30. wbcore/contrib/ai/llm/utils.py +50 -26
  31. wbcore/contrib/authentication/admin.py +2 -2
  32. wbcore/contrib/authentication/factories/__init__.py +8 -1
  33. wbcore/contrib/authentication/factories/users.py +19 -0
  34. wbcore/contrib/authentication/filters.py +1 -2
  35. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +209 -187
  36. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
  37. wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
  38. wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
  39. wbcore/contrib/authentication/models/users.py +3 -3
  40. wbcore/contrib/authentication/models/users_activities.py +1 -1
  41. wbcore/contrib/authentication/serializers/users.py +2 -2
  42. wbcore/contrib/authentication/tests/test_tokens.py +3 -3
  43. wbcore/contrib/authentication/tests/test_users.py +0 -1
  44. wbcore/contrib/authentication/urls.py +0 -4
  45. wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +2 -11
  46. wbcore/contrib/authentication/viewsets/endpoints/users.py +0 -3
  47. wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
  48. wbcore/contrib/authentication/viewsets/users.py +6 -4
  49. wbcore/contrib/color/models.py +2 -1
  50. wbcore/contrib/currency/factories.py +1 -1
  51. wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
  52. wbcore/contrib/currency/models.py +30 -8
  53. wbcore/contrib/currency/serializers.py +5 -1
  54. wbcore/contrib/currency/tests/test_serializers.py +7 -3
  55. wbcore/contrib/currency/tests/test_viewsets.py +1 -1
  56. wbcore/contrib/currency/viewsets/currency.py +2 -2
  57. wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +0 -9
  58. wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +1 -2
  59. wbcore/contrib/dataloader/utils.py +2 -2
  60. wbcore/contrib/directory/factories/__init__.py +1 -1
  61. wbcore/contrib/directory/factories/entries.py +2 -1
  62. wbcore/contrib/directory/filters/entries.py +9 -0
  63. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +728 -714
  64. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
  65. wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
  66. wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
  67. wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
  68. wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
  69. wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
  70. wbcore/contrib/directory/models/contacts.py +2 -2
  71. wbcore/contrib/directory/models/entries.py +31 -5
  72. wbcore/contrib/directory/models/relationships.py +31 -35
  73. wbcore/contrib/directory/permissions.py +6 -0
  74. wbcore/contrib/directory/serializers/companies.py +16 -8
  75. wbcore/contrib/directory/serializers/contacts.py +8 -8
  76. wbcore/contrib/directory/serializers/entries.py +26 -15
  77. wbcore/contrib/directory/serializers/entry_representations.py +4 -2
  78. wbcore/contrib/directory/serializers/persons.py +12 -10
  79. wbcore/contrib/directory/serializers/relationships.py +2 -2
  80. wbcore/contrib/directory/tests/conftest.py +2 -0
  81. wbcore/contrib/directory/tests/disable_signals.py +11 -1
  82. wbcore/contrib/directory/tests/signals.py +2 -2
  83. wbcore/contrib/directory/tests/test_models.py +88 -66
  84. wbcore/contrib/directory/tests/test_serializers.py +1 -1
  85. wbcore/contrib/directory/tests/test_viewsets.py +8 -8
  86. wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
  87. wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
  88. wbcore/contrib/directory/viewsets/contacts.py +6 -6
  89. wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
  90. wbcore/contrib/directory/viewsets/display/contacts.py +1 -14
  91. wbcore/contrib/directory/viewsets/display/entries.py +68 -38
  92. wbcore/contrib/directory/viewsets/display/relationships.py +26 -50
  93. wbcore/contrib/directory/viewsets/endpoints/relationships.py +1 -26
  94. wbcore/contrib/directory/viewsets/entries.py +8 -6
  95. wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
  96. wbcore/contrib/directory/viewsets/relationships.py +16 -2
  97. wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
  98. wbcore/contrib/documents/filters.py +0 -2
  99. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +103 -94
  100. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
  101. wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
  102. wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
  103. wbcore/contrib/documents/tests/test_models.py +32 -28
  104. wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +2 -21
  105. wbcore/contrib/dynamic_preferences/types.py +108 -0
  106. wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
  107. wbcore/contrib/example_app/filters/event.py +3 -1
  108. wbcore/contrib/example_app/filters/match.py +1 -1
  109. wbcore/contrib/example_app/models.py +91 -22
  110. wbcore/contrib/example_app/serializers/person_team.py +4 -4
  111. wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
  112. wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
  113. wbcore/contrib/example_app/tests/test_models/test_match.py +17 -7
  114. wbcore/contrib/example_app/urls.py +2 -0
  115. wbcore/contrib/example_app/views.py +7 -0
  116. wbcore/contrib/example_app/viewsets/displays/team.py +23 -4
  117. wbcore/contrib/example_app/viewsets/menu/menus.py +1 -1
  118. wbcore/contrib/example_app/viewsets/menus.py +1 -1
  119. wbcore/contrib/geography/tests/conftest.py +14 -0
  120. wbcore/contrib/geography/tests/test_models.py +23 -8
  121. wbcore/contrib/geography/tests/test_viewsets.py +96 -2
  122. wbcore/contrib/guardian/tests/test_model_mixins.py +3 -4
  123. wbcore/contrib/guardian/tests/test_tasks.py +9 -9
  124. wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
  125. wbcore/contrib/guardian/viewsets/configs/__init__.py +1 -1
  126. wbcore/contrib/guardian/viewsets/configs/buttons.py +9 -0
  127. wbcore/contrib/guardian/viewsets/configs/endpoints.py +7 -0
  128. wbcore/contrib/guardian/viewsets/viewsets.py +2 -0
  129. wbcore/contrib/i18n/__init__.py +2 -0
  130. wbcore/contrib/i18n/buttons.py +33 -0
  131. wbcore/contrib/i18n/serializers/__init__.py +0 -0
  132. wbcore/contrib/i18n/serializers/fields.py +20 -0
  133. wbcore/contrib/i18n/serializers/mixins.py +13 -0
  134. wbcore/contrib/i18n/tests/conftest.py +11 -0
  135. wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
  136. wbcore/contrib/i18n/translation.py +140 -0
  137. wbcore/contrib/i18n/viewsets.py +36 -0
  138. wbcore/contrib/icons/backends/default.py +1 -0
  139. wbcore/contrib/icons/backends/material.py +1 -0
  140. wbcore/contrib/icons/icons.py +5 -8
  141. wbcore/contrib/io/admin.py +1 -0
  142. wbcore/contrib/io/backends/mail.py +3 -2
  143. wbcore/contrib/io/backends/utils.py +14 -17
  144. wbcore/contrib/io/exceptions.py +8 -0
  145. wbcore/contrib/io/factories.py +1 -1
  146. wbcore/contrib/io/import_export/backends/mail.py +1 -0
  147. wbcore/contrib/io/import_export/backends/sftp.py +29 -20
  148. wbcore/contrib/io/import_export/backends/stream.py +2 -2
  149. wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
  150. wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
  151. wbcore/contrib/io/import_export/parsers/resources.py +50 -0
  152. wbcore/contrib/io/imports.py +33 -25
  153. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +114 -22
  154. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
  155. wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
  156. wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
  157. wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
  158. wbcore/contrib/io/models.py +65 -45
  159. wbcore/contrib/io/resources.py +0 -6
  160. wbcore/contrib/io/serializers.py +2 -2
  161. wbcore/contrib/io/signals.py +4 -0
  162. wbcore/contrib/io/tests/test_backends.py +19 -13
  163. wbcore/contrib/io/tests/test_exports.py +1 -1
  164. wbcore/contrib/io/tests/test_imports.py +1 -1
  165. wbcore/contrib/io/tests/test_models.py +47 -14
  166. wbcore/contrib/io/tests/test_viewsets.py +271 -0
  167. wbcore/contrib/io/viewset_mixins.py +41 -54
  168. wbcore/contrib/notifications/admin.py +1 -0
  169. wbcore/contrib/notifications/apps.py +2 -1
  170. wbcore/contrib/notifications/backends/abstract_backend.py +2 -4
  171. wbcore/contrib/notifications/backends/firebase/backends.py +5 -2
  172. wbcore/contrib/notifications/dispatch.py +18 -7
  173. wbcore/contrib/notifications/factories/notification_types.py +1 -0
  174. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +25 -19
  175. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
  176. wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
  177. wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
  178. wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
  179. wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
  180. wbcore/contrib/notifications/models/notification_types.py +67 -24
  181. wbcore/contrib/notifications/serializers/notification_types.py +16 -1
  182. wbcore/contrib/notifications/tests/test_models/test_tokens.py +8 -0
  183. wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +5 -0
  184. wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +3 -5
  185. wbcore/contrib/notifications/utils.py +3 -2
  186. wbcore/contrib/notifications/viewsets/configs/notification_types.py +28 -6
  187. wbcore/contrib/notifications/viewsets/menus.py +1 -1
  188. wbcore/contrib/notifications/viewsets/notification_types.py +12 -2
  189. wbcore/contrib/pandas/fields.py +38 -10
  190. wbcore/contrib/pandas/filters.py +4 -1
  191. wbcore/contrib/pandas/filterset.py +8 -7
  192. wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +2 -7
  193. wbcore/contrib/pandas/utils.py +1 -1
  194. wbcore/contrib/pandas/views.py +14 -13
  195. wbcore/contrib/tags/models/tags.py +4 -1
  196. wbcore/contrib/workflow/factories/display.py +2 -2
  197. wbcore/contrib/workflow/factories/transition.py +16 -15
  198. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +457 -566
  199. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
  200. wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
  201. wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
  202. wbcore/contrib/workflow/models/data.py +7 -4
  203. wbcore/contrib/workflow/models/process.py +2 -2
  204. wbcore/contrib/workflow/models/step.py +57 -15
  205. wbcore/contrib/workflow/serializers/data.py +8 -8
  206. wbcore/contrib/workflow/serializers/process.py +3 -2
  207. wbcore/contrib/workflow/tests/conftest.py +224 -0
  208. wbcore/contrib/workflow/tests/test_dispatch.py +82 -77
  209. wbcore/contrib/workflow/tests/test_displays.py +10 -88
  210. wbcore/contrib/workflow/tests/test_filters.py +57 -40
  211. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +71 -68
  212. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +78 -38
  213. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +152 -90
  214. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +100 -110
  215. wbcore/contrib/workflow/tests/test_models/step/test_step.py +168 -33
  216. wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
  217. wbcore/contrib/workflow/tests/test_models/test_workflow.py +3 -3
  218. wbcore/contrib/workflow/tests/test_serializers.py +172 -150
  219. wbcore/contrib/workflow/tests/test_viewsets.py +264 -323
  220. wbcore/contrib/workflow/tests/test_workflow_assignees.py +215 -205
  221. wbcore/contrib/workflow/viewsets/process.py +4 -1
  222. wbcore/contrib/workflow/workflows/assignees.py +12 -7
  223. wbcore/dynamic_preferences_registry.py +102 -0
  224. wbcore/enums.py +2 -51
  225. wbcore/filters/fields/choices.py +4 -6
  226. wbcore/filters/fields/content_type.py +15 -4
  227. wbcore/filters/fields/datetime.py +50 -25
  228. wbcore/filters/fields/models.py +18 -9
  229. wbcore/filters/fields/numbers.py +9 -8
  230. wbcore/filters/filterset.py +27 -6
  231. wbcore/filters/mixins.py +41 -42
  232. wbcore/forms.py +6 -6
  233. wbcore/fsm/markdown_extensions.py +1 -1
  234. wbcore/fsm/mixins.py +20 -6
  235. wbcore/locale/de/LC_MESSAGES/django.po +982 -397
  236. wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
  237. wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
  238. wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
  239. wbcore/markdown/models.py +8 -5
  240. wbcore/markdown/views.py +1 -1
  241. wbcore/menus/menus.py +2 -2
  242. wbcore/metadata/configs/buttons/bases.py +10 -7
  243. wbcore/metadata/configs/buttons/buttons.py +2 -1
  244. wbcore/metadata/configs/buttons/enums.py +50 -0
  245. wbcore/metadata/configs/buttons/view_config.py +13 -46
  246. wbcore/metadata/configs/display/display.py +2 -2
  247. wbcore/metadata/configs/display/formatting.py +6 -9
  248. wbcore/metadata/configs/display/instance_display/display.py +5 -2
  249. wbcore/metadata/configs/display/instance_display/pages.py +1 -1
  250. wbcore/metadata/configs/display/instance_display/shortcuts.py +1 -1
  251. wbcore/metadata/configs/display/list_display.py +54 -40
  252. wbcore/metadata/configs/display/models.py +6 -0
  253. wbcore/metadata/configs/display/view_config.py +11 -9
  254. wbcore/metadata/configs/endpoints.py +11 -4
  255. wbcore/metadata/configs/fields.py +6 -1
  256. wbcore/metadata/configs/filter_fields.py +12 -13
  257. wbcore/metadata/configs/identifiers.py +3 -1
  258. wbcore/metadata/tests/test_buttons.py +13 -16
  259. wbcore/models/fields.py +2 -2
  260. wbcore/pagination.py +1 -2
  261. wbcore/permissions/permissions.py +2 -2
  262. wbcore/permissions/utils.py +2 -2
  263. wbcore/release_notes/display.py +2 -8
  264. wbcore/release_notes/serializers.py +2 -9
  265. wbcore/release_notes/viewsets.py +8 -2
  266. wbcore/reversion/viewsets/titles.py +4 -3
  267. wbcore/serializers/__init__.py +2 -0
  268. wbcore/serializers/fields/__init__.py +2 -1
  269. wbcore/serializers/fields/boolean.py +1 -1
  270. wbcore/serializers/fields/choice.py +28 -4
  271. wbcore/serializers/fields/datetime.py +45 -36
  272. wbcore/serializers/fields/fields.py +1 -1
  273. wbcore/serializers/fields/fsm.py +1 -1
  274. wbcore/serializers/fields/list.py +2 -5
  275. wbcore/serializers/fields/mixins.py +24 -11
  276. wbcore/serializers/fields/number.py +6 -23
  277. wbcore/serializers/fields/other.py +2 -10
  278. wbcore/serializers/fields/related.py +4 -6
  279. wbcore/serializers/fields/text.py +1 -1
  280. wbcore/serializers/fields/types.py +2 -0
  281. wbcore/serializers/serializers.py +12 -3
  282. wbcore/signals/__init__.py +1 -0
  283. wbcore/signals/clone.py +4 -0
  284. wbcore/signals/models.py +2 -6
  285. wbcore/tasks.py +2 -2
  286. wbcore/templates/wbcore/email_base_template.html +3 -3
  287. wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
  288. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
  289. wbcore/test/mixins.py +52 -102
  290. wbcore/test/tests.py +6 -9
  291. wbcore/test/utils.py +3 -4
  292. wbcore/tests/e2e/test_e2e.py +2 -2
  293. wbcore/tests/test_cache/test_decorators.py +4 -7
  294. wbcore/tests/test_configs.py +2 -5
  295. wbcore/tests/test_enums.py +2 -1
  296. wbcore/tests/test_fields/test_choice_fields.py +9 -1
  297. wbcore/tests/test_fields/test_number_fields.py +7 -15
  298. wbcore/tests/test_fields/test_other_fields.py +1 -2
  299. wbcore/tests/test_filters/test_mixins.py +35 -35
  300. wbcore/tests/test_list_display.py +0 -2
  301. wbcore/tests/test_models/test_mixins.py +1 -1
  302. wbcore/tests/test_utils/test_date.py +1 -1
  303. wbcore/tests/test_utils/test_date_builder.py +25 -1
  304. wbcore/tests/test_utils/test_primary.py +1 -1
  305. wbcore/urls.py +4 -0
  306. wbcore/utils/date.py +18 -2
  307. wbcore/utils/figures.py +2 -2
  308. wbcore/utils/models.py +21 -4
  309. wbcore/utils/reportlab.py +7 -0
  310. wbcore/utils/rrules.py +3 -1
  311. wbcore/utils/string_loader.py +1 -1
  312. wbcore/utils/strings.py +3 -3
  313. wbcore/utils/views.py +8 -3
  314. wbcore/viewsets/mixins.py +9 -4
  315. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/METADATA +9 -5
  316. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/RECORD +317 -271
  317. wbcore/contrib/geography/tests/test_serializers.py +0 -7
  318. wbcore/contrib/geography/tests/tests.py +0 -13
  319. wbcore/contrib/io/tests/tests.py +0 -19
  320. wbcore/contrib/workflow/tests/tests.py +0 -25
  321. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/WHEEL +0 -0
@@ -1,5 +1,7 @@
1
1
  from typing import Callable
2
2
 
3
+ from django.conf import settings
4
+
3
5
  from ..signals.instance_buttons import add_extra_button
4
6
  from .buttons import add_clear_cache_button
5
7
  from .registry import periodic_cache_registry
@@ -13,9 +15,9 @@ def cache_table(
13
15
  periodic_caching_get_parameters: list[dict[str, str]] | Callable | None = None,
14
16
  ):
15
17
  def _decorator(pandas_view_class):
16
- setattr(pandas_view_class, "CACHE_ENABLED", True)
17
- setattr(pandas_view_class, "CACHE_TIMEOUT", timeout)
18
- setattr(pandas_view_class, "CACHE_KEY_PREFIX", key_prefix)
18
+ pandas_view_class.CACHE_ENABLED = not settings.DEBUG
19
+ pandas_view_class.CACHE_TIMEOUT = timeout
20
+ pandas_view_class.CACHE_KEY_PREFIX = key_prefix
19
21
  add_extra_button.connect(add_clear_cache_button, sender=pandas_view_class, weak=False)
20
22
 
21
23
  if periodic_caching:
wbcore/cache/registry.py CHANGED
@@ -3,6 +3,8 @@ from contextlib import suppress
3
3
  from dataclasses import dataclass
4
4
  from typing import Callable, Generator
5
5
 
6
+ from django.conf import settings
7
+ from django.contrib.sites.models import Site
6
8
  from django.core.cache import cache
7
9
  from dynamic_preferences.models import global_preferences_registry
8
10
  from rest_framework.request import Request
@@ -22,7 +24,7 @@ class CachedClass:
22
24
  view_kwargs: list[dict[str, str]] | Callable | None = None
23
25
  get_parameters: list[dict[str, str]] | Callable | None = None
24
26
 
25
- def _get_requests(self) -> Generator[Request, None, None]:
27
+ def _get_requests(self, **kwargs) -> Generator[Request, None, None]:
26
28
  """
27
29
  Given the stored list of GET parameters, returns a list of instantiated request with the system user as request.user
28
30
 
@@ -32,10 +34,14 @@ class CachedClass:
32
34
  system_user_email = global_preferences_registry.manager()["wbcore__system_user_email"]
33
35
  get_parameters = self.get_parameters if self.get_parameters else [{}]
34
36
  if callable(self.get_parameters):
35
- get_parameters = get_parameters()
37
+ get_parameters = get_parameters(**kwargs)
36
38
 
37
39
  for get_parameter in get_parameters:
38
- request = APIRequestFactory().get("", data=get_parameter)
40
+ # we need to inject the proper host and sheme otherwise the request factory default to http://testserver
41
+ meta = {"HTTP_HOST": Site.objects.get_current().domain}
42
+ if settings.SECURE_PROXY_SSL_HEADER:
43
+ meta["HTTP_X_FORWARDED_PROTO"] = "https"
44
+ request = APIRequestFactory().get("", data=get_parameter, **meta)
39
45
  user = User.objects.get(email=system_user_email)
40
46
  force_authenticate(request, user=user)
41
47
  request.user = user
@@ -52,11 +58,12 @@ class CachedClass:
52
58
  if callable(self.view_kwargs):
53
59
  view_kwargs = view_kwargs()
54
60
  res = []
55
- for request in self._get_requests():
56
- for kwargs in view_kwargs:
61
+ for kwargs in view_kwargs:
62
+ for request in self._get_requests(**kwargs):
57
63
  with suppress(RequiredFilterMissing):
58
- view = self.view_class(request=request, kwargs=kwargs)
59
- setattr(request, "parser_context", {"request": request, "view": view, "kwargs": kwargs})
64
+ view = self.view_class()
65
+ view.setup(request, **kwargs)
66
+ request.parser_context = {"request": request, "view": view, "kwargs": kwargs}
60
67
  cache_key = view._get_cache_key()
61
68
  cache.delete(cache_key)
62
69
  res.append(view._get_dataframe())
@@ -8,4 +8,5 @@ from .configs import (
8
8
  share_config,
9
9
  beta_button,
10
10
  frontend_version,
11
+ user_preferences
11
12
  )
wbcore/configs/configs.py CHANGED
@@ -50,3 +50,8 @@ def beta_button(request: Request) -> tuple[str, dict] | None:
50
50
  @register_config
51
51
  def frontend_version(request: Request) -> tuple[str, str | None]:
52
52
  return "frontend_version", getattr(settings, "FRONTEND_VERSION", None)
53
+
54
+
55
+ @register_config
56
+ def user_preferences(request: Request) -> tuple[str, dict] | None:
57
+ return "user_preferences", reverse("wbcore:user_preferences-list", request=request)
@@ -7,5 +7,5 @@ def register_config(func: Callable) -> Callable:
7
7
  of all configs. This function should only be used in a module called configs, otherwise the auto-discover
8
8
  functionality won't work.
9
9
  """
10
- setattr(func, "_is_config", True)
10
+ func._is_config = True
11
11
  return func
@@ -31,6 +31,7 @@ class Apps:
31
31
  "wbcore.contrib.color",
32
32
  "wbcore.contrib.guardian",
33
33
  "django_celery_beat",
34
+ "modeltrans",
34
35
  "maintenance_mode",
35
36
  ]
36
37
 
@@ -38,13 +39,13 @@ class Apps:
38
39
  return getattr(self, "ADDITIONAL_APPS", []) + getattr(self, "WB_ENDPOINTS", [])
39
40
 
40
41
  @property
41
- def INSTALLED_APPS(self):
42
+ def INSTALLED_APPS(self): # noqa
42
43
  return self._BASE_APPS + self._get_additional_and_wb_apps()
43
44
 
44
45
 
45
46
  class DevApps(Apps):
46
47
  @property
47
- def INSTALLED_APPS(self):
48
+ def INSTALLED_APPS(self): # noqa
48
49
  apps = self._BASE_APPS
49
50
 
50
51
  if self.DEBUG:
@@ -24,7 +24,7 @@ class Authentication:
24
24
  JWT_COOKIE_KEY = values.Value("JWT-access", environ_prefix=None)
25
25
 
26
26
  @property
27
- def SIMPLE_JWT(self):
27
+ def SIMPLE_JWT(self): # noqa
28
28
  return {
29
29
  "ACCESS_TOKEN_LIFETIME": timedelta(seconds=self.JWT_ACCESS_TOKEN_LIFETIME),
30
30
  "REFRESH_TOKEN_LIFETIME": timedelta(seconds=self.JWT_REFRESH_TOKEN_LIFETIME),
@@ -9,7 +9,7 @@ class Base:
9
9
  SITE_ID = values.IntegerValue(1, environ_prefix=None)
10
10
 
11
11
  @property
12
- def PROJECT_NAME(self):
12
+ def PROJECT_NAME(self): # noqa
13
13
  if settings_module := os.environ.get("DJANGO_SETTINGS_MODULE", None):
14
14
  return settings_module.split(".")[0]
15
15
  return None
@@ -8,7 +8,7 @@ class Cache:
8
8
  ) # The default (10 days) timeout in seconds
9
9
 
10
10
  @property
11
- def CACHES(self):
11
+ def CACHES(self): # noqa
12
12
  if self.CACHE_REDIS_URL:
13
13
  return {
14
14
  "default": {
@@ -2,9 +2,10 @@ from configurations import values
2
2
 
3
3
 
4
4
  class I18NL10N:
5
+ MODELTRANS_AVAILABLE_LANGUAGES = ["en", "de", "fr"]
5
6
  TIME_ZONE = values.Value("Europe/Berlin", environ_prefix=None)
6
7
  LANGUAGE_CODE = values.Value("en-us", environ_prefix=None)
7
8
  USE_TZ = values.BooleanValue(True, environ_prefix=None)
8
9
  USE_I18N = values.BooleanValue(
9
- False, environ_prefix=None
10
+ True, environ_prefix=None
10
11
  ) # Setting to True lead to a big performance hit when resolver needs to translate url
@@ -6,7 +6,7 @@ class Maintenance:
6
6
  MAINTENANCE_MODE_STR: str | None = values.Value("False", environ_prefix=None)
7
7
 
8
8
  # We allow maintenance mode to be either True, False or None. In case of None, the specified Backend will take over.
9
- def MAINTENANCE_MODE(self) -> bool | None:
9
+ def MAINTENANCE_MODE(self) -> bool | None: # noqa
10
10
  if value := self.MAINTENANCE_MODE_STR:
11
11
  normalized_value = value.strip().lower()
12
12
  if normalized_value in values.BooleanValue.true_values:
@@ -7,7 +7,7 @@ class Media:
7
7
 
8
8
  class LocalMedia(Media):
9
9
  @property
10
- def MEDIA_ROOT(self):
10
+ def MEDIA_ROOT(self): # noqa
11
11
  return self.BASE_DIR.joinpath("mediafiles")
12
12
 
13
13
 
@@ -14,7 +14,7 @@ class Middleware:
14
14
 
15
15
  class DevMiddleware:
16
16
  @property
17
- def MIDDLEWARE(self):
17
+ def MIDDLEWARE(self): # noqa
18
18
  middleware = []
19
19
  middleware_list = Middleware.MIDDLEWARE.copy()
20
20
  if self.DEBUG:
@@ -6,7 +6,7 @@ class Restframework:
6
6
  REST_FRAMEWORK_THROTTLE_PERIOD = values.Value("hour", environ_prefix=None)
7
7
  REST_FRAMEWORK_USER_THROTTLE_RATES = values.IntegerValue(5000, environ_prefix=None)
8
8
 
9
- def REST_FRAMEWORK(self):
9
+ def REST_FRAMEWORK(self): # noqa
10
10
  rest_framework = {
11
11
  "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
12
12
  "PAGE_SIZE": 25,
@@ -9,11 +9,11 @@ class LocalStaticfiles(Staticfiles):
9
9
  },
10
10
  "staticfiles": {
11
11
  "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
12
- }
12
+ },
13
13
  }
14
14
 
15
15
  @property
16
- def STATIC_ROOT(self):
16
+ def STATIC_ROOT(self): # noqa
17
17
  return self.BASE_DIR.joinpath("staticfiles")
18
18
 
19
19
 
@@ -24,5 +24,5 @@ class S3Staticfiles(Staticfiles):
24
24
  },
25
25
  "staticfiles": {
26
26
  "BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
27
- }
27
+ },
28
28
  }
@@ -46,7 +46,7 @@ class WBCore:
46
46
  MESSAGE_STORAGE = "wbcore.messages.route_message_storage"
47
47
 
48
48
  @property
49
- def FRONTEND_CONTEXT(self):
49
+ def FRONTEND_CONTEXT(self): # noqa
50
50
  base_url = f"{self.CDN_BASE_ENDPOINT_URL}/{self.FRONTEND_VERSION}/"
51
51
  return {
52
52
  "TITLE": "Workbench",
@@ -1,11 +1,15 @@
1
1
  import operator
2
+ from contextlib import suppress
2
3
  from functools import reduce
3
4
 
4
5
  from django.contrib.contenttypes.models import ContentType
6
+ from django.core.exceptions import ObjectDoesNotExist
5
7
  from django.db import models
6
8
  from django.db.models import Q
9
+ from django.urls import NoReverseMatch, Resolver404
7
10
 
8
11
  from wbcore import serializers
12
+ from wbcore.serializers import HyperlinkField
9
13
 
10
14
 
11
15
  class ContentTypeRepresentationSerializer(serializers.RepresentationSerializer):
@@ -50,7 +54,7 @@ class ContentTypeRepresentationSerializer(serializers.RepresentationSerializer):
50
54
  fields = ("id", "app_label", "model", "model_title")
51
55
 
52
56
 
53
- class GenericModel(models.Model):
57
+ class GenericModel(models.Model): # noqa
54
58
  id = models.IntegerField(primary_key=True)
55
59
  label = models.CharField(max_length=256)
56
60
 
@@ -73,12 +77,16 @@ class DynamicObjectIDRepresentationSerializer(serializers.RepresentationSerializ
73
77
  def to_representation(self, value):
74
78
  representation = super().to_representation(value)
75
79
  representation["id"] = getattr(value, "pk", value)
76
- try:
80
+ obj = None
81
+ with suppress(ObjectDoesNotExist):
77
82
  if content_type := getattr(self.parent.instance, self.content_type_field_name, None):
78
83
  obj = content_type.get_object_for_this_type(id=value)
79
- representation["label"] = str(obj)
80
- except Exception:
81
- representation["label"] = str(representation["id"])
84
+ if obj:
85
+ representation["label"] = str(obj)
86
+ with suppress(AttributeError, NoReverseMatch, Resolver404):
87
+ detail_field = HyperlinkField(reverse_name=obj.get_endpoint_basename() + "-detail")
88
+ representation["_detail"] = detail_field.get_attribute(obj)
89
+
82
90
  return representation
83
91
 
84
92
  class Meta:
@@ -1,3 +1,5 @@
1
+ from contextlib import suppress
2
+
1
3
  from django.contrib.contenttypes.models import ContentType
2
4
 
3
5
 
@@ -17,12 +19,10 @@ def get_ancestors_content_type(content_type):
17
19
  ]
18
20
  """
19
21
  for _class in content_type.model_class().__mro__:
20
- try:
22
+ with suppress(Exception):
21
23
  ancestor_content_type = ContentType.objects.get_for_model(_class)
22
24
  if ancestor_content_type.model_class():
23
25
  yield ancestor_content_type
24
- except Exception:
25
- pass
26
26
 
27
27
 
28
28
  def get_view_content_type_id(view):
@@ -3,7 +3,7 @@ from contextlib import suppress
3
3
 
4
4
  from django.contrib.contenttypes.models import ContentType
5
5
  from django.core.exceptions import FieldDoesNotExist, FieldError
6
- from django.db.models import CharField, Value
6
+ from django.db.models import CharField, F, Value
7
7
  from django.db.models.functions import Concat
8
8
  from django.shortcuts import get_object_or_404
9
9
  from django.utils.functional import cached_property
@@ -72,7 +72,7 @@ class DynamicObjectIDRepresentationViewSet(viewsets.RepresentationViewSet):
72
72
  raise FieldError()
73
73
  concat_fields = []
74
74
  for field in self.label_keys:
75
- concat_fields.append(field)
75
+ concat_fields.append(F(field))
76
76
  concat_fields.append(Value(" "))
77
77
  return self.model.objects.annotate(
78
78
  label=Concat(*concat_fields, output_field=CharField()),
@@ -1,6 +1,7 @@
1
1
  from datetime import timedelta
2
2
 
3
3
  from django.utils.translation import gettext_lazy as _
4
+ from psycopg.types.range import DateRange
4
5
 
5
6
  from wbcore import filters as wb_filters
6
7
  from wbcore.contrib.agenda.models import CalendarItem, ConferenceRoom
@@ -34,7 +35,7 @@ class CalendarItemPeriodBaseFilterSet(wb_filters.FilterSet):
34
35
  fields = {}
35
36
 
36
37
 
37
- def get_calendar_period_default(*args, **kwargs) -> dict:
38
+ def get_calendar_period_default(*args, **kwargs):
38
39
  month_start = current_month_date_start(*args, **kwargs)
39
40
  last_monday_from_month_start = month_start - timedelta(days=month_start.weekday())
40
41
 
@@ -42,12 +43,11 @@ def get_calendar_period_default(*args, **kwargs) -> dict:
42
43
  next_week_sunday_after_month = week_after_month + timedelta(
43
44
  days=6 - week_after_month.weekday()
44
45
  ) # weekday will return value between 0 and 6 so in order to get the next Sunday we need to subtract from 6
45
-
46
- return {"period": f"{last_monday_from_month_start:%Y-%m-%d},{next_week_sunday_after_month:%Y-%m-%d}"}
46
+ return DateRange(last_monday_from_month_start, next_week_sunday_after_month)
47
47
 
48
48
 
49
49
  class CalendarItemFilter(CalendarItemPeriodBaseFilterSet):
50
- period = wb_filters.DateTimeRangeFilter(label="Period", required=True, default=get_calendar_period_default)
50
+ period = wb_filters.DateTimeRangeFilter(label="Period", required=True, initial=get_calendar_period_default)
51
51
  item_type = wb_filters.MultipleChoiceFilter(
52
52
  label=_("Type"), choices=CalendarItem.get_item_types_choices(), field_name="item_type"
53
53
  )
@@ -58,6 +58,7 @@ class CalendarItemFilter(CalendarItemPeriodBaseFilterSet):
58
58
  value_key=Entry.get_representation_value_key(),
59
59
  label_key=Entry.get_representation_label_key(),
60
60
  field_name="entities",
61
+ initial=lambda field, request, view: request.user.profile.id,
61
62
  )
62
63
 
63
64
  class Meta:
@@ -1,113 +1,206 @@
1
- # GERMAN TRANSLATIONS FOR AGENDA
1
+ # SOME DESCRIPTIVE TITLE.
2
2
  # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
3
  # This file is distributed under the same license as the PACKAGE package.
4
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
5
  #
6
+ # Translators:
7
+ # Kevin Decoster, 2025
6
8
  #
9
+ #, fuzzy
7
10
  msgid ""
8
11
  msgstr ""
9
- "Project-Id-Version: \n"
12
+ "Project-Id-Version: PACKAGE VERSION\n"
10
13
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2023-04-25 17:08+0200\n"
12
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: \n"
14
- "Language-Team: \n"
15
- "Language: de\n"
14
+ "POT-Creation-Date: 2025-05-30 11:37+0200\n"
15
+ "PO-Revision-Date: 2025-05-30 09:40+0000\n"
16
+ "Last-Translator: Kevin Decoster, 2025\n"
17
+ "Language-Team: German (https://app.transifex.com/stainly/teams/171242/de/)\n"
16
18
  "MIME-Version: 1.0\n"
17
19
  "Content-Type: text/plain; charset=UTF-8\n"
18
20
  "Content-Transfer-Encoding: 8bit\n"
21
+ "Language: de\n"
19
22
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20
- "X-Generator: Poedit 3.2.2\n"
21
23
 
22
- #: wbcore/contrib/agenda/filters.py:25
23
- msgid "Calendar Regarding"
24
- msgstr "Kalendar Für"
24
+ #: contrib/agenda/filters/calendar_item.py:16
25
+ #: contrib/agenda/viewsets/menu/conference_room.py:24
26
+ #: contrib/agenda/viewsets/titles/conference_room.py:22
27
+ msgid "Conference Rooms"
28
+ msgstr ""
29
+
30
+ #: contrib/agenda/filters/calendar_item.py:23
31
+ msgid "Inside Conference Room"
32
+ msgstr ""
25
33
 
26
- #: wbcore/contrib/agenda/filters.py:33 wbcore/contrib/agenda/models.py:50
34
+ #: contrib/agenda/filters/calendar_item.py:52
35
+ #: contrib/agenda/models/calendar_item.py:48
27
36
  msgid "Type"
28
37
  msgstr "Typ"
29
38
 
30
- #: wbcore/contrib/agenda/models.py:15 wbcore/contrib/agenda/models.py:138
31
- msgid "Calendar Item"
32
- msgstr "Kalendareintrag"
33
-
34
- #: wbcore/contrib/agenda/models.py:16
35
- msgid "Absence Request"
36
- msgstr "Abwesenheitsantrag"
39
+ #: contrib/agenda/filters/calendar_item.py:55
40
+ msgid "Calendar Regarding"
41
+ msgstr "Kalendar Für"
37
42
 
38
- #: wbcore/contrib/agenda/models.py:17
39
- msgid "Activity"
40
- msgstr "Aktivität"
43
+ #: contrib/agenda/filters/conference_room.py:10
44
+ #: contrib/agenda/viewsets/menu/conference_room.py:7
45
+ #: contrib/agenda/viewsets/titles/conference_room.py:11
46
+ msgid "Buildings"
47
+ msgstr ""
41
48
 
42
- #: wbcore/contrib/agenda/models.py:18
43
- msgid "Task"
44
- msgstr "Aufgabe"
49
+ #: contrib/agenda/filters/conference_room.py:30
50
+ msgid "Addresses"
51
+ msgstr ""
45
52
 
46
- #: wbcore/contrib/agenda/models.py:21
53
+ #: contrib/agenda/models/calendar_item.py:24
47
54
  msgid "Public"
48
55
  msgstr "Öffentlich"
49
56
 
50
- #: wbcore/contrib/agenda/models.py:22
57
+ #: contrib/agenda/models/calendar_item.py:25
51
58
  msgid "Private"
52
59
  msgstr "Privat"
53
60
 
54
- #: wbcore/contrib/agenda/models.py:23
61
+ #: contrib/agenda/models/calendar_item.py:26
55
62
  msgid "Confidential"
56
63
  msgstr "Vertraulich"
57
64
 
58
- #: wbcore/contrib/agenda/models.py:35
65
+ #: contrib/agenda/models/calendar_item.py:33
59
66
  msgid "Entities"
60
67
  msgstr "Entitäten"
61
68
 
62
- #: wbcore/contrib/agenda/models.py:46
69
+ #: contrib/agenda/models/calendar_item.py:38
70
+ msgid "Icon"
71
+ msgstr ""
72
+
73
+ #: contrib/agenda/models/calendar_item.py:45
63
74
  msgid "Visibility"
64
75
  msgstr "Zugriffsbeschränkung"
65
76
 
66
- #: wbcore/contrib/agenda/models.py:57
77
+ #: contrib/agenda/models/calendar_item.py:54
67
78
  msgid "Period"
68
79
  msgstr "Zeitrahmen"
69
80
 
70
- #: wbcore/contrib/agenda/models.py:59
81
+ #: contrib/agenda/models/calendar_item.py:56
71
82
  msgid "Title"
72
83
  msgstr "Titel"
73
84
 
74
- #: wbcore/contrib/agenda/models.py:62
85
+ #: contrib/agenda/models/calendar_item.py:59
86
+ #: contrib/agenda/models/conference_room.py:90
75
87
  msgid "Conference Room"
76
88
  msgstr "Konferenzraum"
77
89
 
78
- #: wbcore/contrib/agenda/models.py:63
79
- msgid "Check this if it takes place in the conference room"
80
- msgstr ""
81
- "Wählen Sie diese Option aus, wenn die Aktivität im Konferenzraum stattfindet"
82
-
83
- #: wbcore/contrib/agenda/models.py:66
90
+ #: contrib/agenda/models/calendar_item.py:66
84
91
  msgid "All Day"
85
92
  msgstr "Ganztägig"
86
93
 
87
- #: wbcore/contrib/agenda/models.py:66
94
+ #: contrib/agenda/models/calendar_item.py:66
88
95
  msgid "Check this if the activity spans throughout the day"
89
96
  msgstr ""
90
97
  "Wählen Sie diese Option aus, wenn diese Aktivität ganztägig stattfindet"
91
98
 
92
- #: wbcore/contrib/agenda/models.py:68
99
+ #: contrib/agenda/models/calendar_item.py:68
93
100
  msgid "Is Cancelled"
94
101
  msgstr "Ist Abgesagt"
95
102
 
96
- #: wbcore/contrib/agenda/models.py:139
103
+ #: contrib/agenda/models/calendar_item.py:69
104
+ msgid "Is Deletable"
105
+ msgstr ""
106
+
107
+ #: contrib/agenda/models/calendar_item.py:208
108
+ msgid "Calendar Item"
109
+ msgstr "Kalendareintrag"
110
+
111
+ #: contrib/agenda/models/calendar_item.py:209
97
112
  msgid "Calendar Items"
98
113
  msgstr "Kalendareinträge"
99
114
 
100
- #: wbcore/contrib/agenda/serializers.py:38
101
- #, python-brace-format
102
- msgid "Private {type}"
103
- msgstr "Private/r {type}"
115
+ #: contrib/agenda/models/conference_room.py:9
116
+ #: contrib/agenda/models/conference_room.py:49
117
+ #: contrib/agenda/viewsets/display/conference_room.py:18
118
+ #: contrib/agenda/viewsets/display/conference_room.py:31
119
+ msgid "Name"
120
+ msgstr ""
104
121
 
105
- #: wbcore/contrib/agenda/serializers.py:40
106
- #, python-brace-format
107
- msgid "Confidential {type}"
108
- msgstr "Vertrauliche/r {type}"
122
+ #: contrib/agenda/models/conference_room.py:13
123
+ #: contrib/agenda/viewsets/display/conference_room.py:19
124
+ msgid "Address"
125
+ msgstr ""
126
+
127
+ #: contrib/agenda/models/conference_room.py:39
128
+ #: contrib/agenda/models/conference_room.py:54
129
+ #: contrib/agenda/viewsets/display/conference_room.py:33
130
+ msgid "Building"
131
+ msgstr ""
132
+
133
+ #: contrib/agenda/models/conference_room.py:50
134
+ msgid "Email Address"
135
+ msgstr ""
136
+
137
+ #: contrib/agenda/models/conference_room.py:57
138
+ #: contrib/agenda/viewsets/display/conference_room.py:34
139
+ msgid "Capacity"
140
+ msgstr ""
109
141
 
110
- #: wbcore/contrib/agenda/viewsets/menu/calendar_items.py:11
111
- #: wbcore/contrib/agenda/viewsets/titles/calendar_items.py:7
142
+ #: contrib/agenda/models/conference_room.py:58
143
+ #: contrib/agenda/viewsets/display/conference_room.py:35
144
+ msgid "Capable of Videoconferencing"
145
+ msgstr ""
146
+
147
+ #: contrib/agenda/serializers/calendar_item.py:46
148
+ msgid "Item"
149
+ msgstr ""
150
+
151
+ #: contrib/agenda/serializers/calendar_item.py:48
152
+ msgid "Private {}"
153
+ msgstr ""
154
+
155
+ #: contrib/agenda/serializers/calendar_item.py:48
156
+ msgid "Confidential {}"
157
+ msgstr ""
158
+
159
+ #: contrib/agenda/serializers/conference_room.py:66
160
+ msgid "A building with this name and address already exists."
161
+ msgstr ""
162
+
163
+ #: contrib/agenda/serializers/conference_room.py:96
164
+ msgid "A conference room with this email address already exists."
165
+ msgstr ""
166
+
167
+ #: contrib/agenda/serializers/conference_room.py:98
168
+ msgid "A conference room with this name already exists in this building."
169
+ msgstr ""
170
+
171
+ #: contrib/agenda/viewsets/buttons/conference_room.py:16
172
+ msgid "New Address"
173
+ msgstr ""
174
+
175
+ #: contrib/agenda/viewsets/display/conference_room.py:32
176
+ msgid "E-Mail-Address"
177
+ msgstr ""
178
+
179
+ #: contrib/agenda/viewsets/menu/calendar_items.py:7
180
+ #: contrib/agenda/viewsets/titles/calendar_items.py:8
112
181
  msgid "Calendar"
113
182
  msgstr "Kalendar"
183
+
184
+ #: contrib/agenda/viewsets/menu/conference_room.py:14
185
+ msgid "Create Building"
186
+ msgstr ""
187
+
188
+ #: contrib/agenda/viewsets/menu/conference_room.py:31
189
+ msgid "Create Conference Room"
190
+ msgstr ""
191
+
192
+ #: contrib/agenda/viewsets/titles/conference_room.py:8
193
+ msgid "Building: {{name}}"
194
+ msgstr ""
195
+
196
+ #: contrib/agenda/viewsets/titles/conference_room.py:14
197
+ msgid "New Building"
198
+ msgstr ""
199
+
200
+ #: contrib/agenda/viewsets/titles/conference_room.py:19
201
+ msgid "Conference Room: {{name}}"
202
+ msgstr ""
203
+
204
+ #: contrib/agenda/viewsets/titles/conference_room.py:25
205
+ msgid "New Conference Room"
206
+ msgstr ""