Rename ticktickutil, add interface for di
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"`
|
||||||
@@ -35,14 +45,14 @@ type Project struct {
|
|||||||
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"`
|
||||||
@@ -61,13 +71,15 @@ type Task struct {
|
|||||||
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()))
|
||||||
Reference in New Issue
Block a user