Add swagger and spec finder

This commit is contained in:
Melon 2022-09-08 17:22:22 +01:00
parent f2eea7a1e7
commit 52ef284562
Signed by: melon
GPG Key ID: B0ADD5395BCDAAB6
20 changed files with 275 additions and 36 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

View File

@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,26 @@
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: [
{url: "spec/mailbox.yml", name: "Mailbox"},
{url: "spec/mailmaster.yml", name: "Mail Master"},
{url: "spec/mailconfig.yml", name: "Mail Config"},
{url: "spec/nginxconfig.yml", name: "NGINX Config"},
],
"urls.primaryName": "NGINX Config", // 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>
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"os" "os"
"path/filepath"
"strings" "strings"
) )
@ -86,44 +87,59 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
} }
selOrg := "" selOrg := ""
myOrg := "" myOrg := ""
repoSimple := make([]struct{ Name string }, 0) repoSimple := make([]struct {
Name string
Private bool
}, 0)
selRepo := "" selRepo := ""
selModule := "" selModule := ""
selCommitTime := "" selCommitTime := ""
selCommitHash := "" selCommitHash := ""
mySpecs := make([]string, 0)
q := req.URL.Query() q := req.URL.Query()
if q.Has("org") { if q.Has("org") {
selOrg = q.Get("org") selOrg = q.Get("org")
var repos []*gitea.Repository var repos []*gitea.Repository
if selOrg == "$me" { if selOrg == "!me" {
myOrg = myUser.UserName myOrg = myUser.UserName
repos, _, err = giteaClient.ListMyRepos(gitea.ListReposOptions{ListOptions: gitea.ListOptions{Page: 0, PageSize: 100}}) repos, _, err = giteaClient.ListMyRepos(gitea.ListReposOptions{ListOptions: gitea.ListOptions{Page: 0, PageSize: 50}})
} else { } else {
myOrg = selOrg myOrg = selOrg
repos, _, err = giteaClient.ListOrgRepos(myOrg, gitea.ListOrgReposOptions{ListOptions: gitea.ListOptions{Page: 0, PageSize: 100}}) repos, _, err = giteaClient.ListOrgRepos(myOrg, gitea.ListOrgReposOptions{ListOptions: gitea.ListOptions{Page: 0, PageSize: 50}})
} }
if err != nil { if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) http.Error(rw, err.Error(), http.StatusInternalServerError)
return return
} }
repoSimple = make([]struct{ Name string }, len(repos)) repoSimple = make([]struct {
Name string
Private bool
}, len(repos))
for i, j := range repos { for i, j := range repos {
repoSimple[i] = struct{ Name string }{Name: j.Name} repoSimple[i] = struct {
Name string
Private bool
}{Name: j.Name, Private: j.Private}
} }
if q.Has("repo") { if q.Has("repo") {
selRepo = q.Get("repo") selRepo = q.Get("repo")
repo, _, err := giteaClient.GetRepo(myOrg, selRepo) repo, resp, err := giteaClient.GetRepo(myOrg, selRepo)
if err != nil { if err != nil {
if resp.StatusCode != http.StatusNotFound {
http.Error(rw, "GetRepo: "+err.Error(), http.StatusInternalServerError) http.Error(rw, "GetRepo: "+err.Error(), http.StatusInternalServerError)
return return
} }
refs, _, err := giteaClient.GetRepoRefs(myOrg, selRepo, "heads/"+repo.DefaultBranch) }
refs, resp, err := giteaClient.GetRepoRefs(myOrg, selRepo, "heads/"+repo.DefaultBranch)
if err != nil { if err != nil {
if resp.StatusCode != http.StatusNotFound {
http.Error(rw, "GetRepoRefs: "+err.Error(), http.StatusInternalServerError) http.Error(rw, "GetRepoRefs: "+err.Error(), http.StatusInternalServerError)
return return
} }
refs = make([]*gitea.Reference, 0)
}
if len(refs) == 1 { if len(refs) == 1 {
ref := refs[0] ref := refs[0]
commit, _, err := giteaClient.GetSingleCommit(myOrg, selRepo, ref.Object.SHA) commit, _, err := giteaClient.GetSingleCommit(myOrg, selRepo, ref.Object.SHA)
@ -131,18 +147,51 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
http.Error(rw, "GetSingleCommit: "+err.Error(), http.StatusInternalServerError) http.Error(rw, "GetSingleCommit: "+err.Error(), http.StatusInternalServerError)
return return
} }
if q.Has("spec") {
spec := q.Get("spec")
specFile, _, err := giteaClient.GetFile(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")
return
}
selCommitTime = commit.CommitMeta.Created.UTC().Format("20060102150405") selCommitTime = commit.CommitMeta.Created.UTC().Format("20060102150405")
selCommitHash = commit.CommitMeta.SHA[:12] selCommitHash = commit.CommitMeta.SHA[:12]
goMod, _, err := giteaClient.GetFile(myOrg, selRepo, ref.Object.SHA, "go.mod") goMod, resp, err := giteaClient.GetFile(myOrg, selRepo, ref.Object.SHA, "go.mod")
if err != nil { if err != nil {
if resp.StatusCode != http.StatusNotFound {
http.Error(rw, "go.mod: "+err.Error(), http.StatusInternalServerError) http.Error(rw, "go.mod: "+err.Error(), http.StatusInternalServerError)
return return
} }
}
goModStr := string(goMod) goModStr := string(goMod)
goModIdx := strings.Index(goModStr, "\n") goModIdx := strings.Index(goModStr, "\n")
goModLine := goModStr[:goModIdx] goModLine := goModStr[:goModIdx]
goModSpace := strings.Index(goModLine, " ") goModSpace := strings.Index(goModLine, " ")
selModule = goModLine[goModSpace+1:] selModule = goModLine[goModSpace+1:]
trees, resp, err := giteaClient.GetTrees(myOrg, selRepo, ref.Object.SHA, true)
if err != nil {
if resp.StatusCode != http.StatusNotFound {
http.Error(rw, "%s: "+err.Error(), http.StatusInternalServerError)
return
}
}
for i := range trees.Entries {
switch filepath.Ext(trees.Entries[i].Path) {
case ".yml", ".yaml":
mySpecs = append(mySpecs, trees.Entries[i].Path)
}
}
} }
} }
} }
@ -155,25 +204,34 @@ func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *util
err = tmp.Execute(rw, struct { err = tmp.Execute(rw, struct {
Username string Username string
Orgs []struct{ Name string } Orgs []struct{ Name string }
Repos []struct{ Name string } Repos []struct {
Name string
Private bool
}
MyOrg string MyOrg string
SelOrg string SelOrg string
SelRepo string
ShowOrg bool ShowOrg bool
SelModule string SelModule string
ShowRepo bool ShowRepo bool
CommitTime string CommitTime string
CommitHash string CommitHash string
ShowSpec bool
Specs []string
}{ }{
Username: myUser.UserName, Username: myUser.UserName,
Orgs: orgSimple, Orgs: orgSimple,
Repos: repoSimple, Repos: repoSimple,
MyOrg: myOrg, MyOrg: myOrg,
SelOrg: selOrg, SelOrg: selOrg,
SelRepo: selRepo,
SelModule: selModule, SelModule: selModule,
ShowOrg: myOrg != "", ShowOrg: myOrg != "",
ShowRepo: selModule != "", ShowRepo: selModule != "",
CommitTime: selCommitTime, CommitTime: selCommitTime,
CommitHash: selCommitHash, CommitHash: selCommitHash,
ShowSpec: len(mySpecs) > 0,
Specs: mySpecs,
}) })
if err != nil { if err != nil {
fmt.Println("Template execute error:", err) fmt.Println("Template execute error:", err)

View File

@ -28,7 +28,7 @@
<p>Select repository source:</p> <p>Select repository source:</p>
<ul> <ul>
<li> <li>
<a href="?org=$me">{{.Username}} (my user account)</a> <a href="?org=!me">{{.Username}} (my user account)</a>
</li> </li>
{{range .Orgs}} {{range .Orgs}}
<li> <li>
@ -43,7 +43,12 @@
<ul> <ul>
{{range .Repos}} {{range .Repos}}
<li> <li>
<a href="?org={{$.SelOrg}}&repo={{.Name}}">{{$.MyOrg}}/{{.Name}}</a> <a href="?org={{$.SelOrg}}&repo={{.Name}}">
<span>{{$.MyOrg}}/{{.Name}}</span>
{{if .Private}}
<span> (private)</span>
{{end}}
</a>
</li> </li>
{{end}} {{end}}
</ul> </ul>
@ -55,6 +60,18 @@
<p>Go import: go get {{.SelModule}}@v0.0.0-{{.CommitTime}}-{{.CommitHash}}</p> <p>Go import: go get {{.SelModule}}@v0.0.0-{{.CommitTime}}-{{.CommitHash}}</p>
</div> </div>
{{end}} {{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}}
</div> </div>
</body> </body>
</html> </html>