add initial bits for an elm frontend
This commit is contained in:
parent
2fcac629fe
commit
4ad5b2964a
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ result
|
|||||||
gostart
|
gostart
|
||||||
.direnv
|
.direnv
|
||||||
*.db
|
*.db
|
||||||
|
elm-stuff
|
||||||
|
27
elm.json
Normal file
27
elm.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"type": "application",
|
||||||
|
"source-directories": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.1",
|
||||||
|
"dependencies": {
|
||||||
|
"direct": {
|
||||||
|
"elm/browser": "1.0.2",
|
||||||
|
"elm/core": "1.0.5",
|
||||||
|
"elm/html": "1.0.0",
|
||||||
|
"elm/http": "2.0.0",
|
||||||
|
"elm/json": "1.1.3"
|
||||||
|
},
|
||||||
|
"indirect": {
|
||||||
|
"elm/bytes": "1.0.8",
|
||||||
|
"elm/file": "1.0.5",
|
||||||
|
"elm/time": "1.0.0",
|
||||||
|
"elm/url": "1.0.0",
|
||||||
|
"elm/virtual-dom": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test-dependencies": {
|
||||||
|
"direct": {},
|
||||||
|
"indirect": {}
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,8 @@
|
|||||||
sqlc
|
sqlc
|
||||||
sqlite
|
sqlite
|
||||||
rlwrap
|
rlwrap
|
||||||
nodePackages.typescript
|
elmPackages.elm
|
||||||
|
elmPackages.elm-live
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -117,11 +117,9 @@ func watchitemGET(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, http.StatusText(http.StatusUnprocessableEntity), http.StatusUnprocessableEntity)
|
http.Error(w, http.StatusText(http.StatusUnprocessableEntity), http.StatusUnprocessableEntity)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
watches, err := app.queries.GetAllWatchItemsByOwner(app.ctx, ownerID)
|
|
||||||
if err != nil {
|
watches := app.watches.forID(ownerID)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wJson, err := json.Marshal(watches)
|
wJson, err := json.Marshal(watches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
41
main.go
41
main.go
@ -50,6 +50,23 @@ func main() {
|
|||||||
log.Fatal("can't open database: ", err)
|
log.Fatal("can't open database: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbExists := false
|
||||||
|
if *dbFile == ":memory:" {
|
||||||
|
err := tmpDBPopulate(db)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
dbExists = true
|
||||||
|
} else {
|
||||||
|
if _, err := os.Stat(*dbFile); os.IsNotExist(err) {
|
||||||
|
log.Println("Creating database..")
|
||||||
|
if _, err := db.ExecContext(app.ctx, schema); err != nil {
|
||||||
|
log.Fatal("can't create database schema: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbExists = true
|
||||||
|
}
|
||||||
|
|
||||||
app.watches = &WatchResults{}
|
app.watches = &WatchResults{}
|
||||||
app.queries = data.New(db)
|
app.queries = data.New(db)
|
||||||
app.tsServer = &tsnet.Server{
|
app.tsServer = &tsnet.Server{
|
||||||
@ -60,24 +77,12 @@ func main() {
|
|||||||
log.Fatal("can't get ts local client: ", err)
|
log.Fatal("can't get ts local client: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbExists := false
|
/*
|
||||||
if *dbFile == ":memory:" {
|
go func() {
|
||||||
err := tmpDBPopulate(db)
|
time.Sleep(6 * time.Second)
|
||||||
if err != nil {
|
dbExists = true
|
||||||
log.Fatal(err)
|
}()
|
||||||
}
|
*/
|
||||||
} else {
|
|
||||||
if _, err := os.Stat(*dbFile); os.IsNotExist(err) {
|
|
||||||
log.Println("Creating database..")
|
|
||||||
if _, err := db.ExecContext(app.ctx, schema); err != nil {
|
|
||||||
log.Fatal("can't create database schema: ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
time.Sleep(6 * time.Second)
|
|
||||||
dbExists = true
|
|
||||||
}()
|
|
||||||
|
|
||||||
if *key != "" {
|
if *key != "" {
|
||||||
keyData, err := os.ReadFile(*key)
|
keyData, err := os.ReadFile(*key)
|
||||||
|
179
page.go
179
page.go
@ -1,100 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
|
||||||
|
|
||||||
"suah.dev/gostart/data"
|
"suah.dev/gostart/data"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getData(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
|
|
||||||
}
|
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
Title string
|
Title string
|
||||||
System data.Owner
|
System data.Owner
|
||||||
@ -114,94 +26,3 @@ func (p *Page) Sort() {
|
|||||||
return p.PullRequests[i].Number > p.PullRequests[j].Number
|
return p.PullRequests[i].Number > p.PullRequests[j].Number
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type WatchResults []WatchResult
|
|
||||||
|
|
||||||
func (w *WatchResults) forID(ownerID int64) *WatchResults {
|
|
||||||
newResults := WatchResults{}
|
|
||||||
for _, r := range *w {
|
|
||||||
if r.OwnerID == ownerID {
|
|
||||||
newResults = append(newResults, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(newResults, func(i, j int) bool {
|
|
||||||
return newResults[i].Name < newResults[j].Name
|
|
||||||
})
|
|
||||||
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) {
|
|
||||||
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 := getData(qd, ghToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
wr.OwnerID = watch.OwnerID
|
|
||||||
wr.Name = watch.Name
|
|
||||||
wr.Repo = watch.Repo
|
|
||||||
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 {
|
|
||||||
Data Data `json:"data,omitempty"`
|
|
||||||
OwnerID int64
|
|
||||||
Name string
|
|
||||||
Repo string
|
|
||||||
}
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
34
src/Data.elm
Normal file
34
src/Data.elm
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module Data exposing (Edge, Link, Node, Watch, WatchData)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Watch =
|
||||||
|
{ owner_id : Int
|
||||||
|
, name : String
|
||||||
|
, repo : String
|
||||||
|
, result_count : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Node =
|
||||||
|
{ number : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Edge =
|
||||||
|
{ node : Node
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias WatchData =
|
||||||
|
{ search : List Edge
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Link =
|
||||||
|
{ id : Int
|
||||||
|
, owner_id : Int
|
||||||
|
, created_at : String
|
||||||
|
, name : String
|
||||||
|
, url : String
|
||||||
|
, logo_url : String
|
||||||
|
}
|
161
src/Main.elm
Normal file
161
src/Main.elm
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
module Main exposing (..)
|
||||||
|
|
||||||
|
import Browser
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (style)
|
||||||
|
import Html.Events exposing (..)
|
||||||
|
import Http
|
||||||
|
import Json.Decode exposing (Decoder, field, int, list, map3, map4, map5, maybe, string)
|
||||||
|
|
||||||
|
|
||||||
|
main =
|
||||||
|
Browser.element
|
||||||
|
{ init = init
|
||||||
|
, update = update
|
||||||
|
, subscriptions = subscriptions
|
||||||
|
, view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Model
|
||||||
|
= Failure
|
||||||
|
| Loading
|
||||||
|
| Success (List Watch)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Watch =
|
||||||
|
{ owner_id : Int
|
||||||
|
, name : String
|
||||||
|
, repo : String
|
||||||
|
, result_count : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Node =
|
||||||
|
{ number : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Edge =
|
||||||
|
{ node : Node
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias WatchData =
|
||||||
|
{ search : List Edge
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Link =
|
||||||
|
{ id : Int
|
||||||
|
, owner_id : Int
|
||||||
|
, created_at : String
|
||||||
|
, name : String
|
||||||
|
, url : String
|
||||||
|
, logo_url : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init : () -> ( Model, Cmd Msg )
|
||||||
|
init _ =
|
||||||
|
( Loading
|
||||||
|
, Cmd.batch
|
||||||
|
[ getWatches
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= MorePlease
|
||||||
|
| GetWatches (Result Http.Error (List Watch))
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
MorePlease ->
|
||||||
|
( Loading, getWatches )
|
||||||
|
|
||||||
|
GetWatches result ->
|
||||||
|
case result of
|
||||||
|
Ok watches ->
|
||||||
|
( Success watches, Cmd.none )
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
( Failure, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Model -> Sub Msg
|
||||||
|
subscriptions model =
|
||||||
|
Sub.none
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div []
|
||||||
|
[ h2 [] [ text "Watches" ]
|
||||||
|
, viewWatches model
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewWatches : Model -> Html Msg
|
||||||
|
viewWatches model =
|
||||||
|
case model of
|
||||||
|
Failure ->
|
||||||
|
div []
|
||||||
|
[ text "I can't load the watches"
|
||||||
|
, button [ onClick MorePlease ] [ text "Try agan!" ]
|
||||||
|
]
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
text "Loading..."
|
||||||
|
|
||||||
|
Success watches ->
|
||||||
|
div []
|
||||||
|
(List.map viewWatch watches)
|
||||||
|
|
||||||
|
|
||||||
|
viewLinks : Model -> Html Msg
|
||||||
|
viewLinks model =
|
||||||
|
case model of
|
||||||
|
Failure ->
|
||||||
|
div []
|
||||||
|
[ text "I can't load the links"
|
||||||
|
, button [ onClick MorePlease ] [ text "Try agan!" ]
|
||||||
|
]
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
text "Loading..."
|
||||||
|
|
||||||
|
Success links ->
|
||||||
|
text "success links..."
|
||||||
|
|
||||||
|
|
||||||
|
getWatches : Cmd Msg
|
||||||
|
getWatches =
|
||||||
|
Http.get
|
||||||
|
{ url = "/watches"
|
||||||
|
, expect = Http.expectJson GetWatches watchListDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
watchListDecoder : Decoder (List Watch)
|
||||||
|
watchListDecoder =
|
||||||
|
list watchDecoder
|
||||||
|
|
||||||
|
|
||||||
|
watchDecoder : Decoder Watch
|
||||||
|
watchDecoder =
|
||||||
|
map4 Watch
|
||||||
|
(field "owner_id" int)
|
||||||
|
(field "name" string)
|
||||||
|
(field "repo" string)
|
||||||
|
(field "result_count" int)
|
||||||
|
|
||||||
|
|
||||||
|
viewWatch : Watch -> Html Msg
|
||||||
|
viewWatch watch =
|
||||||
|
li []
|
||||||
|
[ text (String.fromInt watch.result_count ++ " " ++ watch.name)
|
||||||
|
, li [] [ text "butter" ]
|
||||||
|
]
|
195
watches.go
Normal file
195
watches.go
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 (w *WatchResults) forID(ownerID int64) *WatchResults {
|
||||||
|
newResults := WatchResults{}
|
||||||
|
for _, r := range *w {
|
||||||
|
if r.OwnerID == ownerID {
|
||||||
|
newResults = append(newResults, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(newResults, func(i, j int) bool {
|
||||||
|
return newResults[i].Name < newResults[j].Name
|
||||||
|
})
|
||||||
|
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) {
|
||||||
|
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.ResultCount = wr.Data.Search.IssueCount
|
||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user