gostart/watches.go
2023-06-07 11:58:14 -06:00

233 lines
4.8 KiB
Go

package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"sort"
"time"
"suah.dev/gostart/data"
)
const gqEndPoint = "https://api.github.com/graphql"
const graphQuery = `
{
search(
query: "is:open is:public archived:false repo:%s in:title %s",
type: ISSUE,
first: 20
) {
issueCount
edges {
node {
... on Issue {
number
title
url
repository {
nameWithOwner
}
createdAt
}
... on PullRequest {
number
title
repository {
nameWithOwner
}
createdAt
url
}
}
}
}
rateLimit {
remaining
resetAt
}
}
`
type GQLQuery struct {
Query string `json:"query"`
}
type WatchResults []WatchResult
func includeWatch(repo string, number int, ignoreList []data.PullRequestIgnore) bool {
for _, pri := range ignoreList {
if pri.Repo == repo && pri.Number == int64(number) {
return false
}
}
return true
}
func (w *WatchResults) forID(ownerID int64) *WatchResults {
newResults := WatchResults{}
tmpResults := WatchResults{}
ctx := context.Background()
ignores, _ := app.queries.GetAllPullRequestIgnores(ctx, ownerID)
for _, r := range *w {
if r.OwnerID == ownerID {
if r.Results == nil {
r.Results = make([]Node, 0)
}
tmpResults = append(tmpResults, r)
}
}
sort.Slice(newResults, func(i, j int) bool {
return newResults[i].Name < newResults[j].Name
})
for _, r := range tmpResults {
tmpResultList := []Node{}
for _, entry := range r.Results {
if includeWatch(entry.Repository.NameWithOwner, entry.Number, ignores) {
tmpResultList = append(tmpResultList, entry)
}
}
r.Results = tmpResultList
r.ResultCount = len(tmpResultList)
newResults = append(newResults, r)
}
return &newResults
}
func (w WatchResults) GetLimits() *RateLimit {
rl := &RateLimit{}
sort.Slice(w, func(i, j int) bool {
return w[i].Data.RateLimit.Remaining < w[j].Data.RateLimit.Remaining
})
if len(w) > 0 {
rl = &w[0].Data.RateLimit
}
return rl
}
func UpdateWatches(ghToken string) (*WatchResults, error) {
if ghToken == "" {
return nil, fmt.Errorf("invalid github token")
}
ctx := context.Background()
w := WatchResults{}
watches, err := app.queries.GetAllWatchItems(ctx)
if err != nil {
return nil, err
}
for _, watch := range watches {
qd := GQLQuery{Query: fmt.Sprintf(graphQuery, watch.Repo, watch.Name)}
wr, err := getWatchData(qd, ghToken)
if err != nil {
return nil, err
}
wr.OwnerID = watch.OwnerID
wr.Name = watch.Name
wr.Repo = watch.Repo
wr.ID = watch.ID
for _, dr := range wr.Data.Search.Edges {
wr.Results = append(wr.Results, dr.Node)
}
sort.Slice(wr.Data.Search.Edges, func(i, j int) bool {
return wr.Data.Search.Edges[i].Node.CreatedAt.After(wr.Data.Search.Edges[j].Node.CreatedAt)
})
w = append(w, *wr)
}
sort.Slice(w, func(i, j int) bool {
return w[i].Name < w[j].Name
})
return &w, nil
}
type WatchResult struct {
ID int64 `json:"id"`
Data Data `json:"data"`
OwnerID int64 `json:"owner_id"`
Name string `json:"name"`
Repo string `json:"repo"`
Results []Node `json:"results"`
ResultCount int `json:"result_count"`
}
type Repository struct {
NameWithOwner string `json:"nameWithOwner,omitempty"`
}
type Node struct {
Number int `json:"number,omitempty"`
Title string `json:"title,omitempty"`
Repository Repository `json:"repository,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
URL string `json:"url,omitempty"`
}
type Edges struct {
Node Node `json:"node,omitempty"`
}
type Search struct {
IssueCount int `json:"issueCount,omitempty"`
Edges []Edges `json:"edges,omitempty"`
}
type RateLimit struct {
Remaining int `json:"remaining,omitempty"`
ResetAt time.Time `json:"resetAt,omitempty"`
}
type Data struct {
Search Search `json:"search,omitempty"`
RateLimit RateLimit `json:"rateLimit,omitempty"`
}
func getWatchData(q GQLQuery, token string) (*WatchResult, error) {
var req *http.Request
var err error
var re = &WatchResult{}
client := &http.Client{}
buf := new(bytes.Buffer)
if err := json.NewEncoder(buf).Encode(q); err != nil {
return nil, err
}
req, err = http.NewRequest("POST", gqEndPoint, buf)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", token))
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Fatal("can't close body: ", err)
}
}()
if err = json.NewDecoder(res.Body).Decode(re); err != nil {
return nil, err
}
return re, nil
}