539 lines
14 KiB
Go
539 lines
14 KiB
Go
|
|
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 <id>
|
||
|
|
Edit task: htask edit <id>
|
||
|
|
Modify task: htask mod <id> -P 1
|
||
|
|
Delete task: htask delete <id>
|
||
|
|
Mark task as Started: htask start <id>
|
||
|
|
Mark task as Done: htask done <id>
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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 <id>")
|
||
|
|
}
|
||
|
|
|
||
|
|
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")
|
||
|
|
}
|