Flowfile 0.4.1__py3-none-any.whl → 0.5.3__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 (332) hide show
  1. build_backends/main.py +25 -22
  2. build_backends/main_prd.py +10 -19
  3. flowfile/__init__.py +179 -73
  4. flowfile/__main__.py +10 -7
  5. flowfile/api.py +52 -59
  6. flowfile/web/__init__.py +14 -9
  7. flowfile/web/static/assets/AdminView-49392a9a.js +713 -0
  8. flowfile/web/static/assets/AdminView-f53bad23.css +129 -0
  9. flowfile/web/static/assets/CloudConnectionView-36bcd6df.css +72 -0
  10. flowfile/web/static/assets/{CloudConnectionManager-d3248f8d.js → CloudConnectionView-f13f202b.js} +11 -11
  11. flowfile/web/static/assets/{CloudStorageReader-d65bf041.js → CloudStorageReader-0023d4a5.js} +10 -8
  12. flowfile/web/static/assets/{CloudStorageReader-29d14fcc.css → CloudStorageReader-24c54524.css} +27 -27
  13. flowfile/web/static/assets/{CloudStorageWriter-b0ee067f.css → CloudStorageWriter-60547855.css} +26 -26
  14. flowfile/web/static/assets/{CloudStorageWriter-e83be3ed.js → CloudStorageWriter-8e781e11.js} +10 -8
  15. flowfile/web/static/assets/{ColumnSelector-47996a16.css → ColumnSelector-371637fb.css} +2 -2
  16. flowfile/web/static/assets/{ColumnSelector-cce661cf.js → ColumnSelector-8ad68ea9.js} +3 -5
  17. flowfile/web/static/assets/{ContextMenu-c13f91d0.css → ContextMenu-26d4dd27.css} +6 -6
  18. flowfile/web/static/assets/{ContextMenu-11a4652a.js → ContextMenu-31ee57f0.js} +3 -3
  19. flowfile/web/static/assets/{ContextMenu-160afb08.js → ContextMenu-69a74055.js} +3 -3
  20. flowfile/web/static/assets/{ContextMenu-cf18d2cc.js → ContextMenu-8e2051c6.js} +3 -3
  21. flowfile/web/static/assets/{ContextMenu-4c74eef1.css → ContextMenu-8ec1729e.css} +6 -6
  22. flowfile/web/static/assets/{ContextMenu-63cfa99b.css → ContextMenu-9b310c60.css} +6 -6
  23. flowfile/web/static/assets/{CrossJoin-d395d38c.js → CrossJoin-03df6938.js} +12 -10
  24. flowfile/web/static/assets/{CrossJoin-1119d18e.css → CrossJoin-71b4cc10.css} +20 -20
  25. flowfile/web/static/assets/CustomNode-59e99a86.css +32 -0
  26. flowfile/web/static/assets/{CustomNode-b812dc0b.js → CustomNode-8479239b.js} +36 -24
  27. flowfile/web/static/assets/{DatabaseConnectionSettings-7000bf2c.js → DatabaseConnectionSettings-869e3efd.js} +5 -4
  28. flowfile/web/static/assets/{DatabaseConnectionSettings-0c04b2e5.css → DatabaseConnectionSettings-e91df89a.css} +13 -13
  29. flowfile/web/static/assets/{DatabaseReader-ae61773c.css → DatabaseReader-36898a00.css} +24 -24
  30. flowfile/web/static/assets/{DatabaseReader-4f035d0c.js → DatabaseReader-c58b9552.js} +25 -15
  31. flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
  32. flowfile/web/static/assets/{DatabaseManager-9662ec5b.js → DatabaseView-d26a9140.js} +11 -11
  33. flowfile/web/static/assets/{DatabaseWriter-2f570e53.css → DatabaseWriter-217a99f1.css} +19 -19
  34. flowfile/web/static/assets/{DatabaseWriter-f65dcd54.js → DatabaseWriter-4d05ddc7.js} +17 -10
  35. flowfile/web/static/assets/{designer-e3c150ec.css → DesignerView-a6d0ee84.css} +629 -538
  36. flowfile/web/static/assets/{designer-f3656d8c.js → DesignerView-e6f5c0e8.js} +1214 -3209
  37. flowfile/web/static/assets/{documentation-52b241e7.js → DocumentationView-2e78ef1b.js} +5 -5
  38. flowfile/web/static/assets/{documentation-12216a74.css → DocumentationView-fd46c656.css} +7 -7
  39. flowfile/web/static/assets/{ExploreData-2d0cf4db.css → ExploreData-10c5acc8.css} +13 -12
  40. flowfile/web/static/assets/{ExploreData-94c43dfc.js → ExploreData-7b54caca.js} +18 -9
  41. flowfile/web/static/assets/{ExternalSource-ac04b3cc.js → ExternalSource-3fa399b2.js} +9 -7
  42. flowfile/web/static/assets/{ExternalSource-e37b6275.css → ExternalSource-47ab05a3.css} +17 -17
  43. flowfile/web/static/assets/Filter-7494ea97.css +48 -0
  44. flowfile/web/static/assets/Filter-8cbbdbf3.js +287 -0
  45. flowfile/web/static/assets/{Formula-bb96803d.css → Formula-53d58c43.css} +7 -7
  46. flowfile/web/static/assets/{Formula-71472193.js → Formula-aac42b1e.js} +13 -11
  47. flowfile/web/static/assets/{FuzzyMatch-1010f966.css → FuzzyMatch-ad6361d6.css} +68 -69
  48. flowfile/web/static/assets/{FuzzyMatch-b317f631.js → FuzzyMatch-cd9bbfca.js} +12 -10
  49. flowfile/web/static/assets/{Pivot-cf333e3d.css → GraphSolver-c24dec17.css} +5 -5
  50. flowfile/web/static/assets/{GraphSolver-754a234f.js → GraphSolver-c7e6780e.js} +13 -11
  51. flowfile/web/static/assets/{GroupBy-6c6f9802.js → GroupBy-93c5d22b.js} +9 -7
  52. flowfile/web/static/assets/{GroupBy-b9505323.css → GroupBy-be7ac0bf.css} +10 -10
  53. flowfile/web/static/assets/{Join-fd79b451.css → Join-28b5e18f.css} +22 -22
  54. flowfile/web/static/assets/{Join-a1b800be.js → Join-a19b2de2.js} +13 -11
  55. flowfile/web/static/assets/LoginView-0df4ed0a.js +134 -0
  56. flowfile/web/static/assets/LoginView-d325d632.css +172 -0
  57. flowfile/web/static/assets/ManualInput-3702e677.css +293 -0
  58. flowfile/web/static/assets/{ManualInput-a9640276.js → ManualInput-8d3374b2.js} +170 -116
  59. flowfile/web/static/assets/{MultiSelect-97213888.js → MultiSelect-ad1b6243.js} +2 -2
  60. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-6ffe088a.js → MultiSelect.vue_vue_type_script_setup_true_lang-e278950d.js} +1 -1
  61. flowfile/web/static/assets/NodeDesigner-40b647c9.js +2610 -0
  62. flowfile/web/static/assets/NodeDesigner-5f53be3f.css +1429 -0
  63. flowfile/web/static/assets/{NumericInput-e638088a.js → NumericInput-7100234c.js} +2 -2
  64. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-90eb2cba.js → NumericInput.vue_vue_type_script_setup_true_lang-5130219f.js} +5 -2
  65. flowfile/web/static/assets/{Output-ddc9079f.css → Output-35e97000.css} +6 -6
  66. flowfile/web/static/assets/{Output-76750610.js → Output-f5efd2aa.js} +60 -38
  67. flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
  68. flowfile/web/static/assets/{Pivot-7814803f.js → Pivot-d981d23c.js} +11 -9
  69. flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
  70. flowfile/web/static/assets/{PivotValidation-f92137d2.js → PivotValidation-39386e95.js} +3 -3
  71. flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
  72. flowfile/web/static/assets/{PivotValidation-76dd431a.js → PivotValidation-63de1f73.js} +3 -3
  73. flowfile/web/static/assets/{PolarsCode-650322d1.css → PolarsCode-2b1f1f23.css} +4 -4
  74. flowfile/web/static/assets/{PolarsCode-889c3008.js → PolarsCode-f9d69217.js} +18 -9
  75. flowfile/web/static/assets/PopOver-b22f049e.js +939 -0
  76. flowfile/web/static/assets/PopOver-d96599db.css +33 -0
  77. flowfile/web/static/assets/{Read-6b17491f.css → Read-36e7bd51.css} +12 -12
  78. flowfile/web/static/assets/{Read-637b72a7.js → Read-aec2e377.js} +83 -105
  79. flowfile/web/static/assets/{RecordCount-2b050c41.js → RecordCount-78ed6845.js} +6 -4
  80. flowfile/web/static/assets/{RecordId-81df7784.js → RecordId-2156e890.js} +8 -6
  81. flowfile/web/static/assets/{SQLQueryComponent-36cef432.css → SQLQueryComponent-1c2f26b4.css} +5 -5
  82. flowfile/web/static/assets/{SQLQueryComponent-88dcfe53.js → SQLQueryComponent-48c72f5b.js} +3 -3
  83. flowfile/web/static/assets/{Sample-258ad2a9.js → Sample-1352ca74.js} +6 -4
  84. flowfile/web/static/assets/SecretSelector-22b5ff89.js +113 -0
  85. flowfile/web/static/assets/SecretSelector-6329f743.css +43 -0
  86. flowfile/web/static/assets/{SecretManager-2a2cb7e2.js → SecretsView-17df66ee.js} +35 -36
  87. flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
  88. flowfile/web/static/assets/{Select-850215fd.js → Select-0aee4c54.js} +9 -7
  89. flowfile/web/static/assets/{SettingsSection-55bae608.js → SettingsSection-0784e157.js} +3 -3
  90. flowfile/web/static/assets/{SettingsSection-71e6b7e3.css → SettingsSection-07fbbc39.css} +4 -4
  91. flowfile/web/static/assets/{SettingsSection-5c696bee.css → SettingsSection-26fe48d4.css} +4 -4
  92. flowfile/web/static/assets/{SettingsSection-2e4d03c4.css → SettingsSection-8f980839.css} +4 -4
  93. flowfile/web/static/assets/{SettingsSection-0e8d9123.js → SettingsSection-cd341bb6.js} +3 -3
  94. flowfile/web/static/assets/{SettingsSection-29b4fa6b.js → SettingsSection-f2002a6d.js} +3 -3
  95. flowfile/web/static/assets/{SingleSelect-bebd408b.js → SingleSelect-460cc0ea.js} +2 -2
  96. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-6093741c.js → SingleSelect.vue_vue_type_script_setup_true_lang-30741bb2.js} +1 -1
  97. flowfile/web/static/assets/{SliderInput-6a05ab61.js → SliderInput-5d926864.js} +7 -4
  98. flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
  99. flowfile/web/static/assets/{Sort-10ab48ed.js → Sort-3cdc971b.js} +9 -7
  100. flowfile/web/static/assets/{Unique-f9fb0809.css → Sort-8a871341.css} +10 -10
  101. flowfile/web/static/assets/{TextInput-df9d6259.js → TextInput-a2d0bfbd.js} +2 -2
  102. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-000e1178.js → TextInput.vue_vue_type_script_setup_true_lang-abad1ca2.js} +5 -2
  103. flowfile/web/static/assets/{TextToRows-5d2c1190.css → TextToRows-12afb4f4.css} +10 -10
  104. flowfile/web/static/assets/{TextToRows-6c2d93d8.js → TextToRows-918945f7.js} +11 -10
  105. flowfile/web/static/assets/{ToggleSwitch-0ff7ac52.js → ToggleSwitch-f0ef5196.js} +2 -2
  106. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-c6dc3029.js → ToggleSwitch.vue_vue_type_script_setup_true_lang-5605c793.js} +1 -1
  107. flowfile/web/static/assets/{UnavailableFields-5edd5322.css → UnavailableFields-54d2f518.css} +6 -6
  108. flowfile/web/static/assets/{UnavailableFields-1bab97cb.js → UnavailableFields-bdad6144.js} +4 -4
  109. flowfile/web/static/assets/{Union-af6c3d9b.css → Union-d6a8d7d5.css} +7 -7
  110. flowfile/web/static/assets/{Union-b563478a.js → Union-e8ab8c86.js} +8 -6
  111. flowfile/web/static/assets/{Unique-f90db5db.js → Unique-8cd4f976.js} +13 -22
  112. flowfile/web/static/assets/{Sort-3643d625.css → Unique-9fb2f567.css} +10 -10
  113. flowfile/web/static/assets/{Unpivot-1e422df3.css → Unpivot-710a2948.css} +7 -7
  114. flowfile/web/static/assets/{Unpivot-bcb0025f.js → Unpivot-8da14095.js} +10 -8
  115. flowfile/web/static/assets/{UnpivotValidation-c4e73b04.js → UnpivotValidation-6f7d89ff.js} +3 -3
  116. flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
  117. flowfile/web/static/assets/{VueGraphicWalker-bb8535e2.js → VueGraphicWalker-3fb312e1.js} +4 -4
  118. flowfile/web/static/assets/{VueGraphicWalker-ed5ab88b.css → VueGraphicWalker-430f0b86.css} +1 -1
  119. flowfile/web/static/assets/{api-4c8e3822.js → api-24483f0d.js} +1 -1
  120. flowfile/web/static/assets/{api-2d6adc4f.js → api-8b81fa73.js} +1 -1
  121. flowfile/web/static/assets/{dropDown-35135ba8.css → dropDown-3d8dc5fa.css} +40 -40
  122. flowfile/web/static/assets/{dropDown-1bca8a74.js → dropDown-ac0fda9d.js} +3 -3
  123. flowfile/web/static/assets/{fullEditor-2985687e.js → fullEditor-5497a84a.js} +11 -10
  124. flowfile/web/static/assets/{fullEditor-178376bb.css → fullEditor-a0be62b3.css} +74 -62
  125. flowfile/web/static/assets/{genericNodeSettings-924759c7.css → genericNodeSettings-3b2507ea.css} +10 -10
  126. flowfile/web/static/assets/{genericNodeSettings-0476ba4e.js → genericNodeSettings-99014e1d.js} +5 -5
  127. flowfile/web/static/assets/index-07dda503.js +38 -0
  128. flowfile/web/static/assets/index-3ba44389.js +2696 -0
  129. flowfile/web/static/assets/{index-50508d4d.css → index-e6289dd0.css} +1945 -569
  130. flowfile/web/static/assets/{index-246f201c.js → index-fb6493ae.js} +41626 -40869
  131. flowfile/web/static/assets/node.types-2c15bb7e.js +82 -0
  132. flowfile/web/static/assets/nodeInput-0eb13f1a.js +2 -0
  133. flowfile/web/static/assets/{outputCsv-d686eeaf.js → outputCsv-8f8ba42d.js} +3 -3
  134. flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
  135. flowfile/web/static/assets/{outputExcel-8809ea2f.js → outputExcel-393f4fef.js} +3 -3
  136. flowfile/web/static/assets/{outputExcel-b41305c0.css → outputExcel-f5d272b2.css} +26 -26
  137. flowfile/web/static/assets/{outputParquet-53ba645a.js → outputParquet-07c81f65.js} +4 -4
  138. flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
  139. flowfile/web/static/assets/{readCsv-053bf97b.js → readCsv-07f6d9ad.js} +21 -20
  140. flowfile/web/static/assets/{readCsv-bca3ed53.css → readCsv-3bfac4c3.css} +15 -15
  141. flowfile/web/static/assets/{readExcel-e1b381ea.css → readExcel-3db6b763.css} +13 -13
  142. flowfile/web/static/assets/{readExcel-ad531eab.js → readExcel-ed69bc8f.js} +10 -12
  143. flowfile/web/static/assets/{readParquet-cee068e2.css → readParquet-c5244ad5.css} +4 -4
  144. flowfile/web/static/assets/{readParquet-58e899a1.js → readParquet-e3ed4528.js} +4 -7
  145. flowfile/web/static/assets/secrets.api-002e7d7e.js +65 -0
  146. flowfile/web/static/assets/{selectDynamic-b38de2ba.js → selectDynamic-80b92899.js} +5 -5
  147. flowfile/web/static/assets/{selectDynamic-aa913ff4.css → selectDynamic-f2fb394f.css} +21 -20
  148. flowfile/web/static/assets/{vue-codemirror.esm-db9b8936.js → vue-codemirror.esm-0965f39f.js} +31 -637
  149. flowfile/web/static/assets/{vue-content-loader.es-b5f3ac30.js → vue-content-loader.es-c506ad97.js} +1 -1
  150. flowfile/web/static/index.html +2 -2
  151. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/METADATA +4 -4
  152. flowfile-0.5.3.dist-info/RECORD +402 -0
  153. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/WHEEL +1 -1
  154. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/entry_points.txt +1 -0
  155. flowfile_core/__init__.py +13 -3
  156. flowfile_core/auth/jwt.py +51 -16
  157. flowfile_core/auth/models.py +32 -7
  158. flowfile_core/auth/password.py +89 -0
  159. flowfile_core/auth/secrets.py +8 -6
  160. flowfile_core/configs/__init__.py +9 -7
  161. flowfile_core/configs/flow_logger.py +15 -14
  162. flowfile_core/configs/node_store/__init__.py +72 -4
  163. flowfile_core/configs/node_store/nodes.py +155 -172
  164. flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
  165. flowfile_core/configs/settings.py +28 -15
  166. flowfile_core/database/connection.py +7 -6
  167. flowfile_core/database/init_db.py +96 -2
  168. flowfile_core/database/models.py +3 -1
  169. flowfile_core/fileExplorer/__init__.py +17 -0
  170. flowfile_core/fileExplorer/funcs.py +123 -57
  171. flowfile_core/fileExplorer/utils.py +10 -11
  172. flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
  173. flowfile_core/flowfile/analytics/analytics_processor.py +27 -24
  174. flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
  175. flowfile_core/flowfile/analytics/utils.py +1 -1
  176. flowfile_core/flowfile/code_generator/code_generator.py +391 -279
  177. flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
  178. flowfile_core/flowfile/connection_manager/models.py +1 -1
  179. flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
  180. flowfile_core/flowfile/database_connection_manager/models.py +1 -1
  181. flowfile_core/flowfile/extensions.py +17 -12
  182. flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
  183. flowfile_core/flowfile/flow_data_engine/create/funcs.py +152 -103
  184. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +526 -477
  185. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
  186. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
  187. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
  188. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
  189. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
  190. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +43 -32
  191. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
  192. flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
  193. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +15 -11
  194. flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
  195. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
  196. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
  197. flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
  198. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
  199. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
  200. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +360 -191
  201. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
  202. flowfile_core/flowfile/flow_data_engine/utils.py +101 -67
  203. flowfile_core/flowfile/flow_graph.py +1011 -561
  204. flowfile_core/flowfile/flow_graph_utils.py +31 -49
  205. flowfile_core/flowfile/flow_node/flow_node.py +332 -232
  206. flowfile_core/flowfile/flow_node/models.py +54 -41
  207. flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
  208. flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
  209. flowfile_core/flowfile/handler.py +82 -32
  210. flowfile_core/flowfile/manage/compatibility_enhancements.py +493 -47
  211. flowfile_core/flowfile/manage/io_flowfile.py +391 -0
  212. flowfile_core/flowfile/node_designer/__init__.py +15 -13
  213. flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
  214. flowfile_core/flowfile/node_designer/custom_node.py +162 -36
  215. flowfile_core/flowfile/node_designer/ui_components.py +136 -35
  216. flowfile_core/flowfile/schema_callbacks.py +77 -54
  217. flowfile_core/flowfile/setting_generator/__init__.py +0 -1
  218. flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
  219. flowfile_core/flowfile/setting_generator/settings.py +72 -55
  220. flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
  221. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
  222. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
  223. flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
  224. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
  225. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
  226. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
  227. flowfile_core/flowfile/util/calculate_layout.py +9 -13
  228. flowfile_core/flowfile/util/execution_orderer.py +25 -17
  229. flowfile_core/flowfile/util/node_skipper.py +4 -4
  230. flowfile_core/flowfile/utils.py +19 -21
  231. flowfile_core/main.py +26 -19
  232. flowfile_core/routes/auth.py +284 -11
  233. flowfile_core/routes/cloud_connections.py +25 -25
  234. flowfile_core/routes/logs.py +21 -29
  235. flowfile_core/routes/public.py +3 -3
  236. flowfile_core/routes/routes.py +77 -43
  237. flowfile_core/routes/secrets.py +25 -27
  238. flowfile_core/routes/user_defined_components.py +483 -4
  239. flowfile_core/run_lock.py +0 -1
  240. flowfile_core/schemas/__init__.py +4 -6
  241. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
  242. flowfile_core/schemas/cloud_storage_schemas.py +59 -55
  243. flowfile_core/schemas/input_schema.py +398 -154
  244. flowfile_core/schemas/output_model.py +50 -35
  245. flowfile_core/schemas/schemas.py +207 -67
  246. flowfile_core/schemas/transform_schema.py +1360 -435
  247. flowfile_core/schemas/yaml_types.py +117 -0
  248. flowfile_core/secret_manager/secret_manager.py +17 -13
  249. flowfile_core/{flowfile/node_designer/data_types.py → types.py} +33 -3
  250. flowfile_core/utils/arrow_reader.py +7 -6
  251. flowfile_core/utils/excel_file_manager.py +3 -3
  252. flowfile_core/utils/fileManager.py +7 -7
  253. flowfile_core/utils/fl_executor.py +8 -10
  254. flowfile_core/utils/utils.py +4 -4
  255. flowfile_core/utils/validate_setup.py +5 -4
  256. flowfile_frame/__init__.py +107 -50
  257. flowfile_frame/adapters.py +2 -9
  258. flowfile_frame/adding_expr.py +73 -32
  259. flowfile_frame/cloud_storage/frame_helpers.py +27 -23
  260. flowfile_frame/cloud_storage/secret_manager.py +12 -26
  261. flowfile_frame/config.py +2 -5
  262. flowfile_frame/expr.py +311 -218
  263. flowfile_frame/expr.pyi +160 -159
  264. flowfile_frame/expr_name.py +23 -23
  265. flowfile_frame/flow_frame.py +581 -489
  266. flowfile_frame/flow_frame.pyi +123 -104
  267. flowfile_frame/flow_frame_methods.py +236 -252
  268. flowfile_frame/group_frame.py +50 -20
  269. flowfile_frame/join.py +2 -2
  270. flowfile_frame/lazy.py +129 -87
  271. flowfile_frame/lazy_methods.py +83 -30
  272. flowfile_frame/list_name_space.py +55 -50
  273. flowfile_frame/selectors.py +148 -68
  274. flowfile_frame/series.py +9 -7
  275. flowfile_frame/utils.py +19 -21
  276. flowfile_worker/__init__.py +12 -4
  277. flowfile_worker/configs.py +11 -19
  278. flowfile_worker/create/__init__.py +14 -27
  279. flowfile_worker/create/funcs.py +143 -94
  280. flowfile_worker/create/models.py +139 -68
  281. flowfile_worker/create/pl_types.py +14 -15
  282. flowfile_worker/create/read_excel_tables.py +34 -41
  283. flowfile_worker/create/utils.py +22 -19
  284. flowfile_worker/external_sources/s3_source/main.py +18 -51
  285. flowfile_worker/external_sources/s3_source/models.py +34 -27
  286. flowfile_worker/external_sources/sql_source/main.py +8 -5
  287. flowfile_worker/external_sources/sql_source/models.py +13 -9
  288. flowfile_worker/flow_logger.py +10 -8
  289. flowfile_worker/funcs.py +214 -155
  290. flowfile_worker/main.py +11 -17
  291. flowfile_worker/models.py +35 -28
  292. flowfile_worker/process_manager.py +2 -3
  293. flowfile_worker/routes.py +121 -93
  294. flowfile_worker/secrets.py +9 -6
  295. flowfile_worker/spawner.py +80 -49
  296. flowfile_worker/utils.py +3 -2
  297. shared/__init__.py +2 -7
  298. shared/storage_config.py +25 -13
  299. test_utils/postgres/commands.py +3 -2
  300. test_utils/postgres/fixtures.py +9 -9
  301. test_utils/s3/commands.py +1 -1
  302. test_utils/s3/data_generator.py +3 -4
  303. test_utils/s3/demo_data_generator.py +4 -7
  304. test_utils/s3/fixtures.py +7 -5
  305. tools/migrate/README.md +56 -0
  306. tools/migrate/__init__.py +12 -0
  307. tools/migrate/__main__.py +118 -0
  308. tools/migrate/legacy_schemas.py +682 -0
  309. tools/migrate/migrate.py +610 -0
  310. tools/migrate/tests/__init__.py +0 -0
  311. tools/migrate/tests/conftest.py +21 -0
  312. tools/migrate/tests/test_migrate.py +622 -0
  313. tools/migrate/tests/test_migration_e2e.py +1009 -0
  314. tools/migrate/tests/test_node_migrations.py +843 -0
  315. flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
  316. flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
  317. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
  318. flowfile/web/static/assets/Filter-812dcbca.js +0 -164
  319. flowfile/web/static/assets/Filter-f62091b3.css +0 -20
  320. flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
  321. flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
  322. flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
  323. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
  324. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
  325. flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
  326. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
  327. flowfile/web/static/assets/secretApi-538058f3.js +0 -46
  328. flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
  329. flowfile-0.4.1.dist-info/RECORD +0 -376
  330. flowfile_core/flowfile/manage/open_flowfile.py +0 -143
  331. {flowfile-0.4.1.dist-info → flowfile-0.5.3.dist-info}/licenses/LICENSE +0 -0
  332. /flowfile_core/flowfile/manage/manage_flowfile.py → /tools/__init__.py +0 -0
@@ -1,18 +1,19 @@
1
1
  import asyncio
2
2
  import json
3
3
  import time
4
+ from collections.abc import AsyncGenerator
4
5
  from pathlib import Path
5
- from typing import AsyncGenerator
6
+
6
7
  import aiofiles
7
- from fastapi import APIRouter, HTTPException, Depends
8
+ from fastapi import APIRouter, Depends, HTTPException
8
9
  from fastapi.responses import StreamingResponse
9
10
 
10
- from flowfile_core import ServerRun
11
- from flowfile_core import flow_file_handler
11
+ from flowfile_core import ServerRun, flow_file_handler
12
+ from flowfile_core.auth.jwt import get_current_active_user, get_current_user_from_query
13
+
12
14
  # Core modules
13
15
  from flowfile_core.configs import logger
14
16
  from flowfile_core.configs.flow_logger import clear_all_flow_logs
15
- from flowfile_core.auth.jwt import get_current_active_user, get_current_user_from_query
16
17
 
17
18
  # Schema and models
18
19
  from flowfile_core.schemas import schemas
@@ -20,7 +21,7 @@ from flowfile_core.schemas import schemas
20
21
  router = APIRouter()
21
22
 
22
23
 
23
- @router.post("/clear-logs", tags=['flow_logging'])
24
+ @router.post("/clear-logs", tags=["flow_logging"])
24
25
  async def clear_logs(current_user=Depends(get_current_active_user)):
25
26
  clear_all_flow_logs()
26
27
  return {"message": "All flow logs have been cleared."}
@@ -31,7 +32,7 @@ async def format_sse_message(data: str) -> str:
31
32
  return f"data: {json.dumps(data)}\n\n"
32
33
 
33
34
 
34
- @router.post("/logs/{flow_id}", tags=['flow_logging'])
35
+ @router.post("/logs/{flow_id}", tags=["flow_logging"])
35
36
  async def add_log(flow_id: int, log_message: str):
36
37
  """Adds a log message to the log file for a given flow_id."""
37
38
  flow = flow_file_handler.get_flow(flow_id)
@@ -41,35 +42,32 @@ async def add_log(flow_id: int, log_message: str):
41
42
  return {"message": "Log added successfully"}
42
43
 
43
44
 
44
- @router.post("/raw_logs", tags=['flow_logging'])
45
+ @router.post("/raw_logs", tags=["flow_logging"])
45
46
  async def add_raw_log(raw_log_input: schemas.RawLogInput):
46
47
  """Adds a log message to the log file for a given flow_id."""
47
- logger.info('Adding raw logs')
48
+ logger.info("Adding raw logs")
48
49
  flow = flow_file_handler.get_flow(raw_log_input.flowfile_flow_id)
49
50
  if not flow:
50
51
  raise HTTPException(status_code=404, detail="Flow not found")
51
52
  flow.flow_logger.get_log_filepath()
52
53
  flow_logger = flow.flow_logger
53
54
  flow_logger.get_log_filepath()
54
- if raw_log_input.log_type == 'INFO':
55
- flow_logger.info(raw_log_input.log_message,
56
- extra=raw_log_input.extra)
57
- elif raw_log_input.log_type == 'ERROR':
58
- flow_logger.error(raw_log_input.log_message,
59
- extra=raw_log_input.extra)
55
+ if raw_log_input.log_type == "INFO":
56
+ flow_logger.info(raw_log_input.log_message, extra=raw_log_input.extra)
57
+ elif raw_log_input.log_type == "ERROR":
58
+ flow_logger.error(raw_log_input.log_message, extra=raw_log_input.extra)
60
59
  return {"message": "Log added successfully"}
61
60
 
62
61
 
63
62
  async def stream_log_file(
64
63
  log_file_path: Path,
65
64
  is_running_callable: callable,
66
- idle_timeout: int = 60 # timeout in seconds
65
+ idle_timeout: int = 60, # timeout in seconds
67
66
  ) -> AsyncGenerator[str, None]:
68
67
  logger.info(f"Streaming log file: {log_file_path}")
69
68
  last_active = time.monotonic()
70
69
  try:
71
- async with aiofiles.open(log_file_path, "r") as file:
72
-
70
+ async with aiofiles.open(log_file_path) as file:
73
71
  # Ensure we start at the beginning
74
72
  await file.seek(0)
75
73
  while is_running_callable():
@@ -78,7 +76,6 @@ async def stream_log_file(
78
76
  yield await format_sse_message("Server is shutting down. Closing connection.")
79
77
  break
80
78
 
81
-
82
79
  line = await file.readline()
83
80
  if line:
84
81
  formatted_message = await format_sse_message(line.strip())
@@ -113,21 +110,17 @@ async def stream_log_file(
113
110
  raise HTTPException(status_code=500, detail=f"Error reading log file: {e}")
114
111
 
115
112
 
116
- @router.get("/logs/{flow_id}", tags=['flow_logging'])
117
- async def stream_logs(
118
- flow_id: int,
119
- idle_timeout: int = 300,
120
- current_user=Depends(get_current_user_from_query)
121
- ):
113
+ @router.get("/logs/{flow_id}", tags=["flow_logging"])
114
+ async def stream_logs(flow_id: int, idle_timeout: int = 300, current_user=Depends(get_current_user_from_query)):
122
115
  """
123
116
  Streams logs for a given flow_id using Server-Sent Events.
124
117
  Requires authentication via token in query parameter.
125
118
  The connection will close gracefully if the server shuts down.
126
119
  """
127
120
  logger.info(f"Starting log stream for flow_id: {flow_id} by user: {current_user.username}")
128
- await asyncio.sleep(.3)
121
+ await asyncio.sleep(0.3)
129
122
  flow = flow_file_handler.get_flow(flow_id)
130
- logger.info('Streaming logs')
123
+ logger.info("Streaming logs")
131
124
  if not flow:
132
125
  raise HTTPException(status_code=404, detail="Flow not found")
133
126
 
@@ -153,6 +146,5 @@ async def stream_logs(
153
146
  "Cache-Control": "no-cache",
154
147
  "Connection": "keep-alive",
155
148
  "Content-Type": "text/event-stream",
156
- }
149
+ },
157
150
  )
158
-
@@ -5,7 +5,7 @@ from fastapi.responses import RedirectResponse
5
5
  router = APIRouter()
6
6
 
7
7
 
8
- @router.get("/", tags=['admin'])
8
+ @router.get("/", tags=["admin"])
9
9
  async def docs_redirect():
10
- """ Redirects to the documentation page."""
11
- return RedirectResponse(url='/docs')
10
+ """Redirects to the documentation page."""
11
+ return RedirectResponse(url="/docs")
@@ -29,7 +29,9 @@ from flowfile_core.database.connection import get_db
29
29
  from flowfile_core.fileExplorer.funcs import (
30
30
  SecureFileExplorer,
31
31
  FileInfo,
32
- get_files_from_directory
32
+ get_files_from_directory,
33
+ validate_file_path,
34
+ validate_path_under_cwd,
33
35
  )
34
36
  from flowfile_core.flowfile.analytics.analytics_processor import AnalyticsProcessor
35
37
  from flowfile_core.flowfile.code_generator.code_generator import export_flow_to_polars
@@ -76,14 +78,19 @@ async def upload_file(file: UploadFile = File(...)) -> JSONResponse:
76
78
  Returns:
77
79
  A JSON response containing the filename and the path where it was saved.
78
80
  """
79
- file_location = f"uploads/{file.filename}"
81
+ safe_name = Path(file.filename).name.replace("..", "")
82
+ if not safe_name:
83
+ raise HTTPException(400, 'Invalid filename')
84
+ uploads_dir = Path("uploads")
85
+ uploads_dir.mkdir(exist_ok=True)
86
+ file_location = uploads_dir / safe_name
80
87
  with open(file_location, "wb+") as file_object:
81
88
  file_object.write(file.file.read())
82
- return JSONResponse(content={"filename": file.filename, "filepath": file_location})
89
+ return JSONResponse(content={"filename": safe_name, "filepath": str(file_location)})
83
90
 
84
91
 
85
- @router.get('/files/files_in_local_directory/', response_model=List[FileInfo], tags=['file manager'])
86
- async def get_local_files(directory: str) -> List[FileInfo]:
92
+ @router.get('/files/files_in_local_directory/', response_model=list[FileInfo], tags=['file manager'])
93
+ async def get_local_files(directory: str) -> list[FileInfo]:
87
94
  """Retrieves a list of files from a specified local directory.
88
95
 
89
96
  Args:
@@ -94,10 +101,21 @@ async def get_local_files(directory: str) -> List[FileInfo]:
94
101
 
95
102
  Raises:
96
103
  HTTPException: 404 if the directory does not exist.
104
+ HTTPException: 403 if access is denied (path outside sandbox).
97
105
  """
98
- files = get_files_from_directory(directory)
99
- if files is None:
106
+ # Validate path is within sandbox before proceeding
107
+ explorer = SecureFileExplorer(
108
+ start_path=storage.user_data_directory,
109
+ sandbox_root=storage.user_data_directory
110
+ )
111
+ validated_path = explorer.get_absolute_path(directory)
112
+ if validated_path is None:
113
+ raise HTTPException(403, 'Access denied or directory does not exist')
114
+ if not validated_path.exists() or not validated_path.is_dir():
100
115
  raise HTTPException(404, 'Directory does not exist')
116
+ files = get_files_from_directory(str(validated_path), sandbox_root=storage.user_data_directory)
117
+ if files is None:
118
+ raise HTTPException(403, 'Access denied or directory does not exist')
101
119
  return files
102
120
 
103
121
 
@@ -179,9 +197,9 @@ def create_directory(new_directory: input_schema.NewDirectory) -> bool:
179
197
  raise error
180
198
 
181
199
 
182
- @router.post('/flow/register/', tags=['editor'])
183
- def register_flow(flow_data: schemas.FlowSettings) -> int:
184
- """Registers a new flow session with the application.
200
+ @router.post("/flow/register/", tags=["editor"])
201
+ def register_flow(flow_data: schemas.FlowSettings, current_user=Depends(get_current_active_user)) -> int:
202
+ """Registers a new flow session with the application for the current user.
185
203
 
186
204
  Args:
187
205
  flow_data: The `FlowSettings` for the new flow.
@@ -189,13 +207,15 @@ def register_flow(flow_data: schemas.FlowSettings) -> int:
189
207
  Returns:
190
208
  The ID of the newly registered flow.
191
209
  """
192
- return flow_file_handler.register_flow(flow_data)
210
+ user_id = current_user.id if current_user else None
211
+ return flow_file_handler.register_flow(flow_data, user_id=user_id)
193
212
 
194
213
 
195
- @router.get('/active_flowfile_sessions/', response_model=List[schemas.FlowSettings])
196
- async def get_active_flow_file_sessions() -> List[schemas.FlowSettings]:
197
- """Retrieves a list of all currently active flow sessions."""
198
- return [flf.flow_settings for flf in flow_file_handler.flowfile_flows]
214
+ @router.get("/active_flowfile_sessions/", response_model=list[schemas.FlowSettings])
215
+ async def get_active_flow_file_sessions(current_user=Depends(get_current_active_user)) -> list[schemas.FlowSettings]:
216
+ """Retrieves a list of all currently active flow sessions for the current user."""
217
+ user_id = current_user.id if current_user else None
218
+ return [flf.flow_settings for flf in flow_file_handler.get_user_flows(user_id)]
199
219
 
200
220
 
201
221
  @router.post("/node/trigger_fetch_data", tags=['editor'])
@@ -266,8 +286,6 @@ def get_run_status(flow_id: int, response: Response):
266
286
  flow = flow_file_handler.get_flow(flow_id)
267
287
  if not flow:
268
288
  raise HTTPException(status_code=404, detail="Flow not found")
269
- if flow.latest_run_info is None:
270
- raise HTTPException(status_code=404, detail="No run information available")
271
289
  if flow.flow_settings.is_running:
272
290
  response.status_code = status.HTTP_202_ACCEPTED
273
291
  else:
@@ -468,31 +486,35 @@ def get_generated_code(flow_id: int) -> str:
468
486
  return export_flow_to_polars(flow)
469
487
 
470
488
 
471
- @router.post('/editor/create_flow/', tags=['editor'])
472
- def create_flow(flow_path: str = None, name: str = None):
489
+ @router.post("/editor/create_flow/", tags=["editor"])
490
+ def create_flow(flow_path: str = None, name: str = None, current_user=Depends(get_current_active_user)):
473
491
  """Creates a new, empty flow file at the specified path and registers a session for it."""
474
492
  if flow_path is not None and name is None:
475
493
  name = Path(flow_path).stem
476
494
  elif flow_path is not None and name is not None:
477
- if name not in flow_path and flow_path.endswith(".flowfile"):
495
+ if name not in flow_path and (flow_path.endswith(".yaml") or flow_path.endswith(".yml")):
478
496
  raise HTTPException(422, 'The name must be part of the flow path when a full path is provided')
479
- elif name in flow_path and not flow_path.endswith(".flowfile"):
480
- flow_path = str(Path(flow_path) / (name + ".flowfile"))
481
- elif name not in flow_path and name.endswith(".flowfile"):
497
+ elif name in flow_path and not (flow_path.endswith(".yaml") or flow_path.endswith(".yml")):
498
+ flow_path = str(Path(flow_path) / (name + ".yaml"))
499
+ elif name not in flow_path and (name.endswith(".yaml") or name.endswith(".yml")):
482
500
  flow_path = str(Path(flow_path) / name)
483
- elif name not in flow_path and not name.endswith(".flowfile"):
484
- flow_path = str(Path(flow_path) / (name + ".flowfile"))
501
+ elif name not in flow_path and not (name.endswith(".yaml") or name.endswith(".yml")):
502
+ flow_path = str(Path(flow_path) / (name + ".yaml"))
485
503
  if flow_path is not None:
504
+ # Validate path is within allowed sandbox
505
+ flow_path = validate_path_under_cwd(flow_path)
486
506
  flow_path_ref = Path(flow_path)
487
507
  if not flow_path_ref.parent.exists():
488
- raise HTTPException(422, 'The directory does not exist')
489
- return flow_file_handler.add_flow(name=name, flow_path=flow_path)
508
+ raise HTTPException(422, "The directory does not exist")
509
+ user_id = current_user.id if current_user else None
510
+ return flow_file_handler.add_flow(name=name, flow_path=flow_path, user_id=user_id)
490
511
 
491
512
 
492
- @router.post('/editor/close_flow/', tags=['editor'])
493
- def close_flow(flow_id: int) -> None:
494
- """Closes an active flow session."""
495
- flow_file_handler.delete_flow(flow_id)
513
+ @router.post("/editor/close_flow/", tags=["editor"])
514
+ def close_flow(flow_id: int, current_user=Depends(get_current_active_user)) -> None:
515
+ """Closes an active flow session for the current user."""
516
+ user_id = current_user.id if current_user else None
517
+ flow_file_handler.delete_flow(flow_id, user_id=user_id)
496
518
 
497
519
 
498
520
  @router.post('/update_settings/', tags=['transform'])
@@ -536,7 +558,15 @@ def add_generic_settings(input_data: Dict[str, Any], node_type: str, current_use
536
558
  def get_list_of_saved_flows(path: str):
537
559
  """Scans a directory for saved flow files (`.flowfile`)."""
538
560
  try:
539
- return get_files_from_directory(path, types=['flowfile'])
561
+ # Validate path is within sandbox before proceeding
562
+ explorer = SecureFileExplorer(
563
+ start_path=storage.user_data_directory,
564
+ sandbox_root=storage.user_data_directory
565
+ )
566
+ validated_path = explorer.get_absolute_path(path)
567
+ if validated_path is None:
568
+ return []
569
+ return get_files_from_directory(str(validated_path), types=['flowfile'], sandbox_root=storage.user_data_directory)
540
570
  except:
541
571
  return []
542
572
 
@@ -598,18 +628,21 @@ async def get_downstream_node_ids(flow_id: int, node_id: int) -> List[int]:
598
628
  return list(node.get_all_dependent_node_ids())
599
629
 
600
630
 
601
- @router.get('/import_flow/', tags=['editor'], response_model=int)
602
- def import_saved_flow(flow_path: str) -> int:
603
- """Imports a flow from a saved `.flowfile` and registers it as a new session."""
604
- flow_path = Path(flow_path)
605
- if not flow_path.exists():
606
- raise HTTPException(404, 'File not found')
607
- return flow_file_handler.import_flow(flow_path)
631
+ @router.get("/import_flow/", tags=["editor"], response_model=int)
632
+ def import_saved_flow(flow_path: str, current_user=Depends(get_current_active_user)) -> int:
633
+ """Imports a flow from a saved `.yaml` and registers it as a new session for the current user."""
634
+ validated_path = validate_path_under_cwd(flow_path)
635
+ if not os.path.exists(validated_path):
636
+ raise HTTPException(404, "File not found")
637
+ user_id = current_user.id if current_user else None
638
+ return flow_file_handler.import_flow(Path(validated_path), user_id=user_id)
608
639
 
609
640
 
610
641
  @router.get('/save_flow', tags=['editor'])
611
642
  def save_flow(flow_id: int, flow_path: str = None):
612
- """Saves the current state of a flow to a `.flowfile`."""
643
+ """Saves the current state of a flow to a `.yaml`."""
644
+ if flow_path is not None:
645
+ flow_path = validate_path_under_cwd(flow_path)
613
646
  flow = flow_file_handler.get_flow(flow_id)
614
647
  flow.save_flow(flow_path=flow_path)
615
648
 
@@ -673,10 +706,11 @@ async def get_instant_function_result(flow_id: int, node_id: int, func_string: s
673
706
  raise HTTPException(status_code=500, detail=str(e))
674
707
 
675
708
 
676
- @router.get('/api/get_xlsx_sheet_names', tags=['excel_reader'], response_model=List[str])
677
- async def get_excel_sheet_names(path: str) -> List[str] | None:
709
+ @router.get('/api/get_xlsx_sheet_names', tags=['excel_reader'], response_model=list[str])
710
+ async def get_excel_sheet_names(path: str) -> list[str] | None:
678
711
  """Retrieves the sheet names from an Excel file."""
679
- sheet_names = excel_file_manager.get_sheet_names(path)
712
+ validated_path = validate_path_under_cwd(path)
713
+ sheet_names = excel_file_manager.get_sheet_names(validated_path)
680
714
  if sheet_names:
681
715
  return sheet_names
682
716
  else:
@@ -5,8 +5,8 @@ This router provides secure endpoints for creating, retrieving, and deleting
5
5
  sensitive credentials for the authenticated user. Secrets are encrypted before
6
6
  being stored and are associated with the user's ID.
7
7
  """
8
+
8
9
  import os
9
- from typing import List
10
10
 
11
11
  from fastapi import APIRouter, Depends, HTTPException
12
12
  from sqlalchemy.orm import Session
@@ -15,12 +15,13 @@ from flowfile_core.auth.jwt import get_current_active_user
15
15
  from flowfile_core.auth.models import Secret, SecretInput
16
16
  from flowfile_core.database import models as db_models
17
17
  from flowfile_core.database.connection import get_db
18
- from flowfile_core.secret_manager.secret_manager import store_secret, delete_secret as delete_secret_action
18
+ from flowfile_core.secret_manager.secret_manager import delete_secret as delete_secret_action
19
+ from flowfile_core.secret_manager.secret_manager import store_secret
19
20
 
20
21
  router = APIRouter(dependencies=[Depends(get_current_active_user)])
21
22
 
22
23
 
23
- @router.get("/secrets", response_model=List[Secret])
24
+ @router.get("/secrets", response_model=list[Secret])
24
25
  async def get_secrets(current_user=Depends(get_current_active_user), db: Session = Depends(get_db)):
25
26
  """Retrieves all secret names for the currently authenticated user.
26
27
 
@@ -42,18 +43,15 @@ async def get_secrets(current_user=Depends(get_current_active_user), db: Session
42
43
  # Prepare response model (without decrypting)
43
44
  secrets = []
44
45
  for db_secret in db_secrets:
45
- secrets.append(Secret(
46
- name=db_secret.name,
47
- value=db_secret.encrypted_value,
48
- user_id=str(db_secret.user_id)
49
- ))
46
+ secrets.append(Secret(name=db_secret.name, value=db_secret.encrypted_value, user_id=str(db_secret.user_id)))
50
47
 
51
48
  return secrets
52
49
 
53
50
 
54
51
  @router.post("/secrets", response_model=Secret)
55
- async def create_secret(secret: SecretInput, current_user=Depends(get_current_active_user),
56
- db: Session = Depends(get_db)) -> Secret:
52
+ async def create_secret(
53
+ secret: SecretInput, current_user=Depends(get_current_active_user), db: Session = Depends(get_db)
54
+ ) -> Secret:
57
55
  """Creates a new secret for the authenticated user.
58
56
 
59
57
  The secret value is encrypted before being stored in the database. A secret
@@ -73,10 +71,11 @@ async def create_secret(secret: SecretInput, current_user=Depends(get_current_ac
73
71
  # Get user ID
74
72
  user_id = 1 if os.environ.get("FLOWFILE_MODE") == "electron" else current_user.id
75
73
 
76
- existing_secret = db.query(db_models.Secret).filter(
77
- db_models.Secret.user_id == user_id,
78
- db_models.Secret.name == secret.name
79
- ).first()
74
+ existing_secret = (
75
+ db.query(db_models.Secret)
76
+ .filter(db_models.Secret.user_id == user_id, db_models.Secret.name == secret.name)
77
+ .first()
78
+ )
80
79
 
81
80
  if existing_secret:
82
81
  raise HTTPException(status_code=400, detail="Secret with this name already exists")
@@ -87,8 +86,9 @@ async def create_secret(secret: SecretInput, current_user=Depends(get_current_ac
87
86
 
88
87
 
89
88
  @router.get("/secrets/{secret_name}", response_model=Secret)
90
- async def get_secret(secret_name: str,
91
- current_user=Depends(get_current_active_user), db: Session = Depends(get_db)) -> Secret:
89
+ async def get_secret(
90
+ secret_name: str, current_user=Depends(get_current_active_user), db: Session = Depends(get_db)
91
+ ) -> Secret:
92
92
  """Retrieves a specific secret by name for the authenticated user.
93
93
 
94
94
  Note: This endpoint returns the secret name and metadata but does not
@@ -109,24 +109,22 @@ async def get_secret(secret_name: str,
109
109
  user_id = 1 if os.environ.get("FLOWFILE_MODE") == "electron" else current_user.id
110
110
 
111
111
  # Get secret from database
112
- db_secret = db.query(db_models.Secret).filter(
113
- db_models.Secret.user_id == user_id,
114
- db_models.Secret.name == secret_name
115
- ).first()
112
+ db_secret = (
113
+ db.query(db_models.Secret)
114
+ .filter(db_models.Secret.user_id == user_id, db_models.Secret.name == secret_name)
115
+ .first()
116
+ )
116
117
 
117
118
  if not db_secret:
118
119
  raise HTTPException(status_code=404, detail="Secret not found")
119
120
 
120
- return Secret(
121
- name=db_secret.name,
122
- value=db_secret.encrypted_value,
123
- user_id=str(db_secret.user_id)
124
- )
121
+ return Secret(name=db_secret.name, value=db_secret.encrypted_value, user_id=str(db_secret.user_id))
125
122
 
126
123
 
127
124
  @router.delete("/secrets/{secret_name}", status_code=204)
128
- async def delete_secret(secret_name: str, current_user=Depends(get_current_active_user),
129
- db: Session = Depends(get_db)) -> None:
125
+ async def delete_secret(
126
+ secret_name: str, current_user=Depends(get_current_active_user), db: Session = Depends(get_db)
127
+ ) -> None:
130
128
  """Deletes a secret by name for the authenticated user.
131
129
 
132
130
  Args: