package main import ( "flag" "fmt" "database/sql" "log" "os" "os/exec" "io/ioutil" "github.com/fatih/color" _ "github.com/mattn/go-sqlite3" "github.com/rodaine/table" "strconv" "time" ) func check(e error) { if e != nil { panic(e) } } const help = ` (ยท)_(o) HaCkErTaSk Basic help ----------- Create task: htask add -t "My new task". List task: htask list List task filetered: htask list -p blog View task: htask view Edit task: htask edit Modify task: htask mod -P 1 Delete task: htask delete Mark task as Started: htask start Mark task as Done: htask done Check more help in README.md file. ` func main() { // Get HTASK_DB env, if doesnt exists create ~/hackertask.db as database. var filedb string if os.Getenv("HTASK_DB") == "" { var homepath = os.Getenv("HOME") filedb = homepath+"/hackertask.db" } else { filedb = os.Getenv("HTASK_DB") } checkDB(filedb) htaskmain(len(os.Args),filedb) } type Task struct { id *int name *string priority *string project *string comments *string status *string createdate *string startdate *string enddate *string duedate *string tags *string } // Main function. func htaskmain(arguments int,filedb string){ var t Task var existid int sqlDB, _ := sql.Open("sqlite3",filedb) defer sqlDB.Close() if len(os.Args) < 2 { fmt.Println(help) os.Exit(0) } switch os.Args[1] { case "add": addCommand := flag.NewFlagSet("add", flag.ExitOnError) t.priority = addCommand.String("P", "5", "Priority") t.project = addCommand.String("p", "default", "Project") t.name = addCommand.String("t", "", "Task name") t.status = addCommand.String("s", "Open", "Status") t.duedate = addCommand.String("d", "NoDate", "Due Date") addCommand.Parse(os.Args[2:]) if *t.name == "" { fmt.Println("Parameter -t should not be empty") os.Exit(0) } else { addTask(sqlDB,*t.name,*t.status,*t.priority,*t.project,*t.duedate) } case "list": listCommand := flag.NewFlagSet("list", flag.ExitOnError) t.priority = listCommand.String("P", "%", "Priority") t.project = listCommand.String("p", "%", "Project") t.status = listCommand.String("s", "%", "Status") t.duedate = listCommand.String("d", "%", "Due Date") listCommand.Parse(os.Args[2:]) listTask(sqlDB,*t.priority,*t.project,*t.status,*t.duedate) case "mod": if len(os.Args) > 2{ modCommand := flag.NewFlagSet("mod", flag.ExitOnError) t.name = modCommand.String("t", "", "Task name") t.priority = modCommand.String("P", "", "Priority") t.project = modCommand.String("p", "", "Project") t.duedate = modCommand.String("d", "", "Due Date") modCommand.Parse(os.Args[3:]) theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) if existid != 0 { modTask(sqlDB,*t.name,*t.priority,*t.project,*t.duedate,theintid) } else { fmt.Println("ID dont exist.") } } else { fmt.Println("Usage: htask mod ") } case "view": if len(os.Args) > 2{ // Convert param 2 into int. theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) if existid != 0 { viewTask(sqlDB,theintid) } else { fmt.Println("ID dont exist.") } } else { fmt.Println("Usage: htask view ") } case "delete": if len(os.Args) > 2{ // Convert param 2 into int. theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) if existid != 0 { deleteTask(sqlDB,theintid) } else { fmt.Println("ID dont exist.") } } else { fmt.Println("Usage: htask delete ") } case "done": if len(os.Args) > 2{ // Convert param 2 into int. theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) existDONE := checkStatus(sqlDB,theintid) if existid != 0 { if existDONE != "Done" { doneTask(sqlDB,theintid) } else { fmt.Println("This task was marked as Done in the past.") } } else { fmt.Println("ID dont exist") } } else { fmt.Println("Usage: htask done ") } case "start": if len(os.Args) > 2{ // Convert param 2 into int. theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) existDONE := checkStatus(sqlDB,theintid) if existid != 0 { if existDONE != "Working" && existDONE != "Done" { startTask(sqlDB,theintid) } else { fmt.Println("This task was started/finished in the past.") } } else { fmt.Println("ID dont exist") } } else { fmt.Println("Usage: htask start ") } case "edit": if len(os.Args) > 2{ // Convert param 2 into int. theintid, err := strconv.Atoi(os.Args[2]) if err != nil { fmt.Println("Parameter should be the ID.") os.Exit(0) } existid = checkID(sqlDB,theintid) if existid != 0 { editTask(sqlDB,theintid) } else { fmt.Println("ID dont exist.") } } else { fmt.Println("Usage: htask edit ") } default: fmt.Println(help) os.Exit(0) } } // Func to add Task. func addTask(db *sql.DB, name string, status string, priority string, project string, duedate string) { date := time.Now().Local().String() insertSQL := `INSERT INTO htask(name, status, priority, project,createdate,duedate) VALUES (?, ?, ?, ?, ?, ?)` statement, err := db.Prepare(insertSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(name, status, priority, project,date,duedate) if err != nil { log.Fatalln(err.Error()) } color.Green("[+] Task added\n") } // Func to mod ify Task. func modTask(db *sql.DB, name string, priority string, project string, duedate string, id int) { // Mod name if name != "" { modSQL := `UPDATE htask set name = ? where id = ?` statement, err := db.Prepare(modSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(name,id) if err != nil { log.Fatalln(err.Error()) } } // Mod priority if priority != "" { modSQL := `UPDATE htask set priority = ? where id = ?` statement, err := db.Prepare(modSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(priority,id) if err != nil { log.Fatalln(err.Error()) } } // Mod project if project != "" { modSQL := `UPDATE htask set project = ? where id = ?` statement, err := db.Prepare(modSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(project,id) if err != nil { log.Fatalln(err.Error()) } } // Mod duedate if duedate != "" { modSQL := `UPDATE htask set duedate = ? where id = ?` statement, err := db.Prepare(modSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(duedate,id) if err != nil { log.Fatalln(err.Error()) } } //If all ok prints: color.Green("[+] Task modified\n") } // Func to show all Tasks. func listTask(db *sql.DB, priority string, project string, status string, duedate string) { headerFmt := color.New(color.FgMagenta, color.Underline).SprintfFunc() columnFmt := color.New(color.FgGreen).SprintfFunc() tbl := table.New("ID", "Priority", "Project", "Task","Status","DueDate") tbl.WithHeaderFormatter(headerFmt).WithFirstColumnFormatter(columnFmt) row, err := db.Query("SELECT * FROM htask where id like '%' and priority like ? and project like ? and status like ? and duedate like ?",priority,project,status,duedate) if err != nil { log.Fatal(err) } defer row.Close() fmt.Printf("\n") for row.Next() { var id int var name string var priority string var project string var status string var duedate string var comments string var createdate string var startdate string var enddate string var tags string row.Scan(&id, &name, &priority, &project, &status, &duedate, &comments, &createdate, &startdate, &enddate, &tags) tbl.AddRow(id,priority,project,name,status,duedate) } tbl.Print() fmt.Printf("\n") } // Func to view comments. func viewTask(db *sql.DB, id int) { row, err := db.Query("SELECT comments FROM htask where id = ?",id) if err != nil { log.Fatal(err) } defer row.Close() fmt.Printf("\n") for row.Next() { var comments string row.Scan(&comments) fmt.Println(comments) } fmt.Printf("\n") } // Func to delete task. func deleteTask(db *sql.DB, id int) { deleteTaskSQL := `DELETE FROM htask WHERE id = ?` statement, err := db.Prepare(deleteTaskSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(id) if err != nil { log.Fatalln(err.Error()) } color.Green("[+] Task %v deleted successfully.\n",id) } // Func to done task. func doneTask(db *sql.DB, id int) { date := time.Now().Local().String() doneTaskSQL := `UPDATE htask set status = "Done",enddate = ? WHERE id = ?` statement, err := db.Prepare(doneTaskSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(date,id) if err != nil { log.Fatalln(err.Error()) } color.Green("[+] Task %v mark as Done.\n",id) } // Func to start task. func startTask(db *sql.DB, id int) { date := time.Now().Local().String() startTaskSQL := `UPDATE htask set status = "Working",startdate = ? WHERE id = ?` statement, err := db.Prepare(startTaskSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(date,id) if err != nil { log.Fatalln(err.Error()) } color.Green("[+] Task %v mark as Working.\n",id) } // Func to edit task. func editTask(db *sql.DB, id int) { // Obtain current comments. var currentcomments string row, err := db.Query("SELECT comments from htask where id = ?",id) if err != nil { log.Fatal(err) } defer row.Close() for row.Next() { var comments string row.Scan( &comments) currentcomments = comments } // Create temp file with current comments var vi string if os.Getenv("EDITOR") == "" { vi = "nvim" } else { vi = os.Getenv("EDITOR") } tmpDir := os.TempDir() tmpFile, tmpFileErr := ioutil.TempFile(tmpDir, "tempFilePrefix") if tmpFileErr != nil { fmt.Printf("Error %s while creating tempFile", tmpFileErr) } path, err := exec.LookPath(vi) if err != nil { fmt.Printf("Error %s while looking up for %s!!", path, vi) } d1 := []byte(currentcomments) err = os.WriteFile(tmpFile.Name(), d1, 0644) check(err) cmd := exec.Command(path, tmpFile.Name()) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err = cmd.Start() if err != nil { fmt.Printf("Start failed: %s", err) } err = cmd.Wait() dat, err := os.ReadFile(tmpFile.Name()) check(err) color.Green("[+] Note saved successfully.\n") currentdata := string(dat) // Update current comments updateCommentsSQL := `UPDATE htask set comments = ? where id = ?` statement, err := db.Prepare(updateCommentsSQL) if err != nil { log.Fatalln(err.Error()) } _, err = statement.Exec(currentdata,id) if err != nil { log.Fatalln(err.Error()) } // Delete temp file os.Remove(tmpFile.Name()) } // Func to check if ID exists func checkID(db *sql.DB, id int ) int{ var total int row, err := db.Query("SELECT count(*) as total from htask where id = ?",id) if err != nil { log.Fatal(err) } defer row.Close() for row.Next() { var count int row.Scan( &count) total = count } return total } // Func to check if task was marked as Done func checkStatus(db *sql.DB, id int ) string{ var resultado string row, err := db.Query("SELECT status from htask where id = ?",id) if err != nil { log.Fatal(err) } defer row.Close() for row.Next() { var status string row.Scan( &status) resultado = status } return resultado } // Func to check if DB file exists, if not, it creates the file. func checkDB(filedb string) { _, err := os.Stat(filedb) //If file htask.db doesnt exist. if err != nil { color.Green("[+]Creating Database\n") file, err := os.Create(filedb) if err != nil { log.Fatal(err.Error()) } file.Close() sqlDB, _ := sql.Open("sqlite3",filedb) defer sqlDB.Close() createTable(sqlDB) } } // Func to create Database file/schema. func createTable(db *sql.DB) { createHtaskTableSQL := `CREATE TABLE htask ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" TEXT, "priority" TEXT, "project" TEXT, "status" TEXT, "duedate" TEXT, "comments" TEXT, "createdate" TEXT, "startdate" TEXT, "enddate" TEXT, "tags" TEXT );` color.Green("[+]Creating htask table...") statement, err := db.Prepare(createHtaskTableSQL) if err != nil { log.Fatal(err.Error()) } statement.Exec() color.Green("[+]HackerTask DB created") }