dmart 1.4.40.post8__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 (489) hide show
  1. dmart/__init__.py +7 -0
  2. dmart/alembic/README +1 -0
  3. dmart/alembic/__init__.py +0 -0
  4. dmart/alembic/env.py +91 -0
  5. dmart/alembic/notes.txt +11 -0
  6. dmart/alembic/script.py.mako +28 -0
  7. dmart/alembic/scripts/__init__.py +0 -0
  8. dmart/alembic/scripts/calculate_checksums.py +77 -0
  9. dmart/alembic/scripts/migration_f7a4949eed19.py +28 -0
  10. dmart/alembic/versions/0f3d2b1a7c21_add_authz_materialized_views.py +87 -0
  11. dmart/alembic/versions/10d2041b94d4_last_checksum_history.py +62 -0
  12. dmart/alembic/versions/1cf4e1ee3cb8_ext_permission_with_filter_fields_values.py +33 -0
  13. dmart/alembic/versions/26bfe19b49d4_rm_failedloginattempts.py +42 -0
  14. dmart/alembic/versions/3c8bca2219cc_add_otp_table.py +38 -0
  15. dmart/alembic/versions/6675fd9dfe42_remove_unique_from_sessions_table.py +36 -0
  16. dmart/alembic/versions/71bc1df82e6a_adding_user_last_login_at.py +43 -0
  17. dmart/alembic/versions/74288ccbd3b5_initial.py +264 -0
  18. dmart/alembic/versions/7520a89a8467_rm_activesession_table.py +39 -0
  19. dmart/alembic/versions/848b623755a4_make_created_nd_updated_at_required.py +138 -0
  20. dmart/alembic/versions/8640dcbebf85_add_notes_to_users.py +32 -0
  21. dmart/alembic/versions/91c94250232a_adding_fk_on_owner_shortname.py +104 -0
  22. dmart/alembic/versions/98ecd6f56f9a_ext_meta_with_owner_group_shortname.py +66 -0
  23. dmart/alembic/versions/9aae9138c4ef_indexing_created_at_updated_at.py +80 -0
  24. dmart/alembic/versions/__init__.py +0 -0
  25. dmart/alembic/versions/b53f916b3f6d_json_to_jsonb.py +492 -0
  26. dmart/alembic/versions/eb5f1ec65156_adding_user_locked_to_device.py +36 -0
  27. dmart/alembic/versions/f7a4949eed19_adding_query_policies_to_meta.py +60 -0
  28. dmart/alembic.ini +117 -0
  29. dmart/api/__init__.py +0 -0
  30. dmart/api/info/__init__.py +0 -0
  31. dmart/api/info/router.py +109 -0
  32. dmart/api/managed/__init__.py +0 -0
  33. dmart/api/managed/router.py +1541 -0
  34. dmart/api/managed/utils.py +1879 -0
  35. dmart/api/public/__init__.py +0 -0
  36. dmart/api/public/router.py +758 -0
  37. dmart/api/qr/__init__.py +0 -0
  38. dmart/api/qr/router.py +108 -0
  39. dmart/api/user/__init__.py +0 -0
  40. dmart/api/user/model/__init__.py +0 -0
  41. dmart/api/user/model/errors.py +14 -0
  42. dmart/api/user/model/requests.py +165 -0
  43. dmart/api/user/model/responses.py +11 -0
  44. dmart/api/user/router.py +1413 -0
  45. dmart/api/user/service.py +270 -0
  46. dmart/bundler.py +52 -0
  47. dmart/cli.py +1133 -0
  48. dmart/config/__init__.py +0 -0
  49. dmart/config/channels.json +11 -0
  50. dmart/config/notification.json +17 -0
  51. dmart/config.env.sample +27 -0
  52. dmart/config.ini.sample +7 -0
  53. dmart/conftest.py +13 -0
  54. dmart/curl.sh +196 -0
  55. dmart/cxb/__init__.py +0 -0
  56. dmart/cxb/assets/@codemirror-Rn7_6DkE.js +10 -0
  57. dmart/cxb/assets/@edraj-CS4NwVbD.js +1 -0
  58. dmart/cxb/assets/@floating-ui-BwwcF-xh.js +1 -0
  59. dmart/cxb/assets/@formatjs-yKEsAtjs.js +1 -0
  60. dmart/cxb/assets/@fortawesome-DRW1UCdr.js +9 -0
  61. dmart/cxb/assets/@jsonquerylang-laKNoFFq.js +12 -0
  62. dmart/cxb/assets/@lezer-za4Q-8Ew.js +1 -0
  63. dmart/cxb/assets/@marijn-DXwl3gUT.js +1 -0
  64. dmart/cxb/assets/@popperjs-l0sNRNKZ.js +1 -0
  65. dmart/cxb/assets/@replit--ERk53eB.js +1 -0
  66. dmart/cxb/assets/@roxi-CGMFK4i8.js +6 -0
  67. dmart/cxb/assets/@typewriter-cCzskkIv.js +17 -0
  68. dmart/cxb/assets/@zerodevx-BlBZjKxu.js +1 -0
  69. dmart/cxb/assets/@zerodevx-CVEpe6WZ.css +1 -0
  70. dmart/cxb/assets/BreadCrumbLite-DAhOx38v.js +1 -0
  71. dmart/cxb/assets/EntryRenderer-CCqV8Rkg.js +32 -0
  72. dmart/cxb/assets/EntryRenderer-DXytdFp9.css +1 -0
  73. dmart/cxb/assets/ListView-BQelo7vZ.js +16 -0
  74. dmart/cxb/assets/ListView-U8of-_c-.css +1 -0
  75. dmart/cxb/assets/Prism--hMplq-p.js +3 -0
  76. dmart/cxb/assets/Prism-Uh6uStUw.css +1 -0
  77. dmart/cxb/assets/Table2Cols-BsbwicQm.js +1 -0
  78. dmart/cxb/assets/_..-BvT6vdHa.css +1 -0
  79. dmart/cxb/assets/_...404_-fuLH_rX9.js +2 -0
  80. dmart/cxb/assets/_...fallback_-Ba_NLmAE.js +1 -0
  81. dmart/cxb/assets/_module-3HrtKAWo.js +3 -0
  82. dmart/cxb/assets/_module-DFKFq0AM.js +4 -0
  83. dmart/cxb/assets/_module-Dgq0ZVtz.js +1 -0
  84. dmart/cxb/assets/ajv-Cpj98o6Y.js +1 -0
  85. dmart/cxb/assets/axios-CG2WSiiR.js +6 -0
  86. dmart/cxb/assets/clsx-B-dksMZM.js +1 -0
  87. dmart/cxb/assets/codemirror-wrapped-line-indent-DPhKvljI.js +1 -0
  88. dmart/cxb/assets/compare-C3AjiGFR.js +1 -0
  89. dmart/cxb/assets/compute-scroll-into-view-Bl8rNFhg.js +1 -0
  90. dmart/cxb/assets/consolite-DlCuI0F9.js +1 -0
  91. dmart/cxb/assets/crelt-C8TCjufn.js +1 -0
  92. dmart/cxb/assets/date-fns-l0sNRNKZ.js +1 -0
  93. dmart/cxb/assets/deepmerge-rn4rBaHU.js +1 -0
  94. dmart/cxb/assets/dmart_services-AL6-IdDE.js +1 -0
  95. dmart/cxb/assets/downloadFile-D08i0YDh.js +1 -0
  96. dmart/cxb/assets/easy-signal-BiPFIK3O.js +1 -0
  97. dmart/cxb/assets/esm-env-rsSWfq8L.js +1 -0
  98. dmart/cxb/assets/export-OF_rTiXu.js +1 -0
  99. dmart/cxb/assets/fast-deep-equal-l0sNRNKZ.js +1 -0
  100. dmart/cxb/assets/fast-diff-C-IidNf4.js +1 -0
  101. dmart/cxb/assets/fast-uri-l0sNRNKZ.js +1 -0
  102. dmart/cxb/assets/flowbite-svelte-BLvjb-sa.js +1 -0
  103. dmart/cxb/assets/flowbite-svelte-CD54FDqW.css +1 -0
  104. dmart/cxb/assets/flowbite-svelte-icons-BI8GVhw_.js +1 -0
  105. dmart/cxb/assets/github-slugger-CQ4oX9Ud.js +1 -0
  106. dmart/cxb/assets/global-igKv-1g9.js +1 -0
  107. dmart/cxb/assets/hookar-BMRD9G9H.js +1 -0
  108. dmart/cxb/assets/immutable-json-patch-DtRO2E_S.js +1 -0
  109. dmart/cxb/assets/import-1vE3gBat.js +1 -0
  110. dmart/cxb/assets/index-B-eTh-ZX.js +1 -0
  111. dmart/cxb/assets/index-BSsK-X71.js +1 -0
  112. dmart/cxb/assets/index-BVyxzKtH.js +1 -0
  113. dmart/cxb/assets/index-BdeNM69f.js +1 -0
  114. dmart/cxb/assets/index-CC-A1ipE.js +1 -0
  115. dmart/cxb/assets/index-CQohGiYB.js +1 -0
  116. dmart/cxb/assets/index-ChjnkpdZ.js +4 -0
  117. dmart/cxb/assets/index-DLP7csA4.js +1 -0
  118. dmart/cxb/assets/index-DTfhnhwd.js +1 -0
  119. dmart/cxb/assets/index-DdXRK7n9.js +2 -0
  120. dmart/cxb/assets/index-DtiCmB4o.js +1 -0
  121. dmart/cxb/assets/index-NBrXBlLA.css +2 -0
  122. dmart/cxb/assets/index-X1uNehO7.js +1 -0
  123. dmart/cxb/assets/index-nrQW6Nrr.js +1 -0
  124. dmart/cxb/assets/info-B986lRiM.js +1 -0
  125. dmart/cxb/assets/intl-messageformat-Dc5UU-HB.js +3 -0
  126. dmart/cxb/assets/jmespath-l0sNRNKZ.js +1 -0
  127. dmart/cxb/assets/json-schema-traverse-l0sNRNKZ.js +1 -0
  128. dmart/cxb/assets/json-source-map-DRgZidqy.js +5 -0
  129. dmart/cxb/assets/jsonpath-plus-l0sNRNKZ.js +1 -0
  130. dmart/cxb/assets/jsonrepair-B30Dx381.js +8 -0
  131. dmart/cxb/assets/lodash-es-DZVAA2ox.js +1 -0
  132. dmart/cxb/assets/marked-DKjyhwJX.js +56 -0
  133. dmart/cxb/assets/marked-gfm-heading-id-U5zO829x.js +2 -0
  134. dmart/cxb/assets/marked-mangle-CDMeiHC6.js +1 -0
  135. dmart/cxb/assets/memoize-one-BdPwpGay.js +1 -0
  136. dmart/cxb/assets/natural-compare-lite-Bg2Xcf-o.js +7 -0
  137. dmart/cxb/assets/pagination-svelte-D5CyoiE_.js +13 -0
  138. dmart/cxb/assets/pagination-svelte-v10nAbbM.css +1 -0
  139. dmart/cxb/assets/plantuml-encoder-C47mzt9T.js +1 -0
  140. dmart/cxb/assets/prismjs-DTUiLGJu.js +9 -0
  141. dmart/cxb/assets/profile-BUf-tKMe.js +1 -0
  142. dmart/cxb/assets/query-CNmXTsgf.js +1 -0
  143. dmart/cxb/assets/queryHelpers-C9iBWwqe.js +1 -0
  144. dmart/cxb/assets/scroll-into-view-if-needed-KR58zyjF.js +1 -0
  145. dmart/cxb/assets/spaces-0oyGvpii.js +1 -0
  146. dmart/cxb/assets/style-mod-Bs6eFhZE.js +3 -0
  147. dmart/cxb/assets/svelte-B2XmcTi_.js +4 -0
  148. dmart/cxb/assets/svelte-awesome-COLlx0DN.css +1 -0
  149. dmart/cxb/assets/svelte-awesome-DhnMA6Q_.js +1 -0
  150. dmart/cxb/assets/svelte-datatables-net-CY7LBj6I.js +1 -0
  151. dmart/cxb/assets/svelte-floating-ui-BlS3sOAQ.js +1 -0
  152. dmart/cxb/assets/svelte-i18n-CT2KkQaN.js +3 -0
  153. dmart/cxb/assets/svelte-jsoneditor-BzfX6Usi.css +1 -0
  154. dmart/cxb/assets/svelte-jsoneditor-CUGSvWId.js +25 -0
  155. dmart/cxb/assets/svelte-select-CegQKzqH.css +1 -0
  156. dmart/cxb/assets/svelte-select-CjHAt_85.js +6 -0
  157. dmart/cxb/assets/tailwind-merge-CJvxXMcu.js +1 -0
  158. dmart/cxb/assets/tailwind-variants-Cj20BoQ3.js +1 -0
  159. dmart/cxb/assets/toast-B9WDyfyI.js +1 -0
  160. dmart/cxb/assets/tslib-pJfR_DrR.js +1 -0
  161. dmart/cxb/assets/typewriter-editor-DkTVIJdm.js +25 -0
  162. dmart/cxb/assets/user-DeK_NB5v.js +1 -0
  163. dmart/cxb/assets/vanilla-picker-l5rcX3cq.js +8 -0
  164. dmart/cxb/assets/w3c-keyname-Vcq4gwWv.js +1 -0
  165. dmart/cxb/config.json +11 -0
  166. dmart/cxb/config.sample.json +11 -0
  167. dmart/cxb/favicon.ico +0 -0
  168. dmart/cxb/favicon.png +0 -0
  169. dmart/cxb/index.html +28 -0
  170. dmart/data_adapters/__init__.py +0 -0
  171. dmart/data_adapters/adapter.py +16 -0
  172. dmart/data_adapters/base_data_adapter.py +467 -0
  173. dmart/data_adapters/file/__init__.py +0 -0
  174. dmart/data_adapters/file/adapter.py +2043 -0
  175. dmart/data_adapters/file/adapter_helpers.py +1013 -0
  176. dmart/data_adapters/file/archive.py +150 -0
  177. dmart/data_adapters/file/create_index.py +331 -0
  178. dmart/data_adapters/file/create_users_folders.py +52 -0
  179. dmart/data_adapters/file/custom_validations.py +68 -0
  180. dmart/data_adapters/file/drop_index.py +40 -0
  181. dmart/data_adapters/file/health_check.py +560 -0
  182. dmart/data_adapters/file/redis_services.py +1110 -0
  183. dmart/data_adapters/helpers.py +27 -0
  184. dmart/data_adapters/sql/__init__.py +0 -0
  185. dmart/data_adapters/sql/adapter.py +3218 -0
  186. dmart/data_adapters/sql/adapter_helpers.py +491 -0
  187. dmart/data_adapters/sql/create_tables.py +451 -0
  188. dmart/data_adapters/sql/create_users_folders.py +53 -0
  189. dmart/data_adapters/sql/db_to_json_migration.py +485 -0
  190. dmart/data_adapters/sql/health_check_sql.py +232 -0
  191. dmart/data_adapters/sql/json_to_db_migration.py +454 -0
  192. dmart/data_adapters/sql/update_query_policies.py +101 -0
  193. dmart/data_generator.py +81 -0
  194. dmart/dmart.py +761 -0
  195. dmart/get_settings.py +7 -0
  196. dmart/hypercorn_config.toml +3 -0
  197. dmart/info.json +1 -0
  198. dmart/languages/__init__.py +0 -0
  199. dmart/languages/arabic.json +15 -0
  200. dmart/languages/english.json +16 -0
  201. dmart/languages/kurdish.json +14 -0
  202. dmart/languages/loader.py +12 -0
  203. dmart/login_creds.sh +7 -0
  204. dmart/login_creds.sh.sample +7 -0
  205. dmart/main.py +563 -0
  206. dmart/manifest.sh +12 -0
  207. dmart/migrate.py +24 -0
  208. dmart/models/__init__.py +0 -0
  209. dmart/models/api.py +203 -0
  210. dmart/models/core.py +597 -0
  211. dmart/models/enums.py +255 -0
  212. dmart/password_gen.py +8 -0
  213. dmart/plugins/__init__.py +0 -0
  214. dmart/plugins/action_log/__init__.py +0 -0
  215. dmart/plugins/action_log/config.json +13 -0
  216. dmart/plugins/action_log/plugin.py +121 -0
  217. dmart/plugins/admin_notification_sender/__init__.py +0 -0
  218. dmart/plugins/admin_notification_sender/config.json +13 -0
  219. dmart/plugins/admin_notification_sender/plugin.py +124 -0
  220. dmart/plugins/ldap_manager/__init__.py +0 -0
  221. dmart/plugins/ldap_manager/config.json +12 -0
  222. dmart/plugins/ldap_manager/dmart.schema +146 -0
  223. dmart/plugins/ldap_manager/plugin.py +100 -0
  224. dmart/plugins/ldap_manager/slapd.conf +53 -0
  225. dmart/plugins/local_notification/__init__.py +0 -0
  226. dmart/plugins/local_notification/config.json +13 -0
  227. dmart/plugins/local_notification/plugin.py +123 -0
  228. dmart/plugins/realtime_updates_notifier/__init__.py +0 -0
  229. dmart/plugins/realtime_updates_notifier/config.json +12 -0
  230. dmart/plugins/realtime_updates_notifier/plugin.py +58 -0
  231. dmart/plugins/redis_db_update/__init__.py +0 -0
  232. dmart/plugins/redis_db_update/config.json +13 -0
  233. dmart/plugins/redis_db_update/plugin.py +188 -0
  234. dmart/plugins/resource_folders_creation/__init__.py +0 -0
  235. dmart/plugins/resource_folders_creation/config.json +12 -0
  236. dmart/plugins/resource_folders_creation/plugin.py +81 -0
  237. dmart/plugins/system_notification_sender/__init__.py +0 -0
  238. dmart/plugins/system_notification_sender/config.json +13 -0
  239. dmart/plugins/system_notification_sender/plugin.py +188 -0
  240. dmart/plugins/update_access_controls/__init__.py +0 -0
  241. dmart/plugins/update_access_controls/config.json +12 -0
  242. dmart/plugins/update_access_controls/plugin.py +9 -0
  243. dmart/publish.sh +57 -0
  244. dmart/pylint.sh +16 -0
  245. dmart/pyrightconfig.json +7 -0
  246. dmart/redis_connections.sh +13 -0
  247. dmart/reload.sh +56 -0
  248. dmart/run.sh +3 -0
  249. dmart/run_notification_campaign.py +85 -0
  250. dmart/sample/spaces/applications/.dm/meta.space.json +30 -0
  251. dmart/sample/spaces/applications/api/.dm/meta.folder.json +1 -0
  252. dmart/sample/spaces/applications/api/.dm/query_all_applications/meta.content.json +1 -0
  253. dmart/sample/spaces/applications/api/.dm/test_by_saad/attachments.media/meta.warframe.json +1 -0
  254. dmart/sample/spaces/applications/api/.dm/test_by_saad/attachments.media/warframe.png +0 -0
  255. dmart/sample/spaces/applications/api/.dm/test_by_saad/meta.content.json +1 -0
  256. dmart/sample/spaces/applications/api/.dm/user_profile/meta.content.json +1 -0
  257. dmart/sample/spaces/applications/api/applications/.dm/create_log/meta.content.json +1 -0
  258. dmart/sample/spaces/applications/api/applications/.dm/create_public_logs/meta.content.json +1 -0
  259. dmart/sample/spaces/applications/api/applications/.dm/meta.folder.json +1 -0
  260. dmart/sample/spaces/applications/api/applications/.dm/query_all_translated_data/meta.content.json +1 -0
  261. dmart/sample/spaces/applications/api/applications/.dm/query_logs/meta.content.json +1 -0
  262. dmart/sample/spaces/applications/api/applications/.dm/query_translated_enums/meta.content.json +1 -0
  263. dmart/sample/spaces/applications/api/applications/.dm/query_translated_others/meta.content.json +1 -0
  264. dmart/sample/spaces/applications/api/applications/.dm/query_translated_resolution/meta.content.json +1 -0
  265. dmart/sample/spaces/applications/api/applications/create_log.json +1 -0
  266. dmart/sample/spaces/applications/api/applications/create_public_logs.json +1 -0
  267. dmart/sample/spaces/applications/api/applications/query_all_translated_data.json +1 -0
  268. dmart/sample/spaces/applications/api/applications/query_logs.json +1 -0
  269. dmart/sample/spaces/applications/api/applications/query_translated_enums.json +1 -0
  270. dmart/sample/spaces/applications/api/applications/query_translated_others.json +1 -0
  271. dmart/sample/spaces/applications/api/applications/query_translated_resolution.json +1 -0
  272. dmart/sample/spaces/applications/api/applications.json +1 -0
  273. dmart/sample/spaces/applications/api/management/.dm/create_subaccount/meta.content.json +1 -0
  274. dmart/sample/spaces/applications/api/management/.dm/meta.folder.json +1 -0
  275. dmart/sample/spaces/applications/api/management/.dm/update_password/meta.content.json +1 -0
  276. dmart/sample/spaces/applications/api/management/create_subaccount.json +53 -0
  277. dmart/sample/spaces/applications/api/management/update_password.json +1 -0
  278. dmart/sample/spaces/applications/api/management.json +1 -0
  279. dmart/sample/spaces/applications/api/query_all_applications.json +15 -0
  280. dmart/sample/spaces/applications/api/test_by_saad.json +1 -0
  281. dmart/sample/spaces/applications/api/user/.dm/meta.folder.json +1 -0
  282. dmart/sample/spaces/applications/api/user/.dm/test_by_saad/meta.content.json +1 -0
  283. dmart/sample/spaces/applications/api/user/.dm/user_profile/meta.content.json +1 -0
  284. dmart/sample/spaces/applications/api/user/test_by_saad.json +1 -0
  285. dmart/sample/spaces/applications/api/user/user_profile.json +1 -0
  286. dmart/sample/spaces/applications/api/user_profile.json +1 -0
  287. dmart/sample/spaces/applications/api.json +1 -0
  288. dmart/sample/spaces/applications/collections/.dm/meta.folder.json +19 -0
  289. dmart/sample/spaces/applications/collections.json +1 -0
  290. dmart/sample/spaces/applications/configurations/.dm/meta.folder.json +1 -0
  291. dmart/sample/spaces/applications/configurations/time_out.json +1 -0
  292. dmart/sample/spaces/applications/configurations.json +19 -0
  293. dmart/sample/spaces/applications/errors.json +1 -0
  294. dmart/sample/spaces/applications/logs/.dm/meta.folder.json +1 -0
  295. dmart/sample/spaces/applications/logs.json +1 -0
  296. dmart/sample/spaces/applications/queries/.dm/meta.folder.json +1 -0
  297. dmart/sample/spaces/applications/queries/.dm/order/meta.content.json +1 -0
  298. dmart/sample/spaces/applications/queries/order.json +1 -0
  299. dmart/sample/spaces/applications/queries.json +1 -0
  300. dmart/sample/spaces/applications/schema/.dm/api/meta.schema.json +1 -0
  301. dmart/sample/spaces/applications/schema/.dm/configuration/meta.schema.json +1 -0
  302. dmart/sample/spaces/applications/schema/.dm/error/meta.schema.json +1 -0
  303. dmart/sample/spaces/applications/schema/.dm/log/meta.schema.json +1 -0
  304. dmart/sample/spaces/applications/schema/.dm/meta.folder.json +1 -0
  305. dmart/sample/spaces/applications/schema/.dm/query/meta.schema.json +16 -0
  306. dmart/sample/spaces/applications/schema/.dm/translation/meta.schema.json +1 -0
  307. dmart/sample/spaces/applications/schema/api.json +28 -0
  308. dmart/sample/spaces/applications/schema/configuration.json +1 -0
  309. dmart/sample/spaces/applications/schema/error.json +43 -0
  310. dmart/sample/spaces/applications/schema/log.json +1 -0
  311. dmart/sample/spaces/applications/schema/query.json +118 -0
  312. dmart/sample/spaces/applications/schema/translation.json +26 -0
  313. dmart/sample/spaces/applications/schema.json +1 -0
  314. dmart/sample/spaces/applications/translations/.dm/meta.folder.json +1 -0
  315. dmart/sample/spaces/applications/translations.json +1 -0
  316. dmart/sample/spaces/archive/.dm/meta.space.json +27 -0
  317. dmart/sample/spaces/custom_plugins/dummy/__pycache__/plugin.cpython-314.pyc +0 -0
  318. dmart/sample/spaces/custom_plugins/dummy/config.json +28 -0
  319. dmart/sample/spaces/custom_plugins/dummy/plugin.py +6 -0
  320. dmart/sample/spaces/custom_plugins/missed_entry/config.json +12 -0
  321. dmart/sample/spaces/custom_plugins/missed_entry/plugin.py +119 -0
  322. dmart/sample/spaces/custom_plugins/own_changed_notification/__pycache__/plugin.cpython-314.pyc +0 -0
  323. dmart/sample/spaces/custom_plugins/own_changed_notification/config.json +12 -0
  324. dmart/sample/spaces/custom_plugins/own_changed_notification/plugin.py +65 -0
  325. dmart/sample/spaces/custom_plugins/reports_stats/config.json +14 -0
  326. dmart/sample/spaces/custom_plugins/reports_stats/plugin.py +82 -0
  327. dmart/sample/spaces/custom_plugins/system_notification_sender/config.json +22 -0
  328. dmart/sample/spaces/custom_plugins/system_notification_sender/notification.py +268 -0
  329. dmart/sample/spaces/custom_plugins/system_notification_sender/plugin.py +98 -0
  330. dmart/sample/spaces/management/.dm/events.jsonl +32 -0
  331. dmart/sample/spaces/management/.dm/meta.space.json +48 -0
  332. dmart/sample/spaces/management/.dm/notifications/attachments.view.json/admin.json +36 -0
  333. dmart/sample/spaces/management/.dm/notifications/attachments.view.json/meta.admin.json +1 -0
  334. dmart/sample/spaces/management/.dm/notifications/attachments.view.json/meta.system.json +1 -0
  335. dmart/sample/spaces/management/.dm/notifications/attachments.view.json/system.json +32 -0
  336. dmart/sample/spaces/management/collections/.dm/meta.folder.json +1 -0
  337. dmart/sample/spaces/management/collections.json +1 -0
  338. dmart/sample/spaces/management/groups/.dm/meta.folder.json +1 -0
  339. dmart/sample/spaces/management/groups.json +1 -0
  340. dmart/sample/spaces/management/health_check/.dm/meta.folder.json +1 -0
  341. dmart/sample/spaces/management/health_check.json +1 -0
  342. dmart/sample/spaces/management/notifications/.dm/meta.folder.json +1 -0
  343. dmart/sample/spaces/management/notifications/admin/.dm/meta.folder.json +9 -0
  344. dmart/sample/spaces/management/notifications/system/.dm/meta.folder.json +9 -0
  345. dmart/sample/spaces/management/notifications.json +1 -0
  346. dmart/sample/spaces/management/permissions/.dm/access_applications/meta.permission.json +31 -0
  347. dmart/sample/spaces/management/permissions/.dm/access_applications_world/meta.permission.json +31 -0
  348. dmart/sample/spaces/management/permissions/.dm/access_messages/meta.permission.json +23 -0
  349. dmart/sample/spaces/management/permissions/.dm/access_personal/meta.permission.json +40 -0
  350. dmart/sample/spaces/management/permissions/.dm/access_protected/meta.permission.json +33 -0
  351. dmart/sample/spaces/management/permissions/.dm/access_public/meta.permission.json +24 -0
  352. dmart/sample/spaces/management/permissions/.dm/browse_all_folders/meta.permission.json +23 -0
  353. dmart/sample/spaces/management/permissions/.dm/create_log/meta.permission.json +24 -0
  354. dmart/sample/spaces/management/permissions/.dm/interviewer/meta.permission.json +1 -0
  355. dmart/sample/spaces/management/permissions/.dm/manage_applications/meta.permission.json +1 -0
  356. dmart/sample/spaces/management/permissions/.dm/manage_debug/meta.permission.json +25 -0
  357. dmart/sample/spaces/management/permissions/.dm/manage_spaces/meta.permission.json +24 -0
  358. dmart/sample/spaces/management/permissions/.dm/meta.folder.json +1 -0
  359. dmart/sample/spaces/management/permissions/.dm/rules_management_default/meta.permission.json +32 -0
  360. dmart/sample/spaces/management/permissions/.dm/super_manager/meta.permission.json +52 -0
  361. dmart/sample/spaces/management/permissions/.dm/view_activity_log/meta.permission.json +26 -0
  362. dmart/sample/spaces/management/permissions/.dm/view_collections/meta.permission.json +29 -0
  363. dmart/sample/spaces/management/permissions/.dm/view_logs/meta.permission.json +30 -0
  364. dmart/sample/spaces/management/permissions/.dm/view_roles/meta.permission.json +29 -0
  365. dmart/sample/spaces/management/permissions/.dm/view_users/meta.permission.json +25 -0
  366. dmart/sample/spaces/management/permissions/.dm/view_world/meta.permission.json +31 -0
  367. dmart/sample/spaces/management/permissions/.dm/world/meta.permission.json +35 -0
  368. dmart/sample/spaces/management/permissions.json +1 -0
  369. dmart/sample/spaces/management/requests.json +1 -0
  370. dmart/sample/spaces/management/roles/.dm/dummy/meta.role.json +12 -0
  371. dmart/sample/spaces/management/roles/.dm/logged_in/meta.role.json +18 -0
  372. dmart/sample/spaces/management/roles/.dm/manager/meta.role.json +13 -0
  373. dmart/sample/spaces/management/roles/.dm/meta.folder.json +1 -0
  374. dmart/sample/spaces/management/roles/.dm/moderator/meta.role.json +13 -0
  375. dmart/sample/spaces/management/roles/.dm/super_admin/meta.role.json +14 -0
  376. dmart/sample/spaces/management/roles/.dm/test_role/meta.role.json +13 -0
  377. dmart/sample/spaces/management/roles/.dm/world/meta.role.json +15 -0
  378. dmart/sample/spaces/management/roles.json +1 -0
  379. dmart/sample/spaces/management/schema/.dm/admin_notification_request/attachments.media/meta.ui_schema.json +10 -0
  380. dmart/sample/spaces/management/schema/.dm/admin_notification_request/attachments.media/ui_schema.json +32 -0
  381. dmart/sample/spaces/management/schema/.dm/admin_notification_request/meta.schema.json +1 -0
  382. dmart/sample/spaces/management/schema/.dm/api/meta.schema.json +1 -0
  383. dmart/sample/spaces/management/schema/.dm/folder_rendering/meta.schema.json +1 -0
  384. dmart/sample/spaces/management/schema/.dm/health_check/meta.schema.json +17 -0
  385. dmart/sample/spaces/management/schema/.dm/meta.folder.json +1 -0
  386. dmart/sample/spaces/management/schema/.dm/meta_schema/meta.schema.json +1 -0
  387. dmart/sample/spaces/management/schema/.dm/metafile/meta.schema.json +14 -0
  388. dmart/sample/spaces/management/schema/.dm/notification/meta.schema.json +1 -0
  389. dmart/sample/spaces/management/schema/.dm/system_notification_request/attachments.media/meta.ui_schema.json +10 -0
  390. dmart/sample/spaces/management/schema/.dm/system_notification_request/attachments.media/ui_schema.json +32 -0
  391. dmart/sample/spaces/management/schema/.dm/system_notification_request/meta.schema.json +1 -0
  392. dmart/sample/spaces/management/schema/.dm/view/meta.schema.json +1 -0
  393. dmart/sample/spaces/management/schema/.dm/workflow/meta.schema.json +1 -0
  394. dmart/sample/spaces/management/schema/admin_notification_request.json +89 -0
  395. dmart/sample/spaces/management/schema/api.json +1 -0
  396. dmart/sample/spaces/management/schema/folder_rendering.json +238 -0
  397. dmart/sample/spaces/management/schema/health_check.json +8 -0
  398. dmart/sample/spaces/management/schema/meta_schema.json +74 -0
  399. dmart/sample/spaces/management/schema/metafile.json +153 -0
  400. dmart/sample/spaces/management/schema/notification.json +28 -0
  401. dmart/sample/spaces/management/schema/system_notification_request.json +57 -0
  402. dmart/sample/spaces/management/schema/view.json +23 -0
  403. dmart/sample/spaces/management/schema/workflow.json +87 -0
  404. dmart/sample/spaces/management/schema.json +1 -0
  405. dmart/sample/spaces/management/users/.dm/alibaba/meta.user.json +23 -0
  406. dmart/sample/spaces/management/users/.dm/anonymous/meta.user.json +18 -0
  407. dmart/sample/spaces/management/users/.dm/dmart/meta.user.json +26 -0
  408. dmart/sample/spaces/management/users/.dm/meta.folder.json +14 -0
  409. dmart/sample/spaces/management/workflows/.dm/channel/meta.content.json +1 -0
  410. dmart/sample/spaces/management/workflows/.dm/meta.folder.json +1 -0
  411. dmart/sample/spaces/management/workflows/channel.json +148 -0
  412. dmart/sample/spaces/management/workflows.json +1 -0
  413. dmart/sample/spaces/maqola/.dm/meta.space.json +33 -0
  414. dmart/sample/spaces/personal/.dm/meta.space.json +24 -0
  415. dmart/sample/spaces/personal/people/.dm/meta.folder.json +1 -0
  416. dmart/sample/spaces/personal/people/dmart/.dm/meta.folder.json +1 -0
  417. dmart/sample/spaces/personal/people/dmart/messages/.dm/0b5f7e7f/meta.content.json +1 -0
  418. dmart/sample/spaces/personal/people/dmart/messages/.dm/meta.folder.json +1 -0
  419. dmart/sample/spaces/personal/people/dmart/messages/.dm/mytest/meta.content.json +1 -0
  420. dmart/sample/spaces/personal/people/dmart/messages/0b5f7e7f.json +1 -0
  421. dmart/sample/spaces/personal/people/dmart/messages/mytest.json +1 -0
  422. dmart/sample/spaces/personal/people/dmart/notifications/.dm/meta.folder.json +1 -0
  423. dmart/sample/spaces/personal/people/dmart/private/.dm/inner/meta.content.json +1 -0
  424. dmart/sample/spaces/personal/people/dmart/private/.dm/meta.folder.json +1 -0
  425. dmart/sample/spaces/personal/people/dmart/private/inner.json +1 -0
  426. dmart/sample/spaces/personal/people/dmart/protected/.dm/avatar/meta.content.json +1 -0
  427. dmart/sample/spaces/personal/people/dmart/protected/.dm/meta.folder.json +1 -0
  428. dmart/sample/spaces/personal/people/dmart/protected/avatar.png +0 -0
  429. dmart/sample/spaces/personal/people/dmart/public/.dm/meta.folder.json +1 -0
  430. dmart/sample/test/.gitignore +2 -0
  431. dmart/sample/test/createcontent.json +9 -0
  432. dmart/sample/test/createmedia.json +9 -0
  433. dmart/sample/test/createmedia_entry.json +6 -0
  434. dmart/sample/test/createschema.json +8 -0
  435. dmart/sample/test/createschemawork.json +11 -0
  436. dmart/sample/test/createticket.json +13 -0
  437. dmart/sample/test/data.json +4 -0
  438. dmart/sample/test/deletecontent.json +12 -0
  439. dmart/sample/test/logo.jpeg +0 -0
  440. dmart/sample/test/my.jpg +0 -0
  441. dmart/sample/test/myticket.json +23 -0
  442. dmart/sample/test/resources.csv +12 -0
  443. dmart/sample/test/schema.json +16 -0
  444. dmart/sample/test/temp.json +1 -0
  445. dmart/sample/test/test.dmart +45 -0
  446. dmart/sample/test/ticket_schema.json +23 -0
  447. dmart/sample/test/ticket_workflow.json +85 -0
  448. dmart/sample/test/ticketbody.json +4 -0
  449. dmart/sample/test/ticketcontent.json +14 -0
  450. dmart/sample/test/updatecontent.json +20 -0
  451. dmart/sample/test/workflow_schema.json +68 -0
  452. dmart/scheduled_notification_handler.py +121 -0
  453. dmart/schema_migration.py +208 -0
  454. dmart/schema_modulate.py +192 -0
  455. dmart/set_admin_passwd.py +75 -0
  456. dmart/sync.py +202 -0
  457. dmart/test_utils.py +34 -0
  458. dmart/utils/__init__.py +0 -0
  459. dmart/utils/access_control.py +306 -0
  460. dmart/utils/async_request.py +8 -0
  461. dmart/utils/exporter.py +309 -0
  462. dmart/utils/firebase_notifier.py +57 -0
  463. dmart/utils/generate_email.py +37 -0
  464. dmart/utils/helpers.py +352 -0
  465. dmart/utils/hypercorn_config.py +12 -0
  466. dmart/utils/internal_error_code.py +60 -0
  467. dmart/utils/jwt.py +124 -0
  468. dmart/utils/logger.py +167 -0
  469. dmart/utils/middleware.py +99 -0
  470. dmart/utils/notification.py +75 -0
  471. dmart/utils/password_hashing.py +16 -0
  472. dmart/utils/plugin_manager.py +202 -0
  473. dmart/utils/query_policies_helper.py +128 -0
  474. dmart/utils/regex.py +44 -0
  475. dmart/utils/repository.py +529 -0
  476. dmart/utils/router_helper.py +19 -0
  477. dmart/utils/settings.py +212 -0
  478. dmart/utils/sms_notifier.py +21 -0
  479. dmart/utils/social_sso.py +67 -0
  480. dmart/utils/templates/activation.html.j2 +26 -0
  481. dmart/utils/templates/reminder.html.j2 +17 -0
  482. dmart/utils/ticket_sys_utils.py +203 -0
  483. dmart/utils/web_notifier.py +29 -0
  484. dmart/websocket.py +231 -0
  485. dmart-1.4.40.post8.dist-info/METADATA +75 -0
  486. dmart-1.4.40.post8.dist-info/RECORD +489 -0
  487. dmart-1.4.40.post8.dist-info/WHEEL +5 -0
  488. dmart-1.4.40.post8.dist-info/entry_points.txt +2 -0
  489. dmart-1.4.40.post8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,188 @@
1
+ import sys
2
+ from models.core import ActionType, Attachment, PluginBase, Event, Space
3
+ from utils.helpers import camel_case
4
+ from data_adapters.file.adapter_helpers import generate_payload_string
5
+ from data_adapters.adapter import data_adapter as db
6
+ from models import core
7
+ from models.enums import ContentType, ResourceType
8
+ from data_adapters.file.redis_services import RedisServices
9
+ from fastapi.logger import logger
10
+ from data_adapters.file.create_index import main as reload_redis
11
+ from utils.settings import settings
12
+ from typing import Any
13
+
14
+
15
+ class Plugin(PluginBase):
16
+ async def hook(self, data: Event):
17
+ if settings.active_data_db == "sql":
18
+ return
19
+
20
+ self.data = data
21
+ # Type narrowing for PyRight
22
+ if (
23
+ not isinstance(data.shortname, str)
24
+ or not isinstance(data.resource_type, ResourceType)
25
+ or not isinstance(data.attributes, dict)
26
+ ):
27
+ logger.error("invalid data at redis_db_update")
28
+ return
29
+
30
+ spaces = await db.get_spaces()
31
+ if (
32
+ data.space_name not in spaces
33
+ or not Space.model_validate_json(spaces[data.space_name]).indexing_enabled
34
+ ):
35
+ return
36
+
37
+ class_type = getattr(
38
+ sys.modules["models.core"],
39
+ camel_case(core.ResourceType(data.resource_type)),
40
+ )
41
+ if issubclass(class_type, Attachment):
42
+ await self.update_parent_entry_payload_string()
43
+ return
44
+
45
+ async with RedisServices() as redis_services:
46
+ if data.resource_type == ResourceType.folder and data.action_type in [
47
+ ActionType.delete,
48
+ ActionType.move,
49
+ ]:
50
+ await reload_redis(for_space=data.space_name)
51
+ return
52
+
53
+ if data.action_type == ActionType.delete:
54
+ doc_id = redis_services.generate_doc_id(
55
+ data.space_name,
56
+ "meta",
57
+ data.shortname,
58
+ data.subpath,
59
+ )
60
+ meta_doc = await redis_services.get_doc_by_id(doc_id)
61
+ # Delete meta doc
62
+ await redis_services.delete_doc(
63
+ data.space_name,
64
+ "meta",
65
+ data.shortname,
66
+ data.subpath,
67
+ )
68
+ # Delete payload doc
69
+ await redis_services.delete_doc(
70
+ data.space_name,
71
+ (
72
+ meta_doc.get("payload", {}).get("schema_shortname", "meta")
73
+ if meta_doc
74
+ else "meta"
75
+ ),
76
+ data.shortname,
77
+ data.subpath,
78
+ )
79
+ return
80
+ try:
81
+ meta = await db.load(
82
+ space_name=data.space_name,
83
+ subpath=data.subpath,
84
+ shortname=data.shortname,
85
+ class_type=class_type,
86
+ user_shortname=data.user_shortname,
87
+ )
88
+ except Exception as _:
89
+ return
90
+
91
+ if data.action_type in [
92
+ ActionType.create,
93
+ ActionType.update,
94
+ ActionType.progress_ticket,
95
+ ]:
96
+ meta_doc_id, meta_json = redis_services.prepare_meta_doc(
97
+ data.space_name, data.subpath, meta
98
+ )
99
+ payload: dict[str, Any] = {}
100
+ if (
101
+ meta.payload
102
+ and meta.payload.content_type == ContentType.json
103
+ and meta.payload.body is not None
104
+ ):
105
+ mypayload = await db.load_resource_payload(
106
+ space_name=data.space_name,
107
+ subpath=data.subpath,
108
+ filename=str(meta.payload.body),
109
+ class_type=class_type,
110
+ )
111
+ payload = mypayload if mypayload else {}
112
+
113
+ meta_json["payload_string"] = await generate_payload_string(
114
+ db,
115
+ space_name=data.space_name,
116
+ subpath=meta_json["subpath"],
117
+ shortname=meta_json["shortname"],
118
+ payload=payload,
119
+ ) if settings.store_payload_string else ""
120
+
121
+ await redis_services.save_doc(meta_doc_id, meta_json)
122
+ if meta.payload:
123
+ payload.update(meta_json)
124
+ await redis_services.save_payload_doc(
125
+ data.space_name,
126
+ data.subpath,
127
+ meta,
128
+ payload,
129
+ data.resource_type,
130
+ )
131
+
132
+ elif data.action_type == ActionType.move:
133
+ await redis_services.move_meta_doc(
134
+ data.space_name,
135
+ data.attributes["src_shortname"],
136
+ data.attributes["src_subpath"],
137
+ data.subpath,
138
+ meta,
139
+ )
140
+ if meta.payload and meta.payload.schema_shortname:
141
+ await redis_services.move_payload_doc(
142
+ data.space_name,
143
+ meta.payload.schema_shortname,
144
+ data.attributes["src_shortname"],
145
+ data.attributes["src_subpath"],
146
+ meta.shortname,
147
+ data.subpath,
148
+ )
149
+
150
+ async def update_parent_entry_payload_string(self) -> None:
151
+ async with RedisServices() as redis_services:
152
+ # get the parent meta doc
153
+ subpath_parts = self.data.subpath.strip("/").split("/")
154
+ if len(subpath_parts) <= 1:
155
+ return
156
+ parent_subpath, parent_shortname = (
157
+ "/".join(subpath_parts[:-1]),
158
+ subpath_parts[-1],
159
+ )
160
+ doc_id = redis_services.generate_doc_id(
161
+ self.data.space_name,
162
+ "meta",
163
+ parent_shortname,
164
+ parent_subpath,
165
+ )
166
+ meta_doc: dict = await redis_services.get_doc_by_id(doc_id)
167
+
168
+ if meta_doc is None:
169
+ raise Exception("Meta doc not found")
170
+
171
+ payload = {}
172
+ if meta_doc.get("payload_doc_id"):
173
+ payload_doc = await redis_services.get_doc_by_id(
174
+ meta_doc["payload_doc_id"]
175
+ )
176
+ payload = {k: v for k, v in payload_doc.items() if k not in meta_doc}
177
+
178
+ # generate the payload string
179
+ meta_doc["payload_string"] = await generate_payload_string(
180
+ db,
181
+ space_name=self.data.space_name,
182
+ subpath=parent_subpath,
183
+ shortname=parent_shortname,
184
+ payload=payload,
185
+ ) if settings.store_payload_string else ""
186
+
187
+ # update parent meta doc
188
+ await redis_services.save_doc(doc_id, meta_doc)
File without changes
@@ -0,0 +1,12 @@
1
+ {
2
+ "shortname": "resource_folders_creation",
3
+ "is_active": true,
4
+ "filters": {
5
+ "subpaths": ["__ALL__"],
6
+ "resource_types": ["user", "space"],
7
+ "schema_shortnames": ["__ALL__"],
8
+ "actions": ["create"]
9
+ },
10
+ "type": "hook",
11
+ "listen_time": "after"
12
+ }
@@ -0,0 +1,81 @@
1
+ from models.core import Folder, PluginBase, Event
2
+ from models.enums import ResourceType
3
+ from data_adapters.file.redis_services import RedisServices
4
+ from fastapi.logger import logger
5
+ from data_adapters.adapter import data_adapter as db
6
+ from utils.settings import settings
7
+
8
+
9
+ class Plugin(PluginBase):
10
+ async def hook(self, data: Event):
11
+ # Type narrowing for PyRight
12
+ if (
13
+ not isinstance(data.shortname, str)
14
+ or not isinstance(data.resource_type, ResourceType)
15
+ or not isinstance(data.attributes, dict)
16
+ ):
17
+ logger.error("invalid data at resource_folders_creation")
18
+ return
19
+
20
+ folders = []
21
+ if data.resource_type == ResourceType.user:
22
+ folders = [
23
+ ("personal", "people", data.shortname),
24
+ ("personal", f"people/{data.shortname}", "notifications"),
25
+ ("personal", f"people/{data.shortname}", "private"),
26
+ ("personal", f"people/{data.shortname}", "protected"),
27
+ ("personal", f"people/{data.shortname}", "public"),
28
+ ("personal", f"people/{data.shortname}", "inbox"),
29
+ ]
30
+ elif data.resource_type == ResourceType.space:
31
+ # sys_schemas = ["meta_schema", "folder_rendering"]
32
+ # for schema_name in sys_schemas:
33
+ # await clone(
34
+ # src_space=settings.management_space,
35
+ # src_subpath="schema",
36
+ # src_shortname=schema_name,
37
+ # dest_space=data.shortname,
38
+ # dest_subpath="schema",
39
+ # dest_shortname=schema_name,
40
+ # class_type=Schema,
41
+ # )
42
+ if settings.active_data_db == "file":
43
+ async with RedisServices() as redis_services:
44
+ await redis_services.create_indices(
45
+ for_space=data.shortname,
46
+ # for_schemas=sys_schemas,
47
+ for_custom_indices=False,
48
+ del_docs=False,
49
+ )
50
+
51
+ # redis_update_plugin = RedisUpdatePlugin()
52
+ # for schema_name in sys_schemas:
53
+ # await redis_update_plugin.hook(Event(
54
+ # space_name=data.shortname,
55
+ # subpath="schema",
56
+ # shortname=schema_name,
57
+ # action_type=ActionType.create,
58
+ # resource_type=ResourceType.schema,
59
+ # user_shortname=data.user_shortname
60
+ # ))
61
+
62
+ folders = [(data.shortname, "/", "schema")]
63
+
64
+ for folder in folders:
65
+ existing_folder = await db.load_or_none(
66
+ space_name=folder[0],
67
+ subpath=folder[1],
68
+ shortname=folder[2],
69
+ class_type=Folder,
70
+ user_shortname=data.user_shortname,
71
+ )
72
+ if existing_folder is None:
73
+ await db.internal_save_model(
74
+ space_name=folder[0],
75
+ subpath=folder[1],
76
+ meta=Folder(
77
+ shortname=folder[2],
78
+ is_active=True,
79
+ owner_shortname=data.user_shortname,
80
+ ),
81
+ )
File without changes
@@ -0,0 +1,13 @@
1
+ {
2
+ "shortname": "system_notification_sender",
3
+ "is_active": false,
4
+ "filters": {
5
+ "subpaths": ["__ALL__"],
6
+ "resource_types": ["__ALL__"],
7
+ "schema_shortnames": ["__ALL__"],
8
+ "actions": ["progress_ticket", "view", "create", "update", "delete", "attach", "move"]
9
+ },
10
+ "type": "hook",
11
+ "ordinal": 1,
12
+ "listen_time": "after"
13
+ }
@@ -0,0 +1,188 @@
1
+ from sys import modules as sys_modules
2
+ from uuid import uuid4
3
+ from models import api
4
+ from models.enums import ContentType, QueryType
5
+ from models.core import (
6
+ ActionType,
7
+ Content,
8
+ NotificationData,
9
+ Payload,
10
+ PluginBase,
11
+ Event,
12
+ Translation,
13
+ )
14
+ from utils.notification import NotificationManager
15
+ from utils.helpers import camel_case, replace_message_vars
16
+ from utils.settings import settings
17
+ from fastapi.logger import logger
18
+ from data_adapters.adapter import data_adapter as db
19
+
20
+
21
+ class Plugin(PluginBase):
22
+ async def hook(self, data: Event):
23
+ """
24
+ after any action
25
+ 1- get the matching SystemNotificationRequest for this action
26
+ 2- generate list of users to send the notification to (based on the action entry):
27
+ 2.1- entry.owner_shortname, entry.group.members?, and entry.collaborators?
28
+ 3- send the notification to the list of generated users
29
+ """
30
+ # Type narrowing for PyRight
31
+ if not isinstance(data.shortname, str):
32
+ logger.warning(
33
+ "data.shortname is None and str is required at system_notification_sender"
34
+ )
35
+ return
36
+
37
+ if data.action_type == ActionType.delete and data.attributes.get("entry"):
38
+ entry = data.attributes["entry"].model_dump()
39
+ else:
40
+ entry = (
41
+ await db.load(
42
+ data.space_name,
43
+ data.subpath,
44
+ data.shortname,
45
+ getattr(sys_modules["models.core"], camel_case(data.resource_type)),
46
+ data.user_shortname,
47
+ )
48
+ ).model_dump()
49
+ if entry["payload"] is not None:
50
+ try:
51
+ entry["payload"]["body"] = await db.load_resource_payload(
52
+ space_name=data.space_name,
53
+ subpath=data.subpath,
54
+ filename=entry["payload"]["body"],
55
+ class_type=getattr(
56
+ sys_modules["models.core"], camel_case(data.resource_type)
57
+ ),
58
+ )
59
+ except Exception as e:
60
+ logger.warning(
61
+ f"Failed to load payload for entry {data.space_name}/{data.subpath}/{data.shortname}: {e}"
62
+ )
63
+ entry["space_name"] = data.space_name
64
+ entry["resource_type"] = str(data.resource_type)
65
+ entry["subpath"] = data.subpath
66
+ # 1- get the matching SystemNotificationRequests
67
+ total, matching_notification_requests = await db.query(api.Query(
68
+ type=QueryType.search,
69
+ retrieve_json_payload=True,
70
+ space_name="management",
71
+ subpath="notifications/system",
72
+ search=f"@payload.body.on_space:{data.space_name} @payload.body.on_subpath:{data.subpath.lstrip('/')} @payload.body.on_action:{data.action_type}",
73
+ limit=30,
74
+ offset=0
75
+ ), "dmart")
76
+ if total == 0:
77
+ return
78
+
79
+ sub_matching_notification_requests = matching_notification_requests[0].model_dump()
80
+ notification_dict = sub_matching_notification_requests
81
+ if (
82
+ "state" in entry
83
+ and notification_dict.get("on_state", "") != ""
84
+ and notification_dict["on_state"] != entry["state"]
85
+ ):
86
+ return
87
+
88
+
89
+ # 2- get list of subscribed users
90
+ notification_subscribers =[]
91
+ # if entry.get("collaborators", None):
92
+ # notification_subscribers.extend(entry["collaborators"].values())
93
+
94
+ data_owner_shortname = entry["owner_shortname"]
95
+ if entry.get("owner_group_shortname", None):
96
+ group_users = await db.get_group_users(entry["owner_group_shortname"])
97
+ notification_subscribers.extend(group_users)
98
+ if data_owner_shortname in notification_subscribers:
99
+ notification_subscribers.remove(data_owner_shortname)
100
+ users_objects: dict[str, dict] = {}
101
+
102
+ for subscriber in notification_subscribers:
103
+ users_objects[subscriber] = (await db.load(
104
+ settings.management_space,
105
+ settings.users_subpath,
106
+ subscriber,
107
+ getattr(sys_modules["models.core"], camel_case("user")),
108
+ data.user_shortname,
109
+ )).model_dump()
110
+ # 3- send the notification
111
+ notification_manager = NotificationManager()
112
+
113
+ formatted_req = await self.prepare_request(notification_dict, entry)
114
+ for receiver in set(notification_subscribers):
115
+ if not formatted_req["push_only"]:
116
+ notification_content = Content(
117
+ shortname=str(uuid4())[:8],
118
+ is_active=True,
119
+ displayname=notification_dict["attributes"]["displayname"],
120
+ description=notification_dict["attributes"]["description"],
121
+ owner_shortname=receiver,
122
+ payload=Payload(
123
+ content_type=ContentType.json,
124
+ body={
125
+ "type": "system",
126
+ "is_read": False,
127
+ "priority": notification_dict["attributes"]["payload"]["body"]["priority"],
128
+ "entry_space": entry["space_name"],
129
+ "entry_subpath": entry["subpath"],
130
+ "entry_shortname": entry["shortname"],
131
+ "resource_type": entry["resource_type"],
132
+ "created_by": data.user_shortname,
133
+ "action_type": str(data.action_type)
134
+ }
135
+ )
136
+ )
137
+ await db.internal_save_model(
138
+ space_name="personal",
139
+ subpath=f"people/{receiver}/notifications",
140
+ meta=notification_content
141
+ )
142
+
143
+ for platform in formatted_req["platforms"]:
144
+ await notification_manager.send(
145
+ platform=platform,
146
+ data=NotificationData(
147
+ receiver=users_objects[receiver],
148
+ title=formatted_req["title"],
149
+ body=formatted_req["body"],
150
+ image_urls=formatted_req["images_urls"],
151
+ deep_link=notification_dict.get("deep_link", {}),
152
+ entry_id=entry["shortname"],
153
+ ),
154
+ )
155
+
156
+ async def prepare_request(self, notification_dict: dict, entry: dict) -> dict:
157
+ for locale in ["ar", "en", "ku"]:
158
+ if "displayname" in notification_dict:
159
+ notification_dict["displayname"][locale] = replace_message_vars(
160
+ notification_dict["displayname"][locale], entry, locale
161
+ )
162
+ if "description" in notification_dict:
163
+ notification_dict["description"][locale] = replace_message_vars(
164
+ notification_dict["description"][locale], entry, locale
165
+ )
166
+
167
+ # Get Notification Request Images
168
+ attachments_path = (
169
+ settings.spaces_folder
170
+ / f"{settings.management_space}"
171
+ f"/{notification_dict['subpath']}/.dm/{notification_dict['shortname']}"
172
+ )
173
+ notification_attachments = await db.get_entry_attachments(
174
+ subpath=f"{notification_dict['subpath']}/{notification_dict['shortname']}",
175
+ attachments_path=attachments_path,
176
+ )
177
+ notification_images = {
178
+ "en": notification_attachments.get("media", {}).get("en"),
179
+ "ar": notification_attachments.get("media", {}).get("ar"),
180
+ "ku": notification_attachments.get("media", {}).get("ku"),
181
+ }
182
+ return {
183
+ "platforms": notification_dict.get("types", []),
184
+ "title": Translation(**notification_dict.get("displayname", {})),
185
+ "body": Translation(**notification_dict.get("description", {})),
186
+ "images_urls": Translation(**notification_images),
187
+ "push_only": notification_dict.get("push_only", False),
188
+ }
File without changes
@@ -0,0 +1,12 @@
1
+ {
2
+ "shortname": "update_access_controls",
3
+ "is_active": true,
4
+ "filters": {
5
+ "subpaths": ["roles", "groups", "permissions", "users"],
6
+ "resource_types": ["group", "role", "permission", "user"],
7
+ "schema_shortnames": ["__ALL__"],
8
+ "actions": ["create", "update", "delete"]
9
+ },
10
+ "type": "hook",
11
+ "listen_time": "after"
12
+ }
@@ -0,0 +1,9 @@
1
+ from models.core import PluginBase, Event
2
+ from utils.access_control import access_control
3
+ from utils.settings import settings
4
+
5
+
6
+ class Plugin(PluginBase):
7
+ async def hook(self, data: Event):
8
+ if settings.active_data_db == "file":
9
+ await access_control.load_permissions_and_roles()
dmart/publish.sh ADDED
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ cd "$(dirname "$0")"
5
+
6
+ echo "Cleaning up dist/, build/, and temporary files..."
7
+ rm -rf dist/ build/ *.egg-info dmart info.json
8
+
9
+ echo "Building CXB..."
10
+ CXB_DIR="../cxb"
11
+ if [ -d "$CXB_DIR" ]; then
12
+ if [ -f "config.json" ]; then
13
+ cp "config.json" "$CXB_DIR/public/config.json"
14
+ elif [ -f "../config.json" ]; then
15
+ cp "../config.json" "$CXB_DIR/public/config.json"
16
+ elif [ ! -f "$CXB_DIR/public/config.json" ] && [ -f "$CXB_DIR/public/config.sample.json" ]; then
17
+ cp "$CXB_DIR/public/config.sample.json" "$CXB_DIR/public/config.json"
18
+ fi
19
+ pushd "$CXB_DIR"
20
+ yarn install
21
+ yarn build
22
+ popd
23
+
24
+ rm -rf cxb
25
+ cp -r "$CXB_DIR/dist/client" cxb
26
+ touch cxb/__init__.py
27
+ else
28
+ echo "CXB directory not found at $CXB_DIR"
29
+ exit 1
30
+ fi
31
+
32
+ echo "Installing dependencies..."
33
+ python3 -m pip install --upgrade pip build twine
34
+ python3 -m pip install .
35
+ if [ -d "requirements" ]; then
36
+ for req in requirements/*.txt; do
37
+ if [ -f "$req" ] && [[ "$req" != *"test.txt" ]]; then
38
+ python3 -m pip install -r "$req"
39
+ fi
40
+ done
41
+ fi
42
+
43
+ echo "Creating standalone bundle..."
44
+ python3 bundler.py
45
+
46
+ echo "Building dmart wheel and sdist..."
47
+ python3 -m build
48
+
49
+ rm -rf cxb
50
+ ln -s "../cxb/dist/client" cxb
51
+
52
+ if [ -f "dmart" ]; then
53
+ mv dmart dist/
54
+ fi
55
+
56
+ echo "Uploading to PyPI..."
57
+ twine upload --non-interactive dist/*.whl
dmart/pylint.sh ADDED
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+
3
+ declare -i RESULT=0
4
+ export PYRIGHT_PYTHON_FORCE_VERSION=latest
5
+ echo "Pyright ..."
6
+ python -m pyright .
7
+ RESULT+=$?
8
+ echo "Ruff ..."
9
+ python -m ruff check --exclude pytests --exclude alembic .
10
+ RESULT+=$?
11
+ echo "Mypy ..."
12
+ python -m mypy --explicit-package-bases --warn-return-any --check-untyped-defs --exclude loadtest --exclude pytests --exclude alembic .
13
+ RESULT+=$?
14
+
15
+ echo "Result : $RESULT"
16
+ exit $RESULT
@@ -0,0 +1,7 @@
1
+ {
2
+ "exclude": [
3
+ "alembic",
4
+ "loadtest",
5
+ "pytests"
6
+ ]
7
+ }
@@ -0,0 +1,13 @@
1
+ REDIS_HOST="$(./get_settings.py | jq -r .redis_host)"
2
+ RESULT+=$?
3
+ REDIS_PORT="$(./get_settings.py | jq -r .redis_port)"
4
+ RESULT+=$?
5
+ REDIS_PASSWORD="$(./get_settings.py | jq -r .redis_password)"
6
+ [ -z $REDIS_PASSWORD ] || REDIS_PASSWORD="--no-auth-warning -a $REDIS_PASSWORD"
7
+
8
+ while true
9
+ do
10
+ redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} ${REDIS_PASSWORD} info | grep connected_clients
11
+ redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} ${REDIS_PASSWORD} info | grep blocked_clients
12
+ sleep 1
13
+ done
dmart/reload.sh ADDED
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+
3
+ declare -i RESULT=0
4
+ source ./login_creds.sh
5
+ RESULT+=$?
6
+ CHECK_MODE="$(./get_settings.py | jq -r .active_data_db)"
7
+
8
+ RESULT+=$?
9
+ PORT="$(./get_settings.py | jq -r .listening_port)"
10
+ RESULT+=$?
11
+ # APP_URL="$(./get_settings.py | jq -r .app_url)"
12
+ APP_URL="http://localhost:$PORT"
13
+
14
+ if [[ "$CHECK_MODE" == "file" ]]; then
15
+ REDIS_HOST="$(./get_settings.py | jq -r .redis_host)"
16
+ RESULT+=$?
17
+ REDIS_PORT="$(./get_settings.py | jq -r .redis_port)"
18
+ RESULT+=$?
19
+ REDIS_PASSWORD="$(./get_settings.py | jq -r .redis_password)"
20
+ [ -z $REDIS_PASSWORD ] || REDIS_PASSWORD="--no-auth-warning -a $REDIS_PASSWORD"
21
+ time ./create_index.py --flushall
22
+ RESULT+=$?
23
+ fi
24
+
25
+ (which systemctl > /dev/null && systemctl --user list-unit-files dmart.service > /dev/null && systemctl --user restart dmart.service) || \
26
+ ( [[ -x "/etc/init.d/dmart" ]] && /etc/init.d/dmart restart )
27
+ RESULT+=$?
28
+ sleep 2
29
+ # RESP=$(curl --write-out '%{http_code}' --silent --output /dev/null "${APP_URL}")
30
+ RESP="000"
31
+ COUNTER=0
32
+ while [ $RESP -ne "200" ]; do
33
+ sleep 1
34
+ COUNTER=$((COUNTER+1))
35
+ echo "Waiting for the server to come up ${RESP} ${COUNTER} seconds"
36
+ RESP=$(curl --write-out '%{http_code}' --silent --connect-timeout 0.5 --output /dev/null "${APP_URL}")
37
+ [[ $COUNTER -ge 30 ]] && break
38
+ done
39
+ sleep 2
40
+
41
+ TOKEN=$(curl -s "${APP_URL}/user/login" -H 'Content-Type: application/json' -d "${SUPERMAN}" | jq -r '.records[0].attributes.access_token')
42
+ curl -s -H "Authorization: Bearer ${TOKEN}" -H "$CT" $APP_URL/user/profile | jq -r '.status'
43
+ RESULT+=$?
44
+
45
+ sleep 1
46
+ curl -s -H "Authorization: Bearer ${TOKEN}" "${APP_URL}/user/profile" | jq '.records[0].attributes.roles'
47
+ RESULT+=$?
48
+ if [[ "$CHECK_MODE" == "file" ]]; then
49
+ sleep 1
50
+ redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} ${REDIS_PASSWORD} JSON.GET users_permissions_dmart | jq -R '.|fromjson|keys|length'
51
+ # RESULT+=$?
52
+ fi
53
+
54
+
55
+ echo "Sum of exist codes = $RESULT"
56
+ exit $RESULT
dmart/run.sh ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ python -m hypercorn main:app --config file:utils/hypercorn_config.py