summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Eilertsen <haraldei@anduin.net>2024-04-24 11:27:42 +0200
committerHarald Eilertsen <haraldei@anduin.net>2024-04-24 11:27:42 +0200
commita4dbf815cc418514a268ca54464c2d1b9c413055 (patch)
tree81d6a5944a00839f37c7d9ea469274f8d8425338
parent1c3e4dba9fe90faa318933a99eecdb9cd5e7481a (diff)
downloadfaktura-a4dbf815cc418514a268ca54464c2d1b9c413055.tar.gz
faktura-a4dbf815cc418514a268ca54464c2d1b9c413055.tar.bz2
faktura-a4dbf815cc418514a268ca54464c2d1b9c413055.zip
cli: Add feature to save clients to the db.
Also introduces a Connection object to handle the actual connection to the remote API. We also load the remote API url and jwt token from the process environment so these are no longer hardcoded into the source code.
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/src/api.rs2
-rw-r--r--cli/src/api/client.rs23
-rw-r--r--cli/src/api/connection.rs36
-rw-r--r--cli/src/main.rs35
5 files changed, 88 insertions, 9 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index be0f14d..f84695f 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -12,4 +12,5 @@ edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
ureq = { version = "2.9.6", features = ["json", "native-certs"] }
diff --git a/cli/src/api.rs b/cli/src/api.rs
index 594530a..da7eb5b 100644
--- a/cli/src/api.rs
+++ b/cli/src/api.rs
@@ -4,5 +4,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pub mod client;
+pub mod connection;
pub use client::Client;
+pub use connection::Connection;
diff --git a/cli/src/api/client.rs b/cli/src/api/client.rs
index eee59b0..9c46db3 100644
--- a/cli/src/api/client.rs
+++ b/cli/src/api/client.rs
@@ -3,25 +3,34 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
use std::error::Error;
+use super::Connection;
-#[derive(Debug, Deserialize)]
+#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Client {
+ #[serde(default)]
pub id: u32,
+
pub name: String,
pub contact: Option<String>,
pub address: Option<String>,
pub email: String,
pub phone: Option<String>,
+
+ #[serde(default)]
pub vat: bool,
}
impl Client {
- pub fn all() -> Result<Vec<Self>, Box<dyn Error>> {
- Ok(ureq::get("http://faktura.ddev.site/api/clients")
- .set("Accept", "application/json")
- .call()?
- .into_json()?)
+ pub fn all(conn: Connection) -> Result<Vec<Self>, Box<dyn Error>> {
+ Ok(conn.get("clients")?)
+ }
+
+ pub fn save(&self, conn: Connection) -> Result<(), Box<dyn Error>> {
+ let resp = conn.post("clients", &self)?;
+
+ println!("{}", resp);
+ Ok(())
}
}
diff --git a/cli/src/api/connection.rs b/cli/src/api/connection.rs
new file mode 100644
index 0000000..f1d7f1c
--- /dev/null
+++ b/cli/src/api/connection.rs
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: 2024 Eilertsens Kodeknekkeri
+// SPDX-FileCopyrightText: 2024 Harald Eilertsen
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+use serde::{Deserialize, Serialize};
+use std::error::Error;
+
+pub struct Connection {
+ pub url: String,
+ pub jwt_token: String,
+}
+
+impl Connection {
+ pub fn new<T: Into<String>>(url: T, jwt_token: T) -> Connection {
+ Connection {
+ url: url.into(),
+ jwt_token: jwt_token.into(),
+ }
+ }
+
+ pub fn get<T: for <'de> Deserialize<'de>>(&self, resource: &str) -> Result<T, Box<dyn Error>> {
+ Ok(ureq::get(&format!("{}/{}", self.url, resource))
+ .set("Accept", "application/json")
+ .call()?
+ .into_json()?)
+ }
+
+ pub fn post<T: Serialize>(&self, resource: &str, data: &T) -> Result<String, Box<dyn Error>> {
+ Ok(ureq::post(&format!("{}/{}", self.url, resource))
+ .set("Authorization", &format!("Bearer {}", self.jwt_token))
+ .set("Content-Type", "application/json")
+ .send_json(&data)?
+ .into_string()?)
+ }
+}
diff --git a/cli/src/main.rs b/cli/src/main.rs
index 4c34e18..ee10d17 100644
--- a/cli/src/main.rs
+++ b/cli/src/main.rs
@@ -7,11 +7,36 @@
mod api;
-use api::Client;
+use api::{Client, Connection};
fn main() -> Result<(), Box<dyn std::error::Error>> {
- let clients = Client::all()?;
+ let conn = Connection::new(
+ std::env::var("FAKTURA_API_URL")?,
+ std::env::var("FAKTURA_JWT_TOKEN")?
+ );
+
+ let mut args = std::env::args().skip(1);
+ if let Some(cmd) = args.next() {
+ match cmd.as_str() {
+ "--list-clients" => {
+ list_clients(conn)?;
+ },
+ "--add-client" => {
+ add_client(conn, &args.next()
+ .expect("expected new client json data"))?;
+ },
+ &_ => {
+ println!("Unknown command: {}", cmd);
+ }
+ }
+ }
+
+ Ok(())
+}
+
+fn list_clients(conn: Connection) -> Result<(), Box<dyn std::error::Error>> {
+ let clients = Client::all(conn)?;
for c in clients {
print!("{}: {} <{}>", c.id, c.name, c.email);
@@ -32,3 +57,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
+
+fn add_client(conn: Connection, json: &str) -> Result<(), Box<dyn std::error::Error>> {
+ let client: Client = serde_json::from_str(json)?;
+ println!("{:?}", client);
+ client.save(conn)
+}