db.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. use crate::{
  2. auth::{Auth, Authentication},
  3. error::AppError,
  4. request::{
  5. EntryRequestBody, RequestBody, RequestHeader, RequestHeaderInsert, RequestHeaderUpdate,
  6. RequestParams, RequestPathParam, WorkspaceRequest,
  7. },
  8. workspace::{
  9. Workspace, WorkspaceEntry, WorkspaceEntryBase, WorkspaceEntryCreate, WorkspaceEntryType,
  10. WorkspaceEntryUpdate, WorkspaceEnvVariable, WorkspaceEnvironment,
  11. },
  12. AppResult,
  13. };
  14. use serde::Deserialize;
  15. use sqlx::{sqlite::SqlitePool, types::Json, QueryBuilder};
  16. use std::collections::HashMap;
  17. use tauri_plugin_log::log;
  18. /// Used in update DTOs for **optional** properties. A value indicates a parameter needs to be updated to whatever is contained in it, a null indicates to set the field to null.
  19. #[derive(Debug, Deserialize)]
  20. pub enum Update<T> {
  21. Value(T),
  22. Null,
  23. }
  24. impl<T: Clone> Clone for Update<T> {
  25. fn clone(&self) -> Self {
  26. match self {
  27. Self::Value(arg0) => Self::Value(arg0.clone()),
  28. Self::Null => Self::Null,
  29. }
  30. }
  31. }
  32. impl<T: Copy> Copy for Update<T> {}
  33. impl<T: Copy> Update<T> {
  34. pub fn value(self) -> Option<T> {
  35. match self {
  36. Update::Value(v) => Some(v),
  37. Update::Null => None,
  38. }
  39. }
  40. }
  41. pub async fn init(url: &str) -> SqlitePool {
  42. let pool = SqlitePool::connect(url)
  43. .await
  44. .expect("error while connecting to db");
  45. sqlx::migrate!()
  46. .run(&pool)
  47. .await
  48. .expect("error in migrations");
  49. pool
  50. }
  51. pub async fn create_workspace(db: SqlitePool, name: String) -> Result<Workspace, String> {
  52. match sqlx::query_as!(
  53. Workspace,
  54. "INSERT INTO workspaces (name) VALUES (?) RETURNING id, name",
  55. name
  56. )
  57. .fetch_one(&db)
  58. .await
  59. {
  60. Ok(workspace) => Ok(workspace),
  61. Err(e) => Err(e.to_string()),
  62. }
  63. }
  64. pub async fn list_workspaces(db: SqlitePool) -> AppResult<Vec<Workspace>> {
  65. Ok(
  66. sqlx::query_as!(Workspace, "SELECT id, name FROM workspaces")
  67. .fetch_all(&db)
  68. .await?,
  69. )
  70. }
  71. /// Check whether the entry whose `id` == `parent_id` supports children.
  72. async fn check_parent(db: &SqlitePool, parent_id: Option<i64>) -> AppResult<()> {
  73. let Some(parent_id) = parent_id else {
  74. return Ok(());
  75. };
  76. let ty = sqlx::query!("SELECT type FROM workspace_entries WHERE id = ?", parent_id)
  77. .fetch_one(db)
  78. .await?
  79. .r#type;
  80. if !matches!(WorkspaceEntryType::from(ty), WorkspaceEntryType::Collection) {
  81. return Err(AppError::InvalidUpdate(format!(
  82. "{parent_id} is not a valid parent ID (type: {ty})"
  83. )));
  84. }
  85. Ok(())
  86. }
  87. pub async fn create_workspace_entry(
  88. db: SqlitePool,
  89. entry: WorkspaceEntryCreate,
  90. ) -> AppResult<WorkspaceEntryBase> {
  91. match entry {
  92. WorkspaceEntryCreate::Collection {
  93. name,
  94. workspace_id,
  95. parent_id,
  96. } => {
  97. check_parent(&db, parent_id).await?;
  98. let entry = sqlx::query_as!(
  99. WorkspaceEntryBase,
  100. r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type) VALUES (?, ?, ?, ?)
  101. RETURNING id, workspace_id, parent_id, name, type, auth, auth_inherit"#,
  102. name,
  103. workspace_id,
  104. parent_id,
  105. 1)
  106. .fetch_one(&db).await?;
  107. Ok(entry)
  108. }
  109. WorkspaceEntryCreate::Request {
  110. name,
  111. workspace_id,
  112. parent_id,
  113. method,
  114. url,
  115. } => {
  116. if let Some(parent) = parent_id {
  117. let ty = sqlx::query!("SELECT type FROM workspace_entries WHERE id = ?", parent)
  118. .fetch_one(&db)
  119. .await?
  120. .r#type;
  121. if !matches!(WorkspaceEntryType::from(ty), WorkspaceEntryType::Collection) {
  122. return Err(AppError::InvalidUpdate(format!(
  123. "{parent} is not a valid parent ID (type: {ty})"
  124. )));
  125. }
  126. }
  127. let mut tx = db.begin().await?;
  128. let entry = match sqlx::query_as!(
  129. WorkspaceEntryBase,
  130. r#"INSERT INTO workspace_entries(name, workspace_id, parent_id, type) VALUES (?, ?, ?, ?)
  131. RETURNING id, workspace_id, name, parent_id, type, auth, auth_inherit"#,
  132. name,
  133. workspace_id,
  134. parent_id,
  135. 0)
  136. .fetch_one(&mut *tx).await {
  137. Ok(entry) => entry,
  138. Err(e) => {
  139. tx.rollback().await?;
  140. return Err(e.into());
  141. }
  142. };
  143. match sqlx::query!(
  144. "INSERT INTO request_params(workspace_id, request_id, method, url) VALUES (?, ?, ?, ?)",
  145. workspace_id,
  146. entry.id,
  147. method,
  148. url
  149. )
  150. .execute(&mut *tx)
  151. .await {
  152. Ok(_) => {},
  153. Err(e) => {
  154. tx.rollback().await?;
  155. return Err(e.into());
  156. }
  157. }
  158. ;
  159. tx.commit().await?;
  160. Ok(entry)
  161. }
  162. }
  163. }
  164. pub async fn insert_request_body(
  165. db: SqlitePool,
  166. entry_id: i64,
  167. body: RequestBody,
  168. ) -> AppResult<EntryRequestBody> {
  169. Ok(sqlx::query_as!(EntryRequestBody, r#"INSERT INTO request_bodies(request_id, content_type, body) VALUES (?, ?, ?) RETURNING id, content_type AS "content_type: _", body"#, entry_id, body.ty, body.content).fetch_one(&db).await?)
  170. }
  171. pub async fn update_request_body(
  172. db: SqlitePool,
  173. id: i64,
  174. body: Update<RequestBody>,
  175. ) -> AppResult<()> {
  176. match body {
  177. Update::Value(body) => {
  178. sqlx::query!(
  179. "UPDATE request_bodies SET content_type = ?, body = ? WHERE id = ?",
  180. body.ty,
  181. body.content,
  182. id,
  183. )
  184. .execute(&db)
  185. .await?;
  186. }
  187. Update::Null => {
  188. sqlx::query!("DELETE FROM request_bodies WHERE id = ?", id)
  189. .execute(&db)
  190. .await?;
  191. }
  192. }
  193. Ok(())
  194. }
  195. pub async fn update_workspace_entry(
  196. db: SqlitePool,
  197. entry_id: i64,
  198. update: WorkspaceEntryUpdate,
  199. ) -> AppResult<()> {
  200. match update {
  201. WorkspaceEntryUpdate::Collection(update) => {
  202. let mut sql = sqlx::query_builder::QueryBuilder::new("UPDATE workspace_entries SET ");
  203. if let Some(parent) = update.parent_id {
  204. check_parent(&db, parent.value()).await?;
  205. }
  206. match (update.name, update.parent_id) {
  207. (None, None) => {
  208. return Err(AppError::InvalidUpdate(
  209. "cannot update entry: no updates present".to_string(),
  210. ))
  211. }
  212. (None, Some(parent_id)) => match parent_id {
  213. Update::Value(v) => {
  214. sql.push("parent_id = ").push_bind(v);
  215. }
  216. Update::Null => {
  217. sql.push("parent_id = NULL ");
  218. }
  219. },
  220. (Some(name), None) => {
  221. sql.push("name = ").push_bind(name);
  222. }
  223. (Some(name), Some(parent_id)) => {
  224. match parent_id {
  225. Update::Value(v) => {
  226. sql.push("parent_id = ").push_bind(v);
  227. }
  228. Update::Null => {
  229. sql.push("parent_id = NULL ");
  230. }
  231. };
  232. sql.push(", name = ").push_bind(name);
  233. }
  234. }
  235. sql.push("WHERE id = ")
  236. .push_bind(entry_id)
  237. .build()
  238. .execute(&db)
  239. .await?;
  240. Ok(())
  241. }
  242. WorkspaceEntryUpdate::Request {
  243. base,
  244. method,
  245. url,
  246. path_params,
  247. } => {
  248. let mut tx = db.begin().await?;
  249. 'entry: {
  250. if let Some(parent) = base.parent_id {
  251. check_parent(&db, parent.value()).await?;
  252. }
  253. let mut sql =
  254. sqlx::query_builder::QueryBuilder::new("UPDATE workspace_entries SET ");
  255. match (base.name, base.parent_id) {
  256. (None, None) => break 'entry,
  257. (None, Some(parent_id)) => match parent_id {
  258. Update::Value(v) => {
  259. sql.push("parent_id = ").push_bind(v);
  260. }
  261. Update::Null => {
  262. sql.push("parent_id = NULL ");
  263. }
  264. },
  265. (Some(name), None) => {
  266. sql.push("name = ").push_bind(name);
  267. }
  268. (Some(name), Some(parent_id)) => {
  269. match parent_id {
  270. Update::Value(v) => {
  271. sql.push("parent_id = ").push_bind(v);
  272. }
  273. Update::Null => {
  274. sql.push("parent_id = NULL ");
  275. }
  276. };
  277. sql.push(", name = ").push_bind(name);
  278. }
  279. }
  280. sql.push("WHERE id = ")
  281. .push_bind(entry_id)
  282. .build()
  283. .execute(&mut *tx)
  284. .await?;
  285. };
  286. 'param: {
  287. let mut sql = sqlx::query_builder::QueryBuilder::new("UPDATE request_params ");
  288. match (method, url) {
  289. (None, None) => break 'param,
  290. (None, Some(url)) => {
  291. sql.push("SET url = ").push_bind(url);
  292. }
  293. (Some(method), None) => {
  294. sql.push("SET method = ").push_bind(method);
  295. }
  296. (Some(method), Some(url)) => {
  297. sql.push("SET method = ")
  298. .push_bind(method)
  299. .push(", url = ")
  300. .push_bind(url);
  301. }
  302. }
  303. sql.push("WHERE request_id = ")
  304. .push_bind(entry_id)
  305. .build()
  306. .execute(&mut *tx)
  307. .await?;
  308. };
  309. if let Some(path_params) = path_params {
  310. if path_params.is_empty() {
  311. sqlx::query!(
  312. "DELETE FROM request_path_params WHERE request_id = ?",
  313. entry_id
  314. )
  315. .execute(&mut *tx)
  316. .await?;
  317. } else {
  318. let mut sql = QueryBuilder::new(
  319. "INSERT INTO request_path_params(position, request_id, name, value) ",
  320. );
  321. sql.push_values(path_params.iter(), |mut b, path| {
  322. b.push_bind(path.position as i64)
  323. .push_bind(entry_id)
  324. .push_bind(&path.name);
  325. if let Some(ref path) = path.value {
  326. b.push_bind(path);
  327. } else {
  328. b.push_bind("");
  329. }
  330. });
  331. sql.push(
  332. r#"
  333. ON CONFLICT(position, request_id) DO UPDATE
  334. SET
  335. value = excluded.value,
  336. name = excluded.name;
  337. DELETE FROM request_path_params
  338. WHERE request_id = "#,
  339. )
  340. .push_bind(entry_id)
  341. .push(" AND position NOT IN (");
  342. let mut sep = sql.separated(", ");
  343. for param in path_params.iter() {
  344. sep.push_bind(param.position as i64);
  345. }
  346. sep.push_unseparated(")");
  347. sql.build().execute(&mut *tx).await?;
  348. }
  349. }
  350. tx.commit().await?;
  351. Ok(())
  352. }
  353. }
  354. }
  355. pub async fn get_workspace_request(db: SqlitePool, id: i64) -> AppResult<WorkspaceRequest> {
  356. let entry = sqlx::query_as!(
  357. WorkspaceEntryBase,
  358. "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE id = ?",
  359. id,
  360. )
  361. .fetch_one(&db)
  362. .await?;
  363. let params = sqlx::query_as!(
  364. RequestParams,
  365. r#"
  366. SELECT
  367. rp.request_id as id,
  368. method as 'method!',
  369. url as 'url!',
  370. content_type as "content_type: _",
  371. body AS "body: _",
  372. rb.id AS "body_id: _"
  373. FROM request_params rp
  374. LEFT JOIN request_bodies rb ON rp.request_id = rb.request_id
  375. WHERE rp.request_id = ?
  376. "#,
  377. id
  378. )
  379. .fetch_one(&db)
  380. .await?;
  381. let headers = sqlx::query_as!(
  382. RequestHeader,
  383. "SELECT id, name, value FROM request_headers WHERE request_id = ?",
  384. entry.id
  385. )
  386. .fetch_all(&db)
  387. .await?;
  388. let path_params = sqlx::query_as!(
  389. RequestPathParam,
  390. "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
  391. entry.id
  392. )
  393. .fetch_all(&db)
  394. .await?;
  395. Ok(WorkspaceRequest::from_params_and_headers(
  396. entry,
  397. params,
  398. headers,
  399. path_params,
  400. ))
  401. }
  402. pub async fn list_workspace_entries(
  403. db: SqlitePool,
  404. workspace_id: i64,
  405. ) -> AppResult<Vec<WorkspaceEntry>> {
  406. let entries = sqlx::query_as!(
  407. WorkspaceEntryBase,
  408. "SELECT id, workspace_id, parent_id, name, type, auth, auth_inherit FROM workspace_entries WHERE workspace_id = ? ORDER BY type DESC",
  409. workspace_id,
  410. )
  411. .fetch_all(&db)
  412. .await?;
  413. let mut request_params: HashMap<i64, RequestParams> = sqlx::query_as!(
  414. RequestParams,
  415. r#"
  416. SELECT rp.request_id as id, method as 'method!', url as 'url!', content_type as "content_type: _", body, rb.id as "body_id: _"
  417. FROM request_params rp
  418. LEFT JOIN request_bodies rb ON rp.request_id = rb.request_id
  419. WHERE workspace_id = ?
  420. "#,
  421. workspace_id
  422. )
  423. .fetch_all(&db)
  424. .await?
  425. .into_iter()
  426. .map(|req| (req.id, req))
  427. .collect();
  428. let mut out: Vec<WorkspaceEntry> = vec![];
  429. for entry in entries {
  430. match entry.r#type {
  431. WorkspaceEntryType::Request => {
  432. let headers = sqlx::query_as!(
  433. RequestHeader,
  434. "SELECT id, name, value FROM request_headers WHERE request_id = ?",
  435. entry.id
  436. )
  437. .fetch_all(&db)
  438. .await?;
  439. let path_params = sqlx::query_as!(
  440. RequestPathParam,
  441. "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
  442. entry.id
  443. )
  444. .fetch_all(&db)
  445. .await?;
  446. let Some(params) = request_params.remove(&entry.id) else {
  447. log::warn!("request {} has no params!", entry.id);
  448. continue;
  449. };
  450. let req =
  451. WorkspaceRequest::from_params_and_headers(entry, params, headers, path_params);
  452. out.push(WorkspaceEntry::new_req(req));
  453. }
  454. WorkspaceEntryType::Collection => {
  455. out.push(WorkspaceEntry::new_col(entry));
  456. }
  457. }
  458. }
  459. Ok(out)
  460. }
  461. pub async fn list_environments(
  462. db: SqlitePool,
  463. workspace_id: i64,
  464. ) -> AppResult<Vec<WorkspaceEnvironment>> {
  465. let records = sqlx::query!(
  466. r#"
  467. SELECT
  468. env.workspace_id,
  469. env.id AS env_id,
  470. env.name AS env_name,
  471. var.id AS "var_id?",
  472. var.name AS "var_name?",
  473. var.value AS "var_value?",
  474. var.secret AS "var_secret?"
  475. FROM workspace_envs env
  476. LEFT JOIN workspace_env_variables var ON env.id = var.env_id
  477. WHERE env.workspace_id = $1"#,
  478. workspace_id
  479. )
  480. .fetch_all(&db)
  481. .await?;
  482. let mut environments: HashMap<i64, WorkspaceEnvironment> = HashMap::new();
  483. for record in records {
  484. if let Some(env) = environments.get_mut(&record.env_id) {
  485. if record.var_id.is_some() {
  486. env.variables.push(WorkspaceEnvVariable {
  487. id: record.var_id.unwrap(),
  488. workspace_id,
  489. env_id: record.env_id,
  490. name: record.var_name.unwrap(),
  491. value: record.var_value.unwrap(),
  492. secret: record.var_secret.unwrap(),
  493. })
  494. }
  495. } else {
  496. let mut env = WorkspaceEnvironment {
  497. id: record.env_id,
  498. name: record.env_name,
  499. workspace_id,
  500. variables: vec![],
  501. };
  502. if record.var_id.is_some() {
  503. env.variables.push(WorkspaceEnvVariable {
  504. id: record.var_id.unwrap(),
  505. workspace_id,
  506. env_id: record.env_id,
  507. name: record.var_name.unwrap(),
  508. value: record.var_value.unwrap(),
  509. secret: record.var_secret.unwrap(),
  510. })
  511. }
  512. environments.insert(record.env_id, env);
  513. }
  514. }
  515. Ok(environments.into_values().collect())
  516. }
  517. pub async fn get_env_variables(
  518. db: &SqlitePool,
  519. env_id: i64,
  520. names: &[&str],
  521. ) -> AppResult<Vec<(String, String)>> {
  522. let mut query =
  523. QueryBuilder::new("SELECT name, value FROM workspace_env_variables WHERE env_id = ");
  524. query.push_bind(env_id);
  525. let mut separated = query.push(" AND name IN (").separated(", ");
  526. for name in names {
  527. separated.push_bind(name);
  528. }
  529. separated.push_unseparated(")");
  530. Ok(query
  531. .build_query_as::<(String, String)>()
  532. .fetch_all(db)
  533. .await?)
  534. }
  535. pub async fn create_environment(
  536. db: SqlitePool,
  537. workspace_id: i64,
  538. name: String,
  539. ) -> AppResult<WorkspaceEnvironment> {
  540. let row = sqlx::query!(
  541. r#"
  542. INSERT INTO workspace_envs (workspace_id, name)
  543. VALUES (?, ?)
  544. RETURNING id, workspace_id, name
  545. "#,
  546. workspace_id,
  547. name
  548. )
  549. .fetch_one(&db)
  550. .await?;
  551. Ok(WorkspaceEnvironment {
  552. id: row.id,
  553. workspace_id: row.workspace_id,
  554. name: row.name,
  555. variables: vec![],
  556. })
  557. }
  558. pub async fn update_environment(db: SqlitePool, env_id: i64, name: String) -> AppResult<()> {
  559. sqlx::query!(
  560. r#"
  561. UPDATE workspace_envs SET name = ? WHERE id = ?
  562. "#,
  563. name,
  564. env_id,
  565. )
  566. .execute(&db)
  567. .await?;
  568. Ok(())
  569. }
  570. pub async fn insert_env_var(
  571. db: SqlitePool,
  572. workspace_id: i64,
  573. env_id: i64,
  574. name: String,
  575. value: String,
  576. secret: bool,
  577. ) -> AppResult<WorkspaceEnvVariable> {
  578. Ok(sqlx::query_as!(
  579. WorkspaceEnvVariable,
  580. r#"
  581. INSERT INTO workspace_env_variables (workspace_id, env_id, name, value, secret)
  582. VALUES (?, ?, ?, ?, ?)
  583. RETURNING id, workspace_id, env_id, name, value, secret
  584. "#,
  585. workspace_id,
  586. env_id,
  587. name,
  588. value,
  589. secret,
  590. )
  591. .fetch_one(&db)
  592. .await?)
  593. }
  594. pub async fn update_env_var(
  595. db: SqlitePool,
  596. id: i64,
  597. name: Option<String>,
  598. value: Option<String>,
  599. secret: Option<bool>,
  600. ) -> AppResult<()> {
  601. sqlx::query_as!(
  602. WorkspaceEnvVariable,
  603. r#"
  604. UPDATE workspace_env_variables
  605. SET
  606. name = COALESCE(?, name),
  607. value = COALESCE(?, value),
  608. secret = COALESCE(?, secret)
  609. WHERE id = ?
  610. "#,
  611. name,
  612. value,
  613. secret,
  614. id,
  615. )
  616. .execute(&db)
  617. .await?;
  618. Ok(())
  619. }
  620. pub async fn delete_env_var(db: SqlitePool, id: i64) -> AppResult<()> {
  621. sqlx::query_as!(
  622. WorkspaceEnvVariable,
  623. r#"
  624. DELETE FROM workspace_env_variables
  625. WHERE id = ?
  626. "#,
  627. id,
  628. )
  629. .execute(&db)
  630. .await?;
  631. Ok(())
  632. }
  633. pub async fn list_request_path_params(db: SqlitePool, id: i64) -> AppResult<Vec<RequestPathParam>> {
  634. Ok(sqlx::query_as!(
  635. RequestPathParam,
  636. "SELECT position, name, value FROM request_path_params WHERE request_id = ?",
  637. id
  638. )
  639. .fetch_all(&db)
  640. .await?)
  641. }
  642. pub async fn insert_headers(
  643. db: SqlitePool,
  644. entry_id: i64,
  645. headers: Vec<RequestHeaderInsert>,
  646. ) -> AppResult<RequestHeader> {
  647. let mut insert = QueryBuilder::new("INSERT INTO request_headers(request_id, name, value) ");
  648. insert.push_values(headers, |mut b, header| {
  649. b.push_bind(entry_id)
  650. .push_bind(header.name)
  651. .push_bind(header.value);
  652. });
  653. Ok(insert
  654. .push("RETURNING id, name, value")
  655. .build_query_as()
  656. .fetch_one(&db)
  657. .await?)
  658. }
  659. pub async fn update_header(db: SqlitePool, header: RequestHeaderUpdate) -> AppResult<()> {
  660. sqlx::query!(
  661. "UPDATE request_headers SET name = COALESCE(?, ''), value = COALESCE(?, '') WHERE id = ?",
  662. header.name,
  663. header.value,
  664. header.id
  665. )
  666. .execute(&db)
  667. .await?;
  668. Ok(())
  669. }
  670. pub async fn delete_header(db: SqlitePool, header_id: i64) -> AppResult<()> {
  671. sqlx::query!("DELETE FROM request_headers WHERE id = ?", header_id)
  672. .execute(&db)
  673. .await?;
  674. Ok(())
  675. }
  676. pub async fn insert_auth(
  677. db: SqlitePool,
  678. workspace_id: i64,
  679. params: Auth,
  680. ) -> AppResult<Authentication> {
  681. let json = Json(&params);
  682. let record = sqlx::query!(
  683. "INSERT INTO auth(workspace_id, name, params) VALUES (?, 'New authentication', ?) RETURNING id, name",
  684. workspace_id,
  685. json
  686. )
  687. .fetch_one(&db)
  688. .await?;
  689. Ok(Authentication {
  690. id: record.id,
  691. workspace_id,
  692. name: record.name,
  693. params,
  694. })
  695. }
  696. pub async fn delete_auth(db: SqlitePool, id: i64) -> AppResult<()> {
  697. sqlx::query!("DELETE FROM auth WHERE id = ?", id)
  698. .execute(&db)
  699. .await?;
  700. Ok(())
  701. }
  702. pub async fn list_auth(db: SqlitePool, workspace_id: i64) -> AppResult<Vec<Authentication>> {
  703. let records = sqlx::query!(
  704. r#"
  705. SELECT id, name, workspace_id, params as "params: Json<Auth>"
  706. FROM auth
  707. WHERE workspace_id = ?
  708. "#,
  709. workspace_id
  710. )
  711. .fetch_all(&db)
  712. .await?;
  713. Ok(records
  714. .into_iter()
  715. .map(|record| Authentication {
  716. id: record.id,
  717. name: record.name,
  718. workspace_id: record.workspace_id,
  719. params: record.params.0,
  720. })
  721. .collect())
  722. }
  723. pub async fn get_auth(db: SqlitePool, id: i64) -> AppResult<Authentication> {
  724. let record = sqlx::query!(
  725. r#"
  726. SELECT id, workspace_id, name, params as "params: Json<Auth>"
  727. FROM auth
  728. WHERE id = ?
  729. "#,
  730. id
  731. )
  732. .fetch_one(&db)
  733. .await?;
  734. Ok(Authentication {
  735. id: record.id,
  736. name: record.name,
  737. workspace_id: record.workspace_id,
  738. params: record.params.0,
  739. })
  740. }
  741. pub async fn set_workspace_entry_auth(
  742. db: SqlitePool,
  743. entry_id: i64,
  744. auth_id: Option<i64>,
  745. inherit: Option<bool>,
  746. ) -> AppResult<()> {
  747. sqlx::query!(
  748. "UPDATE workspace_entries SET auth = ?, auth_inherit = COALESCE(?, auth_inherit) WHERE id = ?",
  749. auth_id,
  750. inherit,
  751. entry_id
  752. )
  753. .execute(&db)
  754. .await?;
  755. Ok(())
  756. }
  757. pub async fn update_auth(db: SqlitePool, auth_id: i64, params: Auth) -> AppResult<()> {
  758. let params = Json(params);
  759. sqlx::query!("UPDATE auth SET params = ? WHERE id = ?", params, auth_id)
  760. .execute(&db)
  761. .await?;
  762. Ok(())
  763. }
  764. pub async fn rename_auth(db: SqlitePool, auth_id: i64, name: String) -> AppResult<()> {
  765. sqlx::query!("UPDATE auth SET name = ? WHERE id = ?", name, auth_id)
  766. .execute(&db)
  767. .await?;
  768. Ok(())
  769. }
  770. /// Check for the existence of an auth ID in the workspace entry. If one does not exist,
  771. /// traverse its parents and attempt to find the first one that is present. If none exist,
  772. /// returns `None`.
  773. pub async fn get_auth_inherited(
  774. db: SqlitePool,
  775. mut parent_id: Option<i64>,
  776. ) -> AppResult<Option<i64>> {
  777. while let Some(id) = parent_id {
  778. let record = sqlx::query!(
  779. "SELECT auth, auth_inherit, parent_id FROM workspace_entries WHERE id = ?",
  780. id
  781. )
  782. .fetch_one(&db)
  783. .await?;
  784. if !record.auth_inherit {
  785. return Ok(record.auth);
  786. }
  787. parent_id = record.parent_id;
  788. }
  789. Ok(None)
  790. }