Skip to content

Commit 8280b67

Browse files
authored
Merge pull request #9 from foobaragency/5-change-command-to-moco-track-to-create-and-track
5 change command to moco track to create and track
2 parents a92397f + 90e6fb0 commit 8280b67

6 files changed

Lines changed: 193 additions & 52 deletions

File tree

cmd/activities.go

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,43 @@ package cmd
33
import (
44
"fmt"
55
"moco/data"
6+
"os"
67
"strconv"
78

89
"github.com/charmbracelet/huh"
10+
"github.com/joho/godotenv"
911
"github.com/spf13/cobra"
1012
)
1113

12-
var newCmd = &cobra.Command{
13-
Use: "new",
14+
var createCmd = &cobra.Command{
15+
Use: "create",
1416
Short: "Create a new activity",
1517
Run: func(cmd *cobra.Command, args []string) {
16-
projectId, _ := cmd.Flags().GetInt("project")
17-
taskId, _ := cmd.Flags().GetInt("task")
18+
projects, err := data.GetProjects()
19+
if err != nil {
20+
fmt.Println("Could not retrieve projects", err)
21+
return
22+
}
23+
24+
// flags has highest priority
25+
projectId, err := cmd.Flags().GetInt("project")
26+
taskId, err := cmd.Flags().GetInt("task")
27+
minutes, err := cmd.Flags().GetInt("minutes")
1828
description, err := cmd.Flags().GetString("description")
1929

20-
projects, err := data.GetProjects()
21-
if err != nil {
22-
fmt.Println("Could not retrieve projects", err)
23-
}
24-
30+
// env has second priority
31+
err = godotenv.Load(".moco")
32+
if projectId == 0 && err == nil {
33+
projectId, err = strconv.Atoi(os.Getenv("MOCO_PROJECT_ID"))
34+
fmt.Println("read projectId", projectId)
35+
}
36+
if taskId == 0 && err == nil {
37+
taskId, err = strconv.Atoi(os.Getenv("MOCO_TASK_ID"))
38+
fmt.Println("read taskId", taskId)
39+
}
40+
41+
// if no flags or config, prompt
2542
if projectId == 0 {
26-
2743
options := make([]huh.Option[int], len(projects))
2844
for i, p := range projects {
2945
options[i] = huh.NewOption[int](p.Name, p.Id)
@@ -55,11 +71,26 @@ var newCmd = &cobra.Command{
5571
}
5672
}
5773

58-
if description == "" {
59-
huh.NewInput().Title("Description:").Prompt(">").Value(&description).Run()
60-
}
61-
62-
err = data.CreateActivity(projectId, taskId, description)
74+
if description == "" {
75+
huh.NewInput().Title("Description:").Prompt("> ").Value(&description).Run()
76+
}
77+
78+
if minutes == 0 {
79+
var minutesStr string
80+
huh.NewInput().Title("Time (minutes, entering '0' or empty will start a timer):").Prompt("> ").Value(&minutesStr).Run()
81+
if minutesStr == "" {
82+
minutes = 0
83+
} else {
84+
minutes, err = strconv.Atoi(minutesStr)
85+
if err != nil {
86+
fmt.Println("Invalid minutes")
87+
return
88+
}
89+
}
90+
}
91+
92+
93+
err = data.CreateActivity(projectId, taskId, description, minutes)
6394
if err != nil {
6495
fmt.Println("Could not create activity:", err)
6596
}
@@ -79,13 +110,13 @@ var editCmd = &cobra.Command{
79110
fmt.Println("Invalid activity id")
80111
return
81112
}
82-
seconds, err := cmd.Flags().GetInt("time")
113+
minutes, err := cmd.Flags().GetInt("time")
83114
description, err := cmd.Flags().GetString("description")
84-
if err != nil || (seconds == 0 && description == "") {
115+
if err != nil || (minutes == 0 && description == "") {
85116
cmd.Help()
86117
return
87118
}
88-
err = data.EditActivity(activityId, seconds, description)
119+
err = data.EditActivity(activityId, minutes, description)
89120
if err != nil {
90121
fmt.Println("Could not edit activity:", err)
91122
}
@@ -118,14 +149,16 @@ var activitiesCmd = &cobra.Command{
118149
}
119150

120151
func init() {
121-
editCmd.Flags().IntP("time", "t", 0, "Set the time for the activity (in seconds)")
152+
editCmd.Flags().IntP("time", "t", 0, "Set the time for the activity (in minutes)")
122153
editCmd.Flags().StringP("description", "d", "", "Set the description for the activity")
123154

124-
activitiesCmd.AddCommand(editCmd)
125-
126-
newCmd.Flags().Bool("no-start", false, "Don't start the activity when created")
127-
activitiesCmd.AddCommand(newCmd)
155+
createCmd.Flags().IntP("project", "p", 0, "Set the project for the activity")
156+
createCmd.Flags().IntP("task", "t", 0, "Set the task for the activity")
157+
createCmd.Flags().StringP("description", "d", "", "Set the description for the activity")
158+
createCmd.Flags().IntP("minutes", "m", 0, "Set the number of minutes for the activity")
128159

160+
activitiesCmd.AddCommand(editCmd)
161+
activitiesCmd.AddCommand(createCmd)
129162
activitiesCmd.AddCommand(deleteCmd)
130163

131164
rootCmd.AddCommand(activitiesCmd)

cmd/login.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ var loginCmd = &cobra.Command{
3232

3333
form := huh.NewForm(
3434
huh.NewGroup(
35-
huh.NewInput().Title("Domain").Prompt("?").Value(&domain),
36-
huh.NewInput().Title("First Name").Prompt("?").Value(&firstName),
37-
huh.NewInput().Title("Last Name").Prompt("?").Value(&lastName),
38-
huh.NewInput().Title("API Key").Prompt("?").Value(&apiKey).Password(true),
35+
huh.NewInput().Title("Domain").Prompt("? ").Value(&domain),
36+
huh.NewInput().Title("First Name").Prompt("? ").Value(&firstName),
37+
huh.NewInput().Title("Last Name").Prompt("? ").Value(&lastName),
38+
huh.NewInput().Title("API Key").Prompt("? ").Value(&apiKey).Password(true),
3939
),
4040
)
4141

cmd/track.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"moco/data"
6+
"os"
7+
"strconv"
8+
9+
"github.com/charmbracelet/huh"
10+
"github.com/joho/godotenv"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var trackCmd = &cobra.Command{
15+
Use: "track",
16+
Short: "Start tracking a new activity",
17+
Run: func(cmd *cobra.Command, args []string) {
18+
projects, err := data.GetProjects()
19+
if err != nil {
20+
fmt.Println("Could not retrieve projects", err)
21+
return
22+
}
23+
24+
// flags get highest priority
25+
projectId, _ := cmd.Flags().GetInt("project")
26+
taskId, _ := cmd.Flags().GetInt("task")
27+
description, _ := cmd.Flags().GetString("description")
28+
29+
// env has second priority
30+
err = godotenv.Load(".moco")
31+
if projectId == 0 && err == nil {
32+
projectId, err = strconv.Atoi(os.Getenv("MOCO_PROJECT_ID"))
33+
fmt.Println("read projectId", projectId)
34+
}
35+
if taskId == 0 && err == nil {
36+
taskId, err = strconv.Atoi(os.Getenv("MOCO_TASK_ID"))
37+
fmt.Println("read taskId", taskId)
38+
}
39+
40+
// if no flags, prompt
41+
if projectId == 0 || err != nil {
42+
options := make([]huh.Option[int], len(projects))
43+
for i, p := range projects {
44+
options[i] = huh.NewOption[int](p.Name, p.Id)
45+
}
46+
47+
pform := huh.NewSelect[int]().Options(options...).Value(&projectId)
48+
pform.Run()
49+
if projectId == 0 {
50+
return
51+
}
52+
}
53+
54+
var project data.Project
55+
for _, p := range projects {
56+
if p.Id == projectId {
57+
project = p
58+
}
59+
}
60+
61+
if taskId == 0 {
62+
options := make([]huh.Option[int], len(project.Tasks))
63+
for i, t := range project.Tasks {
64+
options[i] = huh.NewOption[int](t.Name, t.Id)
65+
}
66+
tform := huh.NewSelect[int]().Options(options...).Value(&taskId)
67+
tform.Run()
68+
if taskId == 0 {
69+
return
70+
}
71+
}
72+
73+
if description == "" {
74+
huh.NewInput().Title("Description:").Prompt("> ").Value(&description).Run()
75+
}
76+
77+
err = data.StartActivity(projectId, taskId, description)
78+
if err != nil {
79+
fmt.Println("Could not create activity:", err)
80+
}
81+
},
82+
}
83+
84+
func init() {
85+
trackCmd.Flags().IntP("project", "p", 0, "Set the project for the activity")
86+
trackCmd.Flags().IntP("task", "t", 0, "Set the task for the activity")
87+
trackCmd.Flags().StringP("description", "d", "", "Set the description for the activity")
88+
89+
rootCmd.AddCommand(trackCmd)
90+
}

data/activities.go

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,6 @@ type Activity struct {
3333
}
3434
}
3535

36-
func StartActivity(activityId int) error {
37-
config := config.Init()
38-
apiKey := config.GetString("api_key")
39-
if apiKey == "" {
40-
return fmt.Errorf("api_key not set")
41-
}
42-
domain := config.GetString("domain")
43-
if domain == "" {
44-
return fmt.Errorf("domain not set")
45-
}
46-
47-
req, _ := http.NewRequest("PATCH", fmt.Sprintf("https://%s.mocoapp.com/api/v1/activities/%d/start_timer", domain, activityId), nil)
48-
req.Header.Add("Authorization", fmt.Sprintf("Token token=%s", apiKey))
49-
client := &http.Client{}
50-
resp, err := client.Do(req)
51-
if err != nil || resp.StatusCode == 422 {
52-
return fmt.Errorf("Something went wrong")
53-
} else if resp.StatusCode == 404 {
54-
return fmt.Errorf("Activity not found")
55-
}
56-
defer resp.Body.Close()
57-
return nil
58-
}
59-
6036
func StopActivity(activityId int) error {
6137
config := config.Init()
6238
apiKey := config.GetString("api_key")
@@ -79,7 +55,46 @@ func StopActivity(activityId int) error {
7955
return nil
8056
}
8157

82-
func CreateActivity(projectId int, taskId int, description string) error {
58+
func CreateActivity(projectId int, taskId int, description string, minutes int) error {
59+
config := config.Init()
60+
apiKey := config.GetString("api_key")
61+
if apiKey == "" {
62+
return fmt.Errorf("api_key not set")
63+
}
64+
domain := config.GetString("domain")
65+
if domain == "" {
66+
return fmt.Errorf("domain not set")
67+
}
68+
69+
type ActivityBody struct {
70+
ProjectId int `json:"project_id"`
71+
TaskId int `json:"task_id"`
72+
Description string `json:"description"`
73+
Date string `json:"date"`
74+
Seconds int `json:"seconds"`
75+
}
76+
marshaledBody, err := json.Marshal(ActivityBody{
77+
ProjectId: projectId,
78+
TaskId: taskId,
79+
Description: description,
80+
Date: time.Now().Format("2006-01-02"),
81+
Seconds: minutes * 60,
82+
})
83+
fmt.Println(string(marshaledBody))
84+
85+
req, _ := http.NewRequest("POST", fmt.Sprintf("https://%s.mocoapp.com/api/v1/activities", domain), bytes.NewReader(marshaledBody))
86+
req.Header.Add("Authorization", fmt.Sprintf("Token token=%s", apiKey))
87+
req.Header.Add("Content-Type", "application/json")
88+
client := &http.Client{}
89+
resp, err := client.Do(req)
90+
if err != nil || resp.StatusCode == 422 {
91+
return fmt.Errorf("Error on response.\n[ERROR] - %s", err)
92+
}
93+
defer resp.Body.Close()
94+
return nil
95+
}
96+
97+
func StartActivity(projectId int, taskId int, description string) error {
8398
config := config.Init()
8499
apiKey := config.GetString("api_key")
85100
domain := config.GetString("domain")

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ require (
4141
github.com/fsnotify/fsnotify v1.7.0 // indirect
4242
github.com/hashicorp/hcl v1.0.0 // indirect
4343
github.com/inconshreveable/mousetrap v1.1.0 // indirect
44+
github.com/joho/godotenv v1.5.1
4445
github.com/magiconair/properties v1.8.7 // indirect
4546
github.com/mitchellh/mapstructure v1.5.0 // indirect
4647
github.com/pelletier/go-toml/v2 v2.1.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
4141
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
4242
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
4343
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
44+
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
45+
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
4446
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
4547
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
4648
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=

0 commit comments

Comments
 (0)