Flowfile 0.5.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 (329) hide show
  1. build_backends/main.py +25 -22
  2. build_backends/main_prd.py +10 -19
  3. flowfile/__init__.py +178 -74
  4. flowfile/__main__.py +10 -7
  5. flowfile/api.py +51 -57
  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-0dfba9f2.js → CloudConnectionView-f13f202b.js} +11 -11
  11. flowfile/web/static/assets/{CloudStorageReader-d5b1b6c9.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-00d87aad.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-4685e75d.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-23e909da.js → ContextMenu-31ee57f0.js} +3 -3
  19. flowfile/web/static/assets/{ContextMenu-70ae0c79.js → ContextMenu-69a74055.js} +3 -3
  20. flowfile/web/static/assets/{ContextMenu-f149cf7c.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-702a3edd.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-b1519993.js → CustomNode-8479239b.js} +36 -24
  27. flowfile/web/static/assets/{DatabaseConnectionSettings-6f3e4ea5.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-d38c7295.js → DatabaseReader-c58b9552.js} +25 -15
  31. flowfile/web/static/assets/DatabaseView-6655afd6.css +57 -0
  32. flowfile/web/static/assets/{DatabaseManager-cf5ef661.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-b04ef46a.js → DatabaseWriter-4d05ddc7.js} +17 -10
  35. flowfile/web/static/assets/{designer-8da3ba3a.css → DesignerView-a6d0ee84.css} +614 -546
  36. flowfile/web/static/assets/{designer-9633482a.js → DesignerView-e6f5c0e8.js} +1107 -3170
  37. flowfile/web/static/assets/{documentation-ca400224.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-5fa10ed8.js → ExploreData-7b54caca.js} +18 -9
  41. flowfile/web/static/assets/{ExternalSource-d39af878.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-6b04fb1d.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-999521f4.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-17dd2198.js → GraphSolver-c7e6780e.js} +13 -11
  51. flowfile/web/static/assets/{GroupBy-6b039e18.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-24d0f113.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-34639209.js → ManualInput-8d3374b2.js} +170 -116
  59. flowfile/web/static/assets/{MultiSelect-0e8724a3.js → MultiSelect-ad1b6243.js} +2 -2
  60. flowfile/web/static/assets/{MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.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-3d63a470.js → NumericInput-7100234c.js} +2 -2
  64. flowfile/web/static/assets/{NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js → NumericInput.vue_vue_type_script_setup_true_lang-5130219f.js} +5 -2
  65. flowfile/web/static/assets/{Output-283fe388.css → Output-35e97000.css} +6 -6
  66. flowfile/web/static/assets/{Output-edea9802.js → Output-f5efd2aa.js} +12 -9
  67. flowfile/web/static/assets/{GraphSolver-f0cb7bfb.css → Pivot-0eda81b4.css} +5 -5
  68. flowfile/web/static/assets/{Pivot-61d19301.js → Pivot-d981d23c.js} +11 -9
  69. flowfile/web/static/assets/PivotValidation-0e905b1a.css +13 -0
  70. flowfile/web/static/assets/{PivotValidation-f97fec5b.js → PivotValidation-39386e95.js} +3 -3
  71. flowfile/web/static/assets/PivotValidation-41b57ad6.css +13 -0
  72. flowfile/web/static/assets/{PivotValidation-de9f43fe.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-bc3c9984.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-e808b239.css → Read-36e7bd51.css} +12 -12
  78. flowfile/web/static/assets/{Read-64a3f259.js → Read-aec2e377.js} +14 -11
  79. flowfile/web/static/assets/{RecordCount-3d5039be.js → RecordCount-78ed6845.js} +6 -4
  80. flowfile/web/static/assets/{RecordId-597510e0.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-df51adbe.js → SQLQueryComponent-48c72f5b.js} +3 -3
  83. flowfile/web/static/assets/{Sample-4be0a507.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-4839be57.js → SecretsView-17df66ee.js} +35 -36
  87. flowfile/web/static/assets/SecretsView-aa291340.css +38 -0
  88. flowfile/web/static/assets/{Select-9b72f201.js → Select-0aee4c54.js} +9 -7
  89. flowfile/web/static/assets/{SettingsSection-f0f75a42.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-e1e9c953.js → SettingsSection-cd341bb6.js} +3 -3
  94. flowfile/web/static/assets/{SettingsSection-7ded385d.js → SettingsSection-f2002a6d.js} +3 -3
  95. flowfile/web/static/assets/{SingleSelect-6c777aac.js → SingleSelect-460cc0ea.js} +2 -2
  96. flowfile/web/static/assets/{SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js → SingleSelect.vue_vue_type_script_setup_true_lang-30741bb2.js} +1 -1
  97. flowfile/web/static/assets/{SliderInput-7cb93e62.js → SliderInput-5d926864.js} +7 -4
  98. flowfile/web/static/assets/SliderInput-f2e4f23c.css +4 -0
  99. flowfile/web/static/assets/{Sort-6cbde21a.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-d9a40c11.js → TextInput-a2d0bfbd.js} +2 -2
  102. flowfile/web/static/assets/{TextInput.vue_vue_type_script_setup_true_lang-5896c375.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-c4fcbf4d.js → TextToRows-918945f7.js} +11 -10
  105. flowfile/web/static/assets/{ToggleSwitch-4ef91d19.js → ToggleSwitch-f0ef5196.js} +2 -2
  106. flowfile/web/static/assets/{ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.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-a03f512c.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-bfe9b996.js → Union-e8ab8c86.js} +8 -6
  111. flowfile/web/static/assets/{Unique-5d023a27.js → Unique-8cd4f976.js} +13 -10
  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-91cc5354.js → Unpivot-8da14095.js} +10 -8
  115. flowfile/web/static/assets/{UnpivotValidation-7ee2de44.js → UnpivotValidation-6f7d89ff.js} +3 -3
  116. flowfile/web/static/assets/UnpivotValidation-d5ca3b7b.css +13 -0
  117. flowfile/web/static/assets/{VueGraphicWalker-e51b9924.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-cf1221f0.js → api-24483f0d.js} +1 -1
  120. flowfile/web/static/assets/{api-c1bad5ca.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-614b998d.js → dropDown-ac0fda9d.js} +3 -3
  123. flowfile/web/static/assets/{fullEditor-f7971590.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-4fe5f36b.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-5429bbf8.js → index-fb6493ae.js} +41626 -40867
  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-076b85ab.js → outputCsv-8f8ba42d.js} +3 -3
  134. flowfile/web/static/assets/outputCsv-b9a072af.css +2499 -0
  135. flowfile/web/static/assets/{outputExcel-0fd17dbe.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-b61e0847.js → outputParquet-07c81f65.js} +4 -4
  138. flowfile/web/static/assets/outputParquet-54597c3c.css +4 -0
  139. flowfile/web/static/assets/{readCsv-a8bb8b61.js → readCsv-07f6d9ad.js} +3 -3
  140. flowfile/web/static/assets/{readCsv-c767cb37.css → readCsv-3bfac4c3.css} +15 -15
  141. flowfile/web/static/assets/{readExcel-806d2826.css → readExcel-3db6b763.css} +13 -13
  142. flowfile/web/static/assets/{readExcel-67b4aee0.js → readExcel-ed69bc8f.js} +5 -5
  143. flowfile/web/static/assets/{readParquet-48c81530.css → readParquet-c5244ad5.css} +4 -4
  144. flowfile/web/static/assets/{readParquet-92ce1dbc.js → readParquet-e3ed4528.js} +3 -3
  145. flowfile/web/static/assets/secrets.api-002e7d7e.js +65 -0
  146. flowfile/web/static/assets/{selectDynamic-92e25ee3.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-41b0e0d7.js → vue-codemirror.esm-0965f39f.js} +31 -640
  149. flowfile/web/static/assets/{vue-content-loader.es-2c8e608f.js → vue-content-loader.es-c506ad97.js} +1 -1
  150. flowfile/web/static/index.html +2 -2
  151. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/METADATA +2 -3
  152. flowfile-0.5.3.dist-info/RECORD +402 -0
  153. flowfile_core/__init__.py +13 -6
  154. flowfile_core/auth/jwt.py +51 -16
  155. flowfile_core/auth/models.py +32 -7
  156. flowfile_core/auth/password.py +89 -0
  157. flowfile_core/auth/secrets.py +8 -6
  158. flowfile_core/configs/__init__.py +9 -7
  159. flowfile_core/configs/flow_logger.py +15 -14
  160. flowfile_core/configs/node_store/__init__.py +72 -4
  161. flowfile_core/configs/node_store/nodes.py +155 -172
  162. flowfile_core/configs/node_store/user_defined_node_registry.py +108 -27
  163. flowfile_core/configs/settings.py +28 -15
  164. flowfile_core/database/connection.py +7 -6
  165. flowfile_core/database/init_db.py +96 -2
  166. flowfile_core/database/models.py +3 -1
  167. flowfile_core/fileExplorer/__init__.py +17 -0
  168. flowfile_core/fileExplorer/funcs.py +123 -57
  169. flowfile_core/fileExplorer/utils.py +10 -11
  170. flowfile_core/flowfile/_extensions/real_time_interface.py +10 -8
  171. flowfile_core/flowfile/analytics/analytics_processor.py +26 -24
  172. flowfile_core/flowfile/analytics/graphic_walker.py +11 -12
  173. flowfile_core/flowfile/analytics/utils.py +1 -1
  174. flowfile_core/flowfile/code_generator/code_generator.py +358 -244
  175. flowfile_core/flowfile/connection_manager/_connection_manager.py +6 -5
  176. flowfile_core/flowfile/connection_manager/models.py +1 -1
  177. flowfile_core/flowfile/database_connection_manager/db_connections.py +60 -44
  178. flowfile_core/flowfile/database_connection_manager/models.py +1 -1
  179. flowfile_core/flowfile/extensions.py +17 -12
  180. flowfile_core/flowfile/flow_data_engine/cloud_storage_reader.py +34 -32
  181. flowfile_core/flowfile/flow_data_engine/create/funcs.py +115 -83
  182. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +481 -423
  183. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +2 -2
  184. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +92 -52
  185. flowfile_core/flowfile/flow_data_engine/flow_file_column/polars_type.py +12 -11
  186. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +6 -6
  187. flowfile_core/flowfile/flow_data_engine/flow_file_column/utils.py +26 -30
  188. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +31 -20
  189. flowfile_core/flowfile/flow_data_engine/join/__init__.py +1 -1
  190. flowfile_core/flowfile/flow_data_engine/join/utils.py +11 -9
  191. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +14 -15
  192. flowfile_core/flowfile/flow_data_engine/pivot_table.py +5 -7
  193. flowfile_core/flowfile/flow_data_engine/polars_code_parser.py +95 -82
  194. flowfile_core/flowfile/flow_data_engine/read_excel_tables.py +66 -65
  195. flowfile_core/flowfile/flow_data_engine/sample_data.py +27 -21
  196. flowfile_core/flowfile/flow_data_engine/subprocess_operations/__init__.py +1 -1
  197. flowfile_core/flowfile/flow_data_engine/subprocess_operations/models.py +13 -11
  198. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +190 -127
  199. flowfile_core/flowfile/flow_data_engine/threaded_processes.py +8 -8
  200. flowfile_core/flowfile/flow_data_engine/utils.py +99 -67
  201. flowfile_core/flowfile/flow_graph.py +918 -571
  202. flowfile_core/flowfile/flow_graph_utils.py +31 -49
  203. flowfile_core/flowfile/flow_node/flow_node.py +330 -233
  204. flowfile_core/flowfile/flow_node/models.py +53 -41
  205. flowfile_core/flowfile/flow_node/schema_callback.py +14 -19
  206. flowfile_core/flowfile/graph_tree/graph_tree.py +41 -41
  207. flowfile_core/flowfile/handler.py +80 -30
  208. flowfile_core/flowfile/manage/compatibility_enhancements.py +209 -126
  209. flowfile_core/flowfile/manage/io_flowfile.py +54 -57
  210. flowfile_core/flowfile/node_designer/__init__.py +15 -13
  211. flowfile_core/flowfile/node_designer/_type_registry.py +34 -37
  212. flowfile_core/flowfile/node_designer/custom_node.py +162 -36
  213. flowfile_core/flowfile/node_designer/ui_components.py +135 -34
  214. flowfile_core/flowfile/schema_callbacks.py +71 -51
  215. flowfile_core/flowfile/setting_generator/__init__.py +0 -1
  216. flowfile_core/flowfile/setting_generator/setting_generator.py +6 -5
  217. flowfile_core/flowfile/setting_generator/settings.py +64 -53
  218. flowfile_core/flowfile/sources/external_sources/base_class.py +12 -10
  219. flowfile_core/flowfile/sources/external_sources/custom_external_sources/external_source.py +27 -17
  220. flowfile_core/flowfile/sources/external_sources/custom_external_sources/sample_users.py +9 -9
  221. flowfile_core/flowfile/sources/external_sources/factory.py +0 -1
  222. flowfile_core/flowfile/sources/external_sources/sql_source/models.py +45 -31
  223. flowfile_core/flowfile/sources/external_sources/sql_source/sql_source.py +198 -73
  224. flowfile_core/flowfile/sources/external_sources/sql_source/utils.py +250 -196
  225. flowfile_core/flowfile/util/calculate_layout.py +9 -13
  226. flowfile_core/flowfile/util/execution_orderer.py +25 -17
  227. flowfile_core/flowfile/util/node_skipper.py +4 -4
  228. flowfile_core/flowfile/utils.py +19 -21
  229. flowfile_core/main.py +26 -19
  230. flowfile_core/routes/auth.py +284 -11
  231. flowfile_core/routes/cloud_connections.py +25 -25
  232. flowfile_core/routes/logs.py +21 -29
  233. flowfile_core/routes/public.py +3 -3
  234. flowfile_core/routes/routes.py +70 -34
  235. flowfile_core/routes/secrets.py +25 -27
  236. flowfile_core/routes/user_defined_components.py +483 -4
  237. flowfile_core/run_lock.py +0 -1
  238. flowfile_core/schemas/__init__.py +4 -6
  239. flowfile_core/schemas/analysis_schemas/graphic_walker_schemas.py +55 -55
  240. flowfile_core/schemas/cloud_storage_schemas.py +59 -53
  241. flowfile_core/schemas/input_schema.py +231 -144
  242. flowfile_core/schemas/output_model.py +49 -34
  243. flowfile_core/schemas/schemas.py +116 -89
  244. flowfile_core/schemas/transform_schema.py +518 -263
  245. flowfile_core/schemas/yaml_types.py +21 -7
  246. flowfile_core/secret_manager/secret_manager.py +17 -13
  247. flowfile_core/types.py +29 -9
  248. flowfile_core/utils/arrow_reader.py +7 -6
  249. flowfile_core/utils/excel_file_manager.py +3 -3
  250. flowfile_core/utils/fileManager.py +7 -7
  251. flowfile_core/utils/fl_executor.py +8 -10
  252. flowfile_core/utils/utils.py +4 -4
  253. flowfile_core/utils/validate_setup.py +5 -4
  254. flowfile_frame/__init__.py +106 -51
  255. flowfile_frame/adapters.py +2 -9
  256. flowfile_frame/adding_expr.py +73 -32
  257. flowfile_frame/cloud_storage/frame_helpers.py +27 -23
  258. flowfile_frame/cloud_storage/secret_manager.py +12 -26
  259. flowfile_frame/config.py +2 -5
  260. flowfile_frame/expr.py +311 -218
  261. flowfile_frame/expr.pyi +160 -159
  262. flowfile_frame/expr_name.py +23 -23
  263. flowfile_frame/flow_frame.py +571 -476
  264. flowfile_frame/flow_frame.pyi +123 -104
  265. flowfile_frame/flow_frame_methods.py +227 -246
  266. flowfile_frame/group_frame.py +50 -20
  267. flowfile_frame/join.py +2 -2
  268. flowfile_frame/lazy.py +129 -87
  269. flowfile_frame/lazy_methods.py +83 -30
  270. flowfile_frame/list_name_space.py +55 -50
  271. flowfile_frame/selectors.py +148 -68
  272. flowfile_frame/series.py +9 -7
  273. flowfile_frame/utils.py +19 -21
  274. flowfile_worker/__init__.py +12 -7
  275. flowfile_worker/configs.py +11 -19
  276. flowfile_worker/create/__init__.py +14 -9
  277. flowfile_worker/create/funcs.py +114 -77
  278. flowfile_worker/create/models.py +46 -43
  279. flowfile_worker/create/pl_types.py +14 -15
  280. flowfile_worker/create/read_excel_tables.py +34 -41
  281. flowfile_worker/create/utils.py +22 -19
  282. flowfile_worker/external_sources/s3_source/main.py +18 -51
  283. flowfile_worker/external_sources/s3_source/models.py +34 -27
  284. flowfile_worker/external_sources/sql_source/main.py +8 -5
  285. flowfile_worker/external_sources/sql_source/models.py +13 -9
  286. flowfile_worker/flow_logger.py +10 -8
  287. flowfile_worker/funcs.py +214 -155
  288. flowfile_worker/main.py +11 -17
  289. flowfile_worker/models.py +35 -28
  290. flowfile_worker/process_manager.py +2 -3
  291. flowfile_worker/routes.py +121 -90
  292. flowfile_worker/secrets.py +9 -6
  293. flowfile_worker/spawner.py +80 -49
  294. flowfile_worker/utils.py +3 -2
  295. shared/__init__.py +2 -7
  296. shared/storage_config.py +25 -13
  297. test_utils/postgres/commands.py +3 -2
  298. test_utils/postgres/fixtures.py +9 -9
  299. test_utils/s3/commands.py +1 -1
  300. test_utils/s3/data_generator.py +3 -4
  301. test_utils/s3/demo_data_generator.py +4 -7
  302. test_utils/s3/fixtures.py +7 -5
  303. tools/migrate/__init__.py +1 -1
  304. tools/migrate/__main__.py +16 -29
  305. tools/migrate/legacy_schemas.py +251 -190
  306. tools/migrate/migrate.py +193 -181
  307. tools/migrate/tests/conftest.py +1 -3
  308. tools/migrate/tests/test_migrate.py +36 -41
  309. tools/migrate/tests/test_migration_e2e.py +28 -29
  310. tools/migrate/tests/test_node_migrations.py +50 -20
  311. flowfile/web/static/assets/CloudConnectionManager-2dfdce2f.css +0 -86
  312. flowfile/web/static/assets/CustomNode-74a37f74.css +0 -32
  313. flowfile/web/static/assets/DatabaseManager-30fa27e5.css +0 -64
  314. flowfile/web/static/assets/Filter-9b6d08db.js +0 -164
  315. flowfile/web/static/assets/Filter-f62091b3.css +0 -20
  316. flowfile/web/static/assets/ManualInput-3246a08d.css +0 -96
  317. flowfile/web/static/assets/PivotValidation-891ddfb0.css +0 -13
  318. flowfile/web/static/assets/PivotValidation-c46cd420.css +0 -13
  319. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +0 -4
  320. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +0 -13
  321. flowfile/web/static/assets/nodeInput-5d0d6b79.js +0 -41
  322. flowfile/web/static/assets/outputCsv-9cc59e0b.css +0 -2499
  323. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +0 -4
  324. flowfile/web/static/assets/secretApi-68435402.js +0 -46
  325. flowfile/web/static/assets/vue-codemirror-bccfde04.css +0 -32
  326. flowfile-0.5.1.dist-info/RECORD +0 -388
  327. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/WHEEL +0 -0
  328. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/entry_points.txt +0 -0
  329. {flowfile-0.5.1.dist-info → flowfile-0.5.3.dist-info}/licenses/LICENSE +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'])
@@ -466,8 +486,8 @@ def get_generated_code(flow_id: int) -> str:
466
486
  return export_flow_to_polars(flow)
467
487
 
468
488
 
469
- @router.post('/editor/create_flow/', tags=['editor'])
470
- 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)):
471
491
  """Creates a new, empty flow file at the specified path and registers a session for it."""
472
492
  if flow_path is not None and name is None:
473
493
  name = Path(flow_path).stem
@@ -481,16 +501,20 @@ def create_flow(flow_path: str = None, name: str = None):
481
501
  elif name not in flow_path and not (name.endswith(".yaml") or name.endswith(".yml")):
482
502
  flow_path = str(Path(flow_path) / (name + ".yaml"))
483
503
  if flow_path is not None:
504
+ # Validate path is within allowed sandbox
505
+ flow_path = validate_path_under_cwd(flow_path)
484
506
  flow_path_ref = Path(flow_path)
485
507
  if not flow_path_ref.parent.exists():
486
- raise HTTPException(422, 'The directory does not exist')
487
- 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)
488
511
 
489
512
 
490
- @router.post('/editor/close_flow/', tags=['editor'])
491
- def close_flow(flow_id: int) -> None:
492
- """Closes an active flow session."""
493
- 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)
494
518
 
495
519
 
496
520
  @router.post('/update_settings/', tags=['transform'])
@@ -534,7 +558,15 @@ def add_generic_settings(input_data: Dict[str, Any], node_type: str, current_use
534
558
  def get_list_of_saved_flows(path: str):
535
559
  """Scans a directory for saved flow files (`.flowfile`)."""
536
560
  try:
537
- 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)
538
570
  except:
539
571
  return []
540
572
 
@@ -596,18 +628,21 @@ async def get_downstream_node_ids(flow_id: int, node_id: int) -> List[int]:
596
628
  return list(node.get_all_dependent_node_ids())
597
629
 
598
630
 
599
- @router.get('/import_flow/', tags=['editor'], response_model=int)
600
- def import_saved_flow(flow_path: str) -> int:
601
- """Imports a flow from a saved `.yaml` and registers it as a new session."""
602
- flow_path = Path(flow_path)
603
- if not flow_path.exists():
604
- raise HTTPException(404, 'File not found')
605
- 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)
606
639
 
607
640
 
608
641
  @router.get('/save_flow', tags=['editor'])
609
642
  def save_flow(flow_id: int, flow_path: str = None):
610
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)
611
646
  flow = flow_file_handler.get_flow(flow_id)
612
647
  flow.save_flow(flow_path=flow_path)
613
648
 
@@ -671,10 +706,11 @@ async def get_instant_function_result(flow_id: int, node_id: int, func_string: s
671
706
  raise HTTPException(status_code=500, detail=str(e))
672
707
 
673
708
 
674
- @router.get('/api/get_xlsx_sheet_names', tags=['excel_reader'], response_model=List[str])
675
- 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:
676
711
  """Retrieves the sheet names from an Excel file."""
677
- 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)
678
714
  if sheet_names:
679
715
  return sheet_names
680
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: