Add swagger injector
This commit is contained in:
parent
52ef284562
commit
7d9b926eb4
1
go.mod
1
go.mod
@ -10,6 +10,7 @@ require (
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/joho/godotenv v1.4.0
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
5
go.sum
5
go.sum
@ -120,8 +120,10 @@ github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@ -381,10 +383,13 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
6
module/gitea/assets/assets.go
Normal file
6
module/gitea/assets/assets.go
Normal file
@ -0,0 +1,6 @@
|
||||
package assets
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed swagger
|
||||
var SwaggerAssets embed.FS
|
21
module/gitea/assets/swagger/swagger-initializer-custom.js
Normal file
21
module/gitea/assets/swagger/swagger-initializer-custom.js
Normal file
@ -0,0 +1,21 @@
|
||||
window.onload = function() {
|
||||
//<editor-fold desc="Changeable Configuration Block">
|
||||
|
||||
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
|
||||
window.ui = SwaggerUIBundle({
|
||||
urls: window.loadUrls,
|
||||
"urls.primaryName": window.loadMain, // default document (if other than the first)
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
|
||||
//</editor-fold>
|
||||
};
|
@ -1,7 +1,9 @@
|
||||
package gitea
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"code.mrmelon54.com/melon/tools/module/gitea/assets"
|
||||
"code.mrmelon54.com/melon/tools/utils"
|
||||
"context"
|
||||
_ "embed"
|
||||
@ -10,15 +12,23 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"golang.org/x/oauth2"
|
||||
"gopkg.in/yaml.v3"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed pages/index.go.html
|
||||
var indexTemplate string
|
||||
var (
|
||||
//go:embed pages/index.go.html
|
||||
indexTemplate string
|
||||
//go:embed pages/swagger.go.html
|
||||
swaggerTemplate string
|
||||
returnCookie = "melon-tools-return-gitea"
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
sessionWrapper func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request)
|
||||
@ -57,6 +67,25 @@ func (m *Module) SetupModule(router *mux.Router, f func(cb func(http.ResponseWri
|
||||
}
|
||||
router.HandleFunc("/", m.getClient(m.homepage))
|
||||
router.HandleFunc("/login", m.sessionWrapper(m.loginPage))
|
||||
router.PathPrefix("/swagger").HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
p := filepath.Join("swagger", filepath.Base(req.URL.Path))
|
||||
open, err := assets.SwaggerAssets.Open(p)
|
||||
if err != nil {
|
||||
http.NotFound(rw, req)
|
||||
return
|
||||
}
|
||||
stat, err := open.Stat()
|
||||
if err != nil {
|
||||
http.NotFound(rw, req)
|
||||
return
|
||||
}
|
||||
seeker, ok := open.(io.ReadSeeker)
|
||||
if ok {
|
||||
http.ServeContent(rw, req, p, stat.ModTime(), seeker)
|
||||
} else {
|
||||
http.NotFound(rw, req)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Module) getClient(cb func(http.ResponseWriter, *http.Request, *utils.State, *gitea.Client)) func(rw http.ResponseWriter, req *http.Request) {
|
||||
@ -65,11 +94,27 @@ func (m *Module) getClient(cb func(http.ResponseWriter, *http.Request, *utils.St
|
||||
cb(rw, req, state, v)
|
||||
return
|
||||
}
|
||||
http.SetCookie(rw, &http.Cookie{
|
||||
Name: returnCookie,
|
||||
Value: req.RequestURI,
|
||||
Path: "/gitea",
|
||||
Expires: time.Now().Add(time.Hour * 1),
|
||||
MaxAge: 3600,
|
||||
})
|
||||
http.Redirect(rw, req, "/gitea/login", http.StatusTemporaryRedirect)
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *utils.State, giteaClient *gitea.Client) {
|
||||
cookie, err := req.Cookie(returnCookie)
|
||||
if err == nil {
|
||||
if cookie.Valid() != nil {
|
||||
http.SetCookie(rw, &http.Cookie{Name: returnCookie, Value: "", Path: "/gitea", Expires: time.Now().Add(-time.Hour), MaxAge: 0})
|
||||
http.Redirect(rw, req, cookie.Value, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
myUser, _, err := giteaClient.GetMyUserInfo()
|
||||
if err != nil {
|
||||
state.Del(KeyOauthClient)
|
||||
@ -95,7 +140,10 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
selModule := ""
|
||||
selCommitTime := ""
|
||||
selCommitHash := ""
|
||||
mySpecs := make([]string, 0)
|
||||
mySpecs := make([]struct {
|
||||
Name string
|
||||
Code int
|
||||
}, 0)
|
||||
|
||||
q := req.URL.Query()
|
||||
if q.Has("org") {
|
||||
@ -150,17 +198,47 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
|
||||
if q.Has("spec") {
|
||||
spec := q.Get("spec")
|
||||
specFile, _, err := giteaClient.GetFile(myOrg, selRepo, ref.Object.SHA, spec)
|
||||
if q.Has("raw") && q.Get("raw") == "true" {
|
||||
open, _, err := giteaClient.GetFile(myOrg, selRepo, ref.Object.SHA, spec)
|
||||
if err != nil {
|
||||
http.Error(rw, "OpenAPI spec raw: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.ServeContent(rw, req, spec, repo.Updated, bytes.NewReader(open))
|
||||
return
|
||||
}
|
||||
contents, _, err := giteaClient.GetContents(myOrg, selRepo, ref.Object.SHA, spec)
|
||||
if err != nil {
|
||||
http.Error(rw, "OpenAPI spec: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rw.Header().Set("Content-Type", "text/html")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
_, _ = fmt.Fprintf(rw, "Showing spec file: '%s'\n", spec)
|
||||
_, _ = fmt.Fprintf(rw, "\n<pre><code>\n")
|
||||
_, _ = rw.Write(specFile)
|
||||
_, _ = fmt.Fprintf(rw, "\n</code></pre>\n")
|
||||
|
||||
tmp, err := template.New("swagger").Parse(swaggerTemplate)
|
||||
if err != nil {
|
||||
fmt.Println("Template parse error:", err)
|
||||
return
|
||||
}
|
||||
q2 := q
|
||||
q2.Set("raw", "true")
|
||||
err = tmp.Execute(rw, struct {
|
||||
LoadUrls []struct {
|
||||
Url string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
LoadMain string
|
||||
}{
|
||||
LoadUrls: []struct {
|
||||
Url string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
}{
|
||||
{Url: "/gitea/?" + q2.Encode(), Name: contents.Name},
|
||||
},
|
||||
LoadMain: contents.Name,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("Template execute error:", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -178,6 +256,9 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
goModLine := goModStr[:goModIdx]
|
||||
goModSpace := strings.Index(goModLine, " ")
|
||||
selModule = goModLine[goModSpace+1:]
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
selModule = ""
|
||||
}
|
||||
|
||||
trees, resp, err := giteaClient.GetTrees(myOrg, selRepo, ref.Object.SHA, true)
|
||||
if err != nil {
|
||||
@ -186,10 +267,31 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
return
|
||||
}
|
||||
}
|
||||
for i := range trees.Entries {
|
||||
switch filepath.Ext(trees.Entries[i].Path) {
|
||||
for _, i := range trees.Entries {
|
||||
switch filepath.Ext(i.Path) {
|
||||
case ".yml", ".yaml":
|
||||
mySpecs = append(mySpecs, trees.Entries[i].Path)
|
||||
file, resp, err := giteaClient.GetFile(myOrg, selRepo, ref.Object.SHA, i.Path)
|
||||
if err != nil {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusForbidden, http.StatusUnauthorized, http.StatusNotFound:
|
||||
mySpecs = append(mySpecs, struct {
|
||||
Name string
|
||||
Code int
|
||||
}{Name: i.Path, Code: resp.StatusCode})
|
||||
}
|
||||
continue
|
||||
}
|
||||
a := struct {
|
||||
OpenAPI string `yaml:"openapi"`
|
||||
}{}
|
||||
err = yaml.Unmarshal(file, &a)
|
||||
if err != nil || a.OpenAPI == "" {
|
||||
continue
|
||||
}
|
||||
mySpecs = append(mySpecs, struct {
|
||||
Name string
|
||||
Code int
|
||||
}{Name: i.Path, Code: http.StatusOK})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,11 +315,14 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
SelRepo string
|
||||
ShowOrg bool
|
||||
SelModule string
|
||||
ShowRepo bool
|
||||
ShowGoMod bool
|
||||
CommitTime string
|
||||
CommitHash string
|
||||
ShowSpec bool
|
||||
Specs []string
|
||||
Specs []struct {
|
||||
Name string
|
||||
Code int
|
||||
}
|
||||
}{
|
||||
Username: myUser.UserName,
|
||||
Orgs: orgSimple,
|
||||
@ -227,7 +332,7 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
|
||||
SelRepo: selRepo,
|
||||
SelModule: selModule,
|
||||
ShowOrg: myOrg != "",
|
||||
ShowRepo: selModule != "",
|
||||
ShowGoMod: selModule != "",
|
||||
CommitTime: selCommitTime,
|
||||
CommitHash: selCommitHash,
|
||||
ShowSpec: len(mySpecs) > 0,
|
||||
|
@ -54,24 +54,28 @@
|
||||
</ul>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .ShowRepo}}
|
||||
<div>
|
||||
<div>
|
||||
{{if .ShowGoMod}}
|
||||
<p>Repository details:</p>
|
||||
<p>Go import: go get {{.SelModule}}@v0.0.0-{{.CommitTime}}-{{.CommitHash}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .ShowSpec}}
|
||||
<div>
|
||||
<p>OpenAPI specs:</p>
|
||||
<ul>
|
||||
{{range .Specs}}
|
||||
<li>
|
||||
<a href="?org={{$.SelOrg}}&repo={{$.SelRepo}}&spec={{.}}" target="_blank">{{.}}</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ShowSpec}}
|
||||
<div>
|
||||
<p>OpenAPI specs:</p>
|
||||
<ul>
|
||||
{{range .Specs}}
|
||||
<li>
|
||||
{{if not (eq .Code 200)}}
|
||||
{{.Name}} ({{.Code}})
|
||||
{{else}}
|
||||
<a href="?org={{$.SelOrg}}&repo={{$.SelRepo}}&spec={{.Name}}" target="_blank">{{.Name}}</a>
|
||||
{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
22
module/gitea/pages/swagger.go.html
Normal file
22
module/gitea/pages/swagger.go.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Swagger | Gitea | Melon Tools</title>
|
||||
<link rel="stylesheet" type="text/css" href="swagger/swagger-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="swagger/index.css" />
|
||||
<link rel="icon" type="image/png" href="swagger/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="swagger/favicon-16x16.png" sizes="16x16" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="swagger/swagger-ui-bundle.js" charset="UTF-8"></script>
|
||||
<script src="swagger/swagger-ui-standalone-preset.js" charset="UTF-8"></script>
|
||||
<script src="swagger/swagger-initializer-custom.js" charset="UTF-8"></script>
|
||||
<script>
|
||||
window.loadUrls = {{.LoadUrls}};
|
||||
window.loadMain = {{.LoadMain}};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user