OXYGENHUB

Coverage / crates/hub/src/web/variables.rs 86.5%

32 of 37 lines run, 5 of 12 functions · run #476 on main · run missed

1
//! The Flow variables panel (hub spec §13.2, oxygenhub#102) shared by
2
//! the administration, organisation and repository settings pages: the
3
//! level's own variables and the ones it inherits.
4
5
use crate::auth::Viewer;
6
use crate::db::accounts;
7
use crate::levels::At;
8
use crate::variables::{self, Seen};
9
use crate::Shared;
10
use serde::Deserialize;
11
12
#[derive(Deserialize)]
13
pub struct VariableForm {
14
    #[serde(rename = "_csrf")]
15
    pub csrf_token: String,
16
    #[serde(default)]
17
    action: String,
18
    #[serde(default)]
19
    name: String,
20
    #[serde(default)]
21
    value: String,
22
}
23
24
/// Everything the panel shows.
25
pub struct Panel {
26
    /// The level's own variables.
27
    pub own: Vec<Seen>,
28
    /// The ones the levels above provide, outermost first.
29
    pub inherited: Vec<Seen>,
30
}
31
32260×
pub async fn panel(app: &Shared, at: &At) -> sqlx::Result<Panel> {
33260×
    let (own, inherited): (Vec<_>, Vec<_>) =
34260×
        variables::seen(&app.db, at.scope, &at.owner).await?.into_iter().partition(|v| v.from.is_empty());
35260×
    Ok(Panel { own, inherited })
36260×
}
37
38
/// Apply the panel's form: `Ok(notice)` or `Err(message for the user)`.
394×
pub async fn apply(app: &Shared, viewer: &Viewer, at: &At, f: VariableForm) -> sqlx::Result<Result<String, String>> {
404×
    let name = f.name.trim();
414×
    if !variables::name_ok(name) {
421×
        return Ok(Err(
431×
            "A variable's name is a letter or _, then letters, digits and _, up to 64, and not FLOW_… (Flow sets those).".into()
441×
        ));
453×
    }
463×
    Ok(Ok(match f.action.as_str() {
473×
        "set" => {
482×
            let value = f.value.replace("\r\n", "\n");
492×
            if !variables::value_ok(&value) {
500×
                return Ok(Err(format!("A value is up to {} characters of text.", variables::MAX_VALUE)));
512×
            }
522×
            let own = variables::list(&app.db, at.scope).await?;
532×
            if own.len() >= variables::MAX_PER_LEVEL && !own.iter().any(|v| v.name == name) {
540×
                return Ok(Err(format!("Up to {} variables here.", variables::MAX_PER_LEVEL)));
552×
            }
562×
            variables::set(&app.db, at.scope, name, &value).await?;
572×
            accounts::audit(&app.db, viewer.account(), "flow.variable.set", &at.label, name).await.ok();
582×
            format!("{name} set.")
59
        }
601×
        "delete" => {
611×
            if !variables::delete(&app.db, at.scope, name).await? {
620×
                return Ok(Err(format!("There is no variable {name} here.")));
631×
            }
641×
            accounts::audit(&app.db, viewer.account(), "flow.variable.deleted", &at.label, name).await.ok();
651×
            format!("{name} removed.")
66
        }
670×
        _ => return Ok(Err("Unknown action.".into())),
68
    }))
694×
}