dmart 1.4.33__py3-none-any.whl → 1.4.36__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 (298) hide show
  1. dmart/__init__.py +8 -0
  2. dmart/alembic/README +1 -0
  3. dmart/alembic/notes.txt +11 -0
  4. dmart/alembic/script.py.mako +28 -0
  5. dmart/alembic.ini +117 -0
  6. dmart/config.env.sample +27 -0
  7. dmart/conftest.py +13 -0
  8. dmart/curl.sh +196 -0
  9. dmart.py → dmart/dmart.py +47 -40
  10. dmart/hypercorn_config.toml +3 -0
  11. dmart/info.json +1 -0
  12. dmart/login_creds.sh +7 -0
  13. dmart/login_creds.sh.sample +7 -0
  14. main.py → dmart/main.py +4 -1
  15. dmart/manifest.sh +12 -0
  16. dmart/plugins/action_log/config.json +13 -0
  17. dmart/plugins/admin_notification_sender/config.json +13 -0
  18. dmart/plugins/ldap_manager/config.json +12 -0
  19. dmart/plugins/ldap_manager/dmart.schema +146 -0
  20. dmart/plugins/ldap_manager/slapd.conf +53 -0
  21. dmart/plugins/local_notification/config.json +13 -0
  22. dmart/plugins/realtime_updates_notifier/config.json +12 -0
  23. dmart/plugins/redis_db_update/config.json +13 -0
  24. dmart/plugins/resource_folders_creation/config.json +12 -0
  25. dmart/plugins/system_notification_sender/config.json +13 -0
  26. dmart/plugins/update_access_controls/config.json +12 -0
  27. dmart/publish.sh +57 -0
  28. dmart/pylint.sh +16 -0
  29. dmart/pyrightconfig.json +7 -0
  30. dmart/redis_connections.sh +13 -0
  31. dmart/reload.sh +56 -0
  32. dmart/run.sh +3 -0
  33. dmart/test_utils.py +34 -0
  34. {dmart-1.4.33.dist-info → dmart-1.4.36.dist-info}/METADATA +1 -1
  35. dmart-1.4.36.dist-info/RECORD +285 -0
  36. dmart-1.4.36.dist-info/entry_points.txt +2 -0
  37. dmart-1.4.36.dist-info/top_level.txt +1 -0
  38. dmart-1.4.33.dist-info/RECORD +0 -264
  39. dmart-1.4.33.dist-info/entry_points.txt +0 -2
  40. dmart-1.4.33.dist-info/top_level.txt +0 -24
  41. pytests/api_user_models_erros_test.py +0 -16
  42. pytests/api_user_models_requests_test.py +0 -98
  43. pytests/archive_test.py +0 -72
  44. pytests/base_test.py +0 -300
  45. pytests/get_settings_test.py +0 -14
  46. pytests/json_to_db_migration_test.py +0 -237
  47. pytests/service_test.py +0 -26
  48. pytests/test_info.py +0 -55
  49. pytests/test_status.py +0 -15
  50. utils/__init__.py +0 -0
  51. {alembic → dmart/alembic}/__init__.py +0 -0
  52. {alembic → dmart/alembic}/env.py +0 -0
  53. {alembic → dmart/alembic}/scripts/__init__.py +0 -0
  54. {alembic → dmart/alembic}/scripts/calculate_checksums.py +0 -0
  55. {alembic → dmart/alembic}/scripts/migration_f7a4949eed19.py +0 -0
  56. {alembic → dmart/alembic}/versions/0f3d2b1a7c21_add_authz_materialized_views.py +0 -0
  57. {alembic → dmart/alembic}/versions/10d2041b94d4_last_checksum_history.py +0 -0
  58. {alembic → dmart/alembic}/versions/1cf4e1ee3cb8_ext_permission_with_filter_fields_values.py +0 -0
  59. {alembic → dmart/alembic}/versions/26bfe19b49d4_rm_failedloginattempts.py +0 -0
  60. {alembic → dmart/alembic}/versions/3c8bca2219cc_add_otp_table.py +0 -0
  61. {alembic → dmart/alembic}/versions/6675fd9dfe42_remove_unique_from_sessions_table.py +0 -0
  62. {alembic → dmart/alembic}/versions/71bc1df82e6a_adding_user_last_login_at.py +0 -0
  63. {alembic → dmart/alembic}/versions/74288ccbd3b5_initial.py +0 -0
  64. {alembic → dmart/alembic}/versions/7520a89a8467_rm_activesession_table.py +0 -0
  65. {alembic → dmart/alembic}/versions/848b623755a4_make_created_nd_updated_at_required.py +0 -0
  66. {alembic → dmart/alembic}/versions/8640dcbebf85_add_notes_to_users.py +0 -0
  67. {alembic → dmart/alembic}/versions/91c94250232a_adding_fk_on_owner_shortname.py +0 -0
  68. {alembic → dmart/alembic}/versions/98ecd6f56f9a_ext_meta_with_owner_group_shortname.py +0 -0
  69. {alembic → dmart/alembic}/versions/9aae9138c4ef_indexing_created_at_updated_at.py +0 -0
  70. {alembic → dmart/alembic}/versions/__init__.py +0 -0
  71. {alembic → dmart/alembic}/versions/b53f916b3f6d_json_to_jsonb.py +0 -0
  72. {alembic → dmart/alembic}/versions/eb5f1ec65156_adding_user_locked_to_device.py +0 -0
  73. {alembic → dmart/alembic}/versions/f7a4949eed19_adding_query_policies_to_meta.py +0 -0
  74. {api → dmart/api}/__init__.py +0 -0
  75. {api → dmart/api}/info/__init__.py +0 -0
  76. {api → dmart/api}/info/router.py +0 -0
  77. {api → dmart/api}/managed/__init__.py +0 -0
  78. {api → dmart/api}/managed/router.py +0 -0
  79. {api → dmart/api}/managed/utils.py +0 -0
  80. {api → dmart/api}/public/__init__.py +0 -0
  81. {api → dmart/api}/public/router.py +0 -0
  82. {api → dmart/api}/qr/__init__.py +0 -0
  83. {api → dmart/api}/qr/router.py +0 -0
  84. {api → dmart/api}/user/__init__.py +0 -0
  85. {api → dmart/api}/user/model/__init__.py +0 -0
  86. {api → dmart/api}/user/model/errors.py +0 -0
  87. {api → dmart/api}/user/model/requests.py +0 -0
  88. {api → dmart/api}/user/model/responses.py +0 -0
  89. {api → dmart/api}/user/router.py +0 -0
  90. {api → dmart/api}/user/service.py +0 -0
  91. /bundler.py → /dmart/bundler.py +0 -0
  92. {config → dmart/config}/__init__.py +0 -0
  93. {config → dmart/config}/channels.json +0 -0
  94. {config → dmart/config}/notification.json +0 -0
  95. {cxb → dmart/cxb}/__init__.py +0 -0
  96. {cxb/client → dmart/cxb}/assets/@codemirror-Rn7_6DkE.js +0 -0
  97. {cxb/client → dmart/cxb}/assets/@edraj-CS4NwVbD.js +0 -0
  98. {cxb/client → dmart/cxb}/assets/@floating-ui-BwwcF-xh.js +0 -0
  99. {cxb/client → dmart/cxb}/assets/@formatjs-yKEsAtjs.js +0 -0
  100. {cxb/client → dmart/cxb}/assets/@fortawesome-DRW1UCdr.js +0 -0
  101. {cxb/client → dmart/cxb}/assets/@jsonquerylang-laKNoFFq.js +0 -0
  102. {cxb/client → dmart/cxb}/assets/@lezer-za4Q-8Ew.js +0 -0
  103. {cxb/client → dmart/cxb}/assets/@marijn-DXwl3gUT.js +0 -0
  104. {cxb/client → dmart/cxb}/assets/@popperjs-l0sNRNKZ.js +0 -0
  105. {cxb/client → dmart/cxb}/assets/@replit--ERk53eB.js +0 -0
  106. {cxb/client → dmart/cxb}/assets/@roxi-CGMFK4i8.js +0 -0
  107. {cxb/client → dmart/cxb}/assets/@typewriter-cCzskkIv.js +0 -0
  108. {cxb/client → dmart/cxb}/assets/@zerodevx-BlBZjKxu.js +0 -0
  109. {cxb/client → dmart/cxb}/assets/@zerodevx-CVEpe6WZ.css +0 -0
  110. {cxb/client → dmart/cxb}/assets/BreadCrumbLite-DAhOx38v.js +0 -0
  111. {cxb/client → dmart/cxb}/assets/EntryRenderer-25YDhRen.js +0 -0
  112. {cxb/client → dmart/cxb}/assets/EntryRenderer-DXytdFp9.css +0 -0
  113. {cxb/client → dmart/cxb}/assets/ListView-BpAycA2h.js +0 -0
  114. {cxb/client → dmart/cxb}/assets/ListView-U8of-_c-.css +0 -0
  115. {cxb/client → dmart/cxb}/assets/Prism--hMplq-p.js +0 -0
  116. {cxb/client → dmart/cxb}/assets/Prism-Uh6uStUw.css +0 -0
  117. {cxb/client → dmart/cxb}/assets/Table2Cols-BsbwicQm.js +0 -0
  118. {cxb/client → dmart/cxb}/assets/_..-BvT6vdHa.css +0 -0
  119. {cxb/client → dmart/cxb}/assets/_...404_-fuLH_rX9.js +0 -0
  120. {cxb/client → dmart/cxb}/assets/_...fallback_-Ba_NLmAE.js +0 -0
  121. {cxb/client → dmart/cxb}/assets/_module-Bfk8MiCs.js +0 -0
  122. {cxb/client → dmart/cxb}/assets/_module-CEW0D5oI.js +0 -0
  123. {cxb/client → dmart/cxb}/assets/_module-Dgq0ZVtz.js +0 -0
  124. {cxb/client → dmart/cxb}/assets/ajv-Cpj98o6Y.js +0 -0
  125. {cxb/client → dmart/cxb}/assets/axios-CG2WSiiR.js +0 -0
  126. {cxb/client → dmart/cxb}/assets/clsx-B-dksMZM.js +0 -0
  127. {cxb/client → dmart/cxb}/assets/codemirror-wrapped-line-indent-DPhKvljI.js +0 -0
  128. {cxb/client → dmart/cxb}/assets/compare-C3AjiGFR.js +0 -0
  129. {cxb/client → dmart/cxb}/assets/compute-scroll-into-view-Bl8rNFhg.js +0 -0
  130. {cxb/client → dmart/cxb}/assets/consolite-DlCuI0F9.js +0 -0
  131. {cxb/client → dmart/cxb}/assets/crelt-C8TCjufn.js +0 -0
  132. {cxb/client → dmart/cxb}/assets/date-fns-l0sNRNKZ.js +0 -0
  133. {cxb/client → dmart/cxb}/assets/deepmerge-rn4rBaHU.js +0 -0
  134. {cxb/client → dmart/cxb}/assets/dmart_services-AL6-IdDE.js +0 -0
  135. {cxb/client → dmart/cxb}/assets/downloadFile-D08i0YDh.js +0 -0
  136. {cxb/client → dmart/cxb}/assets/easy-signal-BiPFIK3O.js +0 -0
  137. {cxb/client → dmart/cxb}/assets/esm-env-rsSWfq8L.js +0 -0
  138. {cxb/client → dmart/cxb}/assets/export-OF_rTiXu.js +0 -0
  139. {cxb/client → dmart/cxb}/assets/fast-deep-equal-l0sNRNKZ.js +0 -0
  140. {cxb/client → dmart/cxb}/assets/fast-diff-C-IidNf4.js +0 -0
  141. {cxb/client → dmart/cxb}/assets/fast-uri-l0sNRNKZ.js +0 -0
  142. {cxb/client → dmart/cxb}/assets/flowbite-svelte-BLvjb-sa.js +0 -0
  143. {cxb/client → dmart/cxb}/assets/flowbite-svelte-CD54FDqW.css +0 -0
  144. {cxb/client → dmart/cxb}/assets/flowbite-svelte-icons-BI8GVhw_.js +0 -0
  145. {cxb/client → dmart/cxb}/assets/github-slugger-CQ4oX9Ud.js +0 -0
  146. {cxb/client → dmart/cxb}/assets/global-igKv-1g9.js +0 -0
  147. {cxb/client → dmart/cxb}/assets/hookar-BMRD9G9H.js +0 -0
  148. {cxb/client → dmart/cxb}/assets/immutable-json-patch-DtRO2E_S.js +0 -0
  149. {cxb/client → dmart/cxb}/assets/import-1vE3gBat.js +0 -0
  150. {cxb/client → dmart/cxb}/assets/index-B-eTh-ZX.js +0 -0
  151. {cxb/client → dmart/cxb}/assets/index-BVyxzKtH.js +0 -0
  152. {cxb/client → dmart/cxb}/assets/index-BdeNM69f.js +0 -0
  153. {cxb/client → dmart/cxb}/assets/index-C6cPO4op.js +0 -0
  154. {cxb/client → dmart/cxb}/assets/index-CC-A1ipE.js +0 -0
  155. {cxb/client → dmart/cxb}/assets/index-CTxJ-lDp.js +0 -0
  156. {cxb/client → dmart/cxb}/assets/index-Cd-F5j_k.js +0 -0
  157. {cxb/client → dmart/cxb}/assets/index-D742rwaM.js +0 -0
  158. {cxb/client → dmart/cxb}/assets/index-DTfhnhwd.js +0 -0
  159. {cxb/client → dmart/cxb}/assets/index-DdXRK7n9.js +0 -0
  160. {cxb/client → dmart/cxb}/assets/index-DtiCmB4o.js +0 -0
  161. {cxb/client → dmart/cxb}/assets/index-NBrXBlLA.css +0 -0
  162. {cxb/client → dmart/cxb}/assets/index-ac-Buu_H.js +0 -0
  163. {cxb/client → dmart/cxb}/assets/index-iYkH7C67.js +0 -0
  164. {cxb/client → dmart/cxb}/assets/info-B986lRiM.js +0 -0
  165. {cxb/client → dmart/cxb}/assets/intl-messageformat-Dc5UU-HB.js +0 -0
  166. {cxb/client → dmart/cxb}/assets/jmespath-l0sNRNKZ.js +0 -0
  167. {cxb/client → dmart/cxb}/assets/json-schema-traverse-l0sNRNKZ.js +0 -0
  168. {cxb/client → dmart/cxb}/assets/json-source-map-DRgZidqy.js +0 -0
  169. {cxb/client → dmart/cxb}/assets/jsonpath-plus-l0sNRNKZ.js +0 -0
  170. {cxb/client → dmart/cxb}/assets/jsonrepair-B30Dx381.js +0 -0
  171. {cxb/client → dmart/cxb}/assets/lodash-es-DZVAA2ox.js +0 -0
  172. {cxb/client → dmart/cxb}/assets/marked-DKjyhwJX.js +0 -0
  173. {cxb/client → dmart/cxb}/assets/marked-gfm-heading-id-U5zO829x.js +0 -0
  174. {cxb/client → dmart/cxb}/assets/marked-mangle-CDMeiHC6.js +0 -0
  175. {cxb/client → dmart/cxb}/assets/memoize-one-BdPwpGay.js +0 -0
  176. {cxb/client → dmart/cxb}/assets/natural-compare-lite-Bg2Xcf-o.js +0 -0
  177. {cxb/client → dmart/cxb}/assets/pagination-svelte-D5CyoiE_.js +0 -0
  178. {cxb/client → dmart/cxb}/assets/pagination-svelte-v10nAbbM.css +0 -0
  179. {cxb/client → dmart/cxb}/assets/plantuml-encoder-C47mzt9T.js +0 -0
  180. {cxb/client → dmart/cxb}/assets/prismjs-DTUiLGJu.js +0 -0
  181. {cxb/client → dmart/cxb}/assets/profile-BUf-tKMe.js +0 -0
  182. {cxb/client → dmart/cxb}/assets/query-CNmXTsgf.js +0 -0
  183. {cxb/client → dmart/cxb}/assets/queryHelpers-C9iBWwqe.js +0 -0
  184. {cxb/client → dmart/cxb}/assets/scroll-into-view-if-needed-KR58zyjF.js +0 -0
  185. {cxb/client → dmart/cxb}/assets/spaces-0oyGvpii.js +0 -0
  186. {cxb/client → dmart/cxb}/assets/style-mod-Bs6eFhZE.js +0 -0
  187. {cxb/client → dmart/cxb}/assets/svelte-B2XmcTi_.js +0 -0
  188. {cxb/client → dmart/cxb}/assets/svelte-awesome-COLlx0DN.css +0 -0
  189. {cxb/client → dmart/cxb}/assets/svelte-awesome-DhnMA6Q_.js +0 -0
  190. {cxb/client → dmart/cxb}/assets/svelte-datatables-net-CY7LBj6I.js +0 -0
  191. {cxb/client → dmart/cxb}/assets/svelte-floating-ui-BlS3sOAQ.js +0 -0
  192. {cxb/client → dmart/cxb}/assets/svelte-i18n-CT2KkQaN.js +0 -0
  193. {cxb/client → dmart/cxb}/assets/svelte-jsoneditor-BzfX6Usi.css +0 -0
  194. {cxb/client → dmart/cxb}/assets/svelte-jsoneditor-CUGSvWId.js +0 -0
  195. {cxb/client → dmart/cxb}/assets/svelte-select-CegQKzqH.css +0 -0
  196. {cxb/client → dmart/cxb}/assets/svelte-select-CjHAt_85.js +0 -0
  197. {cxb/client → dmart/cxb}/assets/tailwind-merge-CJvxXMcu.js +0 -0
  198. {cxb/client → dmart/cxb}/assets/tailwind-variants-Cj20BoQ3.js +0 -0
  199. {cxb/client → dmart/cxb}/assets/toast-B9WDyfyI.js +0 -0
  200. {cxb/client → dmart/cxb}/assets/tslib-pJfR_DrR.js +0 -0
  201. {cxb/client → dmart/cxb}/assets/typewriter-editor-DkTVIJdm.js +0 -0
  202. {cxb/client → dmart/cxb}/assets/user-DeK_NB5v.js +0 -0
  203. {cxb/client → dmart/cxb}/assets/vanilla-picker-l5rcX3cq.js +0 -0
  204. {cxb/client → dmart/cxb}/assets/w3c-keyname-Vcq4gwWv.js +0 -0
  205. {cxb/client → dmart/cxb}/config.json +0 -0
  206. {cxb/client → dmart/cxb}/config.sample.json +0 -0
  207. {cxb/client → dmart/cxb}/favicon.ico +0 -0
  208. {cxb/client → dmart/cxb}/favicon.png +0 -0
  209. {cxb/client → dmart/cxb}/index.html +0 -0
  210. {data_adapters → dmart/data_adapters}/__init__.py +0 -0
  211. {data_adapters → dmart/data_adapters}/adapter.py +0 -0
  212. {data_adapters → dmart/data_adapters}/base_data_adapter.py +0 -0
  213. {data_adapters → dmart/data_adapters}/file/__init__.py +0 -0
  214. {data_adapters → dmart/data_adapters}/file/adapter.py +0 -0
  215. {data_adapters → dmart/data_adapters}/file/adapter_helpers.py +0 -0
  216. {data_adapters → dmart/data_adapters}/file/archive.py +0 -0
  217. {data_adapters → dmart/data_adapters}/file/create_index.py +0 -0
  218. {data_adapters → dmart/data_adapters}/file/create_users_folders.py +0 -0
  219. {data_adapters → dmart/data_adapters}/file/custom_validations.py +0 -0
  220. {data_adapters → dmart/data_adapters}/file/drop_index.py +0 -0
  221. {data_adapters → dmart/data_adapters}/file/health_check.py +0 -0
  222. {data_adapters → dmart/data_adapters}/file/redis_services.py +0 -0
  223. {data_adapters → dmart/data_adapters}/helpers.py +0 -0
  224. {data_adapters → dmart/data_adapters}/sql/__init__.py +0 -0
  225. {data_adapters → dmart/data_adapters}/sql/adapter.py +0 -0
  226. {data_adapters → dmart/data_adapters}/sql/adapter_helpers.py +0 -0
  227. {data_adapters → dmart/data_adapters}/sql/create_tables.py +0 -0
  228. {data_adapters → dmart/data_adapters}/sql/create_users_folders.py +0 -0
  229. {data_adapters → dmart/data_adapters}/sql/db_to_json_migration.py +0 -0
  230. {data_adapters → dmart/data_adapters}/sql/health_check_sql.py +0 -0
  231. {data_adapters → dmart/data_adapters}/sql/json_to_db_migration.py +0 -0
  232. {data_adapters → dmart/data_adapters}/sql/update_query_policies.py +0 -0
  233. /data_generator.py → /dmart/data_generator.py +0 -0
  234. /get_settings.py → /dmart/get_settings.py +0 -0
  235. {languages → dmart/languages}/__init__.py +0 -0
  236. {languages → dmart/languages}/arabic.json +0 -0
  237. {languages → dmart/languages}/english.json +0 -0
  238. {languages → dmart/languages}/kurdish.json +0 -0
  239. {languages → dmart/languages}/loader.py +0 -0
  240. /migrate.py → /dmart/migrate.py +0 -0
  241. {models → dmart/models}/__init__.py +0 -0
  242. {models → dmart/models}/api.py +0 -0
  243. {models → dmart/models}/core.py +0 -0
  244. {models → dmart/models}/enums.py +0 -0
  245. /password_gen.py → /dmart/password_gen.py +0 -0
  246. {plugins → dmart/plugins}/__init__.py +0 -0
  247. {plugins → dmart/plugins}/action_log/__init__.py +0 -0
  248. {plugins → dmart/plugins}/action_log/plugin.py +0 -0
  249. {plugins → dmart/plugins}/admin_notification_sender/__init__.py +0 -0
  250. {plugins → dmart/plugins}/admin_notification_sender/plugin.py +0 -0
  251. {plugins → dmart/plugins}/ldap_manager/__init__.py +0 -0
  252. {plugins → dmart/plugins}/ldap_manager/plugin.py +0 -0
  253. {plugins → dmart/plugins}/local_notification/__init__.py +0 -0
  254. {plugins → dmart/plugins}/local_notification/plugin.py +0 -0
  255. {plugins → dmart/plugins}/realtime_updates_notifier/__init__.py +0 -0
  256. {plugins → dmart/plugins}/realtime_updates_notifier/plugin.py +0 -0
  257. {plugins → dmart/plugins}/redis_db_update/__init__.py +0 -0
  258. {plugins → dmart/plugins}/redis_db_update/plugin.py +0 -0
  259. {plugins → dmart/plugins}/resource_folders_creation/__init__.py +0 -0
  260. {plugins → dmart/plugins}/resource_folders_creation/plugin.py +0 -0
  261. {plugins → dmart/plugins}/system_notification_sender/__init__.py +0 -0
  262. {plugins → dmart/plugins}/system_notification_sender/plugin.py +0 -0
  263. {plugins → dmart/plugins}/update_access_controls/__init__.py +0 -0
  264. {plugins → dmart/plugins}/update_access_controls/plugin.py +0 -0
  265. /run_notification_campaign.py → /dmart/run_notification_campaign.py +0 -0
  266. /scheduled_notification_handler.py → /dmart/scheduled_notification_handler.py +0 -0
  267. /schema_migration.py → /dmart/schema_migration.py +0 -0
  268. /schema_modulate.py → /dmart/schema_modulate.py +0 -0
  269. /set_admin_passwd.py → /dmart/set_admin_passwd.py +0 -0
  270. /sync.py → /dmart/sync.py +0 -0
  271. {pytests → dmart/utils}/__init__.py +0 -0
  272. {utils → dmart/utils}/access_control.py +0 -0
  273. {utils → dmart/utils}/async_request.py +0 -0
  274. {utils → dmart/utils}/exporter.py +0 -0
  275. {utils → dmart/utils}/firebase_notifier.py +0 -0
  276. {utils → dmart/utils}/generate_email.py +0 -0
  277. {utils → dmart/utils}/helpers.py +0 -0
  278. {utils → dmart/utils}/hypercorn_config.py +0 -0
  279. {utils → dmart/utils}/internal_error_code.py +0 -0
  280. {utils → dmart/utils}/jwt.py +0 -0
  281. {utils → dmart/utils}/logger.py +0 -0
  282. {utils → dmart/utils}/middleware.py +0 -0
  283. {utils → dmart/utils}/notification.py +0 -0
  284. {utils → dmart/utils}/password_hashing.py +0 -0
  285. {utils → dmart/utils}/plugin_manager.py +0 -0
  286. {utils → dmart/utils}/query_policies_helper.py +0 -0
  287. {utils → dmart/utils}/regex.py +0 -0
  288. {utils → dmart/utils}/repository.py +0 -0
  289. {utils → dmart/utils}/router_helper.py +0 -0
  290. {utils → dmart/utils}/settings.py +0 -0
  291. {utils → dmart/utils}/sms_notifier.py +0 -0
  292. {utils → dmart/utils}/social_sso.py +0 -0
  293. {utils → dmart/utils}/templates/activation.html.j2 +0 -0
  294. {utils → dmart/utils}/templates/reminder.html.j2 +0 -0
  295. {utils → dmart/utils}/ticket_sys_utils.py +0 -0
  296. {utils → dmart/utils}/web_notifier.py +0 -0
  297. /websocket.py → /dmart/websocket.py +0 -0
  298. {dmart-1.4.33.dist-info → dmart-1.4.36.dist-info}/WHEEL +0 -0
@@ -1,98 +0,0 @@
1
- import pytest
2
- from pydantic import ValidationError
3
-
4
- from api.user.model.requests import (
5
- OTPType,
6
- SendOTPRequest,
7
- PasswordResetRequest,
8
- ConfirmOTPRequest,
9
- UserLoginRequest,
10
- Exception,
11
- Error,
12
- InternalErrorCode
13
- )
14
- import utils.regex as rgx
15
-
16
-
17
- def test_send_otp_request_valid_msisdn():
18
- request = SendOTPRequest(msisdn="7777778110")
19
- result = request.check_fields()
20
- assert result == {"msisdn": "7777778110"}
21
-
22
- def test_send_otp_request_valid_email():
23
- request = SendOTPRequest(email="test@example.com")
24
- result = request.check_fields()
25
- assert result == {"email": "test@example.com"}
26
-
27
- def test_send_otp_request_missing_fields():
28
- # Ensure both fields are explicitly None
29
- with pytest.raises(Exception) as excinfo:
30
- SendOTPRequest(msisdn=None, email=None).check_fields()
31
- assert excinfo.value.status_code == 422
32
- assert excinfo.value.error.code == InternalErrorCode.EMAIL_OR_MSISDN_REQUIRED
33
-
34
- def test_send_otp_request_too_many_fields():
35
- with pytest.raises(Exception) as excinfo:
36
- SendOTPRequest(msisdn="7777778110", email="test@example.com").check_fields()
37
- assert excinfo.value.status_code == 422
38
- assert excinfo.value.error.code == InternalErrorCode.INVALID_STANDALONE_DATA
39
-
40
- def test_password_reset_request_valid_msisdn():
41
- request = PasswordResetRequest(msisdn="7777778110")
42
- result = request.check_fields()
43
- assert result == {"msisdn": "7777778110"}
44
-
45
- def test_password_reset_request_valid_email():
46
- request = PasswordResetRequest(email="test@example.com")
47
- result = request.check_fields()
48
- assert result == {"email": "test@example.com"}
49
-
50
- def test_password_reset_request_missing_fields():
51
- with pytest.raises(Exception) as excinfo:
52
- PasswordResetRequest().check_fields()
53
- assert excinfo.value.status_code == 422
54
- assert excinfo.value.error.code == InternalErrorCode.EMAIL_OR_MSISDN_REQUIRED
55
-
56
- def test_password_reset_request_too_many_fields():
57
- with pytest.raises(Exception) as excinfo:
58
- PasswordResetRequest(msisdn="7777778110", email="test@example.com").check_fields()
59
- assert excinfo.value.status_code == 422
60
- assert excinfo.value.error.code == InternalErrorCode.INVALID_STANDALONE_DATA
61
-
62
- def test_confirm_otp_request_valid():
63
- request = ConfirmOTPRequest(msisdn="7777778110", code="123456")
64
- assert request.msisdn == "7777778110"
65
- assert request.code == "123456"
66
-
67
- def test_confirm_otp_request_invalid_code():
68
- with pytest.raises(ValidationError):
69
- ConfirmOTPRequest(msisdn="7777778110", code="invalid")
70
-
71
- def test_user_login_request_valid_shortname():
72
- request = UserLoginRequest(shortname="john_doo", password="my_secure_password_@_93301")
73
- result = request.check_fields()
74
- assert result == {"shortname": "john_doo"}
75
-
76
- def test_user_login_request_valid_email():
77
- request = UserLoginRequest(email="test@example.com", password="my_secure_password_@_93301")
78
- result = request.check_fields()
79
- assert result == {"email": "test@example.com"}
80
-
81
- def test_user_login_request_valid_msisdn():
82
- request = UserLoginRequest(msisdn="7777778110", password="my_secure_password_@_93301")
83
- result = request.check_fields()
84
- assert result == {"msisdn": "7777778110"}
85
-
86
- def test_user_login_request_missing_fields():
87
- request = UserLoginRequest(password="my_secure_password_@_93301")
88
- result = request.check_fields()
89
- assert result == {}
90
-
91
- def test_user_login_request_too_many_fields():
92
- with pytest.raises(ValueError, match="Too many input has been passed"):
93
- UserLoginRequest(shortname="john_doo", email="test@example.com", msisdn="7777778110", password="my_secure_password_@_93301").check_fields()
94
-
95
- def test_user_login_request_missing_password():
96
- request = UserLoginRequest(shortname="john_doo")
97
- result = request.check_fields()
98
- assert result == {"shortname": "john_doo"}
pytests/archive_test.py DELETED
@@ -1,72 +0,0 @@
1
- # import pytest
2
- # from unittest.mock import patch
3
- # from time import time
4
- # import argparse
5
- # import asyncio
6
- # from archive import redis_doc_to_meta, archive
7
- #
8
- #
9
- # def test_redis_doc_to_meta():
10
- # mock_record = {
11
- # "resource_type": "record",
12
- # "created_at": time(),
13
- # "updated_at": time(),
14
- # }
15
- # expected_keys = ["resource_type", "created_at", "updated_at"]
16
- # with patch("models.core.Record") as MockRecord:
17
- # MockRecord.model_fields.keys.return_value = expected_keys
18
- # MockRecord.model_validate.return_value = mock_record
19
- # meta = redis_doc_to_meta(mock_record)
20
- # assert meta == mock_record
21
- # assert MockRecord.model_fields.keys.call_count == 3
22
- # MockRecord.model_validate.assert_called_once()
23
- #
24
- # def main():
25
- # parser = argparse.ArgumentParser(
26
- # description="Script for archiving records from different spaces and subpaths."
27
- # )
28
- # parser.add_argument("space", type=str, help="The name of the space")
29
- # parser.add_argument("subpath", type=str, help="The subpath within the space")
30
- # parser.add_argument(
31
- # "schema",
32
- # type=str,
33
- # help="The subpath within the space. Optional, if not provided move everything",
34
- # nargs="?",
35
- # )
36
- # parser.add_argument(
37
- # "olderthan",
38
- # type=int,
39
- # help="The number of day, older than which, the entries will be archived (based on updated_at)",
40
- # )
41
- #
42
- # args = parser.parse_args()
43
- # space = args.space
44
- # subpath = args.subpath
45
- # olderthan = args.olderthan
46
- # schema = args.schema or "meta"
47
- #
48
- # asyncio.run(archive(space, subpath, schema, olderthan))
49
- # print("Done.")
50
- #
51
- #
52
- # @pytest.mark.asyncio
53
- # @patch("argparse.ArgumentParser.parse_args")
54
- # @patch("archive.archive")
55
- # async def test_main(mock_archive, mock_parse_args):
56
- # mock_args = argparse.Namespace(
57
- # space="space",
58
- # subpath="subpath",
59
- # schema="schema",
60
- # olderthan=1
61
- # )
62
- # mock_parse_args.return_value = mock_args
63
- #
64
- # with patch("asyncio.run") as mock_asyncio_run:
65
- # mock_asyncio_run.side_effect = lambda x: asyncio.ensure_future(x)
66
- # main()
67
- #
68
- # mock_parse_args.assert_called_once()
69
- # mock_asyncio_run.assert_called_once()
70
- #
71
- # if __name__ == "__main__":
72
- # pytest.main()
pytests/base_test.py DELETED
@@ -1,300 +0,0 @@
1
- import json
2
- from utils.settings import settings
3
- from fastapi import status
4
- from models.api import Query
5
- from models.enums import QueryType, ResourceType, RequestType
6
-
7
- superman = {}
8
- alibaba = {}
9
-
10
- with open("./login_creds.sh", "r") as file:
11
- for line in file.readlines():
12
- if line.strip().startswith("export SUPERMAN"):
13
- superman = json.loads(str(line.strip().split("'")[1]))
14
- if line.strip().startswith("export ALIBABA"):
15
- alibaba = json.loads(str(line.strip().split("'")[1]))
16
-
17
- MANAGEMENT_SPACE: str = f"{settings.management_space}"
18
- USERS_SUBPATH: str = "users"
19
- DEMO_SPACE: str = "test"
20
- DEMO_SUBPATH: str = "content"
21
-
22
-
23
- async def get_superman_cookie(client) -> str:
24
- response = await client.post(
25
- "/user/login",
26
- json={"shortname": superman["shortname"], "password": superman["password"]},
27
- )
28
- print(f"\n {response.json() = } \n creds: {superman = } \n")
29
- assert response.status_code == status.HTTP_200_OK
30
- # client.cookies.set("auth_token", response.cookies["auth_token"])
31
- return str(response.cookies["auth_token"])
32
-
33
- async def set_superman_cookie(client):
34
- response = await client.post(
35
- "/user/login",
36
- json={"shortname": superman["shortname"], "password": superman["password"]},
37
- )
38
- print(f"\n {response.json() = } \n creds: {superman = } \n")
39
- assert response.status_code == status.HTTP_200_OK
40
- client.cookies.set("auth_token", response.cookies["auth_token"])
41
-
42
-
43
- async def set_alibaba_cookie(client):
44
- response = await client.post(
45
- "/user/login",
46
- json={"shortname": alibaba["shortname"], "password": alibaba["password"]},
47
- )
48
- print(f"\n {response.json() = } \n creds: {alibaba = } \n")
49
- assert response.status_code == status.HTTP_200_OK
50
- client.cookies.set("auth_token", response.cookies["auth_token"])
51
-
52
-
53
- async def init_test_db(client) -> None:
54
- # Create the space
55
- await client.post(
56
- "managed/request",
57
- json={
58
- "space_name": DEMO_SPACE,
59
- "request_type": RequestType.create,
60
- "records": [
61
- {
62
- "resource_type": ResourceType.space,
63
- "subpath": "/",
64
- "shortname": DEMO_SPACE,
65
- "attributes": {},
66
- }
67
- ],
68
- },
69
- )
70
-
71
- # Create the folder
72
- await client.post(
73
- "/managed/request",
74
- json={
75
- "space_name": DEMO_SPACE,
76
- "request_type": RequestType.create,
77
- "records": [
78
- {
79
- "resource_type": ResourceType.folder,
80
- "subpath": "/",
81
- "shortname": DEMO_SUBPATH,
82
- "attributes": {},
83
- }
84
- ],
85
- },
86
- )
87
-
88
-
89
- async def delete_space(client) -> None:
90
- headers = {"Content-Type": "application/json"}
91
- endpoint = "/managed/request"
92
- request_data = {
93
- "space_name": DEMO_SPACE,
94
- "request_type": RequestType.delete,
95
- "records": [
96
- {
97
- "resource_type": ResourceType.space,
98
- "subpath": "/",
99
- "shortname": DEMO_SPACE,
100
- "attributes": {},
101
- }
102
- ],
103
- }
104
-
105
- assert_code_and_status_success(
106
- await client.post(endpoint, json=request_data, headers=headers)
107
- )
108
- check_not_found(
109
- await client.get(f"/managed/entry/space/{DEMO_SPACE}/__root__/{DEMO_SPACE}")
110
- )
111
-
112
-
113
- def check_repeated_shortname(response):
114
- json_response = response.json()
115
- assert response.status_code == status.HTTP_400_BAD_REQUEST
116
- assert "failed" == json_response.get("status")
117
- assert "request" == json_response.get("error", {}).get("type")
118
-
119
-
120
- def check_not_found(response):
121
- json_response = response.json()
122
- assert response.status_code == status.HTTP_404_NOT_FOUND
123
- assert "failed" == json_response.get("status")
124
- assert "db" == json_response.get("error").get("type")
125
-
126
-
127
- def check_unauthorized(response):
128
- json_response = response.json()
129
- assert response.status_code == status.HTTP_401_UNAUTHORIZED
130
- assert "failed" == json_response.get("status")
131
- assert "auth" == json_response.get("error", {}).get("type")
132
-
133
-
134
- def assert_code_and_status_success(response):
135
- if response.status_code != status.HTTP_200_OK:
136
- print(
137
- "\n\n\n\n\n========================= ERROR RESPONSE: =========================n:",
138
- response.json(),
139
- "\n\n\n\n\n",
140
- )
141
- json_response = response.json()
142
- print(f"{json_response=}")
143
- assert response.status_code == status.HTTP_200_OK
144
- assert json_response.get("status") == "success"
145
-
146
-
147
- def assert_bad_request(response):
148
- assert response.status_code == status.HTTP_400_BAD_REQUEST
149
- assert response.json()["status"] == "failed"
150
-
151
-
152
- async def assert_resource_created(
153
- client,
154
- query: Query,
155
- res_shortname: str,
156
- res_subpath: str,
157
- res_attributes: dict | None = None,
158
- res_attachments: dict[str, int] | None = None,
159
- ):
160
- if not query.search:
161
- query.search = ""
162
- response = await client.post(
163
- "/managed/query",
164
- json=query.model_dump(exclude_none=True),
165
- )
166
- assert_code_and_status_success(response)
167
- json_response = response.json()
168
- assert json_response["status"] == "success"
169
- assert json_response["attributes"]["returned"] == query.limit
170
- assert json_response["records"][0]["shortname"] == res_shortname
171
- assert json_response["records"][0]["subpath"] in [res_subpath, f"/{res_subpath}"]
172
- if res_attributes:
173
- if "is_active" not in res_attributes:
174
- res_attributes["is_active"] = False
175
- if "tags" not in res_attributes:
176
- res_attributes["tags"] = []
177
- res_attributes["owner_shortname"] = "dmart"
178
-
179
- json_response["records"][0]["attributes"].pop("created_at", None)
180
- json_response["records"][0]["attributes"].pop("updated_at", None)
181
- assert (
182
- json_response["records"][0]["attributes"]["payload"]["body"]
183
- == res_attributes["payload"]["body"]
184
- )
185
-
186
- # Assert correct attachments number for each attachment type returned
187
- if res_attachments:
188
- for attachment_key, attachments in json_response["records"][0][
189
- "attachments"
190
- ].items():
191
- if attachment_key in res_attachments:
192
- assert len(attachments) == res_attachments[attachment_key]
193
-
194
-
195
- async def assert_resource_deleted(client, space: str, subpath: str, shortname: str):
196
- query = Query(
197
- type=QueryType.search,
198
- space_name=space,
199
- subpath=subpath,
200
- search="",
201
- filter_shortnames=[shortname],
202
- retrieve_json_payload=True,
203
- limit=1,
204
- )
205
- response = await client.post("/managed/query", json=query.model_dump(exclude_none=True))
206
- assert_code_and_status_success(response)
207
- assert response.json()["status"] == "success"
208
- assert response.json()["attributes"]["returned"] == 0
209
-
210
-
211
- async def upload_resource_with_payload(
212
- client,
213
- space_name,
214
- record_path: str,
215
- payload_path: str,
216
- payload_type,
217
- attachment=False,
218
- is_fail=False,
219
- ):
220
- with open(record_path, "rb") as request_file, open(
221
- payload_path, "rb"
222
- ) as media_file:
223
- files = {
224
- "request_record": ("record.json", request_file, "application/json"),
225
- "payload_file": (media_file.name.split("/")[-1], media_file, payload_type),
226
- }
227
- response = await client.post(
228
- "managed/resource_with_payload",
229
- headers={},
230
- data={"space_name": space_name},
231
- files=files,
232
- )
233
-
234
- if is_fail:
235
- assert response.status_code == status.HTTP_400_BAD_REQUEST
236
- else:
237
- assert_code_and_status_success(response)
238
-
239
- if attachment:
240
- with open(record_path, 'r') as record_file:
241
- record_data = json.loads(record_file.read())
242
- subpath_parts = record_data["subpath"].split('/')
243
- attach_parent_subpath, attach_parent_shortname = "/".join(subpath_parts[:-1]), subpath_parts[-1]
244
- await assert_resource_created(
245
- client,
246
- query=Query(
247
- type=QueryType.search,
248
- space_name=space_name,
249
- subpath=attach_parent_subpath,
250
- filter_shortnames=[attach_parent_shortname],
251
- retrieve_json_payload=True,
252
- retrieve_attachments=True,
253
- limit=1,
254
- ),
255
- res_shortname=attach_parent_shortname,
256
- res_subpath=attach_parent_subpath,
257
- res_attachments={"media": 1},
258
- )
259
-
260
-
261
- async def delete_resource(client, resource_type: str, del_subpath: str, del_shortname: str):
262
- headers = {"Content-Type": "application/json"}
263
- endpoint = "/managed/request"
264
- request_data = {
265
- "space_name": DEMO_SPACE,
266
- "request_type": RequestType.delete,
267
- "records": [
268
- {
269
- "resource_type": resource_type,
270
- "subpath": del_subpath,
271
- "shortname": del_shortname,
272
- "attributes": {},
273
- }
274
- ],
275
- }
276
-
277
- response = await client.post(endpoint, json=request_data, headers=headers)
278
- assert_code_and_status_success(response)
279
-
280
-
281
- async def retrieve_content_folder(client):
282
- response = await client.get(f"managed/entry/folder/{DEMO_SPACE}/{settings.root_subpath_mw}/{DEMO_SUBPATH}")
283
-
284
- assert response.status_code == status.HTTP_200_OK
285
-
286
- await assert_resource_created(
287
- client,
288
- query=Query(
289
- type=QueryType.search,
290
- space_name=DEMO_SPACE,
291
- subpath="/",
292
- filter_shortnames=[DEMO_SUBPATH],
293
- filter_types=[ResourceType.folder],
294
- retrieve_json_payload=True,
295
- limit=1,
296
- ),
297
- res_shortname=DEMO_SUBPATH,
298
- res_subpath="/",
299
- res_attributes={},
300
- )
@@ -1,14 +0,0 @@
1
- # test_script.py
2
- import subprocess
3
- import pytest
4
-
5
-
6
- @pytest.mark.run(order=4)
7
- def test_script_execution():
8
- result = subprocess.run(
9
- ['python3', 'get_settings.py'],
10
- capture_output=True,
11
- text=True,
12
- check=True
13
- )
14
- assert result.returncode == 0