Refactored import/export

This commit is contained in:
マリウス 2020-10-17 15:50:21 +01:00
parent df06d63fa8
commit 631343388d
No known key found for this signature in database
GPG key ID: C228EF0A530AF06F
6 changed files with 54 additions and 28 deletions

View file

@ -151,7 +151,7 @@ zeit erase 14037730-5c2d-44ff-b70e-81f1dcd4eb5f
``` ```
### Display statistics ### Statistics
![zeit stats](documentation/zeit_stats.png) ![zeit stats](documentation/zeit_stats.png)
@ -159,6 +159,7 @@ zeit erase 14037730-5c2d-44ff-b70e-81f1dcd4eb5f
zeit stats zeit stats
``` ```
### Import tracked activities ### Import tracked activities
```sh ```sh
@ -167,7 +168,7 @@ zeit import --help
The following formats are supported as of right now: The following formats are supported as of right now:
#### Tyme 3 JSON #### `tyme`: Tyme 3 JSON
It is possible to import JSON exports from [Tyme 3](https://www.tyme-app.com). It is possible to import JSON exports from [Tyme 3](https://www.tyme-app.com).
It is important that the JSON is exported with the following options set/unset: It is important that the JSON is exported with the following options set/unset:
@ -192,9 +193,10 @@ then import them again into *zeit*.
Import a Tyme 3 JSON export: Import a Tyme 3 JSON export:
```sh ```sh
zeit import --tyme ./tyme.export.json zeit import --format tyme ./tyme.export.json
``` ```
### Export tracked activities ### Export tracked activities
```sh ```sh
@ -203,7 +205,12 @@ zeit export --help
The following formats are supported as of right now: The following formats are supported as of right now:
#### Tyme 3 JSON #### `zeit`: *zeit* JSON
The *zeit* internal JSON format. Basically a dump of the database including
only tracked activities.
#### `tyme`: Tyme 3 JSON
It is possible to export JSON compatible to the Tyme 3 JSON format. Fields that It is possible to export JSON compatible to the Tyme 3 JSON format. Fields that
are not available in *zeit* will be filled with dummy values, e.g. are not available in *zeit* will be filled with dummy values, e.g.
@ -214,5 +221,5 @@ are not available in *zeit* will be filled with dummy values, e.g.
Export a Tyme 3 JSON: Export a Tyme 3 JSON:
```sh ```sh
zeit export --tyme --project "my project" --since "2020-04-01T15:04:05+07:00" --until "2020-04-04T15:04:05+07:00" zeit export --format tyme --project "my project" --since "2020-04-01T15:04:05+07:00" --until "2020-04-04T15:04:05+07:00"
``` ```

View file

@ -154,10 +154,10 @@ func (entry *Entry) GetOutput() (string) {
return fmt.Sprintf("%s %s on %s from %s to %s (%sh)", color.FgGray.Render(entry.ID), color.FgLightWhite.Render(entry.Task), color.FgLightWhite.Render(entry.Project), color.FgLightWhite.Render(entry.Begin.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(entry.Finish.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(trackDiffOut.Format("15:04"))) return fmt.Sprintf("%s %s on %s from %s to %s (%sh)", color.FgGray.Render(entry.ID), color.FgLightWhite.Render(entry.Task), color.FgLightWhite.Render(entry.Project), color.FgLightWhite.Render(entry.Begin.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(entry.Finish.Format("2006-01-02 15:04 -0700")), color.FgLightWhite.Render(trackDiffOut.Format("15:04")))
} }
func GetFilteredEntries(entries *[]Entry, project string, task string, since time.Time, until time.Time) ([]*Entry, error) { func GetFilteredEntries(entries []Entry, project string, task string, since time.Time, until time.Time) ([]Entry, error) {
var filteredEntries []*Entry var filteredEntries []Entry
for _, entry := range *entries { for _, entry := range entries {
if project != "" && GetIdFromName(entry.Project) != GetIdFromName(project) { if project != "" && GetIdFromName(entry.Project) != GetIdFromName(project) {
continue continue
} }
@ -174,7 +174,7 @@ func GetFilteredEntries(entries *[]Entry, project string, task string, since tim
continue continue
} }
filteredEntries = append(filteredEntries, &entry) filteredEntries = append(filteredEntries, entry)
} }
return filteredEntries, nil return filteredEntries, nil

View file

@ -4,21 +4,30 @@ import (
"os" "os"
"fmt" "fmt"
"time" "time"
"encoding/json"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var exportSince string var exportSince string
var exportUntil string var exportUntil string
func exportTymeJson(user string, entries []*Entry) (string, error) { func exportZeitJson(user string, entries []Entry) (string, error) {
stringified, err := json.Marshal(entries)
if err != nil {
return "", err
}
tyme := Tyme{} return string(stringified), nil
err := tyme.FromEntries(entries) }
if err != nil {
return "", err
}
return tyme.Stringify(), nil func exportTymeJson(user string, entries []Entry) (string, error) {
tyme := Tyme{}
err := tyme.FromEntries(entries)
if err != nil {
return "", err
}
return tyme.Stringify(), nil
} }
var exportCmd = &cobra.Command{ var exportCmd = &cobra.Command{
@ -57,34 +66,40 @@ var exportCmd = &cobra.Command{
} }
} }
var filteredEntries []*Entry var filteredEntries []Entry
filteredEntries, err = GetFilteredEntries(&entries, project, task, since, until) filteredEntries, err = GetFilteredEntries(entries, project, task, since, until)
if err != nil { if err != nil {
fmt.Printf("%s %+v\n", CharError, err) fmt.Printf("%s %+v\n", CharError, err)
os.Exit(1) os.Exit(1)
} }
var output string = "" var output string = ""
if formatTymeJson == true { switch(format) {
case "zeit":
output, err = exportZeitJson(user, filteredEntries)
if err != nil {
fmt.Printf("%s %+v\n", CharError, err)
os.Exit(1)
}
case "tyme":
output, err = exportTymeJson(user, filteredEntries) output, err = exportTymeJson(user, filteredEntries)
if err != nil { if err != nil {
fmt.Printf("%s %+v\n", CharError, err) fmt.Printf("%s %+v\n", CharError, err)
os.Exit(1) os.Exit(1)
} }
} else { default:
fmt.Printf("%s specify an export format; see `zeit export --help` for more info\n", CharError) fmt.Printf("%s specify an export format; see `zeit export --help` for more info\n", CharError)
os.Exit(1) os.Exit(1)
} }
fmt.Printf("%s\n", output) fmt.Printf("%s\n", output)
return return
}, },
} }
func init() { func init() {
rootCmd.AddCommand(exportCmd) rootCmd.AddCommand(exportCmd)
exportCmd.Flags().BoolVar(&formatTymeJson, "tyme", false, "Export to Tyme 3 JSON") exportCmd.Flags().StringVar(&format, "format", "", "Format to export, possible values: zeit, tyme")
exportCmd.Flags().StringVar(&exportSince, "since", "", "Date/time to start the export from") exportCmd.Flags().StringVar(&exportSince, "since", "", "Date/time to start the export from")
exportCmd.Flags().StringVar(&exportUntil, "until", "", "Date/time to export until") exportCmd.Flags().StringVar(&exportUntil, "until", "", "Date/time to export until")
exportCmd.Flags().StringVarP(&project, "project", "p", "", "Project to be exported") exportCmd.Flags().StringVarP(&project, "project", "p", "", "Project to be exported")

View file

@ -59,13 +59,18 @@ var importCmd = &cobra.Command{
user := GetCurrentUser() user := GetCurrentUser()
if formatTymeJson == true { switch(format) {
case "zeit":
// TODO:
fmt.Printf("%s not yet implemented\n", CharError)
os.Exit(1)
case "tyme":
entries, err = importTymeJson(user, args[0]) entries, err = importTymeJson(user, args[0])
if err != nil { if err != nil {
fmt.Printf("%s %+v\n", CharError, err) fmt.Printf("%s %+v\n", CharError, err)
os.Exit(1) os.Exit(1)
} }
} else { default:
fmt.Printf("%s specify an import format; see `zeit import --help` for more info\n", CharError) fmt.Printf("%s specify an import format; see `zeit import --help` for more info\n", CharError)
os.Exit(1) os.Exit(1)
} }
@ -104,7 +109,7 @@ var importCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(importCmd) rootCmd.AddCommand(importCmd)
importCmd.Flags().BoolVar(&formatTymeJson, "tyme", false, "Import from Tyme 3 JSON export") importCmd.Flags().StringVar(&format, "format", "", "Format to import, possible values: zeit, tyme")
var err error var err error
database, err = InitDatabase() database, err = InitDatabase()

View file

@ -14,6 +14,7 @@ var project string
var task string var task string
var notes string var notes string
var format string
var force bool var force bool
const( const(

View file

@ -8,8 +8,6 @@ import (
"time" "time"
) )
var formatTymeJson bool
type TymeEntry struct { type TymeEntry struct {
Billing string `json:"billing"` // "UNBILLED", Billing string `json:"billing"` // "UNBILLED",
Category string `json:"category"` // "Client", Category string `json:"category"` // "Client",
@ -50,7 +48,7 @@ func (tyme *Tyme) Load(filename string) error {
return nil return nil
} }
func (tyme *Tyme) FromEntries(entries []*Entry) error { func (tyme *Tyme) FromEntries(entries []Entry) error {
for _, entry := range entries { for _, entry := range entries {
duration := decimal.NewFromFloat(entry.Finish.Sub(entry.Begin).Minutes()) duration := decimal.NewFromFloat(entry.Finish.Sub(entry.Begin).Minutes())