mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat: option to prefix http route with workspace id (#5461)
* add new column * handled worskpaced route * update .sqlx * update: rename migration file, rewrite query for checking existing route path key, add copy button url for each route trigger * update .sqlx * update sql query * update .sqlx * fix: prevent precedence on query * nits * update .sqlx * update query * Update http_triggers.rs * nits --------- Co-authored-by: HugoCasa <hugo@casademont.ch>
This commit is contained in:
+8
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as \"static_asset_config: _\", is_static_website FROM http_trigger WHERE http_method = $1",
|
||||
"query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n workspace_id, \n is_async, \n requires_auth, \n edited_by, \n email, \n static_asset_config AS \"static_asset_config: _\",\n workspaced_route,\n is_static_website\n FROM \n http_trigger \n WHERE \n http_method = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,6 +55,11 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "workspaced_route",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "is_static_website",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
@@ -88,8 +93,9 @@
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1961d15ae075072bd5f677c95f9b4dac7f747585d98aa8bcf60dcfb4c8124028"
|
||||
"hash": "01b87cdd552c2d5a3cd475eb705110394fe6c8abcc1fa93291fac6f929043d20"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND http_method = $2 AND ($3::TEXT IS NULL OR path != $3))",
|
||||
"query": "\n SELECT EXISTS(\n SELECT 1 \n FROM http_trigger \n WHERE \n ((workspaced_route IS TRUE AND workspace_id || '/' || route_path_key = $1) \n OR (workspaced_route IS FALSE AND route_path_key = $1))\n AND http_method = $2 \n AND ($3::TEXT IS NULL OR path != $3)\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -33,5 +33,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "63b5f03741be97d0e8763dd070649ebb6ec02aa083d7e175c1a02a38935a4024"
|
||||
"hash": "0d8153986cea6166820f601f80d8e67156408b08360d628300b28221ea995a58"
|
||||
}
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as \"static_asset_config: _\", is_static_website FROM http_trigger WHERE workspace_id = $1 AND http_method = $2",
|
||||
"query": "\n SELECT \n path, \n script_path, \n is_flow, \n route_path, \n workspace_id, \n is_async, \n requires_auth, \n edited_by, \n email,\n static_asset_config AS \"static_asset_config: _\",\n workspaced_route,\n is_static_website \n FROM \n http_trigger \n WHERE \n workspace_id = $1 AND \n http_method = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,6 +55,11 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "workspaced_route",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "is_static_website",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
@@ -89,8 +94,9 @@
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "8ff25d890d3f7019c5c6f2b47f29f4c7b2c91094036d9b5037ef9a4ac986ee53"
|
||||
"hash": "300b41622dbcdf908d9e173eee2133239d5806fc50bba2d3fe9d8a6e11627655"
|
||||
}
|
||||
+18
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, http_method as \"http_method: _\", edited_by, email, edited_at, extra_perms, is_async, requires_auth, static_asset_config as \"static_asset_config: _\", is_static_website\n FROM http_trigger\n WHERE workspace_id = $1 AND path = $2",
|
||||
"query": "\n SELECT \n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n script_path, \n is_flow, \n http_method as \"http_method: _\", \n edited_by, \n email, \n edited_at, \n extra_perms, \n is_async, \n requires_auth, \n static_asset_config as \"static_asset_config: _\", \n is_static_website\n FROM \n http_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -25,16 +25,21 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "workspaced_route",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "http_method: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
@@ -52,42 +57,42 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 11,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 12,
|
||||
"name": "is_async",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 13,
|
||||
"name": "requires_auth",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 14,
|
||||
"name": "static_asset_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 15,
|
||||
"name": "is_static_website",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
@@ -112,9 +117,10 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "197321abfe4667256761884970334f58c1b3edfcc1e863ec4316c9742a1ac7c8"
|
||||
"hash": "4353a7de6b4de1df6e19d95a4db8ae89c8d75034a9210233aed2f0414690e37d"
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n http_trigger \n SET \n script_path = $1, \n path = $2, \n is_flow = $3, \n http_method = $4,\n static_asset_config = $5, \n edited_by = $6, \n email = $7, \n is_async = $8, \n requires_auth = $9, \n edited_at = now(), \n is_static_website = $10\n WHERE \n workspace_id = $11 AND \n path = $12\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "5d3401f608b27937285e418f7bd64bd112977c995bf266680c54f58ad57fd4b6"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND workspace_id = $2 AND http_method = $3 AND ($4::TEXT IS NULL OR path != $4))",
|
||||
"query": "\n SELECT EXISTS(\n SELECT 1 \n FROM http_trigger \n WHERE \n route_path_key = $1\n AND workspace_id = $2 \n AND http_method = $3 \n AND ($4::TEXT IS NULL OR path != $4)\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -34,5 +34,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a96ff22bc78b74d7234550a12d9fb5c555c1187b276f1353dae1b2ac0670a92a"
|
||||
"hash": "679a9159a5fca976a3de99fe26806faded2cc63e8f16c201e99ab1725dcff294"
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n http_trigger \n SET \n route_path = $1, \n route_path_key = $2, \n workspaced_route = $3, \n script_path = $4, \n path = $5, \n is_flow = $6, \n http_method = $7, \n static_asset_config = $8, \n edited_by = $9, \n email = $10, \n is_async = $11, \n requires_auth = $12, \n edited_at = now(), \n is_static_website = $13\n WHERE \n workspace_id = $14 AND \n path = $15\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "78e6342696052d0e1f79fd721f5942d4da686a65ab11eefdca16367d2db67963"
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE http_trigger SET script_path = $1, path = $2, is_flow = $3, http_method = $4, static_asset_config = $5, edited_by = $6, email = $7, is_async = $8, requires_auth = $9, edited_at = now(), is_static_website = $10\n WHERE workspace_id = $11 AND path = $12",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "89c08575afb31b70984f6b2b7dd4297af93b5b83ffdfb3ec91eba5df7ad3fd95"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM http_trigger \n WHERE workspace_id = $1 \n AND path = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a269c388056eabe4b045948f451ea74ffbb4c0ed7e694f8f03d92f2a7c118af9"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE path = $1 AND workspace_id = $2)",
|
||||
"query": "SELECT EXISTS(\n SELECT 1 FROM http_trigger \n WHERE path = $1 AND workspace_id = $2\n )",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -19,5 +19,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "9a050ab74cfc13a4b855408e61ebcb0a9d27e5563fa7af5e00a4916b03a62ddb"
|
||||
"hash": "adb0090afd3ce918d8b80ff51d9f6104a430a11d7c5cb9447025d11506585708"
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO http_trigger (workspace_id, path, route_path, route_path_key, script_path, is_flow, is_async, requires_auth, http_method, static_asset_config, edited_by, email, edited_at, is_static_website) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, now(), $13)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b41cef713e822bbd89b49b1f35cc662539d5e4af1dd0b5923d8ee17b772c5677"
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1 AND path = $2)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "b57a188ca137162a2848ebf81fa3aeca9a14ac628c61a358e2c6612c57249b0f"
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE http_trigger \n SET route_path = $1, route_path_key = $2, script_path = $3, path = $4, is_flow = $5, http_method = $6, static_asset_config = $7, edited_by = $8, email = $9, is_async = $10, requires_auth = $11, edited_at = now(), is_static_website = $12\n WHERE workspace_id = $13 AND path = $14",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ccb7aea162fa8781675d547fb82f2996dede4de49c5bd9cca2928209dc40b8f1"
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM http_trigger WHERE workspace_id = $1 AND path = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "dc9a906d6c6156a84fccf4e3a2a7c08d8ed4984409b669162f0a1fc1aa48e188"
|
||||
}
|
||||
+21
-15
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, edited_by, edited_at, email, extra_perms, is_async, requires_auth, http_method as \"http_method: _\", static_asset_config as \"static_asset_config: _\", is_static_website FROM http_trigger\n WHERE workspace_id = $1",
|
||||
"query": "\n SELECT \n workspace_id, \n workspaced_route,\n path, \n route_path, \n route_path_key, \n script_path, \n is_flow, \n edited_by, \n edited_at, \n email, \n extra_perms, \n is_async, \n requires_auth, \n http_method AS \"http_method: _\", \n static_asset_config AS \"static_asset_config: _\", \n is_static_website \n FROM http_trigger\n WHERE workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -10,61 +10,66 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspaced_route",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"ordinal": 3,
|
||||
"name": "route_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"ordinal": 4,
|
||||
"name": "route_path_key",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"ordinal": 5,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 9,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 11,
|
||||
"name": "is_async",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 12,
|
||||
"name": "requires_auth",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 13,
|
||||
"name": "http_method: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
@@ -82,12 +87,12 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 14,
|
||||
"name": "static_asset_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 15,
|
||||
"name": "is_static_website",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
@@ -111,9 +116,10 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "d8aa1a5813fedbb22128112fcdf9d16769811cd5d5ad3b66362cc5bb1750ae6b"
|
||||
"hash": "e44ea5870a8eba1fe3d22d4dfe7734669464a56e470935ce2924723003f3f92b"
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO http_trigger (\n workspace_id, \n path, \n route_path, \n route_path_key,\n workspaced_route,\n script_path, \n is_flow, \n is_async, \n requires_auth, \n http_method, \n static_asset_config, \n edited_by, \n email, \n edited_at, \n is_static_website\n ) \n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, now(), $14\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Bool",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "http_method",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"get",
|
||||
"post",
|
||||
"put",
|
||||
"delete",
|
||||
"patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "eb4779976677308e8ad7c6427bfb45146478f70956919c01718623f0828e0383"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT EXISTS(\n SELECT 1 \n FROM \n http_trigger \n WHERE \n workspace_id = $1 AND \n path = $2\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "f632d08a8d3df691fff9f57fdf926f787287c3cd181a6853056077edba10473d"
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
-- Add down migration script here
|
||||
ALTER TABLE http_trigger
|
||||
DROP COLUMN workspaced_route;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
ALTER TABLE http_trigger
|
||||
ADD COLUMN workspaced_route BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -8116,6 +8116,8 @@ paths:
|
||||
enum: ["get", "post", "put", "delete", "patch"]
|
||||
trigger_path:
|
||||
type: string
|
||||
workspaced_route:
|
||||
type: boolean
|
||||
required:
|
||||
- route_path
|
||||
- http_method
|
||||
@@ -13767,6 +13769,8 @@ components:
|
||||
type: boolean
|
||||
is_static_website:
|
||||
type: boolean
|
||||
workspaced_route:
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- route_path
|
||||
@@ -13784,6 +13788,8 @@ components:
|
||||
type: string
|
||||
route_path:
|
||||
type: string
|
||||
workspaced_route:
|
||||
type: boolean
|
||||
static_asset_config:
|
||||
type: object
|
||||
properties:
|
||||
@@ -13831,6 +13837,8 @@ components:
|
||||
type: string
|
||||
route_path:
|
||||
type: string
|
||||
workspaced_route:
|
||||
type: boolean
|
||||
static_asset_config:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -34,6 +34,7 @@ use windmill_common::{
|
||||
utils::{not_found_if_none, paginate, require_admin, Pagination, StripPath},
|
||||
worker::{to_raw_value, CLOUD_HOSTED},
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref ROUTE_PATH_KEY_RE: regex::Regex = regex::Regex::new(r"/?:[-\w]+").unwrap();
|
||||
@@ -100,7 +101,7 @@ impl TryFrom<&http::Method> for HttpMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct NewTrigger {
|
||||
path: String,
|
||||
route_path: String,
|
||||
@@ -110,6 +111,7 @@ struct NewTrigger {
|
||||
requires_auth: bool,
|
||||
http_method: HttpMethod,
|
||||
static_asset_config: Option<sqlx::types::Json<S3Object>>,
|
||||
workspaced_route: Option<bool>,
|
||||
is_static_website: bool,
|
||||
}
|
||||
|
||||
@@ -131,6 +133,7 @@ pub struct HttpTrigger {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub static_asset_config: Option<sqlx::types::Json<S3Object>>,
|
||||
pub is_static_website: bool,
|
||||
pub workspaced_route: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -143,6 +146,7 @@ struct EditTrigger {
|
||||
requires_auth: bool,
|
||||
http_method: HttpMethod,
|
||||
static_asset_config: Option<sqlx::types::Json<S3Object>>,
|
||||
workspaced_route: Option<bool>,
|
||||
is_static_website: bool,
|
||||
}
|
||||
|
||||
@@ -164,7 +168,24 @@ async fn list_triggers(
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
let (per_page, offset) = paginate(Pagination { per_page: lst.per_page, page: lst.page });
|
||||
let mut sqlb = SqlBuilder::select_from("http_trigger")
|
||||
.field("*")
|
||||
.fields(&[
|
||||
"workspace_id",
|
||||
"path",
|
||||
"route_path",
|
||||
"route_path_key",
|
||||
"workspaced_route",
|
||||
"script_path",
|
||||
"is_flow",
|
||||
"http_method",
|
||||
"edited_by",
|
||||
"email",
|
||||
"edited_at",
|
||||
"extra_perms",
|
||||
"is_async",
|
||||
"requires_auth",
|
||||
"static_asset_config",
|
||||
"is_static_website",
|
||||
])
|
||||
.order_by("edited_at", true)
|
||||
.and_where("workspace_id = ?".bind(&w_id))
|
||||
.offset(offset)
|
||||
@@ -199,9 +220,30 @@ async fn get_trigger(
|
||||
let path = path.to_path();
|
||||
let trigger = sqlx::query_as!(
|
||||
HttpTrigger,
|
||||
r#"SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, http_method as "http_method: _", edited_by, email, edited_at, extra_perms, is_async, requires_auth, static_asset_config as "static_asset_config: _", is_static_website
|
||||
FROM http_trigger
|
||||
WHERE workspace_id = $1 AND path = $2"#,
|
||||
r#"
|
||||
SELECT
|
||||
workspace_id,
|
||||
path,
|
||||
route_path,
|
||||
route_path_key,
|
||||
workspaced_route,
|
||||
script_path,
|
||||
is_flow,
|
||||
http_method as "http_method: _",
|
||||
edited_by,
|
||||
email,
|
||||
edited_at,
|
||||
extra_perms,
|
||||
is_async,
|
||||
requires_auth,
|
||||
static_asset_config as "static_asset_config: _",
|
||||
is_static_website
|
||||
FROM
|
||||
http_trigger
|
||||
WHERE
|
||||
workspace_id = $1 AND
|
||||
path = $2
|
||||
"#,
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
@@ -230,9 +272,16 @@ async fn create_trigger(
|
||||
// route path key is extracted from the route path to check for uniqueness
|
||||
// it replaces /?:{key} with :key
|
||||
// it will also remove the leading / if present, not an issue as we only allow : after slashes
|
||||
let route_path_key = ROUTE_PATH_KEY_RE.replace_all(ct.route_path.as_str(), ":key");
|
||||
|
||||
let exists = route_path_key_exists(&route_path_key, &ct.http_method, &w_id, None, &db).await?;
|
||||
let route_path_key = ROUTE_PATH_KEY_RE.replace_all(&ct.route_path, ":key");
|
||||
let exists = route_path_key_exists(
|
||||
&route_path_key,
|
||||
&ct.http_method,
|
||||
&w_id,
|
||||
None,
|
||||
ct.workspaced_route,
|
||||
&db,
|
||||
)
|
||||
.await?;
|
||||
if exists {
|
||||
return Err(error::Error::BadRequest(
|
||||
"A route already exists with this path".to_string(),
|
||||
@@ -247,11 +296,33 @@ async fn create_trigger(
|
||||
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
sqlx::query!(
|
||||
"INSERT INTO http_trigger (workspace_id, path, route_path, route_path_key, script_path, is_flow, is_async, requires_auth, http_method, static_asset_config, edited_by, email, edited_at, is_static_website) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, now(), $13)",
|
||||
r#"
|
||||
INSERT INTO http_trigger (
|
||||
workspace_id,
|
||||
path,
|
||||
route_path,
|
||||
route_path_key,
|
||||
workspaced_route,
|
||||
script_path,
|
||||
is_flow,
|
||||
is_async,
|
||||
requires_auth,
|
||||
http_method,
|
||||
static_asset_config,
|
||||
edited_by,
|
||||
email,
|
||||
edited_at,
|
||||
is_static_website
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, now(), $14
|
||||
)
|
||||
"#,
|
||||
w_id,
|
||||
ct.path,
|
||||
ct.route_path,
|
||||
&route_path_key,
|
||||
ct.workspaced_route,
|
||||
ct.script_path,
|
||||
ct.is_flow,
|
||||
ct.is_async,
|
||||
@@ -260,9 +331,10 @@ async fn create_trigger(
|
||||
ct.static_asset_config as _,
|
||||
&authed.username,
|
||||
&authed.email,
|
||||
ct.is_static_website,
|
||||
ct.is_static_website
|
||||
)
|
||||
.execute(&mut *tx).await?;
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
audit_log(
|
||||
&mut *tx,
|
||||
@@ -288,7 +360,6 @@ async fn update_trigger(
|
||||
Json(ct): Json<EditTrigger>,
|
||||
) -> error::Result<String> {
|
||||
let path = path.to_path();
|
||||
|
||||
if *CLOUD_HOSTED && (ct.is_static_website || ct.static_asset_config.is_some()) {
|
||||
return Err(error::Error::BadRequest(
|
||||
"Static website and static asset are not supported on cloud".to_string(),
|
||||
@@ -309,9 +380,15 @@ async fn update_trigger(
|
||||
|
||||
let route_path_key = ROUTE_PATH_KEY_RE.replace_all(&route_path, ":key");
|
||||
|
||||
let exists =
|
||||
route_path_key_exists(&route_path_key, &ct.http_method, &w_id, Some(&path), &db)
|
||||
.await?;
|
||||
let exists = route_path_key_exists(
|
||||
&route_path_key,
|
||||
&ct.http_method,
|
||||
&w_id,
|
||||
Some(&path),
|
||||
ct.workspaced_route,
|
||||
&db,
|
||||
)
|
||||
.await?;
|
||||
if exists {
|
||||
return Err(error::Error::BadRequest(
|
||||
"A route already exists with this path".to_string(),
|
||||
@@ -319,13 +396,32 @@ async fn update_trigger(
|
||||
}
|
||||
|
||||
tx = user_db.begin(&authed).await?;
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE http_trigger
|
||||
SET route_path = $1, route_path_key = $2, script_path = $3, path = $4, is_flow = $5, http_method = $6, static_asset_config = $7, edited_by = $8, email = $9, is_async = $10, requires_auth = $11, edited_at = now(), is_static_website = $12
|
||||
WHERE workspace_id = $13 AND path = $14",
|
||||
r#"
|
||||
UPDATE
|
||||
http_trigger
|
||||
SET
|
||||
route_path = $1,
|
||||
route_path_key = $2,
|
||||
workspaced_route = $3,
|
||||
script_path = $4,
|
||||
path = $5,
|
||||
is_flow = $6,
|
||||
http_method = $7,
|
||||
static_asset_config = $8,
|
||||
edited_by = $9,
|
||||
email = $10,
|
||||
is_async = $11,
|
||||
requires_auth = $12,
|
||||
edited_at = now(),
|
||||
is_static_website = $13
|
||||
WHERE
|
||||
workspace_id = $14 AND
|
||||
path = $15
|
||||
"#,
|
||||
route_path,
|
||||
&route_path_key,
|
||||
ct.workspaced_route,
|
||||
ct.script_path,
|
||||
ct.path,
|
||||
ct.is_flow,
|
||||
@@ -339,12 +435,30 @@ async fn update_trigger(
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
.execute(&mut *tx).await?;
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
} else {
|
||||
tx = user_db.begin(&authed).await?;
|
||||
sqlx::query!(
|
||||
"UPDATE http_trigger SET script_path = $1, path = $2, is_flow = $3, http_method = $4, static_asset_config = $5, edited_by = $6, email = $7, is_async = $8, requires_auth = $9, edited_at = now(), is_static_website = $10
|
||||
WHERE workspace_id = $11 AND path = $12",
|
||||
r#"
|
||||
UPDATE
|
||||
http_trigger
|
||||
SET
|
||||
script_path = $1,
|
||||
path = $2,
|
||||
is_flow = $3,
|
||||
http_method = $4,
|
||||
static_asset_config = $5,
|
||||
edited_by = $6,
|
||||
email = $7,
|
||||
is_async = $8,
|
||||
requires_auth = $9,
|
||||
edited_at = now(),
|
||||
is_static_website = $10
|
||||
WHERE
|
||||
workspace_id = $11 AND
|
||||
path = $12
|
||||
"#,
|
||||
ct.script_path,
|
||||
ct.path,
|
||||
ct.is_flow,
|
||||
@@ -358,7 +472,8 @@ async fn update_trigger(
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
.execute(&mut *tx).await?;
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
|
||||
audit_log(
|
||||
@@ -386,9 +501,11 @@ async fn delete_trigger(
|
||||
let path = path.to_path();
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
sqlx::query!(
|
||||
"DELETE FROM http_trigger WHERE workspace_id = $1 AND path = $2",
|
||||
"DELETE FROM http_trigger
|
||||
WHERE workspace_id = $1
|
||||
AND path = $2",
|
||||
w_id,
|
||||
path,
|
||||
path
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
@@ -415,13 +532,17 @@ async fn exists_trigger(
|
||||
) -> JsonResult<bool> {
|
||||
let path = path.to_path();
|
||||
let exists = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT 1 FROM http_trigger WHERE path = $1 AND workspace_id = $2)",
|
||||
"SELECT EXISTS(
|
||||
SELECT 1 FROM http_trigger
|
||||
WHERE path = $1 AND workspace_id = $2
|
||||
)",
|
||||
path,
|
||||
w_id,
|
||||
w_id
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(Json(exists))
|
||||
}
|
||||
|
||||
@@ -430,6 +551,7 @@ struct RouteExists {
|
||||
route_path: String,
|
||||
http_method: HttpMethod,
|
||||
trigger_path: Option<String>,
|
||||
workspaced_route: Option<bool>,
|
||||
}
|
||||
|
||||
async fn route_path_key_exists(
|
||||
@@ -437,37 +559,65 @@ async fn route_path_key_exists(
|
||||
http_method: &HttpMethod,
|
||||
w_id: &str,
|
||||
trigger_path: Option<&str>,
|
||||
workspaced_route: Option<bool>,
|
||||
db: &DB,
|
||||
) -> error::Result<bool> {
|
||||
let exists = if *CLOUD_HOSTED {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND workspace_id = $2 AND http_method = $3 AND ($4::TEXT IS NULL OR path != $4))",
|
||||
&route_path_key,
|
||||
w_id,
|
||||
http_method as &HttpMethod,
|
||||
trigger_path
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT 1 FROM http_trigger WHERE route_path_key = $1 AND http_method = $2 AND ($3::TEXT IS NULL OR path != $3))",
|
||||
r#"
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM http_trigger
|
||||
WHERE
|
||||
route_path_key = $1
|
||||
AND workspace_id = $2
|
||||
AND http_method = $3
|
||||
AND ($4::TEXT IS NULL OR path != $4)
|
||||
)
|
||||
"#,
|
||||
&route_path_key,
|
||||
w_id,
|
||||
http_method as &HttpMethod,
|
||||
trigger_path
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
let route_path_key = match workspaced_route {
|
||||
Some(true) => Cow::Owned(format!("{}/{}", w_id, route_path_key.trim_matches('/'))),
|
||||
_ => Cow::Borrowed(route_path_key),
|
||||
};
|
||||
sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM http_trigger
|
||||
WHERE
|
||||
((workspaced_route IS TRUE AND workspace_id || '/' || route_path_key = $1)
|
||||
OR (workspaced_route IS FALSE AND route_path_key = $1))
|
||||
AND http_method = $2
|
||||
AND ($3::TEXT IS NULL OR path != $3)
|
||||
)
|
||||
"#,
|
||||
&route_path_key,
|
||||
http_method as &HttpMethod,
|
||||
trigger_path
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
async fn exists_route(
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Json(RouteExists { route_path, http_method, trigger_path }): Json<RouteExists>,
|
||||
Json(RouteExists { route_path, http_method, trigger_path, workspaced_route }): Json<
|
||||
RouteExists,
|
||||
>,
|
||||
) -> JsonResult<bool> {
|
||||
let route_path_key = ROUTE_PATH_KEY_RE.replace_all(route_path.as_str(), ":key");
|
||||
|
||||
@@ -476,6 +626,7 @@ async fn exists_route(
|
||||
&http_method,
|
||||
&w_id,
|
||||
trigger_path.as_deref(),
|
||||
workspaced_route,
|
||||
&db,
|
||||
)
|
||||
.await?;
|
||||
@@ -494,6 +645,7 @@ struct TriggerRoute {
|
||||
edited_by: String,
|
||||
email: String,
|
||||
static_asset_config: Option<sqlx::types::Json<S3Object>>,
|
||||
workspaced_route: Option<bool>,
|
||||
is_static_website: bool,
|
||||
}
|
||||
|
||||
@@ -514,7 +666,26 @@ async fn get_http_route_trigger(
|
||||
let route_path = StripPath(splitted.collect::<Vec<_>>().join("/"));
|
||||
let triggers = sqlx::query_as!(
|
||||
TriggerRoute,
|
||||
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as "static_asset_config: _", is_static_website FROM http_trigger WHERE workspace_id = $1 AND http_method = $2"#,
|
||||
r#"
|
||||
SELECT
|
||||
path,
|
||||
script_path,
|
||||
is_flow,
|
||||
route_path,
|
||||
workspace_id,
|
||||
is_async,
|
||||
requires_auth,
|
||||
edited_by,
|
||||
email,
|
||||
static_asset_config AS "static_asset_config: _",
|
||||
workspaced_route,
|
||||
is_static_website
|
||||
FROM
|
||||
http_trigger
|
||||
WHERE
|
||||
workspace_id = $1 AND
|
||||
http_method = $2
|
||||
"#,
|
||||
w_id,
|
||||
http_method as HttpMethod
|
||||
)
|
||||
@@ -524,7 +695,25 @@ async fn get_http_route_trigger(
|
||||
} else {
|
||||
let triggers = sqlx::query_as!(
|
||||
TriggerRoute,
|
||||
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as "static_asset_config: _", is_static_website FROM http_trigger WHERE http_method = $1"#,
|
||||
r#"
|
||||
SELECT
|
||||
path,
|
||||
script_path,
|
||||
is_flow,
|
||||
route_path,
|
||||
workspace_id,
|
||||
is_async,
|
||||
requires_auth,
|
||||
edited_by,
|
||||
email,
|
||||
static_asset_config AS "static_asset_config: _",
|
||||
workspaced_route,
|
||||
is_static_website
|
||||
FROM
|
||||
http_trigger
|
||||
WHERE
|
||||
http_method = $1
|
||||
"#,
|
||||
http_method as HttpMethod
|
||||
)
|
||||
.fetch_all(db)
|
||||
@@ -535,7 +724,10 @@ async fn get_http_route_trigger(
|
||||
let mut router = matchit::Router::new();
|
||||
|
||||
for (idx, trigger) in triggers.iter().enumerate() {
|
||||
let route_path = trigger.route_path.clone();
|
||||
let route_path = match trigger.workspaced_route {
|
||||
Some(true) => format!("{}/{}", &trigger.workspace_id, &trigger.route_path),
|
||||
_ => trigger.route_path.clone(),
|
||||
};
|
||||
if trigger.is_static_website {
|
||||
router
|
||||
.insert(format!("/{}/*wm_subpath", route_path), idx)
|
||||
@@ -583,7 +775,16 @@ async fn get_http_route_trigger(
|
||||
// check that the user has access to the trigger
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
let exists = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1 AND path = $2)",
|
||||
r#"
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM
|
||||
http_trigger
|
||||
WHERE
|
||||
workspace_id = $1 AND
|
||||
path = $2
|
||||
)
|
||||
"#,
|
||||
trigger.workspace_id,
|
||||
trigger.path
|
||||
)
|
||||
|
||||
@@ -534,13 +534,32 @@ pub(crate) async fn tarball_workspace(
|
||||
#[cfg(feature = "http_trigger")]
|
||||
{
|
||||
let http_triggers = sqlx::query_as!(
|
||||
crate::http_triggers::HttpTrigger,
|
||||
"SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, edited_by, edited_at, email, extra_perms, is_async, requires_auth, http_method as \"http_method: _\", static_asset_config as \"static_asset_config: _\", is_static_website FROM http_trigger
|
||||
WHERE workspace_id = $1",
|
||||
&w_id
|
||||
)
|
||||
.fetch_all(&mut *tx)
|
||||
.await?;
|
||||
crate::http_triggers::HttpTrigger,
|
||||
r#"
|
||||
SELECT
|
||||
workspace_id,
|
||||
workspaced_route,
|
||||
path,
|
||||
route_path,
|
||||
route_path_key,
|
||||
script_path,
|
||||
is_flow,
|
||||
edited_by,
|
||||
edited_at,
|
||||
email,
|
||||
extra_perms,
|
||||
is_async,
|
||||
requires_auth,
|
||||
http_method AS "http_method: _",
|
||||
static_asset_config AS "static_asset_config: _",
|
||||
is_static_website
|
||||
FROM http_trigger
|
||||
WHERE workspace_id = $1
|
||||
"#,
|
||||
&w_id
|
||||
)
|
||||
.fetch_all(&mut *tx)
|
||||
.await?;
|
||||
|
||||
for trigger in http_triggers {
|
||||
let trigger_str = &to_string_without_metadata(&trigger, false, None).unwrap();
|
||||
@@ -608,10 +627,7 @@ pub(crate) async fn tarball_workspace(
|
||||
for trigger in sqs_triggers {
|
||||
let trigger_str = &to_string_without_metadata(&trigger, false, None).unwrap();
|
||||
archive
|
||||
.write_to_archive(
|
||||
&trigger_str,
|
||||
&format!("{}.sqs_trigger.json", trigger.path),
|
||||
)
|
||||
.write_to_archive(&trigger_str, &format!("{}.sqs_trigger.json", trigger.path))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ pub struct S3AwsOidcResource {
|
||||
pub audience: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct S3Object {
|
||||
pub s3: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
import CaptureTable from '../CaptureTable.svelte'
|
||||
import ClipboardPanel from '../../details/ClipboardPanel.svelte'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { isObject } from '$lib/utils'
|
||||
import { getHttpRoute } from './utils'
|
||||
|
||||
export let initialTriggerPath: string | undefined = undefined
|
||||
export let dirtyRoutePath: boolean = false
|
||||
export let route_path: string | undefined
|
||||
export let http_method: 'get' | 'post' | 'put' | 'patch' | 'delete' | undefined
|
||||
export let route_path: string = ''
|
||||
export let http_method: 'get' | 'post' | 'put' | 'patch' | 'delete' = 'post'
|
||||
export let can_write: boolean = false
|
||||
export let static_asset_config: { s3: string; storage?: string; filename?: string } | undefined =
|
||||
undefined
|
||||
@@ -29,6 +31,7 @@
|
||||
export let headless: boolean = false
|
||||
export let captureInfo: CaptureInfo | undefined = undefined
|
||||
export let captureTable: CaptureTable | undefined = undefined
|
||||
export let workspaced_route: boolean = false
|
||||
export let isValid = false
|
||||
export let runnableArgs: any = {}
|
||||
let validateTimeout: NodeJS.Timeout | undefined = undefined
|
||||
@@ -36,7 +39,8 @@
|
||||
let routeError: string = ''
|
||||
async function validateRoute(
|
||||
routePath: string | undefined,
|
||||
method: typeof http_method
|
||||
method: typeof http_method,
|
||||
workspaced_route: boolean
|
||||
): Promise<void> {
|
||||
if (validateTimeout) {
|
||||
clearTimeout(validateTimeout)
|
||||
@@ -44,7 +48,7 @@
|
||||
validateTimeout = setTimeout(async () => {
|
||||
if (!routePath || !method || !/^:?[-\w]+(\/:?[-\w]+)*$/.test(routePath)) {
|
||||
routeError = 'Endpoint not valid'
|
||||
} else if (await routeExists(routePath, method)) {
|
||||
} else if (await routeExists(routePath, method, workspaced_route)) {
|
||||
routeError = 'Endpoint already taken'
|
||||
} else {
|
||||
routeError = ''
|
||||
@@ -52,32 +56,23 @@
|
||||
validateTimeout = undefined
|
||||
}, 500)
|
||||
}
|
||||
|
||||
async function routeExists(route_path: string, method: Exclude<typeof http_method, undefined>) {
|
||||
async function routeExists(route_path: string, method: Exclude<typeof http_method, undefined>, workspaced_route: boolean) {
|
||||
return await HttpTriggerService.existsRoute({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: {
|
||||
route_path,
|
||||
http_method: method,
|
||||
trigger_path: initialTriggerPath
|
||||
trigger_path: initialTriggerPath,
|
||||
workspaced_route: workspaced_route
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$: validateRoute(route_path, http_method)
|
||||
$: validateRoute(route_path, http_method, workspaced_route)
|
||||
|
||||
$: isValid = routeError === ''
|
||||
|
||||
function getHttpRoute(route_path: string | undefined) {
|
||||
return `${location.origin}${base}/api/r/${isCloudHosted() ? $workspaceStore + '/' : ''}${
|
||||
route_path ?? ''
|
||||
}`
|
||||
}
|
||||
|
||||
$: fullRoute = getHttpRoute(route_path)
|
||||
|
||||
$: !http_method && (http_method = 'post')
|
||||
$: route_path === undefined && (route_path = '')
|
||||
$: fullRoute = getHttpRoute(route_path, workspaced_route, $workspaceStore ?? '')
|
||||
</script>
|
||||
|
||||
<div>
|
||||
@@ -182,10 +177,26 @@
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="text-red-600 dark:text-red-400 text-2xs mt-1.5"
|
||||
>{dirtyRoutePath ? routeError : ''}</div
|
||||
>
|
||||
{#if !isCloudHosted()}
|
||||
<div class="mt-1">
|
||||
<Toggle
|
||||
size="sm"
|
||||
checked={workspaced_route}
|
||||
on:change={async () => {
|
||||
workspaced_route = !workspaced_route
|
||||
dirtyRoutePath = true
|
||||
}}
|
||||
options={{
|
||||
right: 'Prefix with workspace',
|
||||
rightTooltip:
|
||||
'Prefixes the route with the workspace ID (e.g., {base_url}/api/r/{workspace_id}/{route}). Note: deploying the HTTP trigger to another workspace updates the route workspace prefix accordingly.'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
@@ -34,6 +34,22 @@
|
||||
let script_path = ''
|
||||
let initialScriptPath = ''
|
||||
let fixedScriptPath = ''
|
||||
let path: string = ''
|
||||
let pathError = ''
|
||||
let isValid = false
|
||||
let dirtyRoutePath = false
|
||||
let is_async = false
|
||||
let requires_auth = false
|
||||
let route_path = ''
|
||||
let http_method: 'get' | 'post' | 'put' | 'patch' | 'delete' = 'post'
|
||||
let static_asset_config: { s3: string; storage?: string; filename?: string } | undefined =
|
||||
undefined
|
||||
let is_static_website = false
|
||||
|
||||
let s3FilePicker: S3FilePicker
|
||||
let s3FileUploadRawMode = false
|
||||
let s3Editor: SimpleEditor | undefined = undefined
|
||||
let workspaced_route: boolean = false
|
||||
|
||||
let drawerLoading = true
|
||||
export async function openEdit(ePath: string, isFlow: boolean) {
|
||||
@@ -78,27 +94,12 @@
|
||||
initialPath = ''
|
||||
dirtyPath = false
|
||||
is_static_website = false
|
||||
workspaced_route = false
|
||||
} finally {
|
||||
drawerLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
let path: string = ''
|
||||
let pathError = ''
|
||||
let isValid = false
|
||||
let dirtyRoutePath = false
|
||||
let is_async = false
|
||||
let requires_auth = false
|
||||
let route_path = ''
|
||||
let http_method: 'get' | 'post' | 'put' | 'patch' | 'delete' = 'post'
|
||||
let static_asset_config: { s3: string; storage?: string; filename?: string } | undefined =
|
||||
undefined
|
||||
let is_static_website = false
|
||||
|
||||
let s3FilePicker: S3FilePicker
|
||||
let s3FileUploadRawMode = false
|
||||
let s3Editor: SimpleEditor | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let can_write = true
|
||||
@@ -109,13 +110,13 @@
|
||||
})
|
||||
script_path = s.script_path
|
||||
initialScriptPath = s.script_path
|
||||
|
||||
is_flow = s.is_flow
|
||||
path = s.path
|
||||
route_path = s.route_path
|
||||
http_method = s.http_method ?? 'post'
|
||||
is_async = s.is_async
|
||||
requires_auth = s.requires_auth
|
||||
workspaced_route = s.workspaced_route ?? false
|
||||
if (!isCloudHosted()) {
|
||||
static_asset_config = s.static_asset_config
|
||||
s3FileUploadRawMode = !!static_asset_config
|
||||
@@ -139,7 +140,8 @@
|
||||
route_path: $userStore?.is_admin || $userStore?.is_super_admin ? route_path : undefined,
|
||||
http_method,
|
||||
static_asset_config,
|
||||
is_static_website
|
||||
is_static_website,
|
||||
workspaced_route
|
||||
}
|
||||
})
|
||||
sendUserToast(`Route ${path} updated`)
|
||||
@@ -155,7 +157,8 @@
|
||||
route_path,
|
||||
http_method,
|
||||
static_asset_config,
|
||||
is_static_website
|
||||
is_static_website,
|
||||
workspaced_route
|
||||
}
|
||||
})
|
||||
sendUserToast(`Route ${path} created`)
|
||||
@@ -357,9 +360,7 @@
|
||||
btnClasses="ml-4 mt-2"
|
||||
color="dark"
|
||||
size="xs"
|
||||
href={itemKind === 'flow'
|
||||
? '/flows/add?hub=62'
|
||||
: '/scripts/add?hub=hub%2F11627'}
|
||||
href={itemKind === 'flow' ? '/flows/add?hub=62' : '/scripts/add?hub=hub%2F11627'}
|
||||
target="_blank">Create from template</Button
|
||||
>
|
||||
{/if}
|
||||
@@ -373,6 +374,7 @@
|
||||
bind:isValid
|
||||
bind:dirtyRoutePath
|
||||
bind:http_method
|
||||
bind:workspaced_route
|
||||
{can_write}
|
||||
bind:static_asset_config
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { base } from "$lib/base";
|
||||
import { isCloudHosted } from "$lib/cloud";
|
||||
|
||||
export function getHttpRoute(route_path: string, workspaced_route: boolean, workspace_id: string) {
|
||||
return `${location.origin}${base}/api/r/${
|
||||
isCloudHosted() || workspaced_route ? workspace_id + '/' : ''
|
||||
}${route_path}`
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
export function load() {
|
||||
return {
|
||||
stuff: { title: 'HTTP routes' }
|
||||
stuff: { title: 'HTTP triggers' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
type HttpTrigger,
|
||||
type WorkspaceDeployUISettings
|
||||
} from '$lib/gen'
|
||||
import { canWrite, displayDate, getLocalSetting, storeLocalSetting } from '$lib/utils'
|
||||
import {
|
||||
canWrite,
|
||||
copyToClipboard,
|
||||
displayDate,
|
||||
getLocalSetting,
|
||||
storeLocalSetting
|
||||
} from '$lib/utils'
|
||||
import { base } from '$app/paths'
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { Button, Skeleton } from '$lib/components/common'
|
||||
@@ -15,7 +21,7 @@
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { userStore, workspaceStore, userWorkspaces, enterpriseLicense } from '$lib/stores'
|
||||
import { Route, Code, Eye, Pen, Plus, Share, Trash, FileUp } from 'lucide-svelte'
|
||||
import { Route, Code, Eye, Pen, Plus, Share, Trash, FileUp, ClipboardCopy } from 'lucide-svelte'
|
||||
import { goto } from '$lib/navigation'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
@@ -28,6 +34,8 @@
|
||||
import RouteEditor from '$lib/components/triggers/http/RouteEditor.svelte'
|
||||
import DeployWorkspaceDrawer from '$lib/components/DeployWorkspaceDrawer.svelte'
|
||||
import { ALL_DEPLOYABLE, isDeployable } from '$lib/utils_deployable'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import { getHttpRoute } from '$lib/components/triggers/http/utils'
|
||||
|
||||
type TriggerW = HttpTrigger & { canWrite: boolean }
|
||||
|
||||
@@ -229,7 +237,7 @@
|
||||
<div class="text-center text-sm text-tertiary mt-2"> No routes </div>
|
||||
{:else if items?.length}
|
||||
<div class="border rounded-md divide-y">
|
||||
{#each items.slice(0, nbDisplayed) as { path, edited_by, edited_at, script_path, route_path, is_flow, extra_perms, canWrite, marked, http_method, static_asset_config } (path)}
|
||||
{#each items.slice(0, nbDisplayed) as { workspace_id, workspaced_route, path, edited_by, edited_at, script_path, route_path, is_flow, extra_perms, canWrite, marked, http_method, static_asset_config } (path)}
|
||||
{@const href = `${is_flow ? '/flows/get' : '/scripts/get'}/${script_path}`}
|
||||
|
||||
<div
|
||||
@@ -250,7 +258,10 @@
|
||||
{@html marked}
|
||||
</span>
|
||||
{:else}
|
||||
{http_method.toUpperCase()} /{route_path}
|
||||
{http_method.toUpperCase()}
|
||||
{isCloudHosted() || workspaced_route
|
||||
? workspace_id + '/' + route_path
|
||||
: route_path}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-secondary text-xs truncate text-left font-light">
|
||||
@@ -270,6 +281,15 @@
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 items-center justify-end">
|
||||
<Button
|
||||
on:click={() =>
|
||||
copyToClipboard(getHttpRoute(route_path, workspaced_route ?? false, workspace_id))}
|
||||
color="dark"
|
||||
size="xs"
|
||||
startIcon={{ icon: ClipboardCopy }}
|
||||
>
|
||||
Copy URL
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => routeEditor?.openEdit(path, is_flow)}
|
||||
size="xs"
|
||||
|
||||
Reference in New Issue
Block a user