summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCara Salter <cara@devcara.com>2023-09-03 11:51:38 -0400
committerCara Salter <cara@devcara.com>2023-09-03 11:51:38 -0400
commit1a69cd2e8b919ab450b42802ae578c2d23948a07 (patch)
tree2e0e1bfaa96e80f0a671b80cb197ad81f953ece1
downloadgrocy-reminders-1a69cd2e8b919ab450b42802ae578c2d23948a07.tar.gz
grocy-reminders-1a69cd2e8b919ab450b42802ae578c2d23948a07.zip
Initial commit
Create API client for grocy
-rw-r--r--.gitignore51
-rw-r--r--go.sum2
-rw-r--r--grocy/chores.go53
-rw-r--r--grocy/grocy.go57
-rw-r--r--grocy/user.go53
-rw-r--r--main.go37
6 files changed, 253 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2400acd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+# Created by https://www.toptal.com/developers/gitignore/api/go,vim,dotenv
+# Edit at https://www.toptal.com/developers/gitignore?templates=go,vim,dotenv
+
+### dotenv ###
+.env
+
+### Go ###
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
+
+### Vim ###
+# Swap
+[._]*.s[a-v][a-z]
+!*.svg # comment out if you don't need vector files
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+Sessionx.vim
+
+# Temporary
+.netrwhist
+*~
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
+
+# End of https://www.toptal.com/developers/gitignore/api/go,vim,dotenv
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..d61b19e
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
+github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
diff --git a/grocy/chores.go b/grocy/chores.go
new file mode 100644
index 0000000..3dcdf2e
--- /dev/null
+++ b/grocy/chores.go
@@ -0,0 +1,53 @@
+package grocy
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+)
+
+type Chore struct {
+ ID int `json:"id"`
+ ChoreID int `json:"chore_id"`
+ ChoreName string `json:"chore_name"`
+ LastTrackedTime string `json:"last_tracked_time"`
+ NextEstimatedExecutionTime string `json:"next_estimated_execution_time"`
+ TrackDateOnly int `json:"track_date_only"`
+ NextExecutionAssignedToUserID int `json:"next_execution_assigned_to_user_id"`
+ IsRescheduled int `json:"is_rescheduled"`
+ IsReassigned int `json:"is_reassigned"`
+ NextExecutionAssignedUser User `json:"next_execution_assigned_user"`
+}
+
+type ChoreList []Chore
+
+func (c *Client) GetChores(ctx context.Context) (ChoreList, error) {
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s/chores", c.BaseUrl), nil)
+
+ if err != nil {
+ return nil, err
+ }
+ req.WithContext(ctx)
+
+ var res ChoreList
+ if err := c.sendRequest(req, &res); err != nil {
+ return nil, err
+ }
+
+ return res, nil
+}
+
+func (c *Client) GetChore(ctx context.Context, choreId int) (Chore, error) {
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s/chores/%d", c.BaseUrl, choreId), nil)
+
+ if err != nil {
+ return *new(Chore), err
+ }
+ req.WithContext(ctx)
+
+ var res Chore
+ if err := c.sendRequest(req, &res); err != nil {
+ return *new(Chore), err
+ }
+ return res, nil
+}
diff --git a/grocy/grocy.go b/grocy/grocy.go
new file mode 100644
index 0000000..55c3d2d
--- /dev/null
+++ b/grocy/grocy.go
@@ -0,0 +1,57 @@
+package grocy
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "time"
+)
+
+type Client struct {
+ BaseUrl string
+ apiKey string
+ HTTPClient *http.Client
+}
+
+func NewClient(baseUrl, apiKey string) *Client {
+ return &Client{
+ BaseUrl: baseUrl,
+ apiKey: apiKey,
+ HTTPClient: &http.Client{
+ Timeout: time.Minute,
+ },
+ }
+}
+
+type ErrorResponse struct {
+ ErrorMessage string `json:"error_message"`
+}
+
+func (c *Client) sendRequest(req *http.Request, v interface{}) error {
+ req.Header.Set("Content-Type", "application/json; charset=utf-8")
+ req.Header.Set("Accept", "application/json; charset=utf-8")
+ req.Header.Set("GROCY-API-KEY", c.apiKey)
+
+ res, err := c.HTTPClient.Do(req)
+ if err != nil {
+ return err
+ }
+
+ defer res.Body.Close()
+
+ if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
+ var errRes ErrorResponse
+ if err = json.NewDecoder(res.Body).Decode(&errRes); err == nil {
+ return errors.New(errRes.ErrorMessage)
+ }
+
+ return fmt.Errorf("unknown error, status code: %d", res.StatusCode)
+ }
+
+ if err = json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/grocy/user.go b/grocy/user.go
new file mode 100644
index 0000000..58d3d08
--- /dev/null
+++ b/grocy/user.go
@@ -0,0 +1,53 @@
+package grocy
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+)
+
+type (
+ User struct {
+ Id int `json:"id"`
+ Username string `json:"username"`
+ FirstName string `json:"first_name"`
+ LastName string `json:"last_name"`
+ RowCreated string `json:"row_created_timestamp"`
+ DisplayName string `json:"display_name"`
+ PictureFileName string `json:"picture_file_name"`
+ }
+)
+
+func (c *Client) GetUsers(ctx context.Context) ([]User, error) {
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s/users", c.BaseUrl), nil)
+
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Add("GROCY-API-KEY", c.apiKey)
+ req.WithContext(ctx)
+
+ var res []User
+ if err := c.sendRequest(req, &res); err != nil {
+ return nil, err
+ }
+
+ return res, nil
+}
+
+func (c *Client) GetUserFields(ctx context.Context, userId int) (map[string]string, error) {
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s/userfields/users/%d", c.BaseUrl, userId), nil)
+
+ if err != nil {
+ return nil, err
+ }
+
+ req.WithContext(ctx)
+
+ var res map[string]string
+ if err := c.sendRequest(req, &res); err != nil {
+ return nil, err
+ }
+
+ return res, nil
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..e0777ab
--- /dev/null
+++ b/main.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+
+ "git.devcara.com/grocy-reminders/grocy"
+ "github.com/joho/godotenv"
+)
+
+func main() {
+ err := godotenv.Load(".env")
+ if err != nil {
+ log.Panic(err)
+ }
+ apiClient := grocy.NewClient(os.Getenv("GROCY_BASE_URL"), os.Getenv("GROCY_API_KEY"))
+
+ res, err := apiClient.GetUsers(context.Background())
+
+ if err != nil {
+ log.Panic(err)
+ }
+
+ for _, u := range res {
+
+ userfield, err := apiClient.GetUserFields(context.Background(), u.Id)
+
+ if err != nil {
+ log.Panic(err)
+ }
+
+ fmt.Printf("%s (%s): %s\n", u.Username, u.DisplayName, userfield["discordid"])
+ }
+
+}