Skip to content

Commit

Permalink
Merge branch 'release/v0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
sascha-andres committed Nov 18, 2017
2 parents 0719f9c + 6c364f5 commit b06952e
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.1.0
v0.2.0
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,11 @@ This is in an early phase but used regularly with the toggl backend and from tim

### Dependencies with dep

https://github.com/golang/dep
https://github.com/golang/dep

## History

|Version|Description|
|---|---|
|0.1.0|Initial version|
|0.2.0|Add support for projects|
95 changes: 90 additions & 5 deletions persistence/mysqldriver/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,17 @@ func NewMysql(dsn string) (persistence.Persistor, error) {
}
db.SetMaxIdleConns(0)
db.SetConnMaxLifetime(500)
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS project (
id INT AUTO_INCREMENT NOT NULL,
name NVARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY ( id )
);`)
if err != nil {
return nil, errors.Wrap(err, "Error creating table - project")
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS timenote (
id INT AUTO_INCREMENT NOT NULL,
id_project INT NOT NULL DEFAULT 0,
tag NVARCHAR(100) NOT NULL DEFAULT '',
start TIMESTAMP NOT NULL DEFAULT NOW(),
stop TIMESTAMP,
Expand All @@ -35,7 +44,6 @@ func NewMysql(dsn string) (persistence.Persistor, error) {
if err != nil {
return nil, errors.Wrap(err, "Error creating table - timenote")
}
db.SetConnMaxLifetime(500)
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS line (
id INT AUTO_INCREMENT NOT NULL,
id_timenote INT NOT NULL,
Expand Down Expand Up @@ -138,20 +146,23 @@ func (mysql *MySQLPersistor) Close() error {
// SELECT *, UNIX_TIMESTAMP(`stop`)-UNIX_TIMESTAMP(`start`) FROM `timenotes` WHERE `stop` <> '0000-00-00 00:00:00'
// unix_timestamp(maketime(_,_,_)

func (mysql *MySQLPersistor) ListForDay(delta int) ([]timenote.TimeEntry, error) {
/* func (mysql *MySQLPersistor) ListForDay(delta int) ([]timenote.TimeEntry, error) {
if err := mysql.prepareDb(); err != nil {
return nil, errors.Wrap(err, "Connection to DB not valid")
}
return nil, errors.New("Not yet implemented")
}
}*/

func (mysql *MySQLPersistor) Current() (*timenote.TimeEntry, error) {
if err := mysql.prepareDb(); err != nil {
return nil, errors.Wrap(err, "Connection to DB not valid")
}
row := mysql.databaseConnection.QueryRow("select tag, `text` from timenote where stop = '0000-00-00 00:00:00'")
row := mysql.databaseConnection.QueryRow("select id, tag, `text` from timenote where stop = '0000-00-00 00:00:00'")
var te timenote.TimeEntry
if err := row.Scan(&te.Tag, &te.Note); err != nil {
if err := row.Scan(&te.ID, &te.Tag, &te.Note); err != nil {
if err == sql.ErrNoRows {
return nil, timenote.ErrNoCurrentTimeEntry
}
return nil, errors.Wrap(err, "Could not load record")
}
return &te, nil
Expand All @@ -167,3 +178,77 @@ func (mysql *MySQLPersistor) prepareDb() error {
}
return nil
}

func (mysql *MySQLPersistor) Project(name string) error {
if err := mysql.prepareDb(); err != nil {
return errors.Wrap(err, "Connection to DB not valid")
}

var (
projectID int
err error
)

if name == "" {
projectID = 0
} else {
projectID, err = mysql.getProjectID(name)
if err != nil {
return errors.Wrap(err, "Unable to select project")
}
if projectID == 0 {
projectID, err = mysql.createProject(name)
if err != nil || projectID == 0 {
return errors.Wrap(err, "Unable to select project")
}
}
}

tx, err := mysql.databaseConnection.BeginTx(context.Background(), nil)
if err != nil {
return errors.Wrap(err, "Could not start transaction")
}
if _, err = tx.Exec("update timenote set `id_project`=? where `stop` = '0000-00-00 00:00:00'", projectID); err != nil {
tx.Rollback()
return errors.Wrap(err, "Could not set project")
}
return tx.Commit()
}

func (mysql *MySQLPersistor) createProject(name string) (int, error) {
if err := mysql.prepareDb(); err != nil {
return 0, errors.Wrap(err, "Connection to DB not valid")
}

tx, err := mysql.databaseConnection.BeginTx(context.Background(), nil)
if err != nil {
return 0, errors.Wrap(err, "Could not start transaction")
}
_, err = tx.Exec("insert into project (name) values (?)", name)
if err != nil {
tx.Rollback()
return 0, errors.Wrap(err, "Could not insert project")
}
if err := tx.Commit(); err != nil {
return 0, err
}

return mysql.getProjectID(name)
}

func (mysql *MySQLPersistor) getProjectID(name string) (int, error) {
if err := mysql.prepareDb(); err != nil {
return 0, errors.Wrap(err, "Connection to DB not valid")
}
row := mysql.databaseConnection.QueryRow("select id from project where name = ?", name)
var id int
if err := row.Scan(&id); err != nil {
if err == sql.ErrNoRows {
return 0, nil
}
if err != nil {
return 0, errors.Wrap(err, "Could not load record")
}
}
return id, nil
}
4 changes: 3 additions & 1 deletion persistence/storage_persistor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ type Persistor interface {
Append(line string) error
// Tag sets a tag for the note
Tag(name string) error
// Project adds time entry to a project
Project(name string) error
// Done writes the stop timestamp
Done() error
// Close the connection to the persistence backend
Close() error
// List of entries for the current day - delta
ListForDay(delta int) ([]timenote.TimeEntry, error)
// ListForDay(delta int) ([]timenote.TimeEntry, error)
// Get currently running time entry
Current() (*timenote.TimeEntry, error)
}
60 changes: 58 additions & 2 deletions persistence/toggldriver/toggl.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ func (t *TogglPersistor) Close() error {
return nil
}

func (t *TogglPersistor) ListForDay(delta int) ([]timenote.TimeEntry, error) {
/*func (t *TogglPersistor) ListForDay(delta int) ([]timenote.TimeEntry, error) {
return nil, errors.New("Not yet implemented")
}
}*/

func (t *TogglPersistor) Current() (*timenote.TimeEntry, error) {
account, err := t.session.GetAccount()
Expand All @@ -110,6 +110,7 @@ func (t *TogglPersistor) Current() (*timenote.TimeEntry, error) {
}
var res timenote.TimeEntry
res.Note = te.Description
res.ID = te.ID
return nil, nil
}

Expand All @@ -121,3 +122,58 @@ func getCurrentTimeEntry(account toggl.Account) (*toggl.TimeEntry, error) {
}
return nil, fmt.Errorf("No current time entry")
}

func (t *TogglPersistor) Project(name string) error {
var (
account toggl.Account
projectID int
err error
)

account, err = t.session.GetAccount()
if err != nil {
return errors.Wrap(err, "Unable to get account")
}
if name == "" {
projectID = 0
} else {
projectID, err = t.getProjectID(name)
if projectID == 0 {
projectID, err = t.createProject(account, name)
if err != nil {
return errors.Wrap(err, "Unable to create project")
}
}
}

te, err := getCurrentTimeEntry(account)
if err != nil {
return errors.Wrap(err, "Unable to get running time entry from toggl")
}
te.Pid = projectID
_, err = t.session.UpdateTimeEntry(*te)
return err
}

func (t *TogglPersistor) createProject(account toggl.Account, name string) (int, error) {
res, err := t.session.CreateProject(name, account.Data.Workspaces[0].ID)
if err != nil {
return 0, err
}
return res.ID, nil
}

func (t *TogglPersistor) getProjectID(name string) (int, error) {
account, err := t.session.GetAccount()
if err != nil {
return 0, errors.Wrap(err, "Unable to get account")
}

for _, prj := range account.Data.Projects {
if prj.Name == name {
return prj.ID, nil
}
}

return 0, nil
}
7 changes: 7 additions & 0 deletions timeentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package timenote
import (
"fmt"
"time"

"github.com/pkg/errors"
)

// ErrNoCurrentTimeEntry should be returned in case no running timeentry is found
var ErrNoCurrentTimeEntry = errors.New("timenote: no current timeentry")

type (
// TimeEntry represents a simple note
TimeEntry struct {
// ID is a systerm id which may be set from a persistor
ID int
// Tag is used for grouping
Tag string
// Some text attached to entry
Expand Down
3 changes: 3 additions & 0 deletions timenote/cmd/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ func executeLine(persistence persistence.Persistor, commandline string) error {
case "append":
return persistence.Append(strings.Join(tokenize[1:], " "))
break
case "project":
return persistence.Project(strings.Join(tokenize[1:], " "))
break
case "tag":
return persistence.Tag(strings.Join(tokenize[1:], " "))
break
Expand Down

0 comments on commit b06952e

Please sign in to comment.