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,560 @@
1
+ #!/usr/bin/env -S BACKEND_ENV=config.env python3
2
+
3
+ import argparse
4
+ import asyncio
5
+ import json
6
+ import os
7
+ import shutil
8
+ import sys
9
+ import time
10
+ from datetime import datetime
11
+ from pathlib import Path
12
+
13
+ from jsonschema.validators import Draft7Validator
14
+ from redis.commands.search.query import Query
15
+ from redis.commands.search.result import Result
16
+
17
+ from api.managed.router import serve_request
18
+ from models.core import Folder
19
+ from utils import repository
20
+ from data_adapters.adapter import data_adapter as db
21
+ from data_adapters.file.custom_validations import get_schema_path
22
+ from utils.helpers import camel_case
23
+ from data_adapters.file.redis_services import RedisServices
24
+ from models import core, api
25
+ from models.enums import ContentType, RequestType, ResourceType
26
+ from utils.settings import settings
27
+
28
+ duplicated_entries : dict= {}
29
+
30
+ key_entries: dict = {}
31
+ MAX_INVALID_SIZE = 100
32
+
33
+ # {"space_name": {"schema_name": SCHEMA_DATA_DICT}}
34
+ spaces_schemas: dict[str, dict[str, dict]] = {}
35
+
36
+
37
+ async def main(health_type: str, space_param: str, schemas_param: list):
38
+ try:
39
+ spaces = await db.get_spaces()
40
+ if space_param != "all" and space_param not in spaces:
41
+ print("space name is not found")
42
+ return
43
+ if space_param == "all":
44
+ for space in spaces:
45
+ await main(health_type, space, schemas_param)
46
+ return
47
+ space_obj = core.Space.model_validate_json(spaces[space_param])
48
+ if not space_obj.check_health:
49
+ print(f"EARLY EXIT, health check disabled for space {space_param}")
50
+ return
51
+
52
+ await cleanup_spaces()
53
+ is_full: bool = True if not args.space or args.space == 'all' else False
54
+ print_header()
55
+ if health_type == 'soft':
56
+ print("Running soft healthcheck")
57
+ if not schemas_param and not is_full:
58
+ print('Add the space name and at least one schema')
59
+ return
60
+ if is_full:
61
+ params = await load_spaces_schemas(space_param)
62
+ else:
63
+ params = {space_param: schemas_param}
64
+ for space in params:
65
+ print(f'>>>> Processing {space:<10} <<<<')
66
+ before_time = time.time()
67
+ health_check : dict[str, list|dict] | None = {'invalid_folders': [], 'folders_report': {}}
68
+ for schema in params.get(space, []):
69
+ health_check_res = await soft_health_check(space, schema)
70
+ if health_check_res and health_check and isinstance(health_check['folders_report'], dict):
71
+ health_check['folders_report'].update(health_check_res.get('folders_report', {}))
72
+ print_health_check(health_check)
73
+ await save_health_check_entry(health_check, space)
74
+ print(f'Completed in: {"{:.2f}".format(time.time() - before_time)} sec')
75
+
76
+ elif not health_type or health_type == 'hard':
77
+ print("Running hard healthcheck")
78
+ spaces = {space_param : {}}
79
+ if is_full:
80
+ spaces = await db.get_spaces()
81
+ for space in spaces:
82
+ print(f'>>>> Processing {space:<10} <<<<')
83
+ before_time = time.time()
84
+ health_check = await hard_health_check(space)
85
+ if health_check:
86
+ await save_health_check_entry(health_check, space)
87
+ print_health_check(health_check)
88
+ print(f'Completed in: {"{:.2f}".format(time.time() - before_time)} sec')
89
+ else:
90
+ print("Wrong mode specify [soft or hard]")
91
+ return
92
+ await save_duplicated_entries()
93
+ finally:
94
+ await RedisServices().close_pool()
95
+
96
+
97
+ def print_header() -> None:
98
+ print("{:<32} {:<6} {:<6}".format(
99
+ 'subpath',
100
+ 'valid',
101
+ 'invalid')
102
+ )
103
+
104
+
105
+ def print_health_check(health_check):
106
+ if health_check:
107
+ for schema_path, val in health_check.get('folders_report', {}).items():
108
+ valid = val.get('valid_entries', 0)
109
+ invalid = len(val.get('invalid_entries', []))
110
+ print("{:<32} {:<6} {:<6}".format(
111
+ schema_path,
112
+ valid,
113
+ invalid)
114
+ )
115
+ for one in val.get("invalid_entries", []):
116
+ print(f"\t\t\t\tInvalid item/issues: {one.get('shortname', 'n/a')}/"
117
+ f"{','.join(one.get('issues', []))} - {one.get('exception','')}")
118
+ if health_check.get('invalid_folders'):
119
+ print('Invalid folders :')
120
+ for val in health_check.get('invalid_folders'):
121
+ print(f"\t\t\t\t {val}")
122
+
123
+
124
+ async def load_spaces_schemas(for_space: str | None = None) -> dict:
125
+ global spaces_schemas
126
+ if spaces_schemas:
127
+ return spaces_schemas
128
+ spaces = await db.get_spaces()
129
+ if for_space and for_space != "all" and for_space in spaces:
130
+ spaces_schemas[for_space] = load_space_schemas(for_space)
131
+ return spaces_schemas
132
+ for space_name in spaces:
133
+ schemas = load_space_schemas(space_name)
134
+ if schemas:
135
+ spaces_schemas[space_name] = schemas
136
+ return spaces_schemas
137
+
138
+
139
+ def load_space_schemas(space_name: str) -> dict[str, dict]:
140
+ schemas: dict[str, dict] = {}
141
+ schemas_path = Path(settings.spaces_folder / space_name / "schema" / ".dm")
142
+ if not schemas_path.is_dir():
143
+ return {}
144
+ for entry in os.scandir(schemas_path):
145
+ if not entry.is_dir():
146
+ continue
147
+
148
+ schema_path_meta = Path(schemas_path / entry.name / "meta.schema.json")
149
+ if not schema_path_meta.is_file():
150
+ continue
151
+
152
+ schema_meta = json.loads(schema_path_meta.read_text())
153
+ if schema_meta.get("payload", {}).get('body'):
154
+ schema_path_body = get_schema_path(
155
+ space_name=space_name,
156
+ schema_shortname=schema_meta.get("payload").get('body'),
157
+ )
158
+ if schema_path_body.is_file():
159
+ schemas[schema_meta['shortname']] = json.loads(schema_path_body.read_text())
160
+ return schemas
161
+
162
+
163
+ async def soft_health_check(
164
+ space_name: str,
165
+ schema_name: str,
166
+ ):
167
+ global spaces_schemas
168
+ if space_name not in spaces_schemas:
169
+ await load_spaces_schemas(space_name)
170
+
171
+ schemas = spaces_schemas[space_name]
172
+
173
+ limit = 1000
174
+ offset = 0
175
+ folders_report : dict = {}
176
+ async with RedisServices() as redis:
177
+ try:
178
+ ft_index = redis.ft(f"{space_name}:{schema_name}")
179
+ await ft_index.info()
180
+ except Exception:
181
+ if 'meta_schema' not in schema_name:
182
+ print(f"can't find index: `{space_name}:{schema_name}`")
183
+ return None
184
+ while True:
185
+ search_query = Query(query_string="*")
186
+ search_query.paging(offset, limit)
187
+ offset += limit
188
+ x = await ft_index.search(query=search_query) # type: ignore
189
+ if x and isinstance(x, dict) and "results" in x:
190
+ res_data : list = [one["extra_attributes"]["$"] for one in x["results"] if "extra_attributes" in one]
191
+ if not res_data:
192
+ break
193
+ else:
194
+ break
195
+ for redis_doc_dict in res_data:
196
+ redis_doc_dict = json.loads(redis_doc_dict)
197
+ subpath = redis_doc_dict['subpath']
198
+ meta_doc_content = {}
199
+ payload_doc_content = {}
200
+ resource_class = getattr(
201
+ sys.modules["models.core"],
202
+ camel_case(redis_doc_dict["resource_type"]),
203
+ )
204
+ system_attributes = [
205
+ "payload_string",
206
+ "query_policies",
207
+ "subpath",
208
+ "resource_type",
209
+ "meta_doc_id",
210
+ "payload_doc_id",
211
+ ]
212
+ class_fields = resource_class.model_fields.keys()
213
+ for key, value in redis_doc_dict.items():
214
+ if key in class_fields:
215
+ meta_doc_content[key] = value
216
+ elif key not in system_attributes:
217
+ payload_doc_content[key] = value
218
+
219
+ if not payload_doc_content and redis_doc_dict.get("payload_doc_id"):
220
+ payload_redis_doc = await redis.get_doc_by_id(
221
+ redis_doc_dict["payload_doc_id"]
222
+ )
223
+ if payload_redis_doc:
224
+ not_payload_attr = system_attributes + list(class_fields)
225
+ for key, value in payload_redis_doc.items():
226
+ if key not in not_payload_attr:
227
+ payload_doc_content[key] = value
228
+
229
+ meta_doc_content["created_at"] = datetime.fromtimestamp(
230
+ meta_doc_content["created_at"]
231
+ )
232
+ meta_doc_content["updated_at"] = datetime.fromtimestamp(
233
+ meta_doc_content["updated_at"]
234
+ )
235
+ if not folders_report.get(subpath):
236
+ folders_report[subpath] = {}
237
+
238
+ meta = None
239
+ status = {
240
+ 'is_valid': True,
241
+ "invalid": {
242
+ "issues": [],
243
+ "uuid": redis_doc_dict.get("uuid"),
244
+ "shortname": redis_doc_dict.get("shortname"),
245
+ "resource_type": redis_doc_dict["resource_type"],
246
+ "exception": ""
247
+ }
248
+ }
249
+ try:
250
+ meta = resource_class.model_validate(meta_doc_content)
251
+ except Exception as ex:
252
+ status['is_valid'] = False
253
+ if not isinstance(status, dict) and isinstance(status["invalid"], dict):
254
+ status['invalid']['exception'] = str(ex)
255
+ status['invalid']['issues'].append('meta')
256
+ if meta:
257
+ try:
258
+ if meta.payload and meta.payload.schema_shortname and payload_doc_content is not None:
259
+ schema_dict: dict = schemas.get(meta.payload.schema_shortname, {})
260
+ if schema_dict:
261
+ Draft7Validator(schema_dict).validate(payload_doc_content)
262
+ else:
263
+ continue
264
+ if(
265
+ meta.payload.checksum and
266
+ meta.payload.client_checksum and
267
+ meta.payload.checksum != meta.payload.client_checksum
268
+ ):
269
+ raise Exception(
270
+ f"payload.checksum not equal payload.client_checksum {subpath}/{meta.shortname}"
271
+ )
272
+ if folders_report[subpath].get('valid_entries'):
273
+ folders_report[subpath]['valid_entries'] += 1
274
+ else:
275
+ folders_report[subpath]['valid_entries'] = 1
276
+ status['is_valid'] = True
277
+ except Exception as ex:
278
+ status['is_valid'] = False
279
+ if not isinstance(status, dict) and isinstance(status["invalid"], dict):
280
+ status['invalid']['exception'] = str(ex)
281
+ status['invalid']['issues'].append('payload')
282
+
283
+ if not status['is_valid']:
284
+ if not folders_report.get(subpath, {}).get('invalid_entries'):
285
+ folders_report[subpath]['invalid_entries'] = []
286
+ if meta_doc_content["shortname"] not in folders_report[redis_doc_dict['subpath']]["invalid_entries"]:
287
+ if len(folders_report[redis_doc_dict['subpath']]["invalid_entries"]) >= MAX_INVALID_SIZE:
288
+ break
289
+ folders_report[redis_doc_dict['subpath']]["invalid_entries"].append(status.get('invalid'))
290
+
291
+ # uuid = redis_doc_dict['uuid'][:8]
292
+ # await collect_duplicated_with_key('uuid', uuid)
293
+ # if redis_doc_dict.get('slug'):
294
+ # await collect_duplicated_with_key('slug', redis_doc_dict.get('slug'))
295
+
296
+ return {"invalid_folders": [], "folders_report": folders_report}
297
+
298
+
299
+ async def collect_duplicated_with_key(key, value) -> None:
300
+ spaces = await db.get_spaces()
301
+ async with RedisServices() as redis:
302
+ for space_name, space_data in spaces.items():
303
+ space_data = json.loads(space_data)
304
+ try:
305
+ ft_index = redis.ft(f"{space_name}:meta")
306
+ await ft_index.info()
307
+ except Exception:
308
+ continue
309
+ search_query = Query(query_string=f"@{key}:{value}*")
310
+ search_query.paging(0, 1000)
311
+ x = await ft_index.search(query=search_query) # type: ignore
312
+ if x and isinstance(x, Result):
313
+ res_data: Result = x
314
+ for redis_doc_dict in res_data.docs:
315
+ redis_doc_dict = json.loads(redis_doc_dict.json)
316
+ if isinstance(redis_doc_dict, dict):
317
+ if redis_doc_dict['subpath'] == '/':
318
+ redis_doc_dict['subpath'] = ''
319
+ loc = space_name + "/" + redis_doc_dict['subpath']
320
+ if key not in key_entries:
321
+ key_entries[key] = {}
322
+ if not key_entries[key].get(value):
323
+ key_entries[key][value] = loc
324
+ else:
325
+ if not duplicated_entries.get(key):
326
+ duplicated_entries[key] = {}
327
+ if not duplicated_entries[key].get(value) or \
328
+ key_entries[key][value] not in duplicated_entries[key][value]['loc']:
329
+ duplicated_entries[key][value] = {}
330
+ duplicated_entries[key][value]['loc'] = [key_entries[key][value]]
331
+ duplicated_entries[key][value]['total'] = 1
332
+ if loc not in duplicated_entries[key][value]['loc']:
333
+ duplicated_entries[key][value]['total'] += 1
334
+ duplicated_entries[key][value]['loc'].append(loc)
335
+
336
+
337
+ async def hard_health_check(space_name: str):
338
+ spaces = await db.get_spaces()
339
+ if space_name not in spaces:
340
+ print("space name is not found")
341
+ return None
342
+ # remove checking check_health value from meta space
343
+ # space_obj = core.Space.model_validate_json(spaces[space_name])
344
+ # if not space_obj.check_health:
345
+ # print(f"EARLY EXIT, health check disabled for space {space_name}")
346
+ # return None
347
+
348
+ invalid_folders : list = []
349
+ folders_report: dict[str, dict] = {}
350
+ meta_folders_health: list = []
351
+
352
+ path = settings.spaces_folder / space_name
353
+
354
+ subpaths = os.scandir(path)
355
+ # print(f"{path=} {subpaths=}")
356
+ for subpath in subpaths:
357
+ if subpath.is_file():
358
+ continue
359
+
360
+ await repository.validate_subpath_data(
361
+ space_name=space_name,
362
+ subpath=subpath.path,
363
+ user_shortname='dmart',
364
+ invalid_folders=invalid_folders,
365
+ folders_report=folders_report,
366
+ meta_folders_health=meta_folders_health,
367
+ max_invalid_size=MAX_INVALID_SIZE
368
+ )
369
+ res = {"invalid_folders": invalid_folders, "folders_report": folders_report}
370
+ if meta_folders_health:
371
+ res['invalid_folders'] = meta_folders_health
372
+ return res
373
+
374
+
375
+ async def save_health_check_entry(health_check, space_name: str):
376
+ meta_path = Path(settings.spaces_folder / "management/health_check/.dm" / space_name)
377
+ entry_path = Path(settings.spaces_folder / "management/health_check" / f"{space_name}.json")
378
+ if meta_path.is_dir():
379
+ shutil.rmtree(meta_path)
380
+ if entry_path.is_file():
381
+ os.remove(entry_path)
382
+ await serve_request(
383
+ request=api.Request(
384
+ space_name="management",
385
+ request_type=RequestType.create,
386
+ records=[
387
+ core.Record(
388
+ resource_type=ResourceType.content,
389
+ shortname=space_name,
390
+ subpath="/health_check",
391
+ attributes={
392
+ "is_active": True,
393
+ "updated_at": str(datetime.now()),
394
+ "payload": {
395
+ "schema_shortname": "health_check",
396
+ "content_type": ContentType.json,
397
+ "body": health_check
398
+ }
399
+ },
400
+ )
401
+ ],
402
+ ),
403
+ owner_shortname='dmart',
404
+ )
405
+
406
+
407
+ async def save_duplicated_entries() -> None:
408
+ print('>>>> Processing UUID duplication <<<<')
409
+ before_time = time.time()
410
+ uuid_scanned_entries: set = set()
411
+ uuid_duplicated_entries: dict = {}
412
+
413
+ slug_scanned_entries = set()
414
+ slug_duplicated_entries: dict = {}
415
+ spaces : dict = await db.get_spaces()
416
+ async with RedisServices() as redis:
417
+ for space_name, space_data in spaces.items():
418
+ space_data = json.loads(space_data)
419
+ try:
420
+ ft_index = redis.ft(f"{space_name}:meta")
421
+ index_info = await ft_index.info() # type: ignore
422
+ except Exception:
423
+ continue
424
+ for i in range(0, int(index_info["num_docs"]), 10000): # type: ignore
425
+ search_query = Query(query_string="*")
426
+ search_query.paging(i, 10000)
427
+ x = await ft_index.search(query=search_query) # type: ignore
428
+ if x and isinstance(x, dict) and "results" in x:
429
+ res_data : list = [ one["extra_attributes"]["$"] for one in x["results"] if 'extra_attributes' in one]
430
+ for redis_doc_dict in res_data:
431
+ redis_doc_dict = json.loads(redis_doc_dict)
432
+ if isinstance(redis_doc_dict, dict):
433
+ if "uuid" in redis_doc_dict:
434
+ # Handle UUID
435
+ if "uuid" in redis_doc_dict and redis_doc_dict["uuid"] in uuid_scanned_entries:
436
+ short_uuid = redis_doc_dict["uuid"][:8]
437
+ uuid_duplicated_entries.setdefault(
438
+ short_uuid, {"loc": [], "total": 0}
439
+ )
440
+ uuid_duplicated_entries[short_uuid]["loc"].append(
441
+ space_name + "/" + redis_doc_dict['subpath'] + "/" + redis_doc_dict['shortname']
442
+ )
443
+ uuid_duplicated_entries[short_uuid]["total"]+=1
444
+ else:
445
+ uuid_scanned_entries.add(redis_doc_dict["uuid"])
446
+ else:
447
+ print ("UUID is missing", redis_doc_dict)
448
+
449
+ # Handle Slug
450
+ if "slug" in redis_doc_dict and redis_doc_dict["slug"] in slug_scanned_entries:
451
+ slug_duplicated_entries.setdefault(
452
+ "slug", {"loc": [], "total": 0}
453
+ )
454
+ slug_duplicated_entries["slug"]["loc"].append(
455
+ space_name + "/" + redis_doc_dict['subpath'] + "/" + redis_doc_dict['shortname']
456
+ )
457
+ slug_duplicated_entries["slug"]["total"]+=1
458
+ elif "slug" in redis_doc_dict:
459
+ slug_scanned_entries.add(redis_doc_dict["slug"])
460
+ else:
461
+ print("Loaded document is not a proper dictionary")
462
+
463
+
464
+
465
+
466
+ entry_path = Path(settings.spaces_folder / "management/health_check/.dm/duplicated_entries/meta.content.json")
467
+ request_type = RequestType.create
468
+ if entry_path.is_file():
469
+ request_type = RequestType.update
470
+ await serve_request(
471
+ request=api.Request(
472
+ space_name=settings.management_space,
473
+ request_type=request_type,
474
+ records=[
475
+ core.Record(
476
+ resource_type=ResourceType.content,
477
+ shortname="duplicated_entries",
478
+ subpath="/health_check",
479
+ attributes={
480
+ "is_active": True,
481
+ "updated_at": str(datetime.now()),
482
+ "payload": {
483
+ "schema_shortname": "health_check",
484
+ "content_type": ContentType.json,
485
+ "body": {
486
+ "entries": {
487
+ "uuid": uuid_duplicated_entries,
488
+ "slug": slug_duplicated_entries
489
+ }
490
+ }
491
+ }
492
+ },
493
+ )
494
+ ],
495
+ ),
496
+ owner_shortname='dmart',
497
+ )
498
+
499
+ print(f'Completed in: {"{:.2f}".format(time.time() - before_time)} sec')
500
+
501
+
502
+ async def cleanup_spaces() -> None:
503
+ spaces = await db.get_spaces()
504
+ # create health check path meta
505
+ folder_path = Path(settings.spaces_folder / "management/health_check/.dm")
506
+ if not os.path.isdir(folder_path):
507
+ os.makedirs(folder_path)
508
+ file_path = Path(folder_path / "meta.folder.json")
509
+ # create meta folder
510
+ if not os.path.isfile(file_path):
511
+ meta_obj = Folder(shortname="health_check", is_active=True, owner_shortname='dmart')
512
+ with open(file_path, "w") as f:
513
+ f.write(meta_obj.model_dump_json(exclude_none=True))
514
+ # create health check schema
515
+ if (
516
+ not os.path.isfile(Path(settings.spaces_folder / "management/schema/health_check.json")) or
517
+ not os.path.isfile(Path(settings.spaces_folder / "management/schema/.dm/health_check/meta.schema.json"))
518
+ ):
519
+ meta = core.Schema(
520
+ shortname="health_check",
521
+ is_active=True,
522
+ owner_shortname="dmart",
523
+ payload=core.Payload(
524
+ content_type=ContentType.json,
525
+ body="health_check.json",
526
+ ),
527
+ )
528
+ schema = {
529
+ "type": "object",
530
+ "title": "health_check",
531
+ "additionalProperties": True,
532
+ "properties": {
533
+ },
534
+ "required": []
535
+ }
536
+ await db.save("management", "schema", meta)
537
+ await db.save_payload_from_json("management", "schema", meta, schema)
538
+
539
+ # clean up entries
540
+ for folder_name in os.listdir(folder_path):
541
+ if not os.path.isdir(os.path.join(folder_path, folder_name)):
542
+ continue
543
+ if folder_name not in spaces:
544
+ shutil.rmtree(Path(folder_path / folder_name))
545
+ os.remove(Path(settings.spaces_folder / "management/health_check" / f"{folder_name}.json"))
546
+
547
+
548
+ if __name__ == "__main__":
549
+ parser = argparse.ArgumentParser(
550
+ description="This created for doing health check functionality",
551
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
552
+ )
553
+ parser.add_argument("-t", "--type", help="type of health check (soft or hard)")
554
+ parser.add_argument("-s", "--space", help="hit the target space or pass (all) to make the full health check")
555
+ parser.add_argument("-m", "--schemas", nargs="*", help="hit the target schema inside the space")
556
+
557
+ args = parser.parse_args()
558
+ before_time = time.time()
559
+ asyncio.run(main(args.type, args.space or "all", args.schemas))
560
+ print(f'total time: {"{:.2f}".format(time.time() - before_time)} sec')