go-latestver/api.go

268 lines
7.0 KiB
Go
Raw Normal View History

2021-11-22 02:39:25 +00:00
package main
import (
"encoding/json"
"fmt"
"net/http"
2021-11-22 15:05:03 +00:00
"net/url"
"sort"
2021-11-22 02:39:25 +00:00
"strconv"
2021-11-22 15:05:03 +00:00
"strings"
"time"
2021-11-22 02:39:25 +00:00
2021-11-22 15:05:03 +00:00
"github.com/gorilla/feeds"
2021-11-22 02:39:25 +00:00
"github.com/gorilla/mux"
2021-11-22 15:05:03 +00:00
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/Luzifer/go-latestver/internal/badge"
"github.com/Luzifer/go-latestver/internal/config"
"github.com/Luzifer/go-latestver/internal/database"
"github.com/Luzifer/go-latestver/internal/fetcher"
2021-11-22 02:39:25 +00:00
)
type (
apiCatalogEntry struct {
database.CatalogEntry
database.CatalogMeta
}
)
func buildFullURL(u *url.URL, _ error) string {
2021-11-22 15:05:03 +00:00
return strings.Join([]string{
strings.TrimRight(cfg.BaseURL, "/"),
strings.TrimLeft(u.String(), "/"),
}, "/")
}
func catalogEntryToAPICatalogEntry(ce database.CatalogEntry) (apiCatalogEntry, error) {
cm, err := storage.Catalog.GetMeta(&ce)
if err != nil {
return apiCatalogEntry{}, errors.Wrap(err, "fetching catalog meta")
}
Add PR testing, fix linter errors Squashed commit of the following: commit 2a83adf6c54d6abcf6762760fd38f2505511f545 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:34:49 2021 +0100 Lint: Fix copylocks errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 418f85d504203a6968329e280ecd9cf7d2365373 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:31:38 2021 +0100 Lint: Fix gosec warnings Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 1a977875740be3c40884aa0985578721ceb4ae37 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:28:02 2021 +0100 Lint: Disable gomnd for certain cases Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 5e81cf79ba7256b321442530715a2b53de0a18e1 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:26:01 2021 +0100 Lint: fix ineffassign errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit cb14fae2dad985368e1f05d62f8e778817d01c6f Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:23:42 2021 +0100 Lint: Fix revive linter errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit b3390b8dff9b939caa4e3821a48dd848af0bfba4 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:21:35 2021 +0100 Lint: Remove unrequired dereference Signed-off-by: Knut Ahlers <knut@ahlers.me> commit f9052e6aa530c5b5017249fc6c31bdbb94252760 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:20:43 2021 +0100 Lint: Remove deadcode Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 72b88adaa25a3bb5a7af21da7ed12f08cae36573 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 02:52:27 2021 +0100 Add PR-testing Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me>
2021-12-01 02:38:52 +00:00
for _, l := range fetcher.Get(ce.Fetcher).Links(ce.FetcherConfig) {
var found bool
for _, el := range ce.Links {
if l.Name == el.Name {
found = true
break
}
}
if !found {
ce.Links = append(ce.Links, l)
}
}
return apiCatalogEntry{CatalogEntry: ce, CatalogMeta: *cm}, nil
}
func handleBadge(w http.ResponseWriter, r *http.Request) {
var (
compare = r.FormValue("compare")
vars = mux.Vars(r)
name, tag = vars["name"], vars["tag"]
)
ce, err := configFile.CatalogEntryByTag(name, tag)
if errors.Is(err, config.ErrCatalogEntryNotFound) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
cm, err := storage.Catalog.GetMeta(&ce)
if err != nil {
http.Error(w, "Unable to fetch catalog data", http.StatusInternalServerError)
return
}
color := "green"
if compare != "" && compare != cm.CurrentVersion {
color = "red"
}
svg := badge.Create(ce.Key(), cm.CurrentVersion, color)
w.Header().Add("Content-Type", "image/svg+xml")
if _, err = w.Write(svg); err != nil {
logrus.WithError(err).Error("writing SVG response")
}
}
2021-11-22 02:39:25 +00:00
func handleCatalogGet(w http.ResponseWriter, r *http.Request) {
var (
vars = mux.Vars(r)
name, tag = vars["name"], vars["tag"]
)
ce, err := configFile.CatalogEntryByTag(name, tag)
if errors.Is(err, config.ErrCatalogEntryNotFound) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
ae, err := catalogEntryToAPICatalogEntry(ce)
2021-11-22 02:39:25 +00:00
if err != nil {
logrus.WithError(err).Error("Unable to fetch catalog data")
http.Error(w, "Unable to fetch catalog data", http.StatusInternalServerError)
2021-11-22 02:39:25 +00:00
return
}
w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(ae); err != nil {
logrus.WithError(err).Error("Unable to encode catalog entry")
2021-11-22 02:39:25 +00:00
http.Error(w, "Unable to encode catalog meta", http.StatusInternalServerError)
return
}
}
func handleCatalogGetVersion(w http.ResponseWriter, r *http.Request) {
var (
vars = mux.Vars(r)
name, tag = vars["name"], vars["tag"]
)
ce, err := configFile.CatalogEntryByTag(name, tag)
if errors.Is(err, config.ErrCatalogEntryNotFound) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
cm, err := storage.Catalog.GetMeta(&ce)
if err != nil {
logrus.WithError(err).Error("Unable to fetch catalog meta")
2021-11-22 02:39:25 +00:00
http.Error(w, "Unable to fetch catalog meta", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, cm.CurrentVersion)
}
func handleCatalogList(w http.ResponseWriter, _ *http.Request) {
out := make([]apiCatalogEntry, len(configFile.Catalog))
2021-11-22 02:39:25 +00:00
for i := range configFile.Catalog {
ce := configFile.Catalog[i]
ae, err := catalogEntryToAPICatalogEntry(ce)
2021-11-22 02:39:25 +00:00
if err != nil {
logrus.WithError(err).Error("Unable to fetch catalog data")
http.Error(w, "Unable to fetch catalog data", http.StatusInternalServerError)
2021-11-22 02:39:25 +00:00
return
}
out[i] = ae
2021-11-22 02:39:25 +00:00
}
sort.Slice(out, func(i, j int) bool { return out[i].Key() < out[j].Key() })
2021-11-22 02:39:25 +00:00
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(out); err != nil {
logrus.WithError(err).Error("Unable to encode catalog entry list")
2021-11-22 02:39:25 +00:00
http.Error(w, "Unable to encode catalog meta", http.StatusInternalServerError)
return
}
}
func handleLog(w http.ResponseWriter, r *http.Request) {
2021-11-22 15:05:03 +00:00
logs, err := prepareLogForRequest(r)
switch err {
case nil:
// This is fine
case config.ErrCatalogEntryNotFound:
http.Error(w, "Not found", http.StatusNotFound)
default:
http.Error(w, "Unable to fetch logs", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(logs); err != nil {
logrus.WithError(err).Error("Unable to encode logs")
2021-11-22 15:05:03 +00:00
http.Error(w, "Unable to encode logs", http.StatusInternalServerError)
return
}
}
func handleLogFeed(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
logs, err := prepareLogForRequest(r)
switch err {
case nil:
// This is fine
case config.ErrCatalogEntryNotFound:
http.Error(w, "Not found", http.StatusNotFound)
default:
http.Error(w, "Unable to fetch logs", http.StatusInternalServerError)
return
}
feed := &feeds.Feed{
Description: "Generated by go-latestver: https://github.com/Luzifer/go-latestver",
Link: &feeds.Link{Href: buildFullURL(router.Get("catalog").URL())},
Title: "Latestver Update Log",
}
if vars["name"] != "" {
feed.Title = fmt.Sprintf("Latestver Update Log of %s:%s", vars["name"], vars["tag"])
feed.Link.Href = buildFullURL(router.Get("catalog-entry").URL("name", vars["name"], "tag", vars["tag"]))
2021-11-22 15:05:03 +00:00
}
for _, le := range logs {
feed.Add(&feeds.Item{
Created: le.Timestamp.UTC(),
Description: fmt.Sprintf("%s:%s updated to version %s from %s", le.CatalogName, le.CatalogTag, le.VersionTo, le.VersionFrom),
Id: fmt.Sprintf("%s:%s-%s", le.CatalogName, le.CatalogTag, le.Timestamp.UTC().Format(time.RFC3339)),
Link: &feeds.Link{Href: buildFullURL(router.Get("catalog-entry").URL("name", le.CatalogName, "tag", le.CatalogTag))},
2021-11-22 15:05:03 +00:00
Title: fmt.Sprintf("%s:%s %s", le.CatalogName, le.CatalogTag, le.VersionTo),
})
}
w.Header().Set("Content-Type", "application/rss+xml; charset=utf-8")
if err = feed.WriteRss(w); err != nil {
logrus.WithError(err).Error("Unable to render RSS")
2021-11-22 15:05:03 +00:00
http.Error(w, "Unable to render RSS", http.StatusInternalServerError)
return
}
}
func prepareLogForRequest(r *http.Request) ([]database.LogEntry, error) {
2021-11-22 02:39:25 +00:00
var (
vars = mux.Vars(r)
name, tag = vars["name"], vars["tag"]
num, page = 25, 0
Add PR testing, fix linter errors Squashed commit of the following: commit 2a83adf6c54d6abcf6762760fd38f2505511f545 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:34:49 2021 +0100 Lint: Fix copylocks errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 418f85d504203a6968329e280ecd9cf7d2365373 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:31:38 2021 +0100 Lint: Fix gosec warnings Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 1a977875740be3c40884aa0985578721ceb4ae37 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:28:02 2021 +0100 Lint: Disable gomnd for certain cases Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 5e81cf79ba7256b321442530715a2b53de0a18e1 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:26:01 2021 +0100 Lint: fix ineffassign errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit cb14fae2dad985368e1f05d62f8e778817d01c6f Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:23:42 2021 +0100 Lint: Fix revive linter errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit b3390b8dff9b939caa4e3821a48dd848af0bfba4 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:21:35 2021 +0100 Lint: Remove unrequired dereference Signed-off-by: Knut Ahlers <knut@ahlers.me> commit f9052e6aa530c5b5017249fc6c31bdbb94252760 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:20:43 2021 +0100 Lint: Remove deadcode Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 72b88adaa25a3bb5a7af21da7ed12f08cae36573 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 02:52:27 2021 +0100 Add PR-testing Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me>
2021-12-01 02:38:52 +00:00
ce database.CatalogEntry
2021-11-22 02:39:25 +00:00
err error
logs []database.LogEntry
)
if v, err := strconv.Atoi(r.FormValue("num")); err == nil && v > 0 && v < 100 {
num = v
}
if v, err := strconv.Atoi(r.FormValue("page")); err == nil && v >= 0 {
page = v
}
if name == "" && tag == "" {
logs, err = storage.Logs.List(num, page)
} else {
Add PR testing, fix linter errors Squashed commit of the following: commit 2a83adf6c54d6abcf6762760fd38f2505511f545 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:34:49 2021 +0100 Lint: Fix copylocks errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 418f85d504203a6968329e280ecd9cf7d2365373 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:31:38 2021 +0100 Lint: Fix gosec warnings Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 1a977875740be3c40884aa0985578721ceb4ae37 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:28:02 2021 +0100 Lint: Disable gomnd for certain cases Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 5e81cf79ba7256b321442530715a2b53de0a18e1 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:26:01 2021 +0100 Lint: fix ineffassign errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit cb14fae2dad985368e1f05d62f8e778817d01c6f Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:23:42 2021 +0100 Lint: Fix revive linter errors Signed-off-by: Knut Ahlers <knut@ahlers.me> commit b3390b8dff9b939caa4e3821a48dd848af0bfba4 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:21:35 2021 +0100 Lint: Remove unrequired dereference Signed-off-by: Knut Ahlers <knut@ahlers.me> commit f9052e6aa530c5b5017249fc6c31bdbb94252760 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 03:20:43 2021 +0100 Lint: Remove deadcode Signed-off-by: Knut Ahlers <knut@ahlers.me> commit 72b88adaa25a3bb5a7af21da7ed12f08cae36573 Author: Knut Ahlers <knut@ahlers.me> Date: Wed Dec 1 02:52:27 2021 +0100 Add PR-testing Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me>
2021-12-01 02:38:52 +00:00
ce, err = configFile.CatalogEntryByTag(name, tag)
2021-11-22 02:39:25 +00:00
if errors.Is(err, config.ErrCatalogEntryNotFound) {
2021-11-22 15:05:03 +00:00
return nil, config.ErrCatalogEntryNotFound
2021-11-22 02:39:25 +00:00
}
logs, err = storage.Logs.ListForCatalogEntry(&ce, num, page)
}
2021-11-22 15:05:03 +00:00
return logs, errors.Wrap(err, "listing log entries")
2021-11-22 02:39:25 +00:00
}