diff --git a/internal/dis/component/server/admin/admin.go b/internal/dis/component/server/admin/admin.go
index bd56c73..a57e02e 100644
--- a/internal/dis/component/server/admin/admin.go
+++ b/internal/dis/component/server/admin/admin.go
@@ -124,13 +124,13 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
{
rebuild := admin.instanceRebuild(ctx)
- router.Handler(http.MethodGet, route+"rebuild/:slug", rebuild)
+ router.Handler(http.MethodGet, route+"instance/:slug/rebuild", rebuild)
}
{
- grants := admin.grants(ctx)
- router.Handler(http.MethodGet, route+"grants/:slug", grants)
- router.Handler(http.MethodPost, route+"grants/", grants) // NOTE(twiesing): This path is intentionally different!
+ iUsers := admin.instanceUsers(ctx)
+ router.Handler(http.MethodGet, route+"instance/:slug/users", iUsers)
+ router.Handler(http.MethodPost, route+"grants/", iUsers) // NOTE(twiesing): This path is intentionally different!
}
// add a router for the login page
diff --git a/internal/dis/component/server/admin/html/instance.html b/internal/dis/component/server/admin/html/instance.html
index 4e47d68..5161325 100644
--- a/internal/dis/component/server/admin/html/instance.html
+++ b/internal/dis/component/server/admin/html/instance.html
@@ -6,7 +6,6 @@
-
-
-
-
-
-
-
-
-
- ID
-
-
- Active
-
-
- Name
-
-
-
- Email
-
-
- Roles
-
-
- Created
-
-
- Last Login
-
-
- Action
-
-
-
-
- {{ $slug := .Instance.Slug }}
- {{ $csrf := .CSRF }}
- {{ range $index, $user := .Info.Users }}
-
-
- {{ $user.UID }}
-
-
- {{ $user.Status }}
-
-
- {{ $user.Name }}
-
-
-
- {{ if $user.Mail }}
- {{ $user.Mail }}
- {{ end }}
-
-
- {{ range $role, $unuused := $user.Roles }}
-
- {{ $role }}
-
- {{ end }}
-
-
- {{ $user.Created.Time.Format "2006-01-02T15:04:05Z07:00" }}
-
-
- {{ $user.Login.Time.Format "2006-01-02T15:04:05Z07:00" }}
-
-
-
-
-
- {{ end }}
-
-
-
-
-
-
WissKI Data
diff --git a/internal/dis/component/server/admin/html/grants.html b/internal/dis/component/server/admin/html/instance_users.html
similarity index 58%
rename from internal/dis/component/server/admin/html/grants.html
rename to internal/dis/component/server/admin/html/instance_users.html
index fa152aa..cdf65ea 100644
--- a/internal/dis/component/server/admin/html/grants.html
+++ b/internal/dis/component/server/admin/html/instance_users.html
@@ -1,5 +1,102 @@
{{ $csrf := .CSRF }}
{{ $slug := .Instance.Slug }}
+
+
+
+
Users
+
+
+ This page provides a list of users found in this Drupal instance.
+ You can click the login button to authenticate as that user.
+
+ Please be aware that these never end an already existing session.
+ When already logged into drupal, an error message Access denied may appear.
+ To prevent this, log out of the drupal instance before clicking the button.
+
+
+
+
+
+
+
+
+
+
+ ID
+
+
+ Active
+
+
+ Name
+
+
+
+ Email
+
+
+ Roles
+
+
+ Created
+
+
+ Last Login
+
+
+ Action
+
+
+
+
+ {{ $slug := .Instance.Slug }}
+ {{ $csrf := .CSRF }}
+ {{ range $index, $user := .Users }}
+
+
+ {{ $user.UID }}
+
+
+ {{ $user.Status }}
+
+
+ {{ $user.Name }}
+
+
+
+ {{ if $user.Mail }}
+ {{ $user.Mail }}
+ {{ end }}
+
+
+ {{ range $role, $unuused := $user.Roles }}
+
+ {{ $role }}
+
+ {{ end }}
+
+
+ {{ $user.Created.Time.Format "2006-01-02T15:04:05Z07:00" }}
+
+
+ {{ $user.Login.Time.Format "2006-01-02T15:04:05Z07:00" }}
+
+
+
+
+
+ {{ end }}
+
+
+
+
+
+
Grants
@@ -116,7 +213,7 @@
{{ end }}
- {{ range $unused, $drupal := .Drupals }}
-
+ {{ range $unused, $user := .Users }}
+
{{ end }}
\ No newline at end of file
diff --git a/internal/dis/component/server/admin/instance.go b/internal/dis/component/server/admin/instance.go
index 961a622..13b7ca9 100644
--- a/internal/dis/component/server/admin/instance.go
+++ b/internal/dis/component/server/admin/instance.go
@@ -40,10 +40,6 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
menuInstances,
menuInstance,
),
- templating.Actions(
- menuRebuild,
- menuGrants,
- ),
)
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ic instanceContext, funcs []templating.FlagFunc, err error) {
@@ -67,12 +63,36 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
funcs = []templating.FlagFunc{
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
- templating.ReplaceAction(menuRebuild, component.MenuItem{Title: "Rebuild", Path: template.URL("/admin/rebuild/" + slug)}),
- templating.ReplaceAction(menuGrants, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}),
-
templating.Title(instance.Slug),
+
+ admin.instanceTabs(slug, "overview"),
}
return
})
}
+
+// instanceTabs
+func (admin *Admin) instanceTabs(slug string, active string) templating.FlagFunc {
+ return func(flags templating.Flags, r *http.Request) templating.Flags {
+ flags.Tabs = []component.MenuItem{
+ {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"},
+
+ // 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"},
+ {Title: "Snapshots", Path: template.URL("/instance/" + slug + "/snapshots"), Active: active == "snapshots"},
+ {Title: "Danger Zone", Path: template.URL("/instance/" + slug + "/danger"), Active: active == "danger"},
+ */
+ }
+ return flags
+ }
+}
diff --git a/internal/dis/component/server/admin/instance_rebuild.go b/internal/dis/component/server/admin/instance_rebuild.go
index 75ec07c..ad9b226 100644
--- a/internal/dis/component/server/admin/instance_rebuild.go
+++ b/internal/dis/component/server/admin/instance_rebuild.go
@@ -83,8 +83,9 @@ func (admin *Admin) instanceRebuild(ctx context.Context) http.Handler {
// replace the menu item
funcs = []templating.FlagFunc{
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + instance.Slug)}),
- templating.ReplaceCrumb(menuRebuild, component.MenuItem{Title: "Rebuild", Path: template.URL("/admin/rebuild/" + instance.Slug)}),
+ templating.ReplaceCrumb(menuRebuild, component.MenuItem{Title: "Rebuild", Path: template.URL("/admin/instance/" + instance.Slug + "/rebuild")}),
templating.Title(instance.Slug + " - Rebuild"),
+ admin.instanceTabs(slug, "rebuild"),
}
isc.prepare(true)
diff --git a/internal/dis/component/server/admin/grants.go b/internal/dis/component/server/admin/instance_users.go
similarity index 70%
rename from internal/dis/component/server/admin/grants.go
rename to internal/dis/component/server/admin/instance_users.go
index 4743eb9..19935ff 100644
--- a/internal/dis/component/server/admin/grants.go
+++ b/internal/dis/component/server/admin/instance_users.go
@@ -12,6 +12,7 @@ import (
"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/models"
+ "github.com/FAU-CDI/wisski-distillery/internal/status"
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
"github.com/tkw1536/pkglib/httpx"
"github.com/tkw1536/pkglib/httpx/field"
@@ -21,15 +22,15 @@ import (
"golang.org/x/exp/slices"
)
-//go:embed "html/grants.html"
-var grantsHTML []byte
-var grantsTemplate = templating.Parse[grantsContext](
- "grants.html", grantsHTML, nil,
+//go:embed "html/instance_users.html"
+var instanceUsersHTML []byte
+var instanceUsersTemplate = templating.Parse[instanceUsersContext](
+ "instance_users.html", instanceUsersHTML, nil,
templating.Assets(assets.AssetsAdmin),
)
-type grantsContext struct {
+type instanceUsersContext struct {
templating.RuntimeFlags
Error string
@@ -37,13 +38,14 @@ type grantsContext struct {
instance *wisski.WissKI
Instance models.Instance // current instance
- Grants []models.Grant // grants that exist for the user
+ Users []status.DrupalUser // drupal users
+
Usernames []string // unuused distillery usernames
- Drupals []string // unusued drupal usernames
+ Grants []models.Grant // grants that exist for the user
}
-func (admin *Admin) grants(ctx context.Context) http.Handler {
- tpl := grantsTemplate.Prepare(
+func (admin *Admin) instanceUsers(ctx context.Context) http.Handler {
+ tpl := instanceUsersTemplate.Prepare(
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
@@ -53,16 +55,16 @@ func (admin *Admin) grants(ctx context.Context) http.Handler {
),
)
- return tpl.HTMLHandlerWithFlags(func(r *http.Request) (grantsContext, []templating.FlagFunc, error) {
+ return tpl.HTMLHandlerWithFlags(func(r *http.Request) (instanceUsersContext, []templating.FlagFunc, error) {
if r.Method == http.MethodGet {
- return admin.getGrants(r)
+ return admin.getGrantsUsers(r)
} else {
- return admin.postGrants(r)
+ return admin.postInstanceUsers(r)
}
})
}
-func (admin *Admin) getGrants(r *http.Request) (gc grantsContext, funcs []templating.FlagFunc, err error) {
+func (admin *Admin) getGrantsUsers(r *http.Request) (gc instanceUsersContext, funcs []templating.FlagFunc, err error) {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
funcs, err = gc.use(r, slug, admin)
@@ -70,14 +72,14 @@ func (admin *Admin) getGrants(r *http.Request) (gc grantsContext, funcs []templa
return gc, nil, err
}
- if err := gc.useGrants(r, admin); err != nil {
+ if err := gc.useUsers(r, admin); err != nil {
return gc, nil, err
}
return gc, funcs, nil
}
-func (admin *Admin) postGrants(r *http.Request) (gc grantsContext, funcs []templating.FlagFunc, err error) {
+func (admin *Admin) postInstanceUsers(r *http.Request) (gc instanceUsersContext, funcs []templating.FlagFunc, err error) {
// parse the form
if err := r.ParseForm(); err != nil {
return gc, nil, err
@@ -119,13 +121,13 @@ func (admin *Admin) postGrants(r *http.Request) (gc grantsContext, funcs []templ
}
// fetch the grants for the instance
- if err := gc.useGrants(r, admin); err != nil {
+ if err := gc.useUsers(r, admin); err != nil {
return gc, nil, err
}
return gc, funcs, nil
}
-func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (funcs []templating.FlagFunc, err error) {
+func (gc *instanceUsersContext) use(r *http.Request, slug string, admin *Admin) (funcs []templating.FlagFunc, err error) {
// find the instance itself
gc.instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
@@ -139,13 +141,14 @@ func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (funcs
// replace the functions
funcs = []templating.FlagFunc{
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
- templating.ReplaceCrumb(menuGrants, component.MenuItem{Title: "Grants", Path: template.URL("/admin/grants/" + slug)}),
- templating.Title(gc.Instance.Slug + " - Grants"),
+ templating.ReplaceCrumb(menuGrants, component.MenuItem{Title: "Users & Grants", Path: template.URL("/admin/instance/" + slug + "/users")}),
+ templating.Title(gc.Instance.Slug + " - Users & Grants"),
+ admin.instanceTabs(slug, "users"),
}
return funcs, nil
}
-func (gc *grantsContext) useGrants(r *http.Request, admin *Admin) (err error) {
+func (gc *instanceUsersContext) useUsers(r *http.Request, admin *Admin) (err error) {
gc.Grants, err = admin.dependencies.Policy.Instance(r.Context(), gc.Instance.Slug)
if err != nil {
return err
@@ -169,18 +172,14 @@ func (gc *grantsContext) useGrants(r *http.Request, admin *Admin) (err error) {
gc.Usernames = maps.Keys(userNameMap)
slices.Sort(gc.Usernames)
- // get the drupal usernames
- drupals, err := gc.instance.Users().All(r.Context(), nil)
+ // get the drupal user data
+ gc.Users, err = gc.instance.Users().All(r.Context(), nil)
if err != nil {
return err
}
-
- // and convert them to strings only
- gc.Drupals = make([]string, len(drupals))
- for i, drupal := range drupals {
- gc.Drupals[i] = string(drupal.Name)
- }
- slices.Sort(gc.Drupals)
+ slices.SortFunc(gc.Users, func(a, b status.DrupalUser) int {
+ return int(b.UID) - int(a.UID)
+ })
return nil
}