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,57 @@
1
+ from firebase_admin import credentials, messaging, initialize_app # type: ignore
2
+ from utils.notification import Notifier
3
+ from utils.helpers import lang_code
4
+ from utils.settings import settings
5
+ from models.core import NotificationData
6
+
7
+ class FirebaseNotifier(Notifier):
8
+
9
+ def _init_connection(self) -> None:
10
+ if not hasattr(self, "_firebase_app"):
11
+ firebase_cred = credentials.Certificate(settings.google_application_credentials)
12
+ self._firebase_app = initialize_app(firebase_cred, name="[DEFAULT]")
13
+
14
+
15
+
16
+ async def send(
17
+ self,
18
+ data: NotificationData
19
+ ) -> bool:
20
+ self._init_connection()
21
+ # Receiver should be user.firebase_token
22
+ if "firebase_token" not in data.receiver:
23
+ raise Exception("Missing token for user shortname:"\
24
+ f"{data.receiver.get('shortname')} - msisdn {data.receiver.get('msisdn')}")
25
+ user_lang = lang_code(data.receiver.get("language", "ar"))
26
+ title = data.title.__getattribute__(user_lang)
27
+ body = data.body.__getattribute__(user_lang)
28
+ image_url = (
29
+ data.image_urls.__getattribute__(user_lang) if data.image_urls else ""
30
+ ) or ""
31
+
32
+ alert = messaging.ApsAlert(title = title, body = body)
33
+ aps = messaging.Aps( alert = alert, sound = "default", content_available = True )
34
+ apns = messaging.APNSConfig(
35
+ payload=messaging.APNSPayload(aps),
36
+ fcm_options=messaging.APNSFCMOptions(image=image_url),
37
+ )
38
+ # apns = messaging.APNSConfig( payload = messaging.APNSPayload(aps))
39
+ android_notification_settings = messaging.AndroidNotification(
40
+ priority="high",
41
+ channel_id="FCM_CHANNEL_ID",
42
+ visibility="public",
43
+ image=image_url
44
+ )
45
+ android_config = messaging.AndroidConfig(priority="high", notification=android_notification_settings)
46
+ web_push = messaging.WebpushConfig(headers={"image": image_url})
47
+ message = messaging.Message(
48
+ notification=messaging.Notification(title=title, body=body),
49
+ token=data.receiver["firebase_token"],
50
+ apns=apns,
51
+ android=android_config,
52
+ webpush=web_push,
53
+ data={**data.deep_link, "id": data.entry_id}
54
+ )
55
+ messaging.send(message, app=self._firebase_app)
56
+ return True
57
+
@@ -0,0 +1,37 @@
1
+ from jinja2 import Environment, FileSystemLoader
2
+ from pathlib import Path
3
+
4
+
5
+ def generate_email_from_template(template, data):
6
+ templates_dir = Path(__file__).resolve().parent / "templates"
7
+ environment = Environment(
8
+ loader=FileSystemLoader(str(templates_dir))
9
+ )
10
+ match template:
11
+ case "activation":
12
+ template = environment.get_template("activation.html.j2")
13
+ return template.render(
14
+ name=data.get("name"),
15
+ msisdn=data.get("msisdn"),
16
+ shortname=data.get("shortname"),
17
+ link=data.get("link"),
18
+ )
19
+
20
+ case "reminder":
21
+ template = environment.get_template("reminder.html.j2")
22
+ return template.render(
23
+ name=data.get("name"),
24
+ link=data.get("link"),
25
+ )
26
+ case _:
27
+ return ""
28
+
29
+
30
+ def generate_subject(template):
31
+ match template:
32
+ case "activation":
33
+ return "Welcome to our Platform!"
34
+ case "reminder":
35
+ return "[Reminder] Activate Your Account"
36
+ case _:
37
+ return ""
dmart/utils/helpers.py ADDED
@@ -0,0 +1,352 @@
1
+ from copy import deepcopy
2
+ import csv
3
+ from datetime import datetime
4
+ import json
5
+ from pathlib import Path
6
+ from re import sub as re_sub
7
+ from uuid import UUID
8
+
9
+ import aiofiles
10
+ from jsonschema.validators import _RefResolver as RefResolver # type: ignore
11
+
12
+ # TBD from referencing import Registry, Resource
13
+ # TBD import referencing.jsonschema
14
+ from collections.abc import MutableMapping
15
+ from models.enums import Language
16
+ from typing import Any
17
+ from languages.loader import languages
18
+
19
+
20
+ def flatten_all(d: MutableMapping, parent_key: str = "", sep: str = ".") -> dict:
21
+ items: list = []
22
+ for k, v in d.items():
23
+ new_key = parent_key + sep + k if parent_key else k
24
+ if isinstance(v, MutableMapping):
25
+ items.extend(flatten_all(v, new_key, sep=sep).items())
26
+ elif isinstance(v, list):
27
+ items.extend(flatten_all(flatten_list(v), new_key, sep=sep).items())
28
+ else:
29
+ items.append((new_key, v))
30
+ return dict(items)
31
+
32
+
33
+ def flatten_dict(d, parent_key='', sep='.'):
34
+ items = []
35
+ for k, v in d.items():
36
+ new_key = f"{parent_key}{sep}{k}" if parent_key else k
37
+ if isinstance(v, dict):
38
+ items.extend(flatten_dict(v, new_key, sep=sep).items())
39
+ else:
40
+ items.append((new_key, v))
41
+ return dict(items)
42
+
43
+
44
+ def flatten_list(ll: list, key: str | None = None):
45
+ flattened = {}
46
+ for idx, item in enumerate(ll):
47
+ flattened[f"{key}.{idx}" if key else f"{idx}"] = item
48
+ return flattened
49
+
50
+
51
+ def arr_remove_common(arr1: list, arr2: list):
52
+ for i1 in arr1[:]:
53
+ if i1 in arr2:
54
+ arr1.remove(i1)
55
+ arr2.remove(i1)
56
+
57
+ return arr1, arr2
58
+
59
+
60
+ def get_removed_items(arr1: list, arr2: list):
61
+ removed_items = []
62
+
63
+ for i1 in arr1:
64
+ if i1 not in arr2:
65
+ removed_items.append(i1)
66
+
67
+ return removed_items
68
+
69
+
70
+ def flatten_list_of_dicts_in_dict(d: dict) -> dict:
71
+ """
72
+ example:
73
+ d = {
74
+ "key": [
75
+ {
76
+ 'imsi': '12345',
77
+ 'name': 'Saad Adel'
78
+ },
79
+ {
80
+ 'imsi': '556566',
81
+ 'name': 'Saad Adel'
82
+ }
83
+ ],
84
+ "another": "s",
85
+ "another2": 222,
86
+ }
87
+ return {
88
+ "key.imsi": ['12345', '556566'],
89
+ "key.name": ['Saad Adel', 'Saad Adel'],
90
+ "another": "s",
91
+ "another2": 222,
92
+ }
93
+ """
94
+ flattened_d = deepcopy(d)
95
+ for parent_key, list_of_dict in d.items():
96
+ if (
97
+ isinstance(list_of_dict, list)
98
+ and len(list_of_dict) > 0
99
+ and isinstance(list_of_dict[0], dict)
100
+ ):
101
+ flattened: dict = {}
102
+ for dict_item in list_of_dict:
103
+ for key, value in dict_item.items():
104
+ flattened.setdefault(f"{parent_key}.{key}", [])
105
+ flattened[f"{parent_key}.{key}"].append(value)
106
+ flattened_d.pop(parent_key)
107
+ flattened_d.update(flattened)
108
+
109
+ return flattened_d
110
+
111
+
112
+ def resolve_schema_references(schema: dict, refs: dict = {}) -> dict:
113
+ """Resolves and replaces json-schema $refs with the appropriate dict.
114
+
115
+ Recursively walks the given schema dict, converting every instance
116
+ of $ref in a 'properties' structure with a resolved dict.
117
+
118
+ This modifies the input schema and also returns it.
119
+
120
+ Arguments:
121
+ schema:
122
+ the schema dict
123
+ refs:
124
+ a dict of <string, dict> which forms a store of referenced schemata
125
+
126
+ Returns:
127
+ schema
128
+ """
129
+ refs = refs or {}
130
+ resolved_schema = _resolve_schema_references(
131
+ schema, RefResolver("", schema, store=refs)
132
+ )
133
+ if "definitions" in resolved_schema:
134
+ resolved_schema.pop("definitions")
135
+ return resolved_schema
136
+
137
+
138
+ def _resolve_schema_references(schema: dict, resolver) -> dict:
139
+ if "$ref" in schema:
140
+ reference_path = schema.pop("$ref", None)
141
+ resolved = resolver.resolve(reference_path)[1]
142
+ schema.update(resolved)
143
+ return _resolve_schema_references(schema, resolver)
144
+
145
+ if "properties" in schema:
146
+ for k, val in schema["properties"].items():
147
+ schema["properties"][k] = _resolve_schema_references(val, resolver)
148
+
149
+ if "patternProperties" in schema:
150
+ for k, val in schema["patternProperties"].items():
151
+ schema["patternProperties"][k] = _resolve_schema_references(val, resolver)
152
+
153
+ if "items" in schema:
154
+ schema["items"] = _resolve_schema_references(schema["items"], resolver)
155
+
156
+ if "anyOf" in schema:
157
+ for i, element in enumerate(schema["anyOf"]):
158
+ schema["anyOf"][i] = _resolve_schema_references(element, resolver)
159
+
160
+ if "oneOf" in schema:
161
+ for i, element in enumerate(schema["oneOf"]):
162
+ schema["oneOf"][i] = _resolve_schema_references(element, resolver)
163
+
164
+ return schema
165
+
166
+
167
+ def camel_case(snake_str):
168
+ words = snake_str.split("_")
169
+ return "".join(word.title() for word in words)
170
+
171
+
172
+ def snake_case(camel_str):
173
+ return re_sub(r"(?<!^)(?=[A-Z])", "_", camel_str).lower()
174
+
175
+
176
+ def divide_chunks(lll, n):
177
+ """
178
+ Yield successive n-sized chunks from lll.
179
+ """
180
+
181
+ # looping till length l
182
+ for i in range(0, len(lll), n):
183
+ yield lll[i : i + n]
184
+
185
+
186
+ def remove_none_dict(target: dict[str, Any] ) -> dict[str, Any]:
187
+ new_d: dict = {}
188
+ for key, val in target.items():
189
+ if val is None:
190
+ continue
191
+
192
+ if isinstance(val, dict) :
193
+ new_d[key] = remove_none_dict(val)
194
+ elif isinstance(val, list):
195
+ new_d[key] = remove_none_list(val)
196
+ else:
197
+ new_d[key] = val
198
+
199
+ return new_d
200
+
201
+ def remove_none_list(target: list):
202
+ new_l: list = []
203
+ for val in target:
204
+ if val is None:
205
+ continue
206
+
207
+ if isinstance(val, dict) :
208
+ new_l.append(remove_none_dict(val))
209
+ elif isinstance(val, list):
210
+ new_l.append(remove_none_list(val))
211
+ else:
212
+ new_l.append(val)
213
+
214
+ return new_l
215
+
216
+
217
+ def alter_dict_keys(
218
+ target: dict,
219
+ include: list | None = None,
220
+ exclude: list | None = None,
221
+ parents: str = "",
222
+ ):
223
+ result: dict = {}
224
+ for k in list(target):
225
+ search_for = f"{parents}.{k}" if parents else f"{k}"
226
+ if isinstance(target[k], dict):
227
+ if include and search_for in include:
228
+ result[k] = target[k]
229
+ continue
230
+ if exclude and search_for in exclude:
231
+ continue
232
+ result[k] = alter_dict_keys(
233
+ target[k], include, exclude, search_for if parents else f"{k}"
234
+ )
235
+
236
+ elif (include and search_for not in include) or (
237
+ exclude and search_for in exclude
238
+ ):
239
+ continue
240
+
241
+ else:
242
+ result[k] = target[k]
243
+
244
+ return result
245
+
246
+
247
+ def json_flater(data: dict[str, Any]) -> dict[str, Any]:
248
+ flatened_data = {}
249
+ for k, v in data.items():
250
+ if isinstance(v, dict):
251
+ __flatened_data = json_flater(v)
252
+ _flatened_data = {
253
+ key: val for key, val in __flatened_data.items()
254
+ } # deep copy to resolve the runtime error
255
+ _keys = list(_flatened_data.keys())
256
+ for key in _keys:
257
+ flatened_data[f"{k}.{key}"] = _flatened_data[key]
258
+ if k in flatened_data and key in flatened_data[k]:
259
+ del flatened_data[k][key]
260
+ else:
261
+ flatened_data = {**flatened_data, k: v}
262
+ return flatened_data
263
+
264
+
265
+ def lang_code(lang: Language):
266
+ match lang:
267
+ case Language.ar:
268
+ return "ar"
269
+ case Language.en:
270
+ return "en"
271
+ case Language.ku:
272
+ return "ku"
273
+ case Language.fr:
274
+ return "fr"
275
+ case Language.tr:
276
+ return "tr"
277
+
278
+
279
+ def replace_message_vars(message: str, dest_data: dict, locale: str):
280
+ dest_data_dict = flatten_dict(dest_data)
281
+ for field, value in dest_data_dict.items():
282
+ if isinstance(value, dict) and locale in value:
283
+ value = value[locale]
284
+ if field in ["created_at", "updated_at"]:
285
+ message = message.replace(
286
+ f"{{{field}}}",
287
+ datetime.strptime(str(value), "%Y-%m-%d %H:%M:%S.%f").strftime(
288
+ "%Y-%m-%d %H:%M:%S"
289
+ ),
290
+ )
291
+ else:
292
+ message = message.replace(
293
+ f"{{{field}}}", languages[Language[locale]].get(str(value), str(value))
294
+ )
295
+
296
+ return re_sub(r"\{\w*.*\}", "", message)
297
+
298
+
299
+ def str_to_datetime(str: str, format: str = "%Y-%m-%dT%H:%M:%S.%f"):
300
+ return datetime.strptime(str, format)
301
+
302
+
303
+ def pp(*args, **kwargs):
304
+ """
305
+ Pretty Print
306
+ """
307
+ print_str = "\n\n================== DUMP DATA ==================\n"
308
+ if args:
309
+ for arg in args:
310
+ print_str += f"\n\narg: {arg}"
311
+
312
+ if kwargs:
313
+ for k, v in kwargs.items():
314
+ print_str += f"\n\n{k}: {v}"
315
+
316
+ print_str += "\n\n_____________________END________________________\n\n"
317
+ print(print_str)
318
+
319
+
320
+ async def csv_file_to_json(csv_file_path: Path) -> list[dict[str, Any]]:
321
+ data: list[dict[str, Any]] = []
322
+
323
+ async with aiofiles.open(
324
+ csv_file_path, mode="r", encoding="utf-8", newline=""
325
+ ) as csvf:
326
+ contents = await csvf.readlines()
327
+ csvReader = csv.DictReader(contents)
328
+
329
+ for row in csvReader:
330
+ data.append(row)
331
+
332
+ return data
333
+
334
+ def read_jsonl_file(file_path):
335
+ data = []
336
+ with open(file_path, 'r') as file:
337
+ for line in file:
338
+ data.append(json.loads(line))
339
+ return data
340
+
341
+
342
+ def jq_dict_parser(data):
343
+ if isinstance(data, dict):
344
+ return {k: jq_dict_parser(v) for k, v in data.items()}
345
+ elif isinstance(data, list):
346
+ return [jq_dict_parser(item) for item in data]
347
+ elif isinstance(data, UUID):
348
+ return str(data)
349
+ elif isinstance(data, datetime):
350
+ return str(data)
351
+ else:
352
+ return data
@@ -0,0 +1,12 @@
1
+ from utils.settings import settings
2
+ from os import cpu_count
3
+ from fastapi.logger import logger
4
+ from utils.logger import logging_schema
5
+
6
+
7
+ bind = [f"{settings.listening_host}:{settings.listening_port}"]
8
+ workers = cpu_count()
9
+ backlog = 200
10
+ worker_class = "asyncio"
11
+ logconfig_dict = logging_schema
12
+ errorlog = logger
@@ -0,0 +1,60 @@
1
+ class InternalErrorCode:
2
+ NOT_ALLOWED = 401
3
+ UNPROCESSABLE_ENTITY = 424
4
+ INVALID_IDENTIFIER = 420
5
+ INVALID_CONFIRMATION = 427
6
+ SHORTNAME_ALREADY_EXIST = 400
7
+ SHORTNAME_DOES_NOT_EXIST = 404
8
+ INVALID_DATA = 402
9
+ SOMETHING_WRONG = 430
10
+ INVALID_HEALTH_CHECK = 403
11
+ INVALID_APP_KEY = 555
12
+ INVALID_ROUTE = 230
13
+ OBJECT_NOT_FOUND = 220
14
+ INVALID_SPACE_NAME = 203
15
+ CANNT_DELETE = 204
16
+ ALREADY_EXIST_SPACE_NAME = 205
17
+ MISSING_DATA = 202
18
+ NOT_ALLOWED_LOCATION = 206
19
+ PROVID_SOURCE_PATH = 222
20
+ MISSING_DESTINATION_OR_SHORTNAME = 213
21
+ EMAIL_OR_MSISDN_REQUIRED = 207
22
+ MISSING_METADATA = 208
23
+ MISSING_FILTER_SHORTNAMES = 209
24
+ WORKFLOW_BODY_NOT_FOUND = 218
25
+ NOT_SUPPORTED_TYPE = 217
26
+ SOME_SUPPORTED_TYPE = 219
27
+ TICKET_ALREADY_CLOSED = 299
28
+ INVALID_TICKET_STATUS = 300
29
+ DIR_NOT_FOUND = 22
30
+ LOCK_UNAVAILABLE = 30
31
+ LOCKED_ENTRY = 31
32
+ QR_ERROR = 14
33
+ QR_EXPIRED = 15
34
+ QR_INVALID = 16
35
+ INVALID_INVITATION = 125
36
+ INVALID_PASSWORD_RULES = 17
37
+ INVALID_USERNAME_AND_PASS = 10
38
+ USER_ACCOUNT_LOCKED = 110
39
+ USER_ISNT_VERIFIED = 11
40
+ PASSWORD_NOT_VALIDATED = 13
41
+ PASSWORD_RESET_ERROR = 102
42
+ UNMATCHED_DATA = 19
43
+ CONFLICT = 409
44
+ USERNAME_NOT_EXIST = 18
45
+ OTP_INVALID = 307
46
+ OTP_EXPIRED = 308
47
+ OTP_FAILED = 104
48
+ OTP_ISSUE = 100
49
+ OTP_NEEDED = 115
50
+ OTP_RESEND_BLOCKED = 103
51
+ INVALID_STANDALONE_DATA = 107
52
+ ONE_ARGUMENT_ALLOWED = 101
53
+ DATA_SHOULD_BE_UNIQUE = 415
54
+ INVALID_TOKEN = 47
55
+ EXPIRED_TOKEN = 48
56
+ NOT_AUTHENTICATED = 49
57
+ SESSION = 50
58
+ OBJECT_NOT_SAVED = 51
59
+ JQ_TIMEOUT = 120
60
+ JQ_ERROR = 121
dmart/utils/jwt.py ADDED
@@ -0,0 +1,124 @@
1
+ from time import time
2
+ from typing import Optional, Any
3
+
4
+ from fastapi import Request, status
5
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
6
+
7
+ import jwt
8
+ import models.api as api
9
+ from utils.internal_error_code import InternalErrorCode
10
+ from utils.settings import settings
11
+ from data_adapters.adapter import data_adapter as db
12
+
13
+
14
+ def decode_jwt(token: str) -> dict[str, Any]:
15
+ decoded_token: dict
16
+ try:
17
+ decoded_token = jwt.decode(
18
+ token, settings.jwt_secret, algorithms=[settings.jwt_algorithm]
19
+ )
20
+ except Exception:
21
+ raise api.Exception(
22
+ status.HTTP_401_UNAUTHORIZED,
23
+ api.Error(type="jwtauth", code=InternalErrorCode.INVALID_TOKEN, message="Invalid Token [1]"),
24
+ )
25
+ if (
26
+ not decoded_token
27
+ or "data" not in decoded_token
28
+ or "expires" not in decoded_token
29
+ ):
30
+ raise api.Exception(
31
+ status.HTTP_401_UNAUTHORIZED,
32
+ api.Error(type="jwtauth", code=InternalErrorCode.INVALID_TOKEN, message="Invalid Token [2]"),
33
+ )
34
+ if decoded_token["expires"] <= time():
35
+ raise api.Exception(
36
+ status.HTTP_401_UNAUTHORIZED,
37
+ api.Error(type="jwtauth", code=InternalErrorCode.EXPIRED_TOKEN, message="Expired Token"),
38
+ )
39
+
40
+ if (
41
+ isinstance(decoded_token["data"], dict)
42
+ and decoded_token["data"].get("shortname") is not None
43
+ ):
44
+ return decoded_token["data"]
45
+ else:
46
+ raise api.Exception(
47
+ status.HTTP_401_UNAUTHORIZED,
48
+ api.Error(type="jwtauth", code=InternalErrorCode.INVALID_TOKEN, message="Invalid Token [3]"),
49
+ )
50
+
51
+
52
+ class JWTBearer():
53
+ is_required: bool = True
54
+ http_bearer: HTTPBearer
55
+
56
+ def __init__(self, auto_error: bool = True, is_required: bool = True):
57
+ self.http_bearer = HTTPBearer(auto_error=auto_error)
58
+ self.is_required = is_required
59
+
60
+ async def __call__(self, request: Request) -> str | None:
61
+ user_shortname: str | None = None
62
+ auth_token: str | None = None
63
+ try:
64
+ # Handle token received in Auth header
65
+ credentials: Optional[HTTPAuthorizationCredentials] = await self.http_bearer.__call__(request)
66
+ if credentials and credentials.scheme == "Bearer":
67
+ auth_token = credentials.credentials
68
+
69
+ except Exception:
70
+ # Handle token received in the cookie
71
+ auth_token = request.cookies.get("auth_token")
72
+
73
+ if not auth_token:
74
+ raise api.Exception(
75
+ status.HTTP_401_UNAUTHORIZED,
76
+ api.Error(type="jwtauth", code=InternalErrorCode.NOT_AUTHENTICATED, message="Not authenticated [1]"),
77
+ )
78
+
79
+ decoded = decode_jwt(auth_token)
80
+ user_shortname = decoded["shortname"]
81
+ if not user_shortname:
82
+ raise api.Exception(
83
+ status.HTTP_401_UNAUTHORIZED,
84
+ api.Error(type="jwtauth", code=InternalErrorCode.NOT_AUTHENTICATED, message="Not authenticated [2]"),
85
+ )
86
+
87
+ if decoded["type"] != 'bot' and settings.session_inactivity_ttl:
88
+ _, user_session_token = await db.get_user_session(user_shortname, auth_token)
89
+ if not isinstance(user_session_token, str):
90
+ raise api.Exception(
91
+ status.HTTP_401_UNAUTHORIZED,
92
+ api.Error(
93
+ type="jwtauth", code=InternalErrorCode.NOT_AUTHENTICATED, message="Not authenticated [3]"
94
+ ),
95
+ )
96
+
97
+ return user_shortname
98
+
99
+ class GetJWTToken:
100
+ http_bearer: HTTPBearer
101
+ def __init__(self, auto_error: bool = True):
102
+ self.http_bearer = HTTPBearer(auto_error=auto_error)
103
+
104
+ async def __call__(self, request: Request) -> str | None:
105
+ try:
106
+ credentials: Optional[HTTPAuthorizationCredentials] = await self.http_bearer.__call__(request)
107
+ if credentials and credentials.scheme == "Bearer":
108
+ return credentials.credentials
109
+ except Exception:
110
+ return request.cookies.get("auth_token")
111
+ return None
112
+
113
+
114
+ def generate_jwt(data: dict, expires: int = 86400) -> str:
115
+ payload = {"data": data, "expires": time() + expires}
116
+ return jwt.encode(payload, settings.jwt_secret, algorithm=settings.jwt_algorithm)
117
+
118
+
119
+ async def sign_jwt(data: dict, expires: int = 86400) -> str:
120
+ token = generate_jwt(data, expires)
121
+ if data["type"] != "bot" and settings.session_inactivity_ttl:
122
+ await db.set_user_session(data["shortname"], token)
123
+ return token
124
+