parent
3c27383bbc
commit
cde6c7fe9f
|
@ -116,6 +116,7 @@ name = "cooking-schedule"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"clap",
|
||||
"directories",
|
||||
"reqwest",
|
||||
|
|
|
@ -19,6 +19,9 @@ version = "0.11"
|
|||
[dependencies.anyhow]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.base64]
|
||||
version = "0.13"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "3.2"
|
||||
features = ["cargo"]
|
||||
|
|
|
@ -17,14 +17,14 @@ pub struct Credentials {
|
|||
#[serde(skip)]
|
||||
config_file: PathBuf,
|
||||
|
||||
servers: HashMap<String, Server>,
|
||||
pub servers: HashMap<String, Server>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Server {
|
||||
url: String,
|
||||
login_name: String,
|
||||
password: String,
|
||||
pub url: String,
|
||||
pub login_name: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl Credentials {
|
||||
|
@ -48,6 +48,7 @@ impl Credentials {
|
|||
|
||||
pub fn add(&mut self, server: Url) -> Result<()> {
|
||||
let http_client = reqwest::blocking::Client::builder()
|
||||
.https_only(true)
|
||||
.user_agent(USER_AGENT)
|
||||
.build()?;
|
||||
|
||||
|
|
82
src/main.rs
82
src/main.rs
|
@ -6,11 +6,16 @@ mod constants;
|
|||
|
||||
use {
|
||||
self::config::Config,
|
||||
anyhow::anyhow,
|
||||
base64::write::EncoderWriter as Base64Encoder,
|
||||
clap::{arg, command, ArgMatches, Command},
|
||||
reqwest::Url,
|
||||
std::io::Write,
|
||||
};
|
||||
|
||||
fn parse_args() -> ArgMatches {
|
||||
let server_arg = arg!(-s --server <server> "NextCloud server to connect to").required(false);
|
||||
|
||||
command!()
|
||||
.propagate_version(true)
|
||||
.subcommand_required(true)
|
||||
|
@ -20,6 +25,12 @@ fn parse_args() -> ArgMatches {
|
|||
.about("Authenticate against the provided NextCloud server")
|
||||
.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()
|
||||
}
|
||||
|
||||
|
@ -41,8 +52,79 @@ async fn main() -> anyhow::Result<()> {
|
|||
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`"),
|
||||
};
|
||||
|
||||
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