From 2a1a40f75f4a9ea36f088eb3a54cab61205cb098 Mon Sep 17 00:00:00 2001 From: Tianyu Liu Date: Tue, 22 Oct 2024 16:40:19 +0200 Subject: [PATCH] Rename ticktickutil, add interface for di --- src/cmd/serve.go | 13 +- src/components/homeassistant/homeassistant.go | 16 ++- .../ticktickutil.go} | 127 ++++++++++-------- 3 files changed, 91 insertions(+), 65 deletions(-) rename src/util/{ticktick/ticktick.go => ticktickutil/ticktickutil.go} (72%) diff --git a/src/cmd/serve.go b/src/cmd/serve.go index e06cbd0..1fdf266 100644 --- a/src/cmd/serve.go +++ b/src/cmd/serve.go @@ -21,11 +21,14 @@ import ( "github.com/t-liu93/home-automation-backend/components/locationRecorder" "github.com/t-liu93/home-automation-backend/components/pooRecorder" "github.com/t-liu93/home-automation-backend/util/notion" - "github.com/t-liu93/home-automation-backend/util/ticktick" + "github.com/t-liu93/home-automation-backend/util/ticktickutil" ) -var port string -var scheduler gocron.Scheduler +var ( + port string + scheduler gocron.Scheduler + ticktick *ticktickutil.TicktickUtilImpl +) // serveCmd represents the serve command var serveCmd = &cobra.Command{ @@ -43,7 +46,7 @@ func initUtil() { os.Exit(1) } // init ticktick - ticktick.Init() + ticktick = ticktickutil.Init() } func initComponent() { @@ -51,6 +54,8 @@ func initComponent() { pooRecorder.Init(&scheduler) // init location recorder locationRecorder.Init() + // init homeassistant + homeassistant.Init(ticktick) } func serve(cmd *cobra.Command, args []string) { diff --git a/src/components/homeassistant/homeassistant.go b/src/components/homeassistant/homeassistant.go index 4a68376..b66bf56 100644 --- a/src/components/homeassistant/homeassistant.go +++ b/src/components/homeassistant/homeassistant.go @@ -9,7 +9,7 @@ import ( "time" "github.com/spf13/viper" - "github.com/t-liu93/home-automation-backend/util/ticktick" + "github.com/t-liu93/home-automation-backend/util/ticktickutil" ) type haMessage struct { @@ -23,6 +23,14 @@ type actionTask struct { DueHour int `json:"due_hour"` } +var ( + ticktickUtil ticktickutil.TicktickUtil +) + +func Init(ticktick ticktickutil.TicktickUtil) { + ticktickUtil = ticktick +} + func HandleHaMessage(w http.ResponseWriter, r *http.Request) { var message haMessage decoder := json.NewDecoder(r.Body) @@ -112,13 +120,13 @@ func createActionTask(message haMessage) { dueHour := task.DueHour due := time.Now().Add(time.Hour * time.Duration(dueHour)) dueNextMidnight := time.Date(due.Year(), due.Month(), due.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, 1) - dueTicktick := dueNextMidnight.UTC().Format(ticktick.DateTimeLayout) - ticktickTask := ticktick.Task{ + dueTicktick := dueNextMidnight.UTC().Format(ticktickutil.DateTimeLayout) + ticktickTask := ticktickutil.Task{ ProjectId: projectId, Title: task.Action, DueDate: dueTicktick, } - err = ticktick.CreateTask(ticktickTask) + err = ticktickUtil.CreateTask(ticktickTask) if err != nil { slog.Warn(fmt.Sprintf("Homeassistant.createActionTask Error creating task %s", err)) } diff --git a/src/util/ticktick/ticktick.go b/src/util/ticktickutil/ticktickutil.go similarity index 72% rename from src/util/ticktick/ticktick.go rename to src/util/ticktickutil/ticktickutil.go index 3344e5b..3edc317 100644 --- a/src/util/ticktick/ticktick.go +++ b/src/util/ticktickutil/ticktickutil.go @@ -1,4 +1,4 @@ -package ticktick +package ticktickutil import ( "bytes" @@ -15,59 +15,71 @@ import ( "github.com/spf13/viper" ) -var ( - authState string -) - const ( DateTimeLayout = "2006-01-02T15:04:05-0700" ) -type Project struct { - Id string `json:"id"` - Name string `json:"name"` - Color string `json:"color,omitempty"` - SortOrder int64 `json:"sortOrder,omitempty"` - Closed bool `json:"closed,omitempty"` - GroupId string `json:"groupId,omitempty"` - ViewMode string `json:"viewMode,omitempty"` - Permission string `json:"permission,omitempty"` - Kind string `json:"kind,omitempty"` -} +type ( + TicktickUtil interface { + HandleAuthCode(w http.ResponseWriter, r *http.Request) + GetTasks(projectId string) []Task + HasDuplicateTask(projectId string, taskTitile string) bool + CreateTask(task Task) error + } -type Column struct { - Id string `json:"id"` - Name string `json:"name"` - ProjectId string `json:"projectId"` - SortOrder int64 `json:"sortOrder,omitempty"` -} + TicktickUtilImpl struct { + authState string + } +) -type Task struct { - Id string `json:"id"` - ProjectId string `json:"projectId"` - Title string `json:"title"` - IsAllDay bool `json:"isAllDay,omitempty"` - CompletedTime string `json:"completedTime,omitempty"` - Content string `json:"content,omitempty"` - Desc string `json:"desc,omitempty"` - DueDate string `json:"dueDate,omitempty"` - Items []interface{} `json:"items,omitempty"` - Priority int `json:"priority,omitempty"` - Reminders []string `json:"reminders,omitempty"` - RepeatFlag string `json:"repeatFlag,omitempty"` - SortOrder int64 `json:"sortOrder,omitempty"` - StartDate string `json:"startDate,omitempty"` - Status int32 `json:"status,omitempty"` - TimeZone string `json:"timeZone,omitempty"` -} +type ( + Project struct { + Id string `json:"id"` + Name string `json:"name"` + Color string `json:"color,omitempty"` + SortOrder int64 `json:"sortOrder,omitempty"` + Closed bool `json:"closed,omitempty"` + GroupId string `json:"groupId,omitempty"` + ViewMode string `json:"viewMode,omitempty"` + Permission string `json:"permission,omitempty"` + Kind string `json:"kind,omitempty"` + } -type ProjectData struct { - Project Project `json:"project"` - Tasks []Task `json:"tasks"` - Columns []Column `json:"columns,omitempty"` -} + Column struct { + Id string `json:"id"` + Name string `json:"name"` + ProjectId string `json:"projectId"` + SortOrder int64 `json:"sortOrder,omitempty"` + } -func Init() { + Task struct { + Id string `json:"id"` + ProjectId string `json:"projectId"` + Title string `json:"title"` + IsAllDay bool `json:"isAllDay,omitempty"` + CompletedTime string `json:"completedTime,omitempty"` + Content string `json:"content,omitempty"` + Desc string `json:"desc,omitempty"` + DueDate string `json:"dueDate,omitempty"` + Items []interface{} `json:"items,omitempty"` + Priority int `json:"priority,omitempty"` + Reminders []string `json:"reminders,omitempty"` + RepeatFlag string `json:"repeatFlag,omitempty"` + SortOrder int64 `json:"sortOrder,omitempty"` + StartDate string `json:"startDate,omitempty"` + Status int32 `json:"status,omitempty"` + TimeZone string `json:"timeZone,omitempty"` + } + + ProjectData struct { + Project Project `json:"project"` + Tasks []Task `json:"tasks"` + Columns []Column `json:"columns,omitempty"` + } +) + +func Init() *TicktickUtilImpl { + ticktickUtilImpl := &TicktickUtilImpl{} if !viper.InConfig("ticktick.clientId") { slog.Error("TickTick clientId not found in config file, exiting..") os.Exit(1) @@ -83,14 +95,15 @@ func Init() { } } } else { - beginAuth() + ticktickUtilImpl.beginAuth() } + return ticktickUtilImpl } -func HandleAuthCode(w http.ResponseWriter, r *http.Request) { +func (t *TicktickUtilImpl) HandleAuthCode(w http.ResponseWriter, r *http.Request) { state := r.URL.Query().Get("state") code := r.URL.Query().Get("code") - if state != authState { + if state != t.authState { slog.Warn(fmt.Sprintln("HandleAuthCode Invalid state", state)) http.Error(w, "Invalid state", http.StatusBadRequest) return @@ -148,7 +161,7 @@ func HandleAuthCode(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Authorization successful")) } -func GetTasks(projectId string) []Task { +func (t *TicktickUtilImpl) GetTasks(projectId string) []Task { getTaskUrl := fmt.Sprintf("https://api.ticktick.com/open/v1/project/%s/data", projectId) token := viper.GetString("ticktick.token") req, err := http.NewRequest("GET", getTaskUrl, nil) @@ -184,8 +197,8 @@ func GetTasks(projectId string) []Task { return projectData.Tasks } -func HasDuplicateTask(projectId string, taskTitile string) bool { - tasks := GetTasks(projectId) +func (t *TicktickUtilImpl) HasDuplicateTask(projectId string, taskTitile string) bool { + tasks := t.GetTasks(projectId) for _, task := range tasks { if task.Title == taskTitile { return true @@ -194,8 +207,8 @@ func HasDuplicateTask(projectId string, taskTitile string) bool { return false } -func CreateTask(task Task) error { - if HasDuplicateTask(task.ProjectId, task.Title) { +func (t *TicktickUtilImpl) CreateTask(task Task) error { + if t.HasDuplicateTask(task.ProjectId, task.Title) { return nil } token := viper.GetString("ticktick.token") @@ -259,7 +272,7 @@ func getProjects() ([]Project, error) { return projects, nil } -func beginAuth() { +func (t *TicktickUtilImpl) beginAuth() { if !viper.InConfig("ticktick.redirectUri") { slog.Error("TickTick redirectUri not found in config file, exiting..") os.Exit(1) @@ -272,12 +285,12 @@ func beginAuth() { slog.Error(fmt.Sprintln("Error generating auth state", err)) os.Exit(1) } - authState = hex.EncodeToString(authStateBytes) + t.authState = hex.EncodeToString(authStateBytes) params := url.Values{} params.Add("client_id", viper.GetString("ticktick.clientId")) params.Add("response_type", "code") params.Add("redirect_uri", viper.GetString("ticktick.redirectUri")) - params.Add("state", authState) + params.Add("state", t.authState) params.Add("scope", "tasks:read tasks:write") authUrl.RawQuery = params.Encode() slog.Info(fmt.Sprintln("Please visit the following URL to authorize TickTick:", authUrl.String()))