wbcore 1.59.9__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 (1239) hide show
  1. wbcore/__init__.py +1 -0
  2. wbcore/admin.py +197 -0
  3. wbcore/apps.py +17 -0
  4. wbcore/cache/__init__.py +0 -0
  5. wbcore/cache/buttons.py +23 -0
  6. wbcore/cache/decorators.py +31 -0
  7. wbcore/cache/mixins.py +49 -0
  8. wbcore/cache/registry.py +98 -0
  9. wbcore/cache/views.py +19 -0
  10. wbcore/configs/__init__.py +11 -0
  11. wbcore/configs/configs.py +52 -0
  12. wbcore/configs/decorators.py +11 -0
  13. wbcore/configs/registry.py +35 -0
  14. wbcore/configs/views.py +12 -0
  15. wbcore/configurations/__init__.py +1 -0
  16. wbcore/configurations/base.py +46 -0
  17. wbcore/configurations/configurations/__init__.py +16 -0
  18. wbcore/configurations/configurations/apps.py +55 -0
  19. wbcore/configurations/configurations/authentication.py +44 -0
  20. wbcore/configurations/configurations/base.py +15 -0
  21. wbcore/configurations/configurations/cache.py +20 -0
  22. wbcore/configurations/configurations/celery.py +26 -0
  23. wbcore/configurations/configurations/i18nl10n.py +11 -0
  24. wbcore/configurations/configurations/mail.py +2 -0
  25. wbcore/configurations/configurations/maintenance.py +53 -0
  26. wbcore/configurations/configurations/media.py +22 -0
  27. wbcore/configurations/configurations/middleware.py +27 -0
  28. wbcore/configurations/configurations/network.py +19 -0
  29. wbcore/configurations/configurations/rest_framework.py +42 -0
  30. wbcore/configurations/configurations/static.py +28 -0
  31. wbcore/configurations/configurations/templates.py +17 -0
  32. wbcore/configurations/configurations/uvicorn.py +9 -0
  33. wbcore/configurations/configurations/wbcore.py +61 -0
  34. wbcore/content_type/__init__.py +0 -0
  35. wbcore/content_type/admin.py +8 -0
  36. wbcore/content_type/filters.py +20 -0
  37. wbcore/content_type/serializers.py +98 -0
  38. wbcore/content_type/utils.py +30 -0
  39. wbcore/content_type/viewsets.py +81 -0
  40. wbcore/contrib/__init__.py +0 -0
  41. wbcore/contrib/agenda/__init__.py +0 -0
  42. wbcore/contrib/agenda/admin/__init__.py +2 -0
  43. wbcore/contrib/agenda/admin/calendar_item.py +14 -0
  44. wbcore/contrib/agenda/admin/conference_room.py +19 -0
  45. wbcore/contrib/agenda/apps.py +6 -0
  46. wbcore/contrib/agenda/configurations.py +11 -0
  47. wbcore/contrib/agenda/factories/__init__.py +2 -0
  48. wbcore/contrib/agenda/factories/calendar_item.py +49 -0
  49. wbcore/contrib/agenda/factories/conference_room.py +20 -0
  50. wbcore/contrib/agenda/filters/__init__.py +2 -0
  51. wbcore/contrib/agenda/filters/calendar_item.py +66 -0
  52. wbcore/contrib/agenda/filters/conference_room.py +42 -0
  53. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +206 -0
  54. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
  55. wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
  56. wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
  57. wbcore/contrib/agenda/migrations/0001_initial.py +84 -0
  58. wbcore/contrib/agenda/migrations/0002_initial.py +26 -0
  59. wbcore/contrib/agenda/migrations/0003_calendaritem_endpoint_basename.py +42 -0
  60. wbcore/contrib/agenda/migrations/0004_alter_calendaritem_item_type.py +17 -0
  61. wbcore/contrib/agenda/migrations/0005_building_and_more.py +94 -0
  62. wbcore/contrib/agenda/migrations/0006_calendaritem_is_deletable.py +17 -0
  63. wbcore/contrib/agenda/migrations/0007_alter_calendaritem_options.py +21 -0
  64. wbcore/contrib/agenda/migrations/0008_alter_calendaritem_item_type.py +17 -0
  65. wbcore/contrib/agenda/migrations/0009_alter_calendaritem_icon.py +18 -0
  66. wbcore/contrib/agenda/migrations/__init__.py +0 -0
  67. wbcore/contrib/agenda/models/__init__.py +2 -0
  68. wbcore/contrib/agenda/models/calendar_item.py +240 -0
  69. wbcore/contrib/agenda/models/conference_room.py +96 -0
  70. wbcore/contrib/agenda/release_notes/1_0_0.md +13 -0
  71. wbcore/contrib/agenda/release_notes/__init__.py +0 -0
  72. wbcore/contrib/agenda/serializers/__init__.py +10 -0
  73. wbcore/contrib/agenda/serializers/calendar_item.py +77 -0
  74. wbcore/contrib/agenda/serializers/conference_room.py +99 -0
  75. wbcore/contrib/agenda/signals.py +5 -0
  76. wbcore/contrib/agenda/static/agenda/markdown/documentation/building.md +11 -0
  77. wbcore/contrib/agenda/static/agenda/markdown/documentation/conferenceroom.md +20 -0
  78. wbcore/contrib/agenda/tests/__init__.py +0 -0
  79. wbcore/contrib/agenda/tests/conftest.py +14 -0
  80. wbcore/contrib/agenda/tests/signals.py +17 -0
  81. wbcore/contrib/agenda/tests/test_models.py +34 -0
  82. wbcore/contrib/agenda/tests/test_viewsets.py +172 -0
  83. wbcore/contrib/agenda/tests/tests.py +26 -0
  84. wbcore/contrib/agenda/typings.py +19 -0
  85. wbcore/contrib/agenda/urls.py +26 -0
  86. wbcore/contrib/agenda/viewsets/__init__.py +13 -0
  87. wbcore/contrib/agenda/viewsets/buttons/__init__.py +1 -0
  88. wbcore/contrib/agenda/viewsets/buttons/conference_room.py +21 -0
  89. wbcore/contrib/agenda/viewsets/calendar_items.py +169 -0
  90. wbcore/contrib/agenda/viewsets/conference_room.py +48 -0
  91. wbcore/contrib/agenda/viewsets/display/__init__.py +2 -0
  92. wbcore/contrib/agenda/viewsets/display/calendar_items.py +17 -0
  93. wbcore/contrib/agenda/viewsets/display/conference_room.py +42 -0
  94. wbcore/contrib/agenda/viewsets/endpoints/__init__.py +1 -0
  95. wbcore/contrib/agenda/viewsets/endpoints/calendar_items.py +19 -0
  96. wbcore/contrib/agenda/viewsets/menu/__init__.py +2 -0
  97. wbcore/contrib/agenda/viewsets/menu/calendar_items.py +12 -0
  98. wbcore/contrib/agenda/viewsets/menu/conference_room.py +38 -0
  99. wbcore/contrib/agenda/viewsets/titles/__init__.py +2 -0
  100. wbcore/contrib/agenda/viewsets/titles/calendar_items.py +8 -0
  101. wbcore/contrib/agenda/viewsets/titles/conference_room.py +25 -0
  102. wbcore/contrib/ai/__init__.py +0 -0
  103. wbcore/contrib/ai/apps.py +5 -0
  104. wbcore/contrib/ai/exceptions.py +40 -0
  105. wbcore/contrib/ai/llm/__init__.py +0 -0
  106. wbcore/contrib/ai/llm/config.py +166 -0
  107. wbcore/contrib/ai/llm/decorators.py +10 -0
  108. wbcore/contrib/ai/llm/mixins.py +34 -0
  109. wbcore/contrib/ai/llm/utils.py +69 -0
  110. wbcore/contrib/authentication/__init__.py +9 -0
  111. wbcore/contrib/authentication/admin.py +247 -0
  112. wbcore/contrib/authentication/apps.py +14 -0
  113. wbcore/contrib/authentication/authentication.py +111 -0
  114. wbcore/contrib/authentication/configs.py +10 -0
  115. wbcore/contrib/authentication/configurations.py +60 -0
  116. wbcore/contrib/authentication/dynamic_preferences_registry.py +26 -0
  117. wbcore/contrib/authentication/factories/__init__.py +10 -0
  118. wbcore/contrib/authentication/factories/tokens.py +15 -0
  119. wbcore/contrib/authentication/factories/users.py +112 -0
  120. wbcore/contrib/authentication/factories/users_activities.py +19 -0
  121. wbcore/contrib/authentication/filters.py +17 -0
  122. wbcore/contrib/authentication/fixtures/authentication.json +62 -0
  123. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +632 -0
  124. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
  125. wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
  126. wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
  127. wbcore/contrib/authentication/management/__init__.py +14 -0
  128. wbcore/contrib/authentication/migrations/0001_initial_squashed.py +174 -0
  129. wbcore/contrib/authentication/migrations/0002_profile.py +26 -0
  130. wbcore/contrib/authentication/migrations/0003_alter_user_profile.py +34 -0
  131. wbcore/contrib/authentication/migrations/0004_token.py +51 -0
  132. wbcore/contrib/authentication/migrations/0005_user_external_calendar_settings.py +17 -0
  133. wbcore/contrib/authentication/migrations/0006_auto_20231206_1422.py +13 -0
  134. wbcore/contrib/authentication/migrations/__init__.py +0 -0
  135. wbcore/contrib/authentication/models/__init__.py +3 -0
  136. wbcore/contrib/authentication/models/tokens.py +140 -0
  137. wbcore/contrib/authentication/models/users.py +224 -0
  138. wbcore/contrib/authentication/models/users_activities.py +114 -0
  139. wbcore/contrib/authentication/release_notes/1_0_0.md +13 -0
  140. wbcore/contrib/authentication/release_notes/__init__.py +0 -0
  141. wbcore/contrib/authentication/serializers/__init__.py +14 -0
  142. wbcore/contrib/authentication/serializers/users.py +351 -0
  143. wbcore/contrib/authentication/serializers/users_activites.py +37 -0
  144. wbcore/contrib/authentication/tasks.py +30 -0
  145. wbcore/contrib/authentication/templates/activate_confirm.html +12 -0
  146. wbcore/contrib/authentication/templates/base.html +135 -0
  147. wbcore/contrib/authentication/templates/email_base_template.html +335 -0
  148. wbcore/contrib/authentication/templates/password_reset_done.html +13 -0
  149. wbcore/contrib/authentication/templates/password_reset_email.html +11 -0
  150. wbcore/contrib/authentication/templates/password_reset_email_html.html +43 -0
  151. wbcore/contrib/authentication/templates/password_reset_form.html +23 -0
  152. wbcore/contrib/authentication/templates/password_reset_sent.html +11 -0
  153. wbcore/contrib/authentication/templates/reset_password.html +15 -0
  154. wbcore/contrib/authentication/templates/user_registration_email.html +37 -0
  155. wbcore/contrib/authentication/tests/__init__.py +0 -0
  156. wbcore/contrib/authentication/tests/conftest.py +18 -0
  157. wbcore/contrib/authentication/tests/e2e/__init__.py +1 -0
  158. wbcore/contrib/authentication/tests/e2e/e2e_auth_utility.py +20 -0
  159. wbcore/contrib/authentication/tests/signals.py +18 -0
  160. wbcore/contrib/authentication/tests/test_configs.py +6 -0
  161. wbcore/contrib/authentication/tests/test_serializers.py +6 -0
  162. wbcore/contrib/authentication/tests/test_tasks.py +34 -0
  163. wbcore/contrib/authentication/tests/test_tokens.py +127 -0
  164. wbcore/contrib/authentication/tests/test_users.py +338 -0
  165. wbcore/contrib/authentication/tests/test_viewsets.py +6 -0
  166. wbcore/contrib/authentication/tests/tests.py +15 -0
  167. wbcore/contrib/authentication/urls.py +94 -0
  168. wbcore/contrib/authentication/utils.py +10 -0
  169. wbcore/contrib/authentication/viewsets/__init__.py +19 -0
  170. wbcore/contrib/authentication/viewsets/buttons/__init__.py +1 -0
  171. wbcore/contrib/authentication/viewsets/buttons/users.py +56 -0
  172. wbcore/contrib/authentication/viewsets/display/__init__.py +6 -0
  173. wbcore/contrib/authentication/viewsets/display/user_activities.py +86 -0
  174. wbcore/contrib/authentication/viewsets/display/users.py +73 -0
  175. wbcore/contrib/authentication/viewsets/endpoints/__init__.py +6 -0
  176. wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +14 -0
  177. wbcore/contrib/authentication/viewsets/endpoints/users.py +18 -0
  178. wbcore/contrib/authentication/viewsets/menu/__init__.py +6 -0
  179. wbcore/contrib/authentication/viewsets/menu/user_activities.py +40 -0
  180. wbcore/contrib/authentication/viewsets/menu/users.py +17 -0
  181. wbcore/contrib/authentication/viewsets/titles/__init__.py +12 -0
  182. wbcore/contrib/authentication/viewsets/titles/user_activities.py +32 -0
  183. wbcore/contrib/authentication/viewsets/titles/users.py +27 -0
  184. wbcore/contrib/authentication/viewsets/user_activities.py +224 -0
  185. wbcore/contrib/authentication/viewsets/users.py +331 -0
  186. wbcore/contrib/color/admin.py +28 -0
  187. wbcore/contrib/color/apps.py +5 -0
  188. wbcore/contrib/color/enums.py +17 -0
  189. wbcore/contrib/color/factories.py +10 -0
  190. wbcore/contrib/color/fields.py +29 -0
  191. wbcore/contrib/color/forms.py +13 -0
  192. wbcore/contrib/color/migrations/0001_initial.py +33 -0
  193. wbcore/contrib/color/migrations/0002_alter_colorgradient_colors.py +25 -0
  194. wbcore/contrib/color/migrations/__init__.py +0 -0
  195. wbcore/contrib/color/models.py +63 -0
  196. wbcore/contrib/color/tests/conftest.py +10 -0
  197. wbcore/contrib/color/tests/test_color_models.py +61 -0
  198. wbcore/contrib/color/tests/test_fields.py +25 -0
  199. wbcore/contrib/currency/__init__.py +0 -0
  200. wbcore/contrib/currency/admin.py +33 -0
  201. wbcore/contrib/currency/apps.py +5 -0
  202. wbcore/contrib/currency/dynamic_preferences_registry.py +39 -0
  203. wbcore/contrib/currency/factories.py +40 -0
  204. wbcore/contrib/currency/fixtures/currency.yaml +1014 -0
  205. wbcore/contrib/currency/fixtures/currency_fx_rate.yaml +73585 -0
  206. wbcore/contrib/currency/import_export/__init__.py +0 -0
  207. wbcore/contrib/currency/import_export/backends/__init__.py +1 -0
  208. wbcore/contrib/currency/import_export/backends/fixerio/__init__.py +1 -0
  209. wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +69 -0
  210. wbcore/contrib/currency/import_export/backends/utils.py +5 -0
  211. wbcore/contrib/currency/import_export/handlers/__init__.py +2 -0
  212. wbcore/contrib/currency/import_export/handlers/currency.py +25 -0
  213. wbcore/contrib/currency/import_export/handlers/currency_fx_rates.py +29 -0
  214. wbcore/contrib/currency/import_export/parsers/__init__.py +0 -0
  215. wbcore/contrib/currency/import_export/parsers/fixerio/__init__.py +0 -0
  216. wbcore/contrib/currency/import_export/parsers/fixerio/currency_fx_rates.py +34 -0
  217. wbcore/contrib/currency/migrations/0001_initial.py +89 -0
  218. wbcore/contrib/currency/migrations/__init__.py +0 -0
  219. wbcore/contrib/currency/models.py +199 -0
  220. wbcore/contrib/currency/release_notes/1_0_0.md +13 -0
  221. wbcore/contrib/currency/release_notes/__init__.py +0 -0
  222. wbcore/contrib/currency/serializers.py +45 -0
  223. wbcore/contrib/currency/tests/__init__.py +0 -0
  224. wbcore/contrib/currency/tests/conftest.py +7 -0
  225. wbcore/contrib/currency/tests/test_models.py +115 -0
  226. wbcore/contrib/currency/tests/test_serializers.py +67 -0
  227. wbcore/contrib/currency/tests/test_viewsets.py +196 -0
  228. wbcore/contrib/currency/urls.py +20 -0
  229. wbcore/contrib/currency/viewsets/__init__.py +2 -0
  230. wbcore/contrib/currency/viewsets/buttons/__init__.py +0 -0
  231. wbcore/contrib/currency/viewsets/currency.py +57 -0
  232. wbcore/contrib/currency/viewsets/currency_fx_rates.py +33 -0
  233. wbcore/contrib/currency/viewsets/display/__init__.py +2 -0
  234. wbcore/contrib/currency/viewsets/display/currency.py +38 -0
  235. wbcore/contrib/currency/viewsets/display/currency_fx_rates.py +9 -0
  236. wbcore/contrib/currency/viewsets/endpoints/__init__.py +1 -0
  237. wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +6 -0
  238. wbcore/contrib/currency/viewsets/menu/__init__.py +1 -0
  239. wbcore/contrib/currency/viewsets/menu/currency.py +8 -0
  240. wbcore/contrib/currency/viewsets/preview/__init__.py +1 -0
  241. wbcore/contrib/currency/viewsets/preview/currency.py +10 -0
  242. wbcore/contrib/currency/viewsets/titles/__init__.py +2 -0
  243. wbcore/contrib/currency/viewsets/titles/currency.py +6 -0
  244. wbcore/contrib/currency/viewsets/titles/currency_fx_rates.py +8 -0
  245. wbcore/contrib/dataloader/__init__.py +1 -0
  246. wbcore/contrib/dataloader/apps.py +5 -0
  247. wbcore/contrib/dataloader/dataloaders/__init__.py +2 -0
  248. wbcore/contrib/dataloader/dataloaders/dataloaders.py +25 -0
  249. wbcore/contrib/dataloader/dataloaders/proxies.py +82 -0
  250. wbcore/contrib/dataloader/models/__init__.py +1 -0
  251. wbcore/contrib/dataloader/models/entities.py +30 -0
  252. wbcore/contrib/dataloader/models/querysets/__init__.py +1 -0
  253. wbcore/contrib/dataloader/models/querysets/entities.py +28 -0
  254. wbcore/contrib/dataloader/tests/__init__.py +0 -0
  255. wbcore/contrib/dataloader/tests/conftest.py +26 -0
  256. wbcore/contrib/dataloader/tests/test/__init__.py +0 -0
  257. wbcore/contrib/dataloader/tests/test/dataloaders/__init__.py +0 -0
  258. wbcore/contrib/dataloader/tests/test/dataloaders/dataloaders.py +18 -0
  259. wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +5 -0
  260. wbcore/contrib/dataloader/tests/test/dataloaders/proxies.py +11 -0
  261. wbcore/contrib/dataloader/tests/test/factories.py +13 -0
  262. wbcore/contrib/dataloader/tests/test/models.py +11 -0
  263. wbcore/contrib/dataloader/tests/test_dataloaders.py +38 -0
  264. wbcore/contrib/dataloader/tests/test_entities.py +13 -0
  265. wbcore/contrib/dataloader/utils.py +20 -0
  266. wbcore/contrib/directory/__init__.py +0 -0
  267. wbcore/contrib/directory/admin/__init__.py +14 -0
  268. wbcore/contrib/directory/admin/contacts.py +55 -0
  269. wbcore/contrib/directory/admin/entries.py +235 -0
  270. wbcore/contrib/directory/admin/relationships.py +73 -0
  271. wbcore/contrib/directory/apps.py +6 -0
  272. wbcore/contrib/directory/configs.py +9 -0
  273. wbcore/contrib/directory/configurations.py +70 -0
  274. wbcore/contrib/directory/dynamic_preferences_registry.py +61 -0
  275. wbcore/contrib/directory/factories/__init__.py +35 -0
  276. wbcore/contrib/directory/factories/contacts.py +71 -0
  277. wbcore/contrib/directory/factories/entries.py +174 -0
  278. wbcore/contrib/directory/factories/relationships.py +77 -0
  279. wbcore/contrib/directory/filters/__init__.py +22 -0
  280. wbcore/contrib/directory/filters/contacts.py +234 -0
  281. wbcore/contrib/directory/filters/entries.py +273 -0
  282. wbcore/contrib/directory/filters/relationships.py +90 -0
  283. wbcore/contrib/directory/fixtures/directory.json +3884 -0
  284. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +1700 -0
  285. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
  286. wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
  287. wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
  288. wbcore/contrib/directory/migrations/0001_initial.py +871 -0
  289. wbcore/contrib/directory/migrations/0002_auto_20230414_1553.py +42 -0
  290. wbcore/contrib/directory/migrations/0003_remove_entry_last_event.py +16 -0
  291. wbcore/contrib/directory/migrations/0004_entry_is_draft_entry.py +21 -0
  292. wbcore/contrib/directory/migrations/0005_entry_salutation.py +17 -0
  293. wbcore/contrib/directory/migrations/0006_employeremployeerelationship_position_name.py +23 -0
  294. wbcore/contrib/directory/migrations/0007_alter_bankingcontact_options.py +20 -0
  295. wbcore/contrib/directory/migrations/0008_bankingcontact_access.py +17 -0
  296. wbcore/contrib/directory/migrations/0009_remove_entry_external_identfier_and_more.py +22 -0
  297. wbcore/contrib/directory/migrations/0010_remove_addresscontact_city.py +31 -0
  298. wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
  299. wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
  300. wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
  301. wbcore/contrib/directory/migrations/0014_alter_entry_relationship_managers_and_more.py +28 -0
  302. wbcore/contrib/directory/migrations/__init__.py +0 -0
  303. wbcore/contrib/directory/models/__init__.py +27 -0
  304. wbcore/contrib/directory/models/contacts.py +554 -0
  305. wbcore/contrib/directory/models/entries.py +896 -0
  306. wbcore/contrib/directory/models/relationships.py +624 -0
  307. wbcore/contrib/directory/permissions.py +6 -0
  308. wbcore/contrib/directory/preferences.py +11 -0
  309. wbcore/contrib/directory/release_notes/1_0_0.md +13 -0
  310. wbcore/contrib/directory/release_notes/1_0_1.md +13 -0
  311. wbcore/contrib/directory/release_notes/__init__.py +0 -0
  312. wbcore/contrib/directory/serializers/__init__.py +62 -0
  313. wbcore/contrib/directory/serializers/companies.py +169 -0
  314. wbcore/contrib/directory/serializers/contacts.py +404 -0
  315. wbcore/contrib/directory/serializers/entries.py +355 -0
  316. wbcore/contrib/directory/serializers/entry_representations.py +38 -0
  317. wbcore/contrib/directory/serializers/persons.py +214 -0
  318. wbcore/contrib/directory/serializers/relationships.py +333 -0
  319. wbcore/contrib/directory/signals.py +3 -0
  320. wbcore/contrib/directory/static/directory/markdown/documentation/address.md +38 -0
  321. wbcore/contrib/directory/static/directory/markdown/documentation/banking.md +54 -0
  322. wbcore/contrib/directory/static/directory/markdown/documentation/bankingentry.md +38 -0
  323. wbcore/contrib/directory/static/directory/markdown/documentation/clientmanagerrelationship.md +42 -0
  324. wbcore/contrib/directory/static/directory/markdown/documentation/company.md +52 -0
  325. wbcore/contrib/directory/static/directory/markdown/documentation/companytype.md +2 -0
  326. wbcore/contrib/directory/static/directory/markdown/documentation/customerstatus.md +2 -0
  327. wbcore/contrib/directory/static/directory/markdown/documentation/email.md +20 -0
  328. wbcore/contrib/directory/static/directory/markdown/documentation/employeecompany.md +34 -0
  329. wbcore/contrib/directory/static/directory/markdown/documentation/employerperson.md +43 -0
  330. wbcore/contrib/directory/static/directory/markdown/documentation/person.md +61 -0
  331. wbcore/contrib/directory/static/directory/markdown/documentation/position.md +2 -0
  332. wbcore/contrib/directory/static/directory/markdown/documentation/relationshiptype.md +2 -0
  333. wbcore/contrib/directory/static/directory/markdown/documentation/socialmedia.md +23 -0
  334. wbcore/contrib/directory/static/directory/markdown/documentation/specialization.md +2 -0
  335. wbcore/contrib/directory/static/directory/markdown/documentation/systememployee.md +31 -0
  336. wbcore/contrib/directory/static/directory/markdown/documentation/telephone.md +23 -0
  337. wbcore/contrib/directory/static/directory/markdown/documentation/telephonesearch.md +26 -0
  338. wbcore/contrib/directory/static/directory/markdown/documentation/userisclient.md +14 -0
  339. wbcore/contrib/directory/static/directory/markdown/documentation/userismanager.md +28 -0
  340. wbcore/contrib/directory/static/directory/markdown/documentation/website.md +20 -0
  341. wbcore/contrib/directory/tests/__init__.py +0 -0
  342. wbcore/contrib/directory/tests/conftest.py +62 -0
  343. wbcore/contrib/directory/tests/disable_signals.py +62 -0
  344. wbcore/contrib/directory/tests/e2e/__init__.py +7 -0
  345. wbcore/contrib/directory/tests/e2e/e2e_directory_utility.py +163 -0
  346. wbcore/contrib/directory/tests/signals.py +89 -0
  347. wbcore/contrib/directory/tests/test_configs.py +6 -0
  348. wbcore/contrib/directory/tests/test_filters.py +60 -0
  349. wbcore/contrib/directory/tests/test_models.py +428 -0
  350. wbcore/contrib/directory/tests/test_permissions.py +123 -0
  351. wbcore/contrib/directory/tests/test_serializers.py +217 -0
  352. wbcore/contrib/directory/tests/test_viewsets.py +835 -0
  353. wbcore/contrib/directory/typings.py +17 -0
  354. wbcore/contrib/directory/urls.py +135 -0
  355. wbcore/contrib/directory/viewsets/__init__.py +57 -0
  356. wbcore/contrib/directory/viewsets/buttons/__init__.py +7 -0
  357. wbcore/contrib/directory/viewsets/buttons/contacts.py +17 -0
  358. wbcore/contrib/directory/viewsets/buttons/entries.py +134 -0
  359. wbcore/contrib/directory/viewsets/buttons/relationships.py +64 -0
  360. wbcore/contrib/directory/viewsets/contacts.py +392 -0
  361. wbcore/contrib/directory/viewsets/display/__init__.py +36 -0
  362. wbcore/contrib/directory/viewsets/display/contacts.py +368 -0
  363. wbcore/contrib/directory/viewsets/display/entries.py +532 -0
  364. wbcore/contrib/directory/viewsets/display/relationships.py +292 -0
  365. wbcore/contrib/directory/viewsets/display/utils.py +34 -0
  366. wbcore/contrib/directory/viewsets/endpoints/__init__.py +22 -0
  367. wbcore/contrib/directory/viewsets/endpoints/contacts.py +55 -0
  368. wbcore/contrib/directory/viewsets/endpoints/entries.py +31 -0
  369. wbcore/contrib/directory/viewsets/endpoints/relationships.py +81 -0
  370. wbcore/contrib/directory/viewsets/entries.py +205 -0
  371. wbcore/contrib/directory/viewsets/menu/__init__.py +16 -0
  372. wbcore/contrib/directory/viewsets/menu/contacts.py +26 -0
  373. wbcore/contrib/directory/viewsets/menu/entries.py +62 -0
  374. wbcore/contrib/directory/viewsets/menu/relationships.py +32 -0
  375. wbcore/contrib/directory/viewsets/menu/utils.py +73 -0
  376. wbcore/contrib/directory/viewsets/mixins.py +12 -0
  377. wbcore/contrib/directory/viewsets/previews/__init__.py +2 -0
  378. wbcore/contrib/directory/viewsets/previews/contacts.py +19 -0
  379. wbcore/contrib/directory/viewsets/previews/entries.py +32 -0
  380. wbcore/contrib/directory/viewsets/relationships.py +256 -0
  381. wbcore/contrib/directory/viewsets/titles/__init__.py +30 -0
  382. wbcore/contrib/directory/viewsets/titles/contacts.py +123 -0
  383. wbcore/contrib/directory/viewsets/titles/entries.py +30 -0
  384. wbcore/contrib/directory/viewsets/titles/relationships.py +86 -0
  385. wbcore/contrib/directory/viewsets/titles/utils.py +47 -0
  386. wbcore/contrib/directory/viewsets/utils.py +101 -0
  387. wbcore/contrib/documents/__init__.py +0 -0
  388. wbcore/contrib/documents/admin.py +80 -0
  389. wbcore/contrib/documents/apps.py +6 -0
  390. wbcore/contrib/documents/factories.py +44 -0
  391. wbcore/contrib/documents/filters.py +81 -0
  392. wbcore/contrib/documents/fixtures/docments.json +135 -0
  393. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +281 -0
  394. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
  395. wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
  396. wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
  397. wbcore/contrib/documents/migrations/0001_initial.py +189 -0
  398. wbcore/contrib/documents/migrations/0002_documentmodelrelationship_primary_and_more.py +22 -0
  399. wbcore/contrib/documents/migrations/0003_alter_documentmodelrelationship_unique_together_and_more.py +30 -0
  400. wbcore/contrib/documents/migrations/0004_auto_20240103_0958.py +44 -0
  401. wbcore/contrib/documents/migrations/0005_document_valid_from_document_valid_until_and_more.py +32 -0
  402. wbcore/contrib/documents/migrations/__init__.py +0 -0
  403. wbcore/contrib/documents/models/__init__.py +4 -0
  404. wbcore/contrib/documents/models/document_model_relationships.py +58 -0
  405. wbcore/contrib/documents/models/document_types.py +36 -0
  406. wbcore/contrib/documents/models/documents.py +311 -0
  407. wbcore/contrib/documents/models/mixins.py +10 -0
  408. wbcore/contrib/documents/models/shareable_links.py +91 -0
  409. wbcore/contrib/documents/release_notes/1_0_0.md +13 -0
  410. wbcore/contrib/documents/release_notes/__init__.py +0 -0
  411. wbcore/contrib/documents/serializers/__init__.py +12 -0
  412. wbcore/contrib/documents/serializers/document_model_relationships.py +31 -0
  413. wbcore/contrib/documents/serializers/document_types.py +41 -0
  414. wbcore/contrib/documents/serializers/documents.py +65 -0
  415. wbcore/contrib/documents/serializers/shareable_links.py +91 -0
  416. wbcore/contrib/documents/static/documents/markdown/documentation/document_types.md +21 -0
  417. wbcore/contrib/documents/static/documents/markdown/documentation/documents.md +18 -0
  418. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelink.md +28 -0
  419. wbcore/contrib/documents/static/documents/markdown/documentation/shareablelinkaccess.md +20 -0
  420. wbcore/contrib/documents/tests/conftest.py +30 -0
  421. wbcore/contrib/documents/tests/test_models.py +148 -0
  422. wbcore/contrib/documents/urls.py +43 -0
  423. wbcore/contrib/documents/viewsets/__init__.py +10 -0
  424. wbcore/contrib/documents/viewsets/buttons/__init__.py +3 -0
  425. wbcore/contrib/documents/viewsets/buttons/documents.py +54 -0
  426. wbcore/contrib/documents/viewsets/buttons/shareable_links.py +21 -0
  427. wbcore/contrib/documents/viewsets/buttons/signals.py +14 -0
  428. wbcore/contrib/documents/viewsets/display/__init__.py +4 -0
  429. wbcore/contrib/documents/viewsets/display/document_model_relationships.py +19 -0
  430. wbcore/contrib/documents/viewsets/display/document_types.py +24 -0
  431. wbcore/contrib/documents/viewsets/display/documents.py +102 -0
  432. wbcore/contrib/documents/viewsets/display/shareable_links.py +66 -0
  433. wbcore/contrib/documents/viewsets/document_model_relationships.py +25 -0
  434. wbcore/contrib/documents/viewsets/document_types.py +38 -0
  435. wbcore/contrib/documents/viewsets/documents.py +108 -0
  436. wbcore/contrib/documents/viewsets/endpoints/__init__.py +5 -0
  437. wbcore/contrib/documents/viewsets/endpoints/documents.py +20 -0
  438. wbcore/contrib/documents/viewsets/endpoints/documents_model_relationships.py +14 -0
  439. wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +27 -0
  440. wbcore/contrib/documents/viewsets/menu/__init__.py +1 -0
  441. wbcore/contrib/documents/viewsets/menu/documents.py +25 -0
  442. wbcore/contrib/documents/viewsets/previews/__init__.py +1 -0
  443. wbcore/contrib/documents/viewsets/previews/documents.py +10 -0
  444. wbcore/contrib/documents/viewsets/shareable_links.py +110 -0
  445. wbcore/contrib/documents/viewsets/titles/__init__.py +3 -0
  446. wbcore/contrib/documents/viewsets/titles/document_types.py +14 -0
  447. wbcore/contrib/documents/viewsets/titles/documents.py +27 -0
  448. wbcore/contrib/documents/viewsets/titles/shareable_links.py +14 -0
  449. wbcore/contrib/dynamic_preferences/__init__.py +0 -0
  450. wbcore/contrib/dynamic_preferences/types.py +127 -0
  451. wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
  452. wbcore/contrib/example_app/__init__.py +0 -0
  453. wbcore/contrib/example_app/admin.py +118 -0
  454. wbcore/contrib/example_app/apps.py +6 -0
  455. wbcore/contrib/example_app/factories/__init__.py +8 -0
  456. wbcore/contrib/example_app/factories/event.py +27 -0
  457. wbcore/contrib/example_app/factories/league.py +16 -0
  458. wbcore/contrib/example_app/factories/match.py +26 -0
  459. wbcore/contrib/example_app/factories/person.py +34 -0
  460. wbcore/contrib/example_app/factories/role.py +10 -0
  461. wbcore/contrib/example_app/factories/sport.py +13 -0
  462. wbcore/contrib/example_app/factories/stadium.py +13 -0
  463. wbcore/contrib/example_app/factories/team.py +37 -0
  464. wbcore/contrib/example_app/filters/__init__.py +9 -0
  465. wbcore/contrib/example_app/filters/event.py +83 -0
  466. wbcore/contrib/example_app/filters/league.py +75 -0
  467. wbcore/contrib/example_app/filters/match.py +93 -0
  468. wbcore/contrib/example_app/filters/person.py +78 -0
  469. wbcore/contrib/example_app/filters/role.py +18 -0
  470. wbcore/contrib/example_app/filters/sport.py +27 -0
  471. wbcore/contrib/example_app/filters/stadium.py +31 -0
  472. wbcore/contrib/example_app/filters/team.py +78 -0
  473. wbcore/contrib/example_app/filters/teamresult.py +48 -0
  474. wbcore/contrib/example_app/fixtures/example_app.json +7425 -0
  475. wbcore/contrib/example_app/migrations/0001_initial.py +498 -0
  476. wbcore/contrib/example_app/migrations/0002_sportperson_profile.py +49 -0
  477. wbcore/contrib/example_app/migrations/0003_change_stadium_capacity.py +31 -0
  478. wbcore/contrib/example_app/migrations/0004_alter_player_transfer_value.py +21 -0
  479. wbcore/contrib/example_app/migrations/0005_sportperson_profile_image.py +23 -0
  480. wbcore/contrib/example_app/migrations/0006_league_season_period_player_is_active_and_more.py +116 -0
  481. wbcore/contrib/example_app/migrations/0007_alter_player_options_alter_team_options_and_more.py +40 -0
  482. wbcore/contrib/example_app/migrations/__init__.py +0 -0
  483. wbcore/contrib/example_app/models.py +978 -0
  484. wbcore/contrib/example_app/serializers/__init__.py +31 -0
  485. wbcore/contrib/example_app/serializers/league.py +112 -0
  486. wbcore/contrib/example_app/serializers/match_event.py +305 -0
  487. wbcore/contrib/example_app/serializers/person_team.py +281 -0
  488. wbcore/contrib/example_app/serializers/role.py +16 -0
  489. wbcore/contrib/example_app/serializers/season.py +54 -0
  490. wbcore/contrib/example_app/serializers/sport.py +38 -0
  491. wbcore/contrib/example_app/serializers/stadium.py +59 -0
  492. wbcore/contrib/example_app/serializers/teamresult.py +44 -0
  493. wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
  494. wbcore/contrib/example_app/tests/__init__.py +0 -0
  495. wbcore/contrib/example_app/tests/conftest.py +13 -0
  496. wbcore/contrib/example_app/tests/e2e/__init__.py +1 -0
  497. wbcore/contrib/example_app/tests/e2e/e2e_example_app_utility.py +52 -0
  498. wbcore/contrib/example_app/tests/e2e/test_league.py +70 -0
  499. wbcore/contrib/example_app/tests/e2e/test_person.py +68 -0
  500. wbcore/contrib/example_app/tests/e2e/test_teams.py +57 -0
  501. wbcore/contrib/example_app/tests/signals.py +7 -0
  502. wbcore/contrib/example_app/tests/test_displays.py +41 -0
  503. wbcore/contrib/example_app/tests/test_filters.py +71 -0
  504. wbcore/contrib/example_app/tests/test_models/test_event.py +89 -0
  505. wbcore/contrib/example_app/tests/test_models/test_match.py +220 -0
  506. wbcore/contrib/example_app/tests/test_models/test_others.py +161 -0
  507. wbcore/contrib/example_app/tests/test_serializers/test_league_serializer.py +34 -0
  508. wbcore/contrib/example_app/tests/test_serializers/test_match_serializer.py +139 -0
  509. wbcore/contrib/example_app/tests/test_serializers/test_role_serializer.py +13 -0
  510. wbcore/contrib/example_app/tests/test_serializers/test_sport_serializer.py +14 -0
  511. wbcore/contrib/example_app/tests/test_serializers/test_stadium_serializer.py +14 -0
  512. wbcore/contrib/example_app/tests/test_serializers/test_team_result_serializer.py +30 -0
  513. wbcore/contrib/example_app/tests/test_serializers/test_team_serializer.py +70 -0
  514. wbcore/contrib/example_app/tests/test_utils.py +26 -0
  515. wbcore/contrib/example_app/tests/test_viewsets/test_event_viewset.py +167 -0
  516. wbcore/contrib/example_app/tests/test_viewsets/test_league_viewset.py +84 -0
  517. wbcore/contrib/example_app/tests/test_viewsets/test_match_viewset.py +65 -0
  518. wbcore/contrib/example_app/tests/test_viewsets/test_person_viewset.py +166 -0
  519. wbcore/contrib/example_app/tests/test_viewsets/test_role_viewset.py +75 -0
  520. wbcore/contrib/example_app/tests/test_viewsets/test_sport_viewset.py +75 -0
  521. wbcore/contrib/example_app/tests/test_viewsets/test_stadium_viewset.py +75 -0
  522. wbcore/contrib/example_app/tests/test_viewsets/test_team_viewset.py +92 -0
  523. wbcore/contrib/example_app/tests/test_viewsets/test_teamresult_viewset.py +58 -0
  524. wbcore/contrib/example_app/tests/test_viewsets/test_utils_viewsets.py +124 -0
  525. wbcore/contrib/example_app/urls.py +82 -0
  526. wbcore/contrib/example_app/utils.py +21 -0
  527. wbcore/contrib/example_app/views.py +6 -0
  528. wbcore/contrib/example_app/viewsets/__init__.py +29 -0
  529. wbcore/contrib/example_app/viewsets/buttons/__init__.py +2 -0
  530. wbcore/contrib/example_app/viewsets/buttons/person.py +19 -0
  531. wbcore/contrib/example_app/viewsets/buttons/team.py +24 -0
  532. wbcore/contrib/example_app/viewsets/displays/__init__.py +23 -0
  533. wbcore/contrib/example_app/viewsets/displays/event.py +187 -0
  534. wbcore/contrib/example_app/viewsets/displays/league.py +391 -0
  535. wbcore/contrib/example_app/viewsets/displays/match.py +265 -0
  536. wbcore/contrib/example_app/viewsets/displays/person.py +252 -0
  537. wbcore/contrib/example_app/viewsets/displays/role.py +17 -0
  538. wbcore/contrib/example_app/viewsets/displays/season.py +66 -0
  539. wbcore/contrib/example_app/viewsets/displays/sport.py +116 -0
  540. wbcore/contrib/example_app/viewsets/displays/stadium.py +150 -0
  541. wbcore/contrib/example_app/viewsets/displays/team.py +250 -0
  542. wbcore/contrib/example_app/viewsets/displays/teamresult.py +31 -0
  543. wbcore/contrib/example_app/viewsets/endpoints/__init__.py +12 -0
  544. wbcore/contrib/example_app/viewsets/endpoints/endpoints.py +80 -0
  545. wbcore/contrib/example_app/viewsets/event.py +288 -0
  546. wbcore/contrib/example_app/viewsets/league.py +73 -0
  547. wbcore/contrib/example_app/viewsets/match.py +120 -0
  548. wbcore/contrib/example_app/viewsets/menu/__init__.py +1 -0
  549. wbcore/contrib/example_app/viewsets/menu/menus.py +103 -0
  550. wbcore/contrib/example_app/viewsets/menus.py +64 -0
  551. wbcore/contrib/example_app/viewsets/person.py +134 -0
  552. wbcore/contrib/example_app/viewsets/role.py +25 -0
  553. wbcore/contrib/example_app/viewsets/season.py +23 -0
  554. wbcore/contrib/example_app/viewsets/sport.py +26 -0
  555. wbcore/contrib/example_app/viewsets/stadium.py +31 -0
  556. wbcore/contrib/example_app/viewsets/team.py +69 -0
  557. wbcore/contrib/example_app/viewsets/teamresult.py +107 -0
  558. wbcore/contrib/example_app/viewsets/titles/__init__.py +9 -0
  559. wbcore/contrib/example_app/viewsets/titles/event.py +42 -0
  560. wbcore/contrib/example_app/viewsets/titles/league.py +25 -0
  561. wbcore/contrib/example_app/viewsets/titles/match.py +35 -0
  562. wbcore/contrib/example_app/viewsets/titles/person.py +36 -0
  563. wbcore/contrib/example_app/viewsets/titles/role.py +14 -0
  564. wbcore/contrib/example_app/viewsets/titles/sport.py +14 -0
  565. wbcore/contrib/example_app/viewsets/titles/stadium.py +14 -0
  566. wbcore/contrib/example_app/viewsets/titles/team.py +25 -0
  567. wbcore/contrib/example_app/viewsets/titles/teamresult.py +13 -0
  568. wbcore/contrib/geography/__init__.py +0 -0
  569. wbcore/contrib/geography/admin.py +30 -0
  570. wbcore/contrib/geography/apps.py +5 -0
  571. wbcore/contrib/geography/factories.py +46 -0
  572. wbcore/contrib/geography/fixtures/geography.json +13454 -0
  573. wbcore/contrib/geography/import_export/__init__.py +0 -0
  574. wbcore/contrib/geography/import_export/resources/__init__.py +0 -0
  575. wbcore/contrib/geography/import_export/resources/geography.py +11 -0
  576. wbcore/contrib/geography/migrations/0001_initial.py +110 -0
  577. wbcore/contrib/geography/migrations/0002_geography_geography_geography_tree_i739a.py +17 -0
  578. wbcore/contrib/geography/migrations/__init__.py +0 -0
  579. wbcore/contrib/geography/models.py +150 -0
  580. wbcore/contrib/geography/release_notes/1_0_0.md +13 -0
  581. wbcore/contrib/geography/release_notes/__init__.py +0 -0
  582. wbcore/contrib/geography/serializers.py +29 -0
  583. wbcore/contrib/geography/static/geography/markdown/documentation/geography.md +16 -0
  584. wbcore/contrib/geography/tests/__init__.py +0 -0
  585. wbcore/contrib/geography/tests/conftest.py +26 -0
  586. wbcore/contrib/geography/tests/signals.py +7 -0
  587. wbcore/contrib/geography/tests/test_models.py +27 -0
  588. wbcore/contrib/geography/tests/test_viewsets.py +100 -0
  589. wbcore/contrib/geography/urls.py +13 -0
  590. wbcore/contrib/geography/viewsets/__init__.py +1 -0
  591. wbcore/contrib/geography/viewsets/buttons/__init__.py +0 -0
  592. wbcore/contrib/geography/viewsets/display/__init__.py +1 -0
  593. wbcore/contrib/geography/viewsets/display/geography.py +32 -0
  594. wbcore/contrib/geography/viewsets/endpoints/__init__.py +0 -0
  595. wbcore/contrib/geography/viewsets/geography.py +58 -0
  596. wbcore/contrib/geography/viewsets/menu/__init__.py +1 -0
  597. wbcore/contrib/geography/viewsets/menu/geography.py +8 -0
  598. wbcore/contrib/geography/viewsets/preview/__init__.py +1 -0
  599. wbcore/contrib/geography/viewsets/preview/geography.py +19 -0
  600. wbcore/contrib/geography/viewsets/titles/__init__.py +0 -0
  601. wbcore/contrib/geography/viewsets/titles/geography.py +14 -0
  602. wbcore/contrib/gleap/__init__.py +0 -0
  603. wbcore/contrib/gleap/apps.py +5 -0
  604. wbcore/contrib/gleap/configs.py +12 -0
  605. wbcore/contrib/gleap/configurations.py +6 -0
  606. wbcore/contrib/gleap/hashes.py +13 -0
  607. wbcore/contrib/gleap/tests/__init__.py +0 -0
  608. wbcore/contrib/gleap/tests/conftest.py +1 -0
  609. wbcore/contrib/gleap/tests/tests.py +29 -0
  610. wbcore/contrib/gleap/urls.py +8 -0
  611. wbcore/contrib/gleap/views.py +31 -0
  612. wbcore/contrib/guardian/apps.py +6 -0
  613. wbcore/contrib/guardian/configurations.py +3 -0
  614. wbcore/contrib/guardian/filters.py +21 -0
  615. wbcore/contrib/guardian/migrations/0001_initial.py +103 -0
  616. wbcore/contrib/guardian/migrations/__init__.py +0 -0
  617. wbcore/contrib/guardian/models/__init__.py +1 -0
  618. wbcore/contrib/guardian/models/mixins.py +139 -0
  619. wbcore/contrib/guardian/models/models.py +29 -0
  620. wbcore/contrib/guardian/tasks.py +11 -0
  621. wbcore/contrib/guardian/tests/__init__.py +0 -0
  622. wbcore/contrib/guardian/tests/conftest.py +1 -0
  623. wbcore/contrib/guardian/tests/test_model_mixins.py +92 -0
  624. wbcore/contrib/guardian/tests/test_tasks.py +77 -0
  625. wbcore/contrib/guardian/tests/test_utils.py +196 -0
  626. wbcore/contrib/guardian/tests/test_viewsets.py +48 -0
  627. wbcore/contrib/guardian/urls.py +12 -0
  628. wbcore/contrib/guardian/utils.py +124 -0
  629. wbcore/contrib/guardian/viewsets/__init__.py +1 -0
  630. wbcore/contrib/guardian/viewsets/configs/__init__.py +4 -0
  631. wbcore/contrib/guardian/viewsets/configs/buttons.py +36 -0
  632. wbcore/contrib/guardian/viewsets/configs/displays.py +43 -0
  633. wbcore/contrib/guardian/viewsets/configs/endpoints.py +25 -0
  634. wbcore/contrib/guardian/viewsets/configs/titles.py +16 -0
  635. wbcore/contrib/guardian/viewsets/mixins.py +6 -0
  636. wbcore/contrib/guardian/viewsets/viewsets.py +141 -0
  637. wbcore/contrib/i18n/__init__.py +2 -0
  638. wbcore/contrib/i18n/buttons.py +33 -0
  639. wbcore/contrib/i18n/serializers/__init__.py +0 -0
  640. wbcore/contrib/i18n/serializers/fields.py +20 -0
  641. wbcore/contrib/i18n/serializers/mixins.py +13 -0
  642. wbcore/contrib/i18n/tests/conftest.py +11 -0
  643. wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
  644. wbcore/contrib/i18n/translation.py +141 -0
  645. wbcore/contrib/i18n/viewsets.py +36 -0
  646. wbcore/contrib/icons/__init__.py +1 -0
  647. wbcore/contrib/icons/apps.py +5 -0
  648. wbcore/contrib/icons/backends/__init__.py +5 -0
  649. wbcore/contrib/icons/backends/default.py +375 -0
  650. wbcore/contrib/icons/backends/material.py +136 -0
  651. wbcore/contrib/icons/icons.py +167 -0
  652. wbcore/contrib/icons/models.py +11 -0
  653. wbcore/contrib/icons/serializers.py +18 -0
  654. wbcore/contrib/io/__init__.py +0 -0
  655. wbcore/contrib/io/admin.py +151 -0
  656. wbcore/contrib/io/apps.py +37 -0
  657. wbcore/contrib/io/backends/__init__.py +3 -0
  658. wbcore/contrib/io/backends/abstract.py +60 -0
  659. wbcore/contrib/io/backends/mail.py +39 -0
  660. wbcore/contrib/io/backends/utils.py +39 -0
  661. wbcore/contrib/io/configs/__init__.py +0 -0
  662. wbcore/contrib/io/configs/endpoints.py +13 -0
  663. wbcore/contrib/io/configurations/__init__.py +1 -0
  664. wbcore/contrib/io/configurations/base.py +7 -0
  665. wbcore/contrib/io/dynamic_preferences_registry.py +25 -0
  666. wbcore/contrib/io/enums.py +15 -0
  667. wbcore/contrib/io/exceptions.py +24 -0
  668. wbcore/contrib/io/factories.py +205 -0
  669. wbcore/contrib/io/fixtures/io.json +145 -0
  670. wbcore/contrib/io/import_export/backends/__init__.py +3 -0
  671. wbcore/contrib/io/import_export/backends/mail.py +51 -0
  672. wbcore/contrib/io/import_export/backends/sftp.py +69 -0
  673. wbcore/contrib/io/import_export/backends/stream.py +92 -0
  674. wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
  675. wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
  676. wbcore/contrib/io/import_export/parsers/resources.py +50 -0
  677. wbcore/contrib/io/imports.py +313 -0
  678. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +144 -0
  679. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
  680. wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
  681. wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
  682. wbcore/contrib/io/management/__init__.py +13 -0
  683. wbcore/contrib/io/migrations/0001_initial_squashed.py +319 -0
  684. wbcore/contrib/io/migrations/0002_importsource_creator.py +26 -0
  685. wbcore/contrib/io/migrations/0003_auto_20240103_1000.py +46 -0
  686. wbcore/contrib/io/migrations/0004_alter_importsource_status_exportsource.py +134 -0
  687. wbcore/contrib/io/migrations/0005_exportsource_data_alter_exportsource_query_str_and_more.py +67 -0
  688. wbcore/contrib/io/migrations/0006_alter_exportsource_query_params.py +20 -0
  689. wbcore/contrib/io/migrations/0007_alter_exportsource_query_params.py +23 -0
  690. wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
  691. wbcore/contrib/io/migrations/__init__.py +0 -0
  692. wbcore/contrib/io/mixins.py +37 -0
  693. wbcore/contrib/io/models.py +1037 -0
  694. wbcore/contrib/io/release_notes/1_0_0.md +13 -0
  695. wbcore/contrib/io/release_notes/__init__.py +0 -0
  696. wbcore/contrib/io/resources.py +176 -0
  697. wbcore/contrib/io/serializers.py +137 -0
  698. wbcore/contrib/io/signals.py +4 -0
  699. wbcore/contrib/io/tasks.py +27 -0
  700. wbcore/contrib/io/tests/__init__.py +0 -0
  701. wbcore/contrib/io/tests/conftest.py +42 -0
  702. wbcore/contrib/io/tests/test_backends.py +134 -0
  703. wbcore/contrib/io/tests/test_exports.py +130 -0
  704. wbcore/contrib/io/tests/test_imports.py +168 -0
  705. wbcore/contrib/io/tests/test_models.py +396 -0
  706. wbcore/contrib/io/tests/test_viewsets.py +271 -0
  707. wbcore/contrib/io/urls.py +29 -0
  708. wbcore/contrib/io/utils.py +44 -0
  709. wbcore/contrib/io/viewset_mixins.py +271 -0
  710. wbcore/contrib/io/viewsets.py +139 -0
  711. wbcore/contrib/notifications/__init__.py +0 -0
  712. wbcore/contrib/notifications/admin.py +63 -0
  713. wbcore/contrib/notifications/apps.py +43 -0
  714. wbcore/contrib/notifications/backends/__init__.py +0 -0
  715. wbcore/contrib/notifications/backends/abstract_backend.py +11 -0
  716. wbcore/contrib/notifications/backends/console/__init__.py +1 -0
  717. wbcore/contrib/notifications/backends/console/backends.py +25 -0
  718. wbcore/contrib/notifications/backends/firebase/__init__.py +1 -0
  719. wbcore/contrib/notifications/backends/firebase/backends.py +106 -0
  720. wbcore/contrib/notifications/configs.py +13 -0
  721. wbcore/contrib/notifications/configurations.py +9 -0
  722. wbcore/contrib/notifications/dispatch.py +90 -0
  723. wbcore/contrib/notifications/factories/__init__.py +0 -0
  724. wbcore/contrib/notifications/factories/notification_types.py +24 -0
  725. wbcore/contrib/notifications/factories/notifications.py +17 -0
  726. wbcore/contrib/notifications/factories/tokens.py +12 -0
  727. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +66 -0
  728. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
  729. wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
  730. wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
  731. wbcore/contrib/notifications/migrations/0001_initial.py +116 -0
  732. wbcore/contrib/notifications/migrations/0002_notificationusertoken_unique_user_token_device.py +18 -0
  733. wbcore/contrib/notifications/migrations/0003_notificationusertoken_updated.py +17 -0
  734. wbcore/contrib/notifications/migrations/0004_alter_notification_body.py +17 -0
  735. wbcore/contrib/notifications/migrations/0005_alter_notification_endpoint.py +17 -0
  736. wbcore/contrib/notifications/migrations/0006_notification_created.py +25 -0
  737. wbcore/contrib/notifications/migrations/0007_notificationtype_resource_button_label.py +19 -0
  738. wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
  739. wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
  740. wbcore/contrib/notifications/migrations/__init__.py +0 -0
  741. wbcore/contrib/notifications/models/__init__.py +3 -0
  742. wbcore/contrib/notifications/models/notification_types.py +165 -0
  743. wbcore/contrib/notifications/models/notifications.py +82 -0
  744. wbcore/contrib/notifications/models/tokens.py +46 -0
  745. wbcore/contrib/notifications/release_notes/1_0_0.md +13 -0
  746. wbcore/contrib/notifications/release_notes/__init__.py +0 -0
  747. wbcore/contrib/notifications/serializers/__init__.py +5 -0
  748. wbcore/contrib/notifications/serializers/notification_types.py +51 -0
  749. wbcore/contrib/notifications/serializers/notifications.py +33 -0
  750. wbcore/contrib/notifications/static/notifications/service-worker.js +1 -0
  751. wbcore/contrib/notifications/tasks.py +57 -0
  752. wbcore/contrib/notifications/templates/notifications/notification_template.html +43 -0
  753. wbcore/contrib/notifications/tests/__init__.py +0 -0
  754. wbcore/contrib/notifications/tests/conftest.py +47 -0
  755. wbcore/contrib/notifications/tests/test_backends/__init__.py +0 -0
  756. wbcore/contrib/notifications/tests/test_backends/test_firebase.py +79 -0
  757. wbcore/contrib/notifications/tests/test_configs.py +7 -0
  758. wbcore/contrib/notifications/tests/test_models/__init__.py +0 -0
  759. wbcore/contrib/notifications/tests/test_models/test_notification_types.py +85 -0
  760. wbcore/contrib/notifications/tests/test_models/test_notifications.py +46 -0
  761. wbcore/contrib/notifications/tests/test_models/test_tokens.py +30 -0
  762. wbcore/contrib/notifications/tests/test_serializers/__init__.py +0 -0
  763. wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +59 -0
  764. wbcore/contrib/notifications/tests/test_serializers/test_notifications.py +24 -0
  765. wbcore/contrib/notifications/tests/test_tasks.py +72 -0
  766. wbcore/contrib/notifications/tests/test_utils.py +0 -0
  767. wbcore/contrib/notifications/tests/test_viewsets/__init__.py +0 -0
  768. wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +120 -0
  769. wbcore/contrib/notifications/tests/test_viewsets/test_notifications.py +143 -0
  770. wbcore/contrib/notifications/urls.py +27 -0
  771. wbcore/contrib/notifications/utils.py +27 -0
  772. wbcore/contrib/notifications/views.py +63 -0
  773. wbcore/contrib/notifications/viewsets/__init__.py +5 -0
  774. wbcore/contrib/notifications/viewsets/configs/notification_types.py +49 -0
  775. wbcore/contrib/notifications/viewsets/configs/notifications.py +91 -0
  776. wbcore/contrib/notifications/viewsets/menus.py +15 -0
  777. wbcore/contrib/notifications/viewsets/notification_types.py +51 -0
  778. wbcore/contrib/notifications/viewsets/notifications.py +58 -0
  779. wbcore/contrib/pandas/__init__.py +0 -0
  780. wbcore/contrib/pandas/fields.py +172 -0
  781. wbcore/contrib/pandas/filters.py +118 -0
  782. wbcore/contrib/pandas/filterset.py +28 -0
  783. wbcore/contrib/pandas/metadata.py +15 -0
  784. wbcore/contrib/pandas/tests/__init__.py +0 -0
  785. wbcore/contrib/pandas/tests/test_base.py +22 -0
  786. wbcore/contrib/pandas/tests/test_fields/__init__.py +0 -0
  787. wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +19 -0
  788. wbcore/contrib/pandas/tests/test_filters/__init__.py +0 -0
  789. wbcore/contrib/pandas/tests/test_filters/test_pandas.py +115 -0
  790. wbcore/contrib/pandas/tests/test_views.py +22 -0
  791. wbcore/contrib/pandas/utils.py +170 -0
  792. wbcore/contrib/pandas/views.py +158 -0
  793. wbcore/contrib/tags/__init__.py +0 -0
  794. wbcore/contrib/tags/admin.py +17 -0
  795. wbcore/contrib/tags/apps.py +9 -0
  796. wbcore/contrib/tags/factories.py +28 -0
  797. wbcore/contrib/tags/filters.py +43 -0
  798. wbcore/contrib/tags/migrations/0001_initial.py +62 -0
  799. wbcore/contrib/tags/migrations/__init__.py +0 -0
  800. wbcore/contrib/tags/models/__init__.py +2 -0
  801. wbcore/contrib/tags/models/mixins.py +27 -0
  802. wbcore/contrib/tags/models/tags.py +107 -0
  803. wbcore/contrib/tags/release_notes/1_0_0.md +13 -0
  804. wbcore/contrib/tags/release_notes/__init__.py +0 -0
  805. wbcore/contrib/tags/serializers.py +90 -0
  806. wbcore/contrib/tags/signals.py +19 -0
  807. wbcore/contrib/tags/tests/__init__.py +0 -0
  808. wbcore/contrib/tags/tests/conftest.py +7 -0
  809. wbcore/contrib/tags/tests/tests.py +144 -0
  810. wbcore/contrib/tags/urls.py +15 -0
  811. wbcore/contrib/tags/viewsets/__init__.py +10 -0
  812. wbcore/contrib/tags/viewsets/display.py +50 -0
  813. wbcore/contrib/tags/viewsets/menu.py +15 -0
  814. wbcore/contrib/tags/viewsets/viewsets.py +58 -0
  815. wbcore/contrib/workflow/__init__.py +1 -0
  816. wbcore/contrib/workflow/admin/__init__.py +15 -0
  817. wbcore/contrib/workflow/admin/condition.py +9 -0
  818. wbcore/contrib/workflow/admin/data.py +15 -0
  819. wbcore/contrib/workflow/admin/display.py +9 -0
  820. wbcore/contrib/workflow/admin/process.py +37 -0
  821. wbcore/contrib/workflow/admin/step.py +92 -0
  822. wbcore/contrib/workflow/admin/transition.py +9 -0
  823. wbcore/contrib/workflow/admin/workflow.py +9 -0
  824. wbcore/contrib/workflow/apps.py +25 -0
  825. wbcore/contrib/workflow/configs.py +11 -0
  826. wbcore/contrib/workflow/decorators.py +25 -0
  827. wbcore/contrib/workflow/dispatch.py +24 -0
  828. wbcore/contrib/workflow/factories/__init__.py +18 -0
  829. wbcore/contrib/workflow/factories/condition.py +16 -0
  830. wbcore/contrib/workflow/factories/data.py +23 -0
  831. wbcore/contrib/workflow/factories/display.py +28 -0
  832. wbcore/contrib/workflow/factories/process.py +70 -0
  833. wbcore/contrib/workflow/factories/step.py +157 -0
  834. wbcore/contrib/workflow/factories/transition.py +27 -0
  835. wbcore/contrib/workflow/factories/workflow.py +20 -0
  836. wbcore/contrib/workflow/filters/__init__.py +24 -0
  837. wbcore/contrib/workflow/filters/condition.py +24 -0
  838. wbcore/contrib/workflow/filters/data.py +25 -0
  839. wbcore/contrib/workflow/filters/process.py +165 -0
  840. wbcore/contrib/workflow/filters/step.py +227 -0
  841. wbcore/contrib/workflow/filters/transition.py +42 -0
  842. wbcore/contrib/workflow/filters/workflow.py +44 -0
  843. wbcore/contrib/workflow/fixtures/workflow.json +612 -0
  844. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +1180 -0
  845. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
  846. wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
  847. wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
  848. wbcore/contrib/workflow/migrations/0001_initial.py +788 -0
  849. wbcore/contrib/workflow/migrations/0002_alter_step_step_type.py +31 -0
  850. wbcore/contrib/workflow/migrations/0003_alter_condition_attribute_name_and_more.py +75 -0
  851. wbcore/contrib/workflow/migrations/0004_alter_userstep_assignee_method.py +27 -0
  852. wbcore/contrib/workflow/migrations/0005_alter_userstep_assignee_method.py +17 -0
  853. wbcore/contrib/workflow/migrations/__init__.py +0 -0
  854. wbcore/contrib/workflow/models/__init__.py +19 -0
  855. wbcore/contrib/workflow/models/condition.py +124 -0
  856. wbcore/contrib/workflow/models/data.py +242 -0
  857. wbcore/contrib/workflow/models/display.py +34 -0
  858. wbcore/contrib/workflow/models/process.py +244 -0
  859. wbcore/contrib/workflow/models/step.py +778 -0
  860. wbcore/contrib/workflow/models/transition.py +71 -0
  861. wbcore/contrib/workflow/models/workflow.py +317 -0
  862. wbcore/contrib/workflow/serializers/__init__.py +37 -0
  863. wbcore/contrib/workflow/serializers/condition.py +65 -0
  864. wbcore/contrib/workflow/serializers/data.py +136 -0
  865. wbcore/contrib/workflow/serializers/display.py +25 -0
  866. wbcore/contrib/workflow/serializers/process.py +184 -0
  867. wbcore/contrib/workflow/serializers/signals.py +26 -0
  868. wbcore/contrib/workflow/serializers/step.py +365 -0
  869. wbcore/contrib/workflow/serializers/transition.py +81 -0
  870. wbcore/contrib/workflow/serializers/workflow.py +125 -0
  871. wbcore/contrib/workflow/sites.py +43 -0
  872. wbcore/contrib/workflow/static/workflow/markdown/documentation/assignedprocessstep.md +33 -0
  873. wbcore/contrib/workflow/static/workflow/markdown/documentation/condition.md +24 -0
  874. wbcore/contrib/workflow/static/workflow/markdown/documentation/decisionstep.md +30 -0
  875. wbcore/contrib/workflow/static/workflow/markdown/documentation/emailstep.md +45 -0
  876. wbcore/contrib/workflow/static/workflow/markdown/documentation/finishstep.md +33 -0
  877. wbcore/contrib/workflow/static/workflow/markdown/documentation/joinstep.md +33 -0
  878. wbcore/contrib/workflow/static/workflow/markdown/documentation/process.md +33 -0
  879. wbcore/contrib/workflow/static/workflow/markdown/documentation/processstep.md +51 -0
  880. wbcore/contrib/workflow/static/workflow/markdown/documentation/scriptstep.md +33 -0
  881. wbcore/contrib/workflow/static/workflow/markdown/documentation/splitstep.md +30 -0
  882. wbcore/contrib/workflow/static/workflow/markdown/documentation/startstep.md +27 -0
  883. wbcore/contrib/workflow/static/workflow/markdown/documentation/transition.md +27 -0
  884. wbcore/contrib/workflow/static/workflow/markdown/documentation/userstep.md +42 -0
  885. wbcore/contrib/workflow/static/workflow/markdown/documentation/workflow.md +32 -0
  886. wbcore/contrib/workflow/templates/Test_Templates.txt +25 -0
  887. wbcore/contrib/workflow/tests/__init__.py +0 -0
  888. wbcore/contrib/workflow/tests/conftest.py +281 -0
  889. wbcore/contrib/workflow/tests/test_configs.py +6 -0
  890. wbcore/contrib/workflow/tests/test_dispatch.py +94 -0
  891. wbcore/contrib/workflow/tests/test_displays.py +42 -0
  892. wbcore/contrib/workflow/tests/test_filters.py +104 -0
  893. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +82 -0
  894. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +85 -0
  895. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +167 -0
  896. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +117 -0
  897. wbcore/contrib/workflow/tests/test_models/step/test_script_step.py +24 -0
  898. wbcore/contrib/workflow/tests/test_models/step/test_split_step.py +49 -0
  899. wbcore/contrib/workflow/tests/test_models/step/test_step.py +756 -0
  900. wbcore/contrib/workflow/tests/test_models/step/test_user_step.py +225 -0
  901. wbcore/contrib/workflow/tests/test_models/test_condition.py +103 -0
  902. wbcore/contrib/workflow/tests/test_models/test_data.py +134 -0
  903. wbcore/contrib/workflow/tests/test_models/test_process.py +98 -0
  904. wbcore/contrib/workflow/tests/test_models/test_transition.py +128 -0
  905. wbcore/contrib/workflow/tests/test_models/test_workflow.py +358 -0
  906. wbcore/contrib/workflow/tests/test_serializers.py +200 -0
  907. wbcore/contrib/workflow/tests/test_viewsets.py +300 -0
  908. wbcore/contrib/workflow/tests/test_workflow_assignees.py +236 -0
  909. wbcore/contrib/workflow/urls.py +67 -0
  910. wbcore/contrib/workflow/utils.py +13 -0
  911. wbcore/contrib/workflow/viewsets/__init__.py +17 -0
  912. wbcore/contrib/workflow/viewsets/buttons/__init__.py +1 -0
  913. wbcore/contrib/workflow/viewsets/buttons/step.py +68 -0
  914. wbcore/contrib/workflow/viewsets/condition.py +32 -0
  915. wbcore/contrib/workflow/viewsets/data.py +33 -0
  916. wbcore/contrib/workflow/viewsets/display/__init__.py +15 -0
  917. wbcore/contrib/workflow/viewsets/display/condition.py +51 -0
  918. wbcore/contrib/workflow/viewsets/display/data.py +51 -0
  919. wbcore/contrib/workflow/viewsets/display/process.py +186 -0
  920. wbcore/contrib/workflow/viewsets/display/step.py +454 -0
  921. wbcore/contrib/workflow/viewsets/display/transition.py +76 -0
  922. wbcore/contrib/workflow/viewsets/display/workflow.py +168 -0
  923. wbcore/contrib/workflow/viewsets/endpoints/__init__.py +5 -0
  924. wbcore/contrib/workflow/viewsets/endpoints/condition.py +9 -0
  925. wbcore/contrib/workflow/viewsets/endpoints/data.py +9 -0
  926. wbcore/contrib/workflow/viewsets/endpoints/process.py +11 -0
  927. wbcore/contrib/workflow/viewsets/endpoints/step.py +24 -0
  928. wbcore/contrib/workflow/viewsets/endpoints/transition.py +19 -0
  929. wbcore/contrib/workflow/viewsets/menu/__init__.py +15 -0
  930. wbcore/contrib/workflow/viewsets/menu/condition.py +19 -0
  931. wbcore/contrib/workflow/viewsets/menu/data.py +19 -0
  932. wbcore/contrib/workflow/viewsets/menu/process.py +19 -0
  933. wbcore/contrib/workflow/viewsets/menu/step.py +124 -0
  934. wbcore/contrib/workflow/viewsets/menu/transition.py +19 -0
  935. wbcore/contrib/workflow/viewsets/menu/workflow.py +19 -0
  936. wbcore/contrib/workflow/viewsets/process.py +175 -0
  937. wbcore/contrib/workflow/viewsets/step.py +229 -0
  938. wbcore/contrib/workflow/viewsets/titles/__init__.py +16 -0
  939. wbcore/contrib/workflow/viewsets/titles/condition.py +14 -0
  940. wbcore/contrib/workflow/viewsets/titles/data.py +14 -0
  941. wbcore/contrib/workflow/viewsets/titles/process.py +27 -0
  942. wbcore/contrib/workflow/viewsets/titles/step.py +102 -0
  943. wbcore/contrib/workflow/viewsets/titles/transition.py +14 -0
  944. wbcore/contrib/workflow/viewsets/titles/workflow.py +14 -0
  945. wbcore/contrib/workflow/viewsets/transition.py +58 -0
  946. wbcore/contrib/workflow/viewsets/workflow.py +37 -0
  947. wbcore/contrib/workflow/workflows/__init__.py +1 -0
  948. wbcore/contrib/workflow/workflows/assignees.py +88 -0
  949. wbcore/crontab/__init__.py +0 -0
  950. wbcore/crontab/serializers.py +24 -0
  951. wbcore/crontab/viewsets.py +10 -0
  952. wbcore/dispatch.py +56 -0
  953. wbcore/docs/__init__.py +23 -0
  954. wbcore/docs/orderable.md +29 -0
  955. wbcore/docs/reparent.md +13 -0
  956. wbcore/dynamic_preferences_registry.py +131 -0
  957. wbcore/enums.py +50 -0
  958. wbcore/filters/__init__.py +21 -0
  959. wbcore/filters/backends.py +19 -0
  960. wbcore/filters/defaults.py +70 -0
  961. wbcore/filters/fields/__init__.py +15 -0
  962. wbcore/filters/fields/booleans.py +7 -0
  963. wbcore/filters/fields/choices.py +60 -0
  964. wbcore/filters/fields/content_type.py +45 -0
  965. wbcore/filters/fields/datetime.py +117 -0
  966. wbcore/filters/fields/models.py +123 -0
  967. wbcore/filters/fields/multiple_lookups.py +20 -0
  968. wbcore/filters/fields/numbers.py +48 -0
  969. wbcore/filters/fields/text.py +7 -0
  970. wbcore/filters/filterset.py +250 -0
  971. wbcore/filters/lookups.py +41 -0
  972. wbcore/filters/mixins.py +111 -0
  973. wbcore/filters/utils.py +21 -0
  974. wbcore/forms.py +125 -0
  975. wbcore/frontend.py +23 -0
  976. wbcore/frontend_user_configuration.py +96 -0
  977. wbcore/fsm/__init__.py +0 -0
  978. wbcore/fsm/markdown_extensions.py +31 -0
  979. wbcore/fsm/mixins.py +128 -0
  980. wbcore/locale/de/LC_MESSAGES/django.po +1252 -0
  981. wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
  982. wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
  983. wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
  984. wbcore/management/__init__.py +88 -0
  985. wbcore/management/commands/__init__.py +0 -0
  986. wbcore/management/commands/bootstrap.py +18 -0
  987. wbcore/management/commands/clean_obsolete_object.py +21 -0
  988. wbcore/management/commands/handle_release_notes.py +54 -0
  989. wbcore/markdown/__init__.py +1 -0
  990. wbcore/markdown/admin.py +9 -0
  991. wbcore/markdown/dynamic_preferences_registry.py +16 -0
  992. wbcore/markdown/models.py +41 -0
  993. wbcore/markdown/template.py +38 -0
  994. wbcore/markdown/utils.py +37 -0
  995. wbcore/markdown/views.py +50 -0
  996. wbcore/menus/__init__.py +2 -0
  997. wbcore/menus/menus.py +96 -0
  998. wbcore/menus/registry.py +28 -0
  999. wbcore/menus/views.py +41 -0
  1000. wbcore/messages.py +60 -0
  1001. wbcore/metadata/__init__.py +0 -0
  1002. wbcore/metadata/configs/__init__.py +0 -0
  1003. wbcore/metadata/configs/base.py +86 -0
  1004. wbcore/metadata/configs/buttons/__init__.py +4 -0
  1005. wbcore/metadata/configs/buttons/bases.py +89 -0
  1006. wbcore/metadata/configs/buttons/buttons.py +138 -0
  1007. wbcore/metadata/configs/buttons/enums.py +68 -0
  1008. wbcore/metadata/configs/buttons/metadata.py +8 -0
  1009. wbcore/metadata/configs/buttons/view_config.py +145 -0
  1010. wbcore/metadata/configs/display/__init__.py +4 -0
  1011. wbcore/metadata/configs/display/configs.py +16 -0
  1012. wbcore/metadata/configs/display/display.py +234 -0
  1013. wbcore/metadata/configs/display/formatting.py +47 -0
  1014. wbcore/metadata/configs/display/instance_display/__init__.py +15 -0
  1015. wbcore/metadata/configs/display/instance_display/display.py +40 -0
  1016. wbcore/metadata/configs/display/instance_display/enums.py +7 -0
  1017. wbcore/metadata/configs/display/instance_display/layouts/__init__.py +3 -0
  1018. wbcore/metadata/configs/display/instance_display/layouts/inlines.py +58 -0
  1019. wbcore/metadata/configs/display/instance_display/layouts/layouts.py +77 -0
  1020. wbcore/metadata/configs/display/instance_display/layouts/sections.py +43 -0
  1021. wbcore/metadata/configs/display/instance_display/operators.py +22 -0
  1022. wbcore/metadata/configs/display/instance_display/pages.py +40 -0
  1023. wbcore/metadata/configs/display/instance_display/shortcuts.py +81 -0
  1024. wbcore/metadata/configs/display/instance_display/signals.py +3 -0
  1025. wbcore/metadata/configs/display/instance_display/styles.py +42 -0
  1026. wbcore/metadata/configs/display/instance_display/utils.py +74 -0
  1027. wbcore/metadata/configs/display/list_display.py +290 -0
  1028. wbcore/metadata/configs/display/models.py +26 -0
  1029. wbcore/metadata/configs/display/view_config.py +85 -0
  1030. wbcore/metadata/configs/display/views.py +48 -0
  1031. wbcore/metadata/configs/display/windows.py +28 -0
  1032. wbcore/metadata/configs/documentations.py +11 -0
  1033. wbcore/metadata/configs/endpoints.py +189 -0
  1034. wbcore/metadata/configs/fields.py +22 -0
  1035. wbcore/metadata/configs/filter_fields.py +41 -0
  1036. wbcore/metadata/configs/identifiers.py +27 -0
  1037. wbcore/metadata/configs/ordering_fields.py +24 -0
  1038. wbcore/metadata/configs/paginations.py +11 -0
  1039. wbcore/metadata/configs/preview.py +41 -0
  1040. wbcore/metadata/configs/primary_keys.py +9 -0
  1041. wbcore/metadata/configs/search_fields.py +9 -0
  1042. wbcore/metadata/configs/titles.py +48 -0
  1043. wbcore/metadata/configs/window_types.py +13 -0
  1044. wbcore/metadata/exceptions.py +0 -0
  1045. wbcore/metadata/metadata.py +34 -0
  1046. wbcore/metadata/mixins.py +106 -0
  1047. wbcore/metadata/tests/__init__.py +0 -0
  1048. wbcore/metadata/tests/test_buttons.py +165 -0
  1049. wbcore/metadata/utils.py +4 -0
  1050. wbcore/migrations/0001_initial_squashed_squashed_0010_preset_appliedpreset.py +398 -0
  1051. wbcore/migrations/0011_genericmodel.py +22 -0
  1052. wbcore/migrations/0012_delete_notification.py +15 -0
  1053. wbcore/migrations/0013_delete_colorgradient.py +14 -0
  1054. wbcore/migrations/0014_biguserobjectpermission_system.py +44 -0
  1055. wbcore/migrations/__init__.py +0 -0
  1056. wbcore/models/__init__.py +6 -0
  1057. wbcore/models/base.py +184 -0
  1058. wbcore/models/fields.py +29 -0
  1059. wbcore/models/orderable.py +6 -0
  1060. wbcore/pagination.py +64 -0
  1061. wbcore/pandas/__init__.py +53 -0
  1062. wbcore/pandas/fields.py +25 -0
  1063. wbcore/pandas/filterset.py +9 -0
  1064. wbcore/pandas/utils.py +25 -0
  1065. wbcore/pandas/views.py +9 -0
  1066. wbcore/permissions/__init__.py +0 -0
  1067. wbcore/permissions/backend.py +36 -0
  1068. wbcore/permissions/mixins.py +72 -0
  1069. wbcore/permissions/permissions.py +51 -0
  1070. wbcore/permissions/registry.py +33 -0
  1071. wbcore/permissions/shortcuts.py +38 -0
  1072. wbcore/permissions/utils.py +26 -0
  1073. wbcore/release_notes/__init__.py +0 -0
  1074. wbcore/release_notes/admin.py +30 -0
  1075. wbcore/release_notes/buttons.py +26 -0
  1076. wbcore/release_notes/display.py +52 -0
  1077. wbcore/release_notes/filters.py +36 -0
  1078. wbcore/release_notes/models.py +66 -0
  1079. wbcore/release_notes/serializers.py +12 -0
  1080. wbcore/release_notes/utils.py +14 -0
  1081. wbcore/release_notes/viewsets.py +52 -0
  1082. wbcore/reversion/__init__.py +0 -0
  1083. wbcore/reversion/filters.py +39 -0
  1084. wbcore/reversion/serializers.py +81 -0
  1085. wbcore/reversion/viewsets/__init__.py +6 -0
  1086. wbcore/reversion/viewsets/buttons.py +95 -0
  1087. wbcore/reversion/viewsets/displays.py +45 -0
  1088. wbcore/reversion/viewsets/endpoints.py +30 -0
  1089. wbcore/reversion/viewsets/titles.py +19 -0
  1090. wbcore/reversion/viewsets/viewsets.py +112 -0
  1091. wbcore/routers.py +63 -0
  1092. wbcore/search/__init__.py +62 -0
  1093. wbcore/serializers/__init__.py +68 -0
  1094. wbcore/serializers/fields/__init__.py +59 -0
  1095. wbcore/serializers/fields/boolean.py +51 -0
  1096. wbcore/serializers/fields/choice.py +60 -0
  1097. wbcore/serializers/fields/datetime.py +178 -0
  1098. wbcore/serializers/fields/fields.py +193 -0
  1099. wbcore/serializers/fields/file.py +20 -0
  1100. wbcore/serializers/fields/fsm.py +20 -0
  1101. wbcore/serializers/fields/json.py +56 -0
  1102. wbcore/serializers/fields/list.py +104 -0
  1103. wbcore/serializers/fields/mixins.py +196 -0
  1104. wbcore/serializers/fields/number.py +94 -0
  1105. wbcore/serializers/fields/other.py +34 -0
  1106. wbcore/serializers/fields/primary_key.py +22 -0
  1107. wbcore/serializers/fields/related.py +150 -0
  1108. wbcore/serializers/fields/text.py +141 -0
  1109. wbcore/serializers/fields/types.py +46 -0
  1110. wbcore/serializers/mixins.py +24 -0
  1111. wbcore/serializers/serializers.py +425 -0
  1112. wbcore/serializers/utils.py +143 -0
  1113. wbcore/shares/__init__.py +1 -0
  1114. wbcore/shares/config.py +64 -0
  1115. wbcore/shares/decorator.py +13 -0
  1116. wbcore/shares/signals.py +3 -0
  1117. wbcore/shares/sites.py +29 -0
  1118. wbcore/shares/views.py +25 -0
  1119. wbcore/signals/__init__.py +7 -0
  1120. wbcore/signals/clone.py +4 -0
  1121. wbcore/signals/filters.py +3 -0
  1122. wbcore/signals/instance_buttons.py +5 -0
  1123. wbcore/signals/merge.py +4 -0
  1124. wbcore/signals/models.py +4 -0
  1125. wbcore/signals/permissions.py +3 -0
  1126. wbcore/signals/serializers.py +5 -0
  1127. wbcore/tasks.py +87 -0
  1128. wbcore/template.py +29 -0
  1129. wbcore/templates/errors/404.html +134 -0
  1130. wbcore/templates/errors/500.html +138 -0
  1131. wbcore/templates/errors/503.html +132 -0
  1132. wbcore/templates/errors/custom.html +132 -0
  1133. wbcore/templates/forms.py +0 -0
  1134. wbcore/templates/notifications/email_template.html +43 -0
  1135. wbcore/templates/reversion/__init__.py +0 -0
  1136. wbcore/templates/reversion/compare_detail.html +19 -0
  1137. wbcore/templates/wbcore/admin/change_list.html +8 -0
  1138. wbcore/templates/wbcore/admin/csv_form.html +15 -0
  1139. wbcore/templates/wbcore/dynamic_color_array.html +29 -0
  1140. wbcore/templates/wbcore/email_base_template.html +335 -0
  1141. wbcore/templates/wbcore/email_notification_template.html +10 -0
  1142. wbcore/templates/wbcore/frontend.html +51 -0
  1143. wbcore/test/__init__.py +30 -0
  1144. wbcore/test/e2e_helpers_methods/e2e_checks.py +127 -0
  1145. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +397 -0
  1146. wbcore/test/mixins.py +660 -0
  1147. wbcore/test/signals.py +6 -0
  1148. wbcore/test/tests.py +129 -0
  1149. wbcore/test/utils.py +227 -0
  1150. wbcore/tests/__init__.py +0 -0
  1151. wbcore/tests/conftest.py +55 -0
  1152. wbcore/tests/e2e/__init__.py +0 -0
  1153. wbcore/tests/e2e/test_e2e.py +25 -0
  1154. wbcore/tests/models.py +6 -0
  1155. wbcore/tests/test_cache/__init__.py +0 -0
  1156. wbcore/tests/test_cache/test_decorators.py +28 -0
  1157. wbcore/tests/test_cache/test_mixins.py +30 -0
  1158. wbcore/tests/test_cache/test_registry.py +58 -0
  1159. wbcore/tests/test_configs.py +58 -0
  1160. wbcore/tests/test_enums.py +56 -0
  1161. wbcore/tests/test_fields/__init__.py +0 -0
  1162. wbcore/tests/test_fields/test_boolean_fields.py +49 -0
  1163. wbcore/tests/test_fields/test_choice_fields.py +57 -0
  1164. wbcore/tests/test_fields/test_datetime_fields.py +152 -0
  1165. wbcore/tests/test_fields/test_fields.py +24 -0
  1166. wbcore/tests/test_fields/test_file_fields.py +52 -0
  1167. wbcore/tests/test_fields/test_json_fields.py +28 -0
  1168. wbcore/tests/test_fields/test_list_fields.py +27 -0
  1169. wbcore/tests/test_fields/test_mixins.py +112 -0
  1170. wbcore/tests/test_fields/test_number_fields.py +166 -0
  1171. wbcore/tests/test_fields/test_other_fields.py +60 -0
  1172. wbcore/tests/test_fields/test_primary_key_fields.py +52 -0
  1173. wbcore/tests/test_fields/test_related.py +81 -0
  1174. wbcore/tests/test_fields/test_text_fields.py +118 -0
  1175. wbcore/tests/test_filters/__init__.py +0 -0
  1176. wbcore/tests/test_filters/test_mixins.py +109 -0
  1177. wbcore/tests/test_list_display.py +29 -0
  1178. wbcore/tests/test_models/__init__.py +0 -0
  1179. wbcore/tests/test_models/test_fields.py +26 -0
  1180. wbcore/tests/test_models/test_mixins.py +32 -0
  1181. wbcore/tests/test_new_display/__init__.py +0 -0
  1182. wbcore/tests/test_new_display/test_inlines.py +13 -0
  1183. wbcore/tests/test_new_display/test_layouts.py +15 -0
  1184. wbcore/tests/test_new_display/test_operators.py +16 -0
  1185. wbcore/tests/test_new_display/test_pages.py +8 -0
  1186. wbcore/tests/test_new_display/test_sections.py +0 -0
  1187. wbcore/tests/test_new_display/test_shortcuts.py +38 -0
  1188. wbcore/tests/test_new_display/test_utils.py +49 -0
  1189. wbcore/tests/test_pagination.py +32 -0
  1190. wbcore/tests/test_permissions/test_backend.py +29 -0
  1191. wbcore/tests/test_serializers/__init__.py +0 -0
  1192. wbcore/tests/test_serializers/test_fields.py +141 -0
  1193. wbcore/tests/test_serializers/test_mixins.py +54 -0
  1194. wbcore/tests/test_serializers/test_related.py +78 -0
  1195. wbcore/tests/test_something.py +39 -0
  1196. wbcore/tests/test_utils/__init__.py +0 -0
  1197. wbcore/tests/test_utils/test_date.py +50 -0
  1198. wbcore/tests/test_utils/test_date_builder.py +124 -0
  1199. wbcore/tests/test_utils/test_primary.py +80 -0
  1200. wbcore/tests/test_utils/test_signals.py +40 -0
  1201. wbcore/tests/test_viewsets.py +21 -0
  1202. wbcore/urls.py +117 -0
  1203. wbcore/utils/__init__.py +13 -0
  1204. wbcore/utils/cache.py +8 -0
  1205. wbcore/utils/date.py +237 -0
  1206. wbcore/utils/date_builder/__init__.py +18 -0
  1207. wbcore/utils/date_builder/components.py +42 -0
  1208. wbcore/utils/date_builder/offsets.py +27 -0
  1209. wbcore/utils/deprecations.py +11 -0
  1210. wbcore/utils/enum.py +23 -0
  1211. wbcore/utils/figures.py +286 -0
  1212. wbcore/utils/html.py +8 -0
  1213. wbcore/utils/importlib.py +13 -0
  1214. wbcore/utils/itertools.py +40 -0
  1215. wbcore/utils/models.py +293 -0
  1216. wbcore/utils/numbers.py +69 -0
  1217. wbcore/utils/prettytable.py +35 -0
  1218. wbcore/utils/print.py +29 -0
  1219. wbcore/utils/renderers.py +13 -0
  1220. wbcore/utils/reportlab.py +7 -0
  1221. wbcore/utils/rrules.py +82 -0
  1222. wbcore/utils/serializers.py +9 -0
  1223. wbcore/utils/settings.py +5 -0
  1224. wbcore/utils/signals.py +36 -0
  1225. wbcore/utils/string_loader.py +42 -0
  1226. wbcore/utils/strings.py +77 -0
  1227. wbcore/utils/urls.py +70 -0
  1228. wbcore/utils/views.py +207 -0
  1229. wbcore/views.py +26 -0
  1230. wbcore/viewsets/__init__.py +12 -0
  1231. wbcore/viewsets/encoders.py +18 -0
  1232. wbcore/viewsets/generics.py +5 -0
  1233. wbcore/viewsets/mixins.py +295 -0
  1234. wbcore/viewsets/utils.py +27 -0
  1235. wbcore/viewsets/viewsets.py +202 -0
  1236. wbcore/workers.py +8 -0
  1237. wbcore-1.59.9.dist-info/METADATA +65 -0
  1238. wbcore-1.59.9.dist-info/RECORD +1239 -0
  1239. wbcore-1.59.9.dist-info/WHEEL +5 -0
@@ -0,0 +1,32 @@
1
+ # Workflows
2
+
3
+ A workflow consists of steps it can go through with each one having a different purpose based on the type of the step. The steps are connected by transitions to be able to transition from one step to another. Conditions can be attached to a transition to prevent transitioning to the next step based on certain parameters. Workflows are always directional.
4
+
5
+ ![Example Workflow](data:image/png;base64,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)
6
+
7
+ ## Columns:
8
+ 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.
9
+
10
+ ### Name:
11
+ The name of the workflow.
12
+
13
+ ### Single Instance Execution:
14
+ Indicates wether the workflow is restricted to only one running workflow at a time. If a model is attached to the workflow this will restrict the workflow execution per model instance.
15
+
16
+ ### Attached Model:
17
+ The model this workflow is attached to (e.g. Activity). Used to display buttons in the model instances to steer the workflow, set a status field or evaluate conditions.
18
+
19
+ ### Model Status Field:
20
+ The status field name in the attached model that needs to be updated by the workflow. Only applicable if attached model is set.
21
+
22
+ ### Preserve Instance:
23
+ This will preserve the attached instance's state in a JSON field when starting the workflow. You then have the option to write this data back onto the instance in a finish step, effectively preserving the instance's state throughout the workflow. Only applicable if attached model is set.
24
+
25
+ ## Filters:
26
+ Filters are accessed by clicking on the symbol in the top left corner of the window.
27
+
28
+ ### Associated Step:
29
+ Displays the workflow that the specified step is a part of.
30
+
31
+ ## Search Field:
32
+ Typing in the search field allows to filter the workflows by name.
@@ -0,0 +1,25 @@
1
+ TEMPLATES = [
2
+ {
3
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
4
+ "DIRS": ["wbcrm/templates/email"],
5
+ "APP_DIRS": True,
6
+ "OPTIONS": {
7
+ "context_processors": [
8
+ "django.template.context_processors.debug",
9
+ "django.template.context_processors.request",
10
+ "django.contrib.auth.context_processors.auth",
11
+ "django.contrib.messages.context_processors.messages",
12
+ ],
13
+ },
14
+ },
15
+ ]
16
+
17
+
18
+ from django.views.generic.base import TemplateView
19
+
20
+ class HomeView(TemplateView):
21
+
22
+ template_name = "global_daily_summery.html"
23
+
24
+
25
+ path("templates", viewsets.HomeView.as_view(), name="templates"),
File without changes
@@ -0,0 +1,281 @@
1
+ import pytest
2
+ from django.apps import apps
3
+ from django.db.backends.base.base import BaseDatabaseWrapper
4
+ from pytest_mock import MockerFixture
5
+ from rest_framework.test import APIRequestFactory, APIClient
6
+ from django.db.models.signals import pre_migrate
7
+ from pytest_factoryboy import register
8
+ from wbcore.contrib.geography.tests.signals import app_pre_migration
9
+ from wbcore.contrib.workflow.factories import (
10
+ ConditionFactory,
11
+ DataFactory,
12
+ DataValueFactory,
13
+ DecisionStepFactory,
14
+ EmailStepFactory,
15
+ FinishStepFactory,
16
+ JoinStepFactory,
17
+ ProcessFactory,
18
+ ProcessStepFactory,
19
+ RandomChildStepFactory,
20
+ ScriptStepFactory,
21
+ SplitStepFactory,
22
+ StartStepFactory,
23
+ StepFactory,
24
+ TransitionFactory,
25
+ UserStepFactory,
26
+ WorkflowFactory,
27
+ )
28
+ from wbcore.contrib.authentication.factories import PermissionFactory
29
+
30
+ from wbcore.contrib.workflow.models import (
31
+ ProcessStep,
32
+ Step,
33
+ )
34
+
35
+ from wbcore.contrib.workflow.serializers import (
36
+ AssignedProcessStepSerializer,
37
+ ConditionModelSerializer,
38
+ DataModelSerializer,
39
+ DecisionStepModelSerializer,
40
+ ProcessModelSerializer,
41
+ ProcessStepModelSerializer,
42
+ TransitionModelSerializer,
43
+ WorkflowModelSerializer,
44
+ )
45
+
46
+ from wbcore.tests.conftest import *
47
+
48
+ register(WorkflowFactory)
49
+ register(EmailStepFactory)
50
+ register(TransitionFactory)
51
+ register(DataFactory)
52
+ register(ProcessStepFactory)
53
+ register(UserStepFactory)
54
+ register(ConditionFactory)
55
+ register(RandomChildStepFactory)
56
+ register(FinishStepFactory)
57
+ register(ProcessFactory)
58
+ register(DecisionStepFactory)
59
+ register(SplitStepFactory)
60
+ register(JoinStepFactory)
61
+ register(ScriptStepFactory)
62
+ register(StepFactory)
63
+ register(DataValueFactory)
64
+ register(StartStepFactory)
65
+
66
+
67
+ # ============================== General Fixtures ==============================
68
+
69
+
70
+ @pytest.fixture
71
+ def api_client(super_user):
72
+ client = APIClient()
73
+ client.force_authenticate(user=super_user)
74
+ return client
75
+
76
+
77
+ @pytest.fixture
78
+ def request_factory():
79
+ return APIRequestFactory()
80
+
81
+
82
+ @pytest.fixture
83
+ def super_user(django_db_setup, django_db_blocker):
84
+ return UserFactory(is_superuser=True)
85
+
86
+
87
+ @pytest.fixture
88
+ def user(django_db_setup, django_db_blocker):
89
+ with django_db_blocker.unblock():
90
+ return UserFactory(is_superuser=False)
91
+
92
+
93
+ @pytest.fixture()
94
+ def user_step():
95
+ return UserStepFactory(step_type=Step.StepType.USERSTEP)
96
+
97
+
98
+ @pytest.fixture
99
+ def permission(django_db_setup, django_db_blocker):
100
+ with django_db_blocker.unblock():
101
+ return PermissionFactory()
102
+
103
+
104
+ # ============================== Condition Fixtures ==============================
105
+
106
+
107
+ @pytest.fixture
108
+ def condition(conditions):
109
+ return conditions[0]
110
+
111
+
112
+ @pytest.fixture
113
+ def condition_build():
114
+ transition = TransitionFactory()
115
+ instance = ConditionFactory.build(transition=transition)
116
+ return ConditionModelSerializer(instance).data
117
+
118
+
119
+ @pytest.fixture
120
+ def conditions():
121
+ return ConditionFactory.create_batch(3)
122
+
123
+
124
+ # ============================== Data Fixtures ==============================
125
+
126
+
127
+ @pytest.fixture
128
+ def data():
129
+ return DataFactory.create_batch(3)
130
+
131
+
132
+ @pytest.fixture
133
+ def data_build(workflow):
134
+ instance = DataFactory.build(workflow=workflow)
135
+ return DataModelSerializer(instance).data
136
+
137
+
138
+ @pytest.fixture
139
+ def singular_data(data):
140
+ return data[0]
141
+
142
+
143
+ # ============================== Decision Step Fixtures ==============================
144
+
145
+
146
+ @pytest.fixture
147
+ def decision_step(decision_steps):
148
+ return decision_steps[0]
149
+
150
+
151
+ @pytest.fixture
152
+ def decision_step_build(workflow):
153
+ instance = DecisionStepFactory.build(workflow=workflow)
154
+ return DecisionStepModelSerializer(instance).data
155
+
156
+
157
+ @pytest.fixture
158
+ def decision_steps():
159
+ return DecisionStepFactory.create_batch(3)
160
+
161
+
162
+ # ============================== Process Fixtures ==============================
163
+
164
+
165
+ @pytest.fixture
166
+ def process(processes):
167
+ return processes[0]
168
+
169
+
170
+ @pytest.fixture
171
+ def process_build():
172
+ instance = ProcessFactory.build()
173
+ return ProcessModelSerializer(instance).data
174
+
175
+
176
+ @pytest.fixture
177
+ def processes():
178
+ return ProcessFactory.create_batch(3)
179
+
180
+
181
+ # ============================== Process Step Fixtures ==============================
182
+
183
+
184
+ @pytest.fixture
185
+ def process_step(process_steps):
186
+ return process_steps[0]
187
+
188
+
189
+ @pytest.fixture
190
+ def process_steps():
191
+ return ProcessStepFactory.create_batch(3)
192
+
193
+
194
+ @pytest.fixture
195
+ def process_steps_build():
196
+ instance = ProcessStepFactory.build()
197
+ return ProcessStepModelSerializer(instance).data
198
+
199
+
200
+ @pytest.fixture
201
+ def mocked_process_step(mocker: MockerFixture):
202
+ return mocker.MagicMock(spec=ProcessStep)
203
+
204
+
205
+ # ============================== Assigned Process Step Fixtures ==============================
206
+
207
+
208
+ @pytest.fixture
209
+ def assigned_process_step(assigned_process_steps):
210
+ return assigned_process_steps[0]
211
+
212
+
213
+ @pytest.fixture
214
+ def assigned_process_steps(super_user, user_step):
215
+ return ProcessStepFactory.create_batch(
216
+ 3,
217
+ step=user_step,
218
+ state=ProcessStep.StepState.ACTIVE,
219
+ assignee=super_user,
220
+ )
221
+
222
+
223
+ @pytest.fixture
224
+ def assigned_process_steps_build(super_user, user_step):
225
+ instance = ProcessStepFactory.build(
226
+ step=user_step, state=ProcessStep.StepState.ACTIVE, assignee=super_user
227
+ )
228
+ return AssignedProcessStepSerializer(instance).data
229
+
230
+
231
+ # ============================== Transition Fixtures ==============================
232
+
233
+
234
+ @pytest.fixture
235
+ def transition(transitions):
236
+ return transitions[0]
237
+
238
+
239
+ @pytest.fixture
240
+ def transition_build():
241
+ to_step = FinishStepFactory()
242
+ from_step = StartStepFactory(workflow=to_step.workflow)
243
+ instance = TransitionFactory.build(to_step=to_step, from_step=from_step)
244
+ return TransitionModelSerializer(instance).data
245
+
246
+
247
+ @pytest.fixture
248
+ def transitions():
249
+ return TransitionFactory.create_batch(3)
250
+
251
+
252
+ # ============================== Workflow Fixtures ==============================
253
+
254
+
255
+ @pytest.fixture
256
+ def workflow(workflows):
257
+ return workflows[0]
258
+
259
+
260
+ @pytest.fixture
261
+ def workflow_build():
262
+ instance = WorkflowFactory.build()
263
+ return WorkflowModelSerializer(instance).data
264
+
265
+
266
+ @pytest.fixture
267
+ def workflows():
268
+ return WorkflowFactory.create_batch(3)
269
+
270
+
271
+ @pytest.fixture(autouse=True, scope="session")
272
+ def django_test_environment(django_test_environment):
273
+ from django.apps import apps
274
+
275
+ get_models = apps.get_models
276
+
277
+ for m in [m for m in get_models() if not m._meta.managed]:
278
+ m._meta.managed = True
279
+
280
+
281
+ pre_migrate.connect(app_pre_migration, sender=apps.get_app_config("geography"))
@@ -0,0 +1,6 @@
1
+ from wbcore.configs.registry import ConfigRegistry
2
+
3
+
4
+ def test_workflow_config(config_registry: ConfigRegistry):
5
+ workflow = config_registry.get_config_dict()["workflow"]
6
+ assert workflow["endpoint"]
@@ -0,0 +1,94 @@
1
+ import pytest
2
+ from pytest_mock import MockerFixture
3
+
4
+ from wbcore.contrib.workflow.dispatch import check_workflow_for_instance
5
+ from wbcore.contrib.workflow.models import Process, ProcessStep, Step, Workflow
6
+
7
+
8
+ class TestDispatch:
9
+ @pytest.fixture
10
+ def mocked_instance(self, mocker: MockerFixture):
11
+ return mocker.MagicMock()
12
+
13
+ # Fixture that automatically patches ContentType lookup in every test.
14
+ @pytest.fixture(autouse=True)
15
+ def patch_content_type(self, mocker: MockerFixture):
16
+ return mocker.patch(
17
+ "wbcore.contrib.workflow.dispatch.ContentType.objects.get_for_model",
18
+ return_value="dummy_content_type",
19
+ )
20
+
21
+ # Fixture for creating a fake process step with a mismatching status.
22
+ @pytest.fixture
23
+ def mocked_process_step(self, mocker: MockerFixture):
24
+ # Create the fake casted step.
25
+ mocked_casted_step = mocker.MagicMock(spec=Step)
26
+
27
+ # Create a fake workflow with a status field.
28
+ mocked_workflow = mocker.MagicMock(spec=Workflow)
29
+ mocked_workflow.status_field = "status_a"
30
+
31
+ # Create a fake process that uses the workflow.
32
+ mocked_process = mocker.MagicMock(spec=Process)
33
+ mocked_process.workflow = mocked_workflow
34
+
35
+ # Create a fake process step with a mismatching status.
36
+ mocked_process_step = mocker.MagicMock(spec=ProcessStep)
37
+ mocked_process_step.process = mocked_process
38
+ mocked_process_step.status = "status_b"
39
+ mocked_process_step.step.get_casted_step.return_value = mocked_casted_step
40
+
41
+ return mocked_process_step, mocked_casted_step
42
+
43
+ def test_check_workflow_for_instance_fail_process_steps(
44
+ self, mocked_instance, mocked_process_step, mocker: MockerFixture
45
+ ):
46
+ # Arrange
47
+ mocked_process_step, mocked_casted_step = mocked_process_step
48
+
49
+ # Patch ProcessStep.objects.filter to return a fake process step.
50
+ mocker.patch(
51
+ "wbcore.contrib.workflow.models.ProcessStep.objects.filter",
52
+ return_value=[mocked_process_step],
53
+ )
54
+ # Patch get_start_steps_for_instance to return an empty list.
55
+ mocker.patch(
56
+ "wbcore.contrib.workflow.models.Workflow.get_start_steps_for_instance",
57
+ return_value=[],
58
+ )
59
+
60
+ # Act
61
+ check_workflow_for_instance(sender=None, instance=mocked_instance, created=True)
62
+
63
+ # Assert: Ensure set_failed was called with the correct arguments.
64
+ mocked_casted_step.set_failed.assert_called_once_with(mocked_process_step, "Invalid status detected!")
65
+
66
+ def test_check_workflow_for_instance_start_workflow(self, mocked_instance, mocker: MockerFixture):
67
+ # Arrange: Create two fake start steps, each with its own workflow.
68
+ fake_start_step1 = mocker.MagicMock()
69
+ fake_workflow1 = mocker.MagicMock(spec=Workflow)
70
+ fake_start_step1.workflow = fake_workflow1
71
+
72
+ fake_start_step2 = mocker.MagicMock()
73
+ fake_workflow2 = mocker.MagicMock(spec=Workflow)
74
+ fake_start_step2.workflow = fake_workflow2
75
+
76
+ # Patch get_start_steps_for_instance to return our fake start steps.
77
+ get_start_steps_patch = mocker.patch(
78
+ "wbcore.contrib.workflow.models.Workflow.get_start_steps_for_instance",
79
+ return_value=[fake_start_step1, fake_start_step2],
80
+ )
81
+ # Patch ProcessStep.objects.filter to return an empty list.
82
+ mocker.patch(
83
+ "wbcore.contrib.workflow.models.ProcessStep.objects.filter",
84
+ return_value=[],
85
+ )
86
+
87
+ # Act
88
+ check_workflow_for_instance(sender=None, instance=mocked_instance, created=True)
89
+
90
+ # Assert: Verify that get_start_steps_for_instance was called with our instance.
91
+ get_start_steps_patch.assert_called_once_with(mocked_instance)
92
+ # Verify that each fake workflow's start_workflow was called with its corresponding start step and the instance.
93
+ fake_workflow1.start_workflow.assert_called_once_with(fake_start_step1, mocked_instance)
94
+ fake_workflow2.start_workflow.assert_called_once_with(fake_start_step2, mocked_instance)
@@ -0,0 +1,42 @@
1
+ from rest_framework.test import APIRequestFactory
2
+
3
+ from wbcore.contrib.color.enums import WBColor
4
+ from wbcore.contrib.workflow.models import ProcessStep
5
+ from wbcore.contrib.workflow.viewsets.display.process import (
6
+ get_state_formatting,
7
+ get_state_legend,
8
+ )
9
+
10
+
11
+ class TestProcessStep:
12
+ api_factory = APIRequestFactory()
13
+
14
+ def test_get_state_legend(self):
15
+ color_map = [
16
+ (ProcessStep.StepState.FAILED, WBColor.GREEN_LIGHT.value),
17
+ (ProcessStep.StepState.CANCELED, WBColor.BLUE_LIGHT.value),
18
+ ]
19
+ assert set((y.icon, y.label, y.value) for y in get_state_legend(color_map)[0].items) == {
20
+ (
21
+ WBColor.GREEN_LIGHT.value,
22
+ ProcessStep.StepState.FAILED.label,
23
+ ProcessStep.StepState.FAILED.value,
24
+ ),
25
+ (
26
+ WBColor.BLUE_LIGHT.value,
27
+ ProcessStep.StepState.CANCELED.label,
28
+ ProcessStep.StepState.CANCELED.value,
29
+ ),
30
+ }
31
+
32
+ def test_get_state_formatting(self):
33
+ color_map = [
34
+ (ProcessStep.StepState.WAITING, WBColor.GREY.value),
35
+ (ProcessStep.StepState.ACTIVE, WBColor.YELLOW_DARK.value),
36
+ ]
37
+ assert set(
38
+ (y.style["backgroundColor"], y.condition[1]) for y in get_state_formatting(color_map)[0].formatting_rules
39
+ ) == {
40
+ (WBColor.GREY.value, ProcessStep.StepState.WAITING.value),
41
+ (WBColor.YELLOW_DARK.value, ProcessStep.StepState.ACTIVE.value),
42
+ }