Rename ticktickutil, add interface for di

This commit is contained in:
2024-10-22 16:40:19 +02:00
parent f295779566
commit 2a1a40f75f
3 changed files with 91 additions and 65 deletions

View File

@@ -21,11 +21,14 @@ import (
"github.com/t-liu93/home-automation-backend/components/locationRecorder" "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/components/pooRecorder"
"github.com/t-liu93/home-automation-backend/util/notion" "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 (
var scheduler gocron.Scheduler port string
scheduler gocron.Scheduler
ticktick *ticktickutil.TicktickUtilImpl
)
// serveCmd represents the serve command // serveCmd represents the serve command
var serveCmd = &cobra.Command{ var serveCmd = &cobra.Command{
@@ -43,7 +46,7 @@ func initUtil() {
os.Exit(1) os.Exit(1)
} }
// init ticktick // init ticktick
ticktick.Init() ticktick = ticktickutil.Init()
} }
func initComponent() { func initComponent() {
@@ -51,6 +54,8 @@ func initComponent() {
pooRecorder.Init(&scheduler) pooRecorder.Init(&scheduler)
// init location recorder // init location recorder
locationRecorder.Init() locationRecorder.Init()
// init homeassistant
homeassistant.Init(ticktick)
} }
func serve(cmd *cobra.Command, args []string) { func serve(cmd *cobra.Command, args []string) {

View File

@@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/spf13/viper" "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 { type haMessage struct {
@@ -23,6 +23,14 @@ type actionTask struct {
DueHour int `json:"due_hour"` DueHour int `json:"due_hour"`
} }
var (
ticktickUtil ticktickutil.TicktickUtil
)
func Init(ticktick ticktickutil.TicktickUtil) {
ticktickUtil = ticktick
}
func HandleHaMessage(w http.ResponseWriter, r *http.Request) { func HandleHaMessage(w http.ResponseWriter, r *http.Request) {
var message haMessage var message haMessage
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
@@ -112,13 +120,13 @@ func createActionTask(message haMessage) {
dueHour := task.DueHour dueHour := task.DueHour
due := time.Now().Add(time.Hour * time.Duration(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) 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) dueTicktick := dueNextMidnight.UTC().Format(ticktickutil.DateTimeLayout)
ticktickTask := ticktick.Task{ ticktickTask := ticktickutil.Task{
ProjectId: projectId, ProjectId: projectId,
Title: task.Action, Title: task.Action,
DueDate: dueTicktick, DueDate: dueTicktick,
} }
err = ticktick.CreateTask(ticktickTask) err = ticktickUtil.CreateTask(ticktickTask)
if err != nil { if err != nil {
slog.Warn(fmt.Sprintf("Homeassistant.createActionTask Error creating task %s", err)) slog.Warn(fmt.Sprintf("Homeassistant.createActionTask Error creating task %s", err))
} }

View File

@@ -1,4 +1,4 @@
package ticktick package ticktickutil
import ( import (
"bytes" "bytes"
@@ -15,15 +15,25 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
var (
authState string
)
const ( const (
DateTimeLayout = "2006-01-02T15:04:05-0700" DateTimeLayout = "2006-01-02T15:04:05-0700"
) )
type Project struct { type (
TicktickUtil interface {
HandleAuthCode(w http.ResponseWriter, r *http.Request)
GetTasks(projectId string) []Task
HasDuplicateTask(projectId string, taskTitile string) bool
CreateTask(task Task) error
}
TicktickUtilImpl struct {
authState string
}
)
type (
Project struct {
Id string `json:"id"` Id string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
Color string `json:"color,omitempty"` Color string `json:"color,omitempty"`
@@ -33,16 +43,16 @@ type Project struct {
ViewMode string `json:"viewMode,omitempty"` ViewMode string `json:"viewMode,omitempty"`
Permission string `json:"permission,omitempty"` Permission string `json:"permission,omitempty"`
Kind string `json:"kind,omitempty"` Kind string `json:"kind,omitempty"`
} }
type Column struct { Column struct {
Id string `json:"id"` Id string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
ProjectId string `json:"projectId"` ProjectId string `json:"projectId"`
SortOrder int64 `json:"sortOrder,omitempty"` SortOrder int64 `json:"sortOrder,omitempty"`
} }
type Task struct { Task struct {
Id string `json:"id"` Id string `json:"id"`
ProjectId string `json:"projectId"` ProjectId string `json:"projectId"`
Title string `json:"title"` Title string `json:"title"`
@@ -59,15 +69,17 @@ type Task struct {
StartDate string `json:"startDate,omitempty"` StartDate string `json:"startDate,omitempty"`
Status int32 `json:"status,omitempty"` Status int32 `json:"status,omitempty"`
TimeZone string `json:"timeZone,omitempty"` TimeZone string `json:"timeZone,omitempty"`
} }
type ProjectData struct { ProjectData struct {
Project Project `json:"project"` Project Project `json:"project"`
Tasks []Task `json:"tasks"` Tasks []Task `json:"tasks"`
Columns []Column `json:"columns,omitempty"` Columns []Column `json:"columns,omitempty"`
} }
)
func Init() { func Init() *TicktickUtilImpl {
ticktickUtilImpl := &TicktickUtilImpl{}
if !viper.InConfig("ticktick.clientId") { if !viper.InConfig("ticktick.clientId") {
slog.Error("TickTick clientId not found in config file, exiting..") slog.Error("TickTick clientId not found in config file, exiting..")
os.Exit(1) os.Exit(1)
@@ -83,14 +95,15 @@ func Init() {
} }
} }
} else { } 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") state := r.URL.Query().Get("state")
code := r.URL.Query().Get("code") code := r.URL.Query().Get("code")
if state != authState { if state != t.authState {
slog.Warn(fmt.Sprintln("HandleAuthCode Invalid state", state)) slog.Warn(fmt.Sprintln("HandleAuthCode Invalid state", state))
http.Error(w, "Invalid state", http.StatusBadRequest) http.Error(w, "Invalid state", http.StatusBadRequest)
return return
@@ -148,7 +161,7 @@ func HandleAuthCode(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Authorization successful")) 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) getTaskUrl := fmt.Sprintf("https://api.ticktick.com/open/v1/project/%s/data", projectId)
token := viper.GetString("ticktick.token") token := viper.GetString("ticktick.token")
req, err := http.NewRequest("GET", getTaskUrl, nil) req, err := http.NewRequest("GET", getTaskUrl, nil)
@@ -184,8 +197,8 @@ func GetTasks(projectId string) []Task {
return projectData.Tasks return projectData.Tasks
} }
func HasDuplicateTask(projectId string, taskTitile string) bool { func (t *TicktickUtilImpl) HasDuplicateTask(projectId string, taskTitile string) bool {
tasks := GetTasks(projectId) tasks := t.GetTasks(projectId)
for _, task := range tasks { for _, task := range tasks {
if task.Title == taskTitile { if task.Title == taskTitile {
return true return true
@@ -194,8 +207,8 @@ func HasDuplicateTask(projectId string, taskTitile string) bool {
return false return false
} }
func CreateTask(task Task) error { func (t *TicktickUtilImpl) CreateTask(task Task) error {
if HasDuplicateTask(task.ProjectId, task.Title) { if t.HasDuplicateTask(task.ProjectId, task.Title) {
return nil return nil
} }
token := viper.GetString("ticktick.token") token := viper.GetString("ticktick.token")
@@ -259,7 +272,7 @@ func getProjects() ([]Project, error) {
return projects, nil return projects, nil
} }
func beginAuth() { func (t *TicktickUtilImpl) beginAuth() {
if !viper.InConfig("ticktick.redirectUri") { if !viper.InConfig("ticktick.redirectUri") {
slog.Error("TickTick redirectUri not found in config file, exiting..") slog.Error("TickTick redirectUri not found in config file, exiting..")
os.Exit(1) os.Exit(1)
@@ -272,12 +285,12 @@ func beginAuth() {
slog.Error(fmt.Sprintln("Error generating auth state", err)) slog.Error(fmt.Sprintln("Error generating auth state", err))
os.Exit(1) os.Exit(1)
} }
authState = hex.EncodeToString(authStateBytes) t.authState = hex.EncodeToString(authStateBytes)
params := url.Values{} params := url.Values{}
params.Add("client_id", viper.GetString("ticktick.clientId")) params.Add("client_id", viper.GetString("ticktick.clientId"))
params.Add("response_type", "code") params.Add("response_type", "code")
params.Add("redirect_uri", viper.GetString("ticktick.redirectUri")) params.Add("redirect_uri", viper.GetString("ticktick.redirectUri"))
params.Add("state", authState) params.Add("state", t.authState)
params.Add("scope", "tasks:read tasks:write") params.Add("scope", "tasks:read tasks:write")
authUrl.RawQuery = params.Encode() authUrl.RawQuery = params.Encode()
slog.Info(fmt.Sprintln("Please visit the following URL to authorize TickTick:", authUrl.String())) slog.Info(fmt.Sprintln("Please visit the following URL to authorize TickTick:", authUrl.String()))