Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/export #8

Merged
merged 21 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
/target
*.db
*.db
*.html
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jourst"
version = "0.4.0"
version = "0.7.0"
edition = "2021"
authors = ["Yalın Pala <yalinpala@proton.me>"]
description = "Simple command line todo tool"
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ This project has been developed to better understand the Rust programming langua

This is a simple command line-based to do management application. With this application, you can record tasks, view the task list, mark tasks as completed, and perform deletion operations.

## Features
- Add
- List
- Mark task as completed
- Remove
- Sync
- Export

## Basic Usage

[![asciicast](https://asciinema.org/a/3105sxzOoBnl9uIj5svYjeaG8.svg)](https://asciinema.org/a/3105sxzOoBnl9uIj5svYjeaG8)
Expand Down
16 changes: 16 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum Action {
List,
Done,
Sync,
Export,
}

#[derive(ValueEnum, Clone, PartialEq, Debug)]
Expand All @@ -31,6 +32,12 @@ pub enum ListCommandType {
Undone,
}

#[derive(ValueEnum, Clone, PartialEq, Debug)]
pub enum ExportCommandType {
Markdown,
Html,
}

#[derive(Parser, Debug)]
#[clap(author, about = "Simple command line task manager", version)]
pub struct Cli {
Expand All @@ -52,6 +59,9 @@ pub enum ActionType {
/// Mark a todo as done.
Done(DoneCommand),

/// Export todos
Export(ExportCommand),

/// Carries the to do that were not done on time to today.
Sync,
}
Expand Down Expand Up @@ -85,6 +95,12 @@ pub struct ListCommand {
pub date: ListCommandDate,
}

#[derive(Debug, Args)]
pub struct ExportCommand {
#[clap(short = 't', long = "type", default_value = "html")]
pub export_type: ExportCommandType,
}

#[derive(Debug, Args)]
pub struct DoneCommand {
/// The id of the todo.
Expand Down
82 changes: 79 additions & 3 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use chrono::{DateTime, Local};
use chrono::{DateTime, Local, NaiveDate};
use colored::Colorize;
use std::io::{self, Write};
use std::{
collections::HashMap,
io::{self, Write},
};

use crate::{
args::{AddCommandDate, ListCommandDate, ListCommandType},
models::Todo,
models::{self, Todo},
};

pub fn get_date(date: &AddCommandDate) -> DateTime<Local> {
Expand Down Expand Up @@ -66,6 +69,48 @@ pub fn print_result<T, E>(result: Result<T, E>) -> Result<(), io::Error> {
}
}

pub fn generate_html(groups: HashMap<NaiveDate, Vec<models::Todo>>) -> String {
let header: &str = r#"<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
"#;

let footer: &str = r#"
</body>
</html>
"#;

let mut content = header.to_owned();

for (date, todos) in groups.iter() {
let h1 = format!(r#"<h1>{}</h1>"#, date);

content.push_str(&h1);

for todo in todos {
let check = if todo.completed { "checked" } else { "" };

let checkbox = format!(
r#"
<input type="checkbox" id="{}" {}">
<label for="{}">{}</label><br>
"#,
todo.id, check, todo.id, todo.content
);

content.push_str(&checkbox);
}
}

content.push_str(footer);

content
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -159,4 +204,35 @@ mod tests {
let result = Ok::<(), ()>(());
assert_eq!(print_result(result).is_ok(), true);
}

#[test]
fn test_generate_html() {
use chrono::NaiveDate;
use models::Todo;
use std::collections::HashMap;

// Create some sample data
let mut groups: HashMap<NaiveDate, Vec<Todo>> = HashMap::new();
let todos = vec![
Todo {
id: 1,
content: "Buy groceries".to_owned(),
completed: false,
when_will_it_be_done: Local::now().naive_local().into(),
},
Todo {
id: 2,
content: "Clean the house".to_owned(),
completed: true,
when_will_it_be_done: Local::now().naive_local().into(),
},
];
groups.insert(NaiveDate::from_ymd_opt(2023, 7, 1).unwrap(), todos);

// Call the generate_html function
let html = generate_html(groups);
let slice = &html[0..15];

assert_eq!(slice, "<!DOCTYPE html>");
}
}
34 changes: 34 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use std::{
collections::HashMap,
fs,
io::{self, Write},
};

use args::Cli;
use chrono::NaiveDate;
use clap::Parser;
use colored::Colorize;
use repositories::todo_repository::TodoRepository;

use crate::{args::ActionType, models::todo::NewTodo};
Expand Down Expand Up @@ -60,5 +67,32 @@ fn main() {

let _ = helpers::print_result(result);
}
ActionType::Export(export_command) => {
let _command = export_command;
let mut groups: HashMap<NaiveDate, Vec<models::Todo>> = HashMap::new();

let filter = models::todo::FilterTodo {
completed: None,
when_will_it_be_done: None,
};

let todos = TodoRepository::find_all(&mut connection, filter);

match todos {
Err(e) => println!("{:?}", e),
Ok(result) => {
result.into_iter().for_each(|todo| {
let group = groups.entry(todo.when_will_it_be_done).or_insert(vec![]);
group.push(todo);
});
}
}

let content = helpers::generate_html(groups);

fs::write("index.html", content).expect("Unable to write file!");

let _ = writeln!(io::stdout(), "{}", "Ok!".green());
}
}
}
16 changes: 15 additions & 1 deletion tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,18 @@ fn test_sync() -> Result<(), Box<dyn std::error::Error>> {
.stdout(predicate::str::contains("Ok!"));

Ok(())
}
}

#[test]
#[ignore]
fn test_export() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin("jourst")?;

cmd.arg("export");

cmd.assert()
.success()
.stdout(predicate::str::contains("Ok!"));

Ok(())
}