package hackatime import ( "encoding/json" "errors" "farga/lib" "fmt" "io" "net/http" "net/url" "time" ) type ProjectItem struct { Name string `json:"name"` TotalSeconds uint `json:"total_seconds"` PrettyTime string } type ProjectResponse struct { Projects []ProjectItem `json:"projects"` } type User struct { ID uint `json:"id"` SlackID string `json:"slack_id"` Emails []string `json:"emails"` } // 5 second timeout fetch for API requests, authenticates itself with a Bearer. func fetch(url string, bearer string) ([]byte, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { fmt.Println(err) return nil, err } req.Header.Add("Accept", "application/json") req.Header.Add("Authorization", "Bearer "+bearer) // user's oauth secret client := &http.Client{ Timeout: 5 * time.Second, // 5 second timeout } res, err := client.Do(req) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode != 200 { return nil, errors.New("Hackatime API returned non-ok status code: " + fmt.Sprint(res.StatusCode)) } body, err := io.ReadAll(res.Body) return body, err } // get a user from their bearer/secret hackatime token. func UserInfo(bearer string) (*User, error) { requestUrl := "https://hackatime.hackclub.com/api/v1/authenticated/me" body, err := fetch(requestUrl, bearer) if err != nil { return nil, err } var user User err = json.Unmarshal(body, &user) return &user, err } // gets all projects from a given oauth token func Projects(bearer string) ([]ProjectItem, error) { requestUrl := "https://hackatime.hackclub.com/api/v1/authenticated/projects" body, err := fetch(requestUrl, bearer) if err != nil { return nil, err } var projects ProjectResponse err = json.Unmarshal(body, &projects) return projects.Projects, err } // gets a single project. func Project(bearer string, name string) (ProjectItem, error) { requestUrl := "https://hackatime.hackclub.com/api/v1/authenticated/projects?projects=" + url.QueryEscape(name) // urlencoded in case someone tries to be funny. body, err := fetch(requestUrl, bearer) if err != nil { return ProjectItem{}, err } var projects ProjectResponse err = json.Unmarshal(body, &projects) // if no such project, if len(projects.Projects) == 0 { return ProjectItem{}, errors.New("Hackatime project not found.") // todo: } project := projects.Projects[0] project.PrettyTime = lib.FormatTime(int(project.TotalSeconds)) return project, err }