Add basic version of the CLI
This commit is contained in:
		
						commit
						cf1736f9e2
					
				| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					# Created by https://www.toptal.com/developers/gitignore/api/rust
 | 
				
			||||||
 | 
					# Edit at https://www.toptal.com/developers/gitignore?templates=rust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Rust ###
 | 
				
			||||||
 | 
					# Generated by Cargo
 | 
				
			||||||
 | 
					# will have compiled files and executables
 | 
				
			||||||
 | 
					debug/
 | 
				
			||||||
 | 
					target/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# These are backup files generated by rustfmt
 | 
				
			||||||
 | 
					**/*.rs.bk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSVC Windows builds of rustc generate these, which store debugging information
 | 
				
			||||||
 | 
					*.pdb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# End of https://www.toptal.com/developers/gitignore/api/rust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.devenv
 | 
				
			||||||
 | 
					.envrc
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "work-timer-cli"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					chrono = { version = "0.4.38", features = ["serde"] }
 | 
				
			||||||
 | 
					clap = "4.5.20"
 | 
				
			||||||
 | 
					http = "1.1.0"
 | 
				
			||||||
 | 
					reqwest = {version="0.12.9", features = ["json"]}
 | 
				
			||||||
 | 
					serde = {version="1.0.214", features = ["derive"]}
 | 
				
			||||||
 | 
					serde_json = "1.0.132"
 | 
				
			||||||
 | 
					tokio = {version="1.41.0", features = ["full"]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[bin]]
 | 
				
			||||||
 | 
					name = "timer"
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					FROM rust:alpine3.19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN apk add --no-cache musl-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADD ./ /app
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					RUN cargo build --release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMD [ "/app/target/release/timer" ]
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "nodes": {
 | 
				
			||||||
 | 
					    "flake-parts": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "nixpkgs-lib": [
 | 
				
			||||||
 | 
					          "nixpkgs"
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1727826117,
 | 
				
			||||||
 | 
					        "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=",
 | 
				
			||||||
 | 
					        "owner": "hercules-ci",
 | 
				
			||||||
 | 
					        "repo": "flake-parts",
 | 
				
			||||||
 | 
					        "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "hercules-ci",
 | 
				
			||||||
 | 
					        "repo": "flake-parts",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "nixpkgs": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1730200266,
 | 
				
			||||||
 | 
					        "narHash": "sha256-l253w0XMT8nWHGXuXqyiIC/bMvh1VRszGXgdpQlfhvU=",
 | 
				
			||||||
 | 
					        "owner": "NixOS",
 | 
				
			||||||
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
 | 
					        "rev": "807e9154dcb16384b1b765ebe9cd2bba2ac287fd",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "NixOS",
 | 
				
			||||||
 | 
					        "ref": "nixos-unstable",
 | 
				
			||||||
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "root": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "flake-parts": "flake-parts",
 | 
				
			||||||
 | 
					        "nixpkgs": "nixpkgs"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "root": "root",
 | 
				
			||||||
 | 
					  "version": 7
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    description = "Generic Rust Flake";
 | 
				
			||||||
 | 
					    inputs = {
 | 
				
			||||||
 | 
					        nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
 | 
				
			||||||
 | 
					        flake-parts = {
 | 
				
			||||||
 | 
					            url = "github:hercules-ci/flake-parts";
 | 
				
			||||||
 | 
					            inputs.nixpkgs-lib.follows = "nixpkgs";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    outputs = inputs @ {flake-parts, ...}:
 | 
				
			||||||
 | 
					        flake-parts.lib.mkFlake {inherit inputs;} {
 | 
				
			||||||
 | 
					            systems = ["x86_64-linux" "aarch64-linux"];
 | 
				
			||||||
 | 
					            perSystem = {
 | 
				
			||||||
 | 
					                pkgs,
 | 
				
			||||||
 | 
					                ...
 | 
				
			||||||
 | 
					            }: let
 | 
				
			||||||
 | 
					            app = pkgs.rustPlatform.buildRustPackage {
 | 
				
			||||||
 | 
					                pname = "work-timer";
 | 
				
			||||||
 | 
					                version = "0.1.0";
 | 
				
			||||||
 | 
					                cargoLock = {
 | 
				
			||||||
 | 
					                    lockFile = ./Cargo.lock;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                src = ./.;
 | 
				
			||||||
 | 
					                buildInputs = [ pkgs.openssl ];
 | 
				
			||||||
 | 
					                nativeBuildInputs = [ pkgs.pkg-config ];
 | 
				
			||||||
 | 
					                PKG_CONFIG_PATH="${pkgs.openssl.dev}/lib/pkgconfig";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            in {
 | 
				
			||||||
 | 
					                packages = {
 | 
				
			||||||
 | 
					                    default = app;
 | 
				
			||||||
 | 
					                    inherit app;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					use clap::{arg, Command};
 | 
				
			||||||
 | 
					use work_timer_cli::commands::{start, stop, edit, status, Settings};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn cli() -> Command {
 | 
				
			||||||
 | 
					    Command::new("timer")
 | 
				
			||||||
 | 
					        .about("A tracker for time spent working")
 | 
				
			||||||
 | 
					        .subcommand_required(true)
 | 
				
			||||||
 | 
					        .arg_required_else_help(true)
 | 
				
			||||||
 | 
					        .allow_external_subcommands(true)
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            arg!(--project <PROJECT> "The project associated with this session")
 | 
				
			||||||
 | 
					            .short('p')
 | 
				
			||||||
 | 
					            .default_value("trackbox")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            arg!(--server <URL> "The base URL of the tracking server")
 | 
				
			||||||
 | 
					            .short('s')
 | 
				
			||||||
 | 
					            .default_value("http://localhost:3000")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            arg!(--json "Use JSON output")
 | 
				
			||||||
 | 
					            .short('j')
 | 
				
			||||||
 | 
					            .default_value("true")
 | 
				
			||||||
 | 
					            .default_missing_value("false")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
 | 
					            Command::new("start")
 | 
				
			||||||
 | 
					                .about("Start tracking a working session")
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
 | 
					                    arg!(<DESCRIPTION> "A description to add for this session")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
 | 
					            Command::new("stop")
 | 
				
			||||||
 | 
					                .about("Finish the working session currently being tracked")
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
 | 
					                    arg!(<ID> "The ID of the session to stop")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
 | 
					            Command::new("edit")
 | 
				
			||||||
 | 
					                .about("Edit a list of sessions")
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
 | 
					                    arg!(-n <NUM> "The maximum number of sessions to edit")
 | 
				
			||||||
 | 
					                    .default_value("10")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
 | 
					                    arg!(--since <TIMESTAMP> "A timestamp to start from. Can be ISO8601 or 'today' or a weekday")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .arg(
 | 
				
			||||||
 | 
					                    arg!(--until <TIMESTAMP> "A timestamp to end at. Can be ISO8601 or 'today' or a weekday")
 | 
				
			||||||
 | 
					                    .required(false)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .subcommand(
 | 
				
			||||||
 | 
					            Command::new("status")
 | 
				
			||||||
 | 
					                .about("Get an overview of recent sessions")
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tokio::main]
 | 
				
			||||||
 | 
					async fn main() {
 | 
				
			||||||
 | 
					    let matches = cli().get_matches();
 | 
				
			||||||
 | 
					    let project = matches.get_one::<String>("project").unwrap();
 | 
				
			||||||
 | 
					    let url = matches.get_one::<String>("server").unwrap();
 | 
				
			||||||
 | 
					    let json = matches.get_one::<bool>("json").unwrap();
 | 
				
			||||||
 | 
					    let settings = Settings { project: project.to_string(), url: url.to_string(), json: *json };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match matches.subcommand() {
 | 
				
			||||||
 | 
					        Some(("start", sub_matches)) => {
 | 
				
			||||||
 | 
					            let description = sub_matches.get_one::<String>("DESCRIPTION");
 | 
				
			||||||
 | 
					            start(settings, description).await.unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Some(("stop", sub_matches)) => {
 | 
				
			||||||
 | 
					            let id = sub_matches.get_one::<i32>("ID");
 | 
				
			||||||
 | 
					            stop(settings, id).await.unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Some(("edit", sub_matches)) => {
 | 
				
			||||||
 | 
					            let since = sub_matches.get_one::<String>("since");
 | 
				
			||||||
 | 
					            let until = sub_matches.get_one::<String>("until");
 | 
				
			||||||
 | 
					            let num = sub_matches.get_one::<String>("NUM");
 | 
				
			||||||
 | 
					            edit(settings, since, until, num).await.unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Some(("status", _)) => {
 | 
				
			||||||
 | 
					            status(settings).await.unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,165 @@
 | 
				
			||||||
 | 
					use std::{collections::HashMap, io::Write};
 | 
				
			||||||
 | 
					use chrono::Datelike;
 | 
				
			||||||
 | 
					use chrono::NaiveDateTime;
 | 
				
			||||||
 | 
					use reqwest::Client;
 | 
				
			||||||
 | 
					use serde_json::json;
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    env::{temp_dir, var},
 | 
				
			||||||
 | 
					    fs::File,
 | 
				
			||||||
 | 
					    io::Read,
 | 
				
			||||||
 | 
					    process::Command,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Settings {
 | 
				
			||||||
 | 
					    pub url: String,
 | 
				
			||||||
 | 
					    pub project: String,
 | 
				
			||||||
 | 
					    pub json: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct WorkPeriod {
 | 
				
			||||||
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    pub project: String,
 | 
				
			||||||
 | 
					    pub start_time: NaiveDateTime,
 | 
				
			||||||
 | 
					    pub end_time: Option<NaiveDateTime>,
 | 
				
			||||||
 | 
					    pub description: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn start(settings: Settings, description: Option<&String>) -> Result<(), reqwest::Error> {
 | 
				
			||||||
 | 
					    let mut map = HashMap::new();
 | 
				
			||||||
 | 
					    map.insert("project", settings.project);
 | 
				
			||||||
 | 
					    if let Some(description) = description {
 | 
				
			||||||
 | 
					        map.insert("description", description.to_string());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let client = Client::new();
 | 
				
			||||||
 | 
					    let response = client.post(settings.url + "/api/tracking")
 | 
				
			||||||
 | 
					        .json(&map)
 | 
				
			||||||
 | 
					        .send()
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !response.status().is_success() {
 | 
				
			||||||
 | 
					        println!("{:?}", response.text().await);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn stop(settings: Settings, id: Option<&i32>) -> Result<(), reqwest::Error> {
 | 
				
			||||||
 | 
					    let mut map = HashMap::new();
 | 
				
			||||||
 | 
					    map.insert("project", settings.project);
 | 
				
			||||||
 | 
					    if let Some(id) = id {
 | 
				
			||||||
 | 
					        map.insert("id", format!("{}", id));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let client = Client::new();
 | 
				
			||||||
 | 
					    let response = client.delete(settings.url + "/api/tracking")
 | 
				
			||||||
 | 
					        .json(&map)
 | 
				
			||||||
 | 
					        .send()
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !response.status().is_success() {
 | 
				
			||||||
 | 
					        println!("{:?}", response.text().await);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_timestamp(timestamp: &str) -> String {
 | 
				
			||||||
 | 
					    let now = chrono::Local::now();
 | 
				
			||||||
 | 
					    let weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
 | 
				
			||||||
 | 
					    if timestamp == "today" {
 | 
				
			||||||
 | 
					        return now.format("%Y-%m-%dT00:00:00").to_string();
 | 
				
			||||||
 | 
					    } else if timestamp == "yesterday" {
 | 
				
			||||||
 | 
					        return (now - chrono::Duration::days(1)).format("%Y-%m-%dT00:00:00").to_string();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        for (i, weekday) in weekdays.iter().enumerate() {
 | 
				
			||||||
 | 
					            if timestamp == *weekday {
 | 
				
			||||||
 | 
					                let days = (now.weekday().num_days_from_monday() as i64 - i as i64) % 7;
 | 
				
			||||||
 | 
					                return (now - chrono::Duration::days(days)).format("%Y-%m-%dT00:00:00").to_string();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return timestamp.to_string();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_periods(body: String) -> Result<Vec<WorkPeriod>, serde_json::Error> {
 | 
				
			||||||
 | 
					    let periods: Vec<WorkPeriod> = serde_json::from_str(&body)?;
 | 
				
			||||||
 | 
					    Ok(periods)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn to_json(periods: Vec<WorkPeriod>) -> Result<String, serde_json::Error> {
 | 
				
			||||||
 | 
					    let json = json!(periods);
 | 
				
			||||||
 | 
					    Ok(serde_json::to_string_pretty(&json)?)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn edit_periods(periods: Vec<WorkPeriod>) -> Result<Vec<WorkPeriod>, std::io::Error> {
 | 
				
			||||||
 | 
					    let content = to_json(periods)?;
 | 
				
			||||||
 | 
					    let editor = var("EDITOR").unwrap_or("vi".to_string());
 | 
				
			||||||
 | 
					    let mut file_path = temp_dir();
 | 
				
			||||||
 | 
					    file_path.push("Periods.json");
 | 
				
			||||||
 | 
					    let mut file = File::create(&file_path).expect("Could not create file");
 | 
				
			||||||
 | 
					    file.write_all(content.as_bytes())?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Command::new(editor)
 | 
				
			||||||
 | 
					        .arg(&file_path)
 | 
				
			||||||
 | 
					        .status()
 | 
				
			||||||
 | 
					        .expect("Something went wrong");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut editable = String::new();
 | 
				
			||||||
 | 
					    File::open(file_path)
 | 
				
			||||||
 | 
					        .expect("Could not open file")
 | 
				
			||||||
 | 
					        .read_to_string(&mut editable)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let periods: Vec<WorkPeriod> = serde_json::from_str(&editable).expect("Could not parse JSON");
 | 
				
			||||||
 | 
					    Ok(periods)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn update_period(settings: &Settings, period: WorkPeriod) -> Result<(), reqwest::Error> {
 | 
				
			||||||
 | 
					    let client = Client::new();
 | 
				
			||||||
 | 
					    let response = client.put(settings.url.to_string() + "/api/history/" + &period.id.to_string())
 | 
				
			||||||
 | 
					        .json(&period)
 | 
				
			||||||
 | 
					        .send()
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !response.status().is_success() {
 | 
				
			||||||
 | 
					        println!("{:?}", response.text().await);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn edit(settings: Settings, since: Option<&String>, until: Option<&String>, num: Option<&String>) -> Result<(), reqwest::Error> {
 | 
				
			||||||
 | 
					    let mut params = vec![
 | 
				
			||||||
 | 
					        ("project", settings.project.to_owned()),
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    if let Some(since) = since {
 | 
				
			||||||
 | 
					        params.push(("since", parse_timestamp(since)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if let Some(until) = until {
 | 
				
			||||||
 | 
					        params.push(("until", parse_timestamp(until)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if let Some(num) = num {
 | 
				
			||||||
 | 
					        params.push(("count", num.to_string()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let client = Client::new();
 | 
				
			||||||
 | 
					    let url = reqwest::Url::parse_with_params((settings.url.to_owned() + "/api/history").as_str(), ¶ms).unwrap();
 | 
				
			||||||
 | 
					    let response = client.get(url)
 | 
				
			||||||
 | 
					        .send()
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if !response.status().is_success() {
 | 
				
			||||||
 | 
					        println!("{:?}", response.text().await);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        let body = response.text().await.unwrap();
 | 
				
			||||||
 | 
					        let periods = parse_periods(body).unwrap();
 | 
				
			||||||
 | 
					        let res = edit_periods(periods).unwrap();
 | 
				
			||||||
 | 
					        for period in res {
 | 
				
			||||||
 | 
					            update_period(&settings, period).await.unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub async fn status(settings: Settings) -> Result<(), reqwest::Error> {
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					pub mod commands;
 | 
				
			||||||
		Loading…
	
		Reference in New Issue