parent
3c27383bbc
commit
cde6c7fe9f
|
@ -116,6 +116,7 @@ name = "cooking-schedule"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
"directories",
|
"directories",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
|
|
@ -19,6 +19,9 @@ version = "0.11"
|
||||||
[dependencies.anyhow]
|
[dependencies.anyhow]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
||||||
|
[dependencies.base64]
|
||||||
|
version = "0.13"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "3.2"
|
version = "3.2"
|
||||||
features = ["cargo"]
|
features = ["cargo"]
|
||||||
|
|
|
@ -17,14 +17,14 @@ pub struct Credentials {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
config_file: PathBuf,
|
config_file: PathBuf,
|
||||||
|
|
||||||
servers: HashMap<String, Server>,
|
pub servers: HashMap<String, Server>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
url: String,
|
pub url: String,
|
||||||
login_name: String,
|
pub login_name: String,
|
||||||
password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Credentials {
|
impl Credentials {
|
||||||
|
@ -48,6 +48,7 @@ impl Credentials {
|
||||||
|
|
||||||
pub fn add(&mut self, server: Url) -> Result<()> {
|
pub fn add(&mut self, server: Url) -> Result<()> {
|
||||||
let http_client = reqwest::blocking::Client::builder()
|
let http_client = reqwest::blocking::Client::builder()
|
||||||
|
.https_only(true)
|
||||||
.user_agent(USER_AGENT)
|
.user_agent(USER_AGENT)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
|
|
82
src/main.rs
82
src/main.rs
|
@ -6,11 +6,16 @@ mod constants;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
self::config::Config,
|
self::config::Config,
|
||||||
|
anyhow::anyhow,
|
||||||
|
base64::write::EncoderWriter as Base64Encoder,
|
||||||
clap::{arg, command, ArgMatches, Command},
|
clap::{arg, command, ArgMatches, Command},
|
||||||
reqwest::Url,
|
reqwest::Url,
|
||||||
|
std::io::Write,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_args() -> ArgMatches {
|
fn parse_args() -> ArgMatches {
|
||||||
|
let server_arg = arg!(-s --server <server> "NextCloud server to connect to").required(false);
|
||||||
|
|
||||||
command!()
|
command!()
|
||||||
.propagate_version(true)
|
.propagate_version(true)
|
||||||
.subcommand_required(true)
|
.subcommand_required(true)
|
||||||
|
@ -20,6 +25,12 @@ fn parse_args() -> ArgMatches {
|
||||||
.about("Authenticate against the provided NextCloud server")
|
.about("Authenticate against the provided NextCloud server")
|
||||||
.arg(arg!(<server> "NextCloud server to connect to")),
|
.arg(arg!(<server> "NextCloud server to connect to")),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("import")
|
||||||
|
.about("Import the given URLs into NextCloud's cookbook")
|
||||||
|
.arg(server_arg)
|
||||||
|
.arg(arg!(<url> ... "One or more URLs each pointing to page with a recipe to import in NextCloud")),
|
||||||
|
)
|
||||||
.get_matches()
|
.get_matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +52,79 @@ async fn main() -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
Some(("import", sub_matches)) => {
|
||||||
|
let server_name = sub_matches
|
||||||
|
.get_one::<String>("server")
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let servers = &configuration.credentials.servers;
|
||||||
|
match servers.len() {
|
||||||
|
0 => panic!("No NextCloud server set up yet, use '{} init' first", env!("CARGO_BIN_NAME")),
|
||||||
|
1 => servers.iter().next().unwrap().0,
|
||||||
|
_ => panic!("More than one NextCloud server set up, use the '--server' option to specify which one to use. Known servers: {:#?}", servers.keys().collect::<Vec<_>>()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let api_client = ApiClient::new(&server_name, &configuration)?;
|
||||||
|
for url in sub_matches
|
||||||
|
.get_many::<String>("url")
|
||||||
|
.expect("At least one url is required")
|
||||||
|
{
|
||||||
|
let response = api_client
|
||||||
|
.client
|
||||||
|
.post(api_client.base_url.join("apps/cookbook/import")?)
|
||||||
|
.json(&serde_json::json!({
|
||||||
|
"url": url,
|
||||||
|
}))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
println!("{:#?}", response); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ApiClient {
|
||||||
|
pub base_url: Url,
|
||||||
|
pub client: reqwest::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiClient {
|
||||||
|
pub fn new(server_name: &str, configuration: &Config) -> anyhow::Result<Self> {
|
||||||
|
let server = configuration
|
||||||
|
.credentials
|
||||||
|
.servers
|
||||||
|
.get(server_name)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"Unknown server {}. Did you use '{} init' first? Known servers: {:#?}",
|
||||||
|
server_name,
|
||||||
|
env!("CARGO_BIN_NAME"),
|
||||||
|
configuration.credentials.servers.keys().collect::<Vec<_>>()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
use reqwest::header;
|
||||||
|
let mut default_headers = header::HeaderMap::new();
|
||||||
|
let mut auth_header = b"Basic ".to_vec();
|
||||||
|
{
|
||||||
|
let mut encoder = Base64Encoder::new(&mut auth_header, base64::STANDARD);
|
||||||
|
write!(encoder, "{}:{}", server.login_name, server.password).unwrap();
|
||||||
|
}
|
||||||
|
let mut auth_header = header::HeaderValue::from_bytes(&auth_header)?;
|
||||||
|
auth_header.set_sensitive(true);
|
||||||
|
default_headers.insert(header::AUTHORIZATION, auth_header);
|
||||||
|
|
||||||
|
let client = reqwest::Client::builder()
|
||||||
|
.user_agent(constants::USER_AGENT)
|
||||||
|
.default_headers(default_headers)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
Ok(ApiClient {
|
||||||
|
base_url: Url::parse(&server.url)?,
|
||||||
|
client: client,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue