panel/admin: Continue moving out information
This page further splits up the admin page into several parts.
This commit is contained in:
parent
ff92df3a87
commit
419902c59b
12 changed files with 645 additions and 271 deletions
|
|
@ -75,6 +75,10 @@ var (
|
|||
menuGrants = component.DummyMenuItem()
|
||||
menuPurge = component.DummyMenuItem()
|
||||
menuSnapshots = component.DummyMenuItem()
|
||||
menuSSH = component.DummyMenuItem()
|
||||
menuStats = component.DummyMenuItem()
|
||||
menuData = component.DummyMenuItem()
|
||||
menuDrupal = component.DummyMenuItem()
|
||||
)
|
||||
|
||||
func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http.Handler, err error) {
|
||||
|
|
@ -145,6 +149,26 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
|
|||
router.Handler(http.MethodGet, route+"instance/:slug/snapshots", snapshots)
|
||||
}
|
||||
|
||||
{
|
||||
ssh := admin.instanceSSH(ctx)
|
||||
router.Handler(http.MethodGet, route+"instance/:slug/ssh", ssh)
|
||||
}
|
||||
|
||||
{
|
||||
stats := admin.instanceStats(ctx)
|
||||
router.Handler(http.MethodGet, route+"instance/:slug/stats", stats)
|
||||
}
|
||||
|
||||
{
|
||||
data := admin.instanceData(ctx)
|
||||
router.Handler(http.MethodGet, route+"instance/:slug/data", data)
|
||||
}
|
||||
|
||||
{
|
||||
drupal := admin.instanceDrupal(ctx)
|
||||
router.Handler(http.MethodGet, route+"instance/:slug/drupal", drupal)
|
||||
}
|
||||
|
||||
// add a router for the login page
|
||||
router.Handler(http.MethodPost, route+"login", admin.loginHandler(ctx))
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
<a class="pure-button pure-button-small" href="#overview">Info & Status</a>
|
||||
<a class="pure-button pure-button-small" href="#requirements">Drupal Status Report</a>
|
||||
<a class="pure-button pure-button-small" href="#wisski">WissKI Data</a>
|
||||
<a class="pure-button pure-button-small" href="#stats">Statistics</a>
|
||||
<a class="pure-button pure-button-small" href="#ssh">SSH Keys</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -126,39 +124,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Drupal Info
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Drupal Version
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Info.DrupalVersion }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Default Theme
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Info.Theme }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
|
|
@ -288,228 +253,3 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="requirements">Drupal Status Report</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
ID
|
||||
</th>
|
||||
<th>
|
||||
Severity
|
||||
</th>
|
||||
<th>
|
||||
Title
|
||||
</th>
|
||||
<th>
|
||||
Value
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{ range $name, $req := .Info.Requirements }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $req.ID }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Level }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Title }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Value }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Description }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="wisski">WissKI Data</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Pathbuilders
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{ range $name, $xml := .Info.Pathbuilders }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $name }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="pathbuilder" data-name="{{ $name }}">{{ $xml }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
URI Prefixes
|
||||
|
||||
{{ if .Info.NoPrefixes }}
|
||||
(excluded from resolver)
|
||||
{{ end }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range $index, $prefix := .Info.Prefixes }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $prefix }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="stats">Statistics</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
Bundles
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Label
|
||||
</th>
|
||||
<th>
|
||||
Machine Name
|
||||
</th>
|
||||
<th>
|
||||
Count
|
||||
</th>
|
||||
<th>
|
||||
LastEdit
|
||||
</th>
|
||||
<th>
|
||||
MainBundle
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Info.Statistics.Bundles.Bundles }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ .Label }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .MachineName }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Count }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .LastEdit.Time.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .MainBundle }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Triplestore
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
URI
|
||||
</th>
|
||||
<th>
|
||||
Count
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Info.Statistics.Triplestore.Graphs }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ .URI }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Count }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="ssh">SSH Keys</h2>
|
||||
<table class="pure-table pure-table-bordered padding">
|
||||
<tbody>
|
||||
{{ range .Info.SSHKeys }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ . }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
|||
61
internal/dis/component/server/admin/html/instance_data.html
Normal file
61
internal/dis/component/server/admin/html/instance_data.html
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="wisski">WissKI Data</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Pathbuilders
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{ range $name, $xml := .Pathbuilders }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $name }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="pathbuilder" data-name="{{ $name }}">{{ $xml }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
URI Prefixes
|
||||
|
||||
{{ if .NoPrefixes }}
|
||||
(excluded from resolver)
|
||||
{{ end }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range $index, $prefix := .Prefixes }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $prefix }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<div class="pure-u-1-1">
|
||||
<h2 id="info">Drupal Information</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Drupal Info
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Drupal Version
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .DrupalVersion }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Default Theme
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .DefaultTheme }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="requirements">Status Report</h2>
|
||||
<p>
|
||||
This mirrors the <em>Status Report</em> page found inside drupal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
ID
|
||||
</th>
|
||||
<th>
|
||||
Severity
|
||||
</th>
|
||||
<th>
|
||||
Title
|
||||
</th>
|
||||
<th>
|
||||
Value
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{ range $name, $req := .Requirements }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $req.ID }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Level }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Title }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Value }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $req.Description }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
38
internal/dis/component/server/admin/html/instance_ssh.html
Normal file
38
internal/dis/component/server/admin/html/instance_ssh.html
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<div class="pure-u-1-1">
|
||||
<h2>SSH Access</h2>
|
||||
<p>
|
||||
Every WissKI Instance comes with access via SSH.
|
||||
Every distillery user that has administrative access to this instance can access it.
|
||||
Furthermore, every distillery administrator has access.
|
||||
</p>
|
||||
<p>
|
||||
To access the ssh server of this instance, use:
|
||||
</p>
|
||||
<code class="copy">
|
||||
<pre>ssh -J {{ .PanelDomain }}:{{ .Port }} www-data@{{ .Hostname }}</pre>
|
||||
</code>
|
||||
<p>
|
||||
For this to work, configure an ssh key on your <a href="/user/ssh">Personal SSH Page</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2>SSH Keys</h2>
|
||||
<p>
|
||||
This page lists all SSH Keys that have access to this system.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<table class="pure-table pure-table-bordered padding">
|
||||
<tbody>
|
||||
{{ range .SSHKeys }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ . }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
98
internal/dis/component/server/admin/html/instance_stats.html
Normal file
98
internal/dis/component/server/admin/html/instance_stats.html
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<div class="pure-u-1-1">
|
||||
<p>
|
||||
This page contains statistics generated by the <em>WissKI Statistics</em> module.
|
||||
If the module is not available, this page may be empty.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
Bundles
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Label
|
||||
</th>
|
||||
<th>
|
||||
Machine Name
|
||||
</th>
|
||||
<th>
|
||||
Count
|
||||
</th>
|
||||
<th>
|
||||
LastEdit
|
||||
</th>
|
||||
<th>
|
||||
MainBundle
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Statistics.Bundles.Bundles }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ .Label }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .MachineName }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Count }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .LastEdit.Time.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .MainBundle }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Triplestore
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
URI
|
||||
</th>
|
||||
<th>
|
||||
Count
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Statistics.Triplestore.Graphs }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ .URI }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Count }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -79,19 +79,12 @@ func (admin *Admin) instanceTabs(slug string, active string) templating.FlagFunc
|
|||
{Title: "Overview", Path: template.URL("/admin/instance/" + slug), Active: active == "overview"},
|
||||
{Title: "Rebuild", Path: template.URL("/admin/instance/" + slug + "/rebuild"), Active: active == "rebuild"},
|
||||
{Title: "Users & Grants", Path: template.URL("/admin/instance/" + slug + "/users"), Active: active == "users"},
|
||||
{Title: "Drupal Status", Path: template.URL("/admin/instance/" + slug + "/drupal"), Active: active == "drupal"},
|
||||
{Title: "WissKI Data", Path: template.URL("/admin/instance/" + slug + "/data"), Active: active == "data"},
|
||||
{Title: "WissKI Stats", Path: template.URL("/admin/instance/" + slug + "/stats"), Active: active == "stats"},
|
||||
{Title: "SSH", Path: template.URL("/admin/instance/" + slug + "/ssh"), Active: active == "ssh"},
|
||||
{Title: "Snapshots", Path: template.URL("/admin/instance/" + slug + "/snapshots"), Active: active == "snapshots"},
|
||||
{Title: "Purge", Path: template.URL("/admin/instance/" + slug + "/purge"), Active: active == "purge"},
|
||||
|
||||
// TODO: These still need to be migrated to their own tabs
|
||||
// Then we also need to redo the main page
|
||||
/*
|
||||
{Title: "Status", Path: template.URL("/instance/" + slug + "/status"), Active: active == "status"},
|
||||
{Title: "Database", Path: template.URL("/instance/" + slug + "/database"), Active: active == "database"},
|
||||
{Title: "Drupal", Path: template.URL("/instance/" + slug + "/drupal"), Active: active == "drupal"},
|
||||
{Title: "Users & Grants", Path: template.URL("/instance/" + slug + "/users"), Active: active == "users"},
|
||||
{Title: "Stats", Path: template.URL("/instance/" + slug + "/stats"), Active: active == "stats"},
|
||||
{Title: "SSH", Path: template.URL("/instance/" + slug + "/ssh"), Active: active == "ssh"},
|
||||
*/
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
|
|
|||
77
internal/dis/component/server/admin/instance_data.go
Normal file
77
internal/dis/component/server/admin/instance_data.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||
"github.com/tkw1536/pkglib/httpx"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
//go:embed "html/instance_data.html"
|
||||
var instanceDataHTML []byte
|
||||
var instanceDataTemplate = templating.Parse[instanceDataContext](
|
||||
"instance_data.html", instanceDataHTML, nil,
|
||||
|
||||
templating.Assets(assets.AssetsAdmin),
|
||||
)
|
||||
|
||||
type instanceDataContext struct {
|
||||
templating.RuntimeFlags
|
||||
|
||||
Instance *wisski.WissKI
|
||||
Pathbuilders map[string]string
|
||||
NoPrefixes bool
|
||||
Prefixes []string
|
||||
}
|
||||
|
||||
func (admin *Admin) instanceData(ctx context.Context) http.Handler {
|
||||
tpl := instanceDataTemplate.Prepare(
|
||||
admin.dependencies.Templating,
|
||||
templating.Crumbs(
|
||||
menuAdmin,
|
||||
menuInstances,
|
||||
menuInstance,
|
||||
menuData,
|
||||
),
|
||||
)
|
||||
|
||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceDataContext, funcs []templating.FlagFunc, err error) {
|
||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||
|
||||
// setup the context with just the instance
|
||||
ctx.Instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrNotFound
|
||||
}
|
||||
|
||||
server := ctx.Instance.PHP().NewServer()
|
||||
defer server.Close()
|
||||
|
||||
ctx.Pathbuilders, err = ctx.Instance.Pathbuilder().GetAll(r.Context(), server)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
prefixes := ctx.Instance.Prefixes()
|
||||
ctx.NoPrefixes = prefixes.NoPrefix()
|
||||
ctx.Prefixes, err = prefixes.All(r.Context(), server)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
return ctx, []templating.FlagFunc{
|
||||
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + ctx.Instance.Slug)}),
|
||||
templating.ReplaceCrumb(menuData, component.MenuItem{Title: "SSH", Path: template.URL("/admin/instance/" + ctx.Instance.Slug + "/data")}),
|
||||
templating.Title(ctx.Instance.Slug + " - Data"),
|
||||
admin.instanceTabs(slug, "data"),
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
86
internal/dis/component/server/admin/instance_drupal.go
Normal file
86
internal/dis/component/server/admin/instance_drupal.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||
"github.com/tkw1536/pkglib/httpx"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
//go:embed "html/instance_drupal.html"
|
||||
var instanceDrupalHTML []byte
|
||||
var instanceDrupalTemplate = templating.Parse[instanceDrupalContext](
|
||||
"instance_drupal.html", instanceDrupalHTML, nil,
|
||||
|
||||
templating.Assets(assets.AssetsAdmin),
|
||||
)
|
||||
|
||||
type instanceDrupalContext struct {
|
||||
templating.RuntimeFlags
|
||||
|
||||
Instance *wisski.WissKI
|
||||
|
||||
DrupalVersion string
|
||||
DefaultTheme string
|
||||
|
||||
Requirements []status.Requirement
|
||||
}
|
||||
|
||||
func (admin *Admin) instanceDrupal(ctx context.Context) http.Handler {
|
||||
tpl := instanceDrupalTemplate.Prepare(
|
||||
admin.dependencies.Templating,
|
||||
templating.Crumbs(
|
||||
menuAdmin,
|
||||
menuInstances,
|
||||
menuInstance,
|
||||
menuDrupal,
|
||||
),
|
||||
)
|
||||
|
||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceDrupalContext, funcs []templating.FlagFunc, err error) {
|
||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||
|
||||
// setup the context with just the instance
|
||||
ctx.Instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrNotFound
|
||||
}
|
||||
|
||||
server := ctx.Instance.PHP().NewServer()
|
||||
defer server.Close()
|
||||
|
||||
// get the requirements
|
||||
ctx.Requirements, err = ctx.Instance.Requirements().Get(r.Context(), server)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
// get the drupal version
|
||||
ctx.DrupalVersion, err = ctx.Instance.Version().Get(r.Context(), server)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
// get the default theme
|
||||
ctx.DefaultTheme, err = ctx.Instance.Theme().Get(r.Context(), server)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
return ctx, []templating.FlagFunc{
|
||||
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + ctx.Instance.Slug)}),
|
||||
templating.ReplaceCrumb(menuDrupal, component.MenuItem{Title: "Drupal Status", Path: template.URL("/admin/instance/" + ctx.Instance.Slug + "/drupal")}),
|
||||
templating.Title(ctx.Instance.Slug + " - Drupal Status"),
|
||||
admin.instanceTabs(slug, "drupal"),
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
80
internal/dis/component/server/admin/instance_ssh.go
Normal file
80
internal/dis/component/server/admin/instance_ssh.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||
"github.com/tkw1536/pkglib/httpx"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
//go:embed "html/instance_ssh.html"
|
||||
var instanceSSHHTML []byte
|
||||
var instanceSSHTemplate = templating.Parse[instanceSSHContext](
|
||||
"instance_ssh.html", instanceSSHHTML, nil,
|
||||
|
||||
templating.Assets(assets.AssetsAdmin),
|
||||
)
|
||||
|
||||
type instanceSSHContext struct {
|
||||
templating.RuntimeFlags
|
||||
|
||||
Instance *wisski.WissKI
|
||||
SSHKeys []string
|
||||
|
||||
Hostname string
|
||||
PanelDomain string
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (admin *Admin) instanceSSH(ctx context.Context) http.Handler {
|
||||
tpl := instanceSSHTemplate.Prepare(
|
||||
admin.dependencies.Templating,
|
||||
templating.Crumbs(
|
||||
menuAdmin,
|
||||
menuInstances,
|
||||
menuInstance,
|
||||
menuSSH,
|
||||
),
|
||||
)
|
||||
|
||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceSSHContext, funcs []templating.FlagFunc, err error) {
|
||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||
|
||||
// setup the context with just the instance
|
||||
ctx.Instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrNotFound
|
||||
}
|
||||
|
||||
ctx.Hostname = ctx.Instance.Domain()
|
||||
ctx.PanelDomain = admin.Config.HTTP.PanelDomain()
|
||||
ctx.Port = admin.Config.Listen.SSHPort
|
||||
|
||||
keys, err := ctx.Instance.SSH().Keys(r.Context())
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
ctx.SSHKeys = make([]string, len(keys))
|
||||
for i, key := range keys {
|
||||
ctx.SSHKeys[i] = string(gossh.MarshalAuthorizedKey(key))
|
||||
}
|
||||
|
||||
return ctx, []templating.FlagFunc{
|
||||
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + ctx.Instance.Slug)}),
|
||||
templating.ReplaceCrumb(menuSSH, component.MenuItem{Title: "SSH", Path: template.URL("/admin/instance/" + ctx.Instance.Slug + "/ssh")}),
|
||||
templating.Title(ctx.Instance.Slug + " - SSH"),
|
||||
admin.instanceTabs(slug, "ssh"),
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
67
internal/dis/component/server/admin/instance_stats.go
Normal file
67
internal/dis/component/server/admin/instance_stats.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/status"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||
"github.com/tkw1536/pkglib/httpx"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
//go:embed "html/instance_stats.html"
|
||||
var instanceStatsHTML []byte
|
||||
var instanceStatsTemplate = templating.Parse[instanceStatsContext](
|
||||
"instance_stats.html", instanceStatsHTML, nil,
|
||||
|
||||
templating.Assets(assets.AssetsAdmin),
|
||||
)
|
||||
|
||||
type instanceStatsContext struct {
|
||||
templating.RuntimeFlags
|
||||
|
||||
Instance *wisski.WissKI
|
||||
Statistics status.Statistics
|
||||
}
|
||||
|
||||
func (admin *Admin) instanceStats(ctx context.Context) http.Handler {
|
||||
tpl := instanceStatsTemplate.Prepare(
|
||||
admin.dependencies.Templating,
|
||||
templating.Crumbs(
|
||||
menuAdmin,
|
||||
menuInstances,
|
||||
menuInstance,
|
||||
menuStats,
|
||||
),
|
||||
)
|
||||
|
||||
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ctx instanceStatsContext, funcs []templating.FlagFunc, err error) {
|
||||
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
|
||||
|
||||
// setup the context with just the instance
|
||||
ctx.Instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrNotFound
|
||||
}
|
||||
|
||||
// read statistics
|
||||
ctx.Statistics, err = ctx.Instance.Stats().Get(r.Context(), nil)
|
||||
if err != nil {
|
||||
return ctx, nil, httpx.ErrInternalServerError
|
||||
}
|
||||
|
||||
return ctx, []templating.FlagFunc{
|
||||
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + ctx.Instance.Slug)}),
|
||||
templating.ReplaceCrumb(menuStats, component.MenuItem{Title: "SSH", Path: template.URL("/admin/instance/" + ctx.Instance.Slug + "/stats")}),
|
||||
templating.Title(ctx.Instance.Slug + " - Stats"),
|
||||
admin.instanceTabs(slug, "stats"),
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
|
@ -122,6 +122,22 @@ func (wisski *WissKI) Blocks() *extras.Blocks {
|
|||
return export[*extras.Blocks](wisski)
|
||||
}
|
||||
|
||||
func (wisski *WissKI) Stats() *extras.Stats {
|
||||
return export[*extras.Stats](wisski)
|
||||
}
|
||||
|
||||
func (wisski *WissKI) Requirements() *extras.Requirements {
|
||||
return export[*extras.Requirements](wisski)
|
||||
}
|
||||
|
||||
func (wisski *WissKI) Version() *extras.Version {
|
||||
return export[*extras.Version](wisski)
|
||||
}
|
||||
|
||||
func (wisski *WissKI) Theme() *extras.Theme {
|
||||
return export[*extras.Theme](wisski)
|
||||
}
|
||||
|
||||
//
|
||||
// All components
|
||||
// THESE SHOULD NEVER BE CALLED DIRECTLY
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue