Update to new goprogram version

This commit is contained in:
Tom Wiesing 2023-11-01 22:01:24 +01:00
parent 7bd9570bc0
commit 873fdcd5c2
No known key found for this signature in database
106 changed files with 478 additions and 825 deletions

View file

@ -1,75 +1 @@
package dis
import (
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/tkw1536/pkglib/collection"
"github.com/tkw1536/pkglib/lifetime"
)
//
// ==== init ====
//
func (dis *Distillery) init() {
dis.lifetimeInit.Do(func() {
dis.lifetime.Init = component.Init
lifetime.RegisterGroup[component.Backupable](&dis.lifetime)
lifetime.RegisterGroup[component.Snapshotable](&dis.lifetime)
lifetime.RegisterGroup[component.DistilleryFetcher](&dis.lifetime)
lifetime.RegisterGroup[component.Installable](&dis.lifetime)
lifetime.RegisterGroup[component.Provisionable](&dis.lifetime)
lifetime.RegisterGroup[component.Routeable](&dis.lifetime)
lifetime.RegisterGroup[component.Cronable](&dis.lifetime)
lifetime.RegisterGroup[component.UserDeleteHook](&dis.lifetime)
lifetime.RegisterGroup[component.Table](&dis.lifetime)
lifetime.RegisterGroup[component.Menuable](&dis.lifetime)
lifetime.RegisterGroup[component.ScopeProvider](&dis.lifetime)
})
}
//
// ==== registration ====
//
// manual initializes a component from the provided distillery.
func manual[C component.Component](init func(component C)) initFunc {
return func(context ctx) component.Component {
return lifetime.Make(context, init)
}
}
// use is like r, but does not provided additional initialization
func auto[C component.Component](context ctx) component.Component {
return lifetime.Make[component.Component, C](context, nil)
}
// register returns all components of the distillery
func (dis *Distillery) register(context ctx) []component.Component {
return collection.MapSlice(
dis.allComponents(),
func(f initFunc) component.Component {
return f(context)
},
)
}
// ctx is a context for component initialization
type ctx = *lifetime.InjectorContext[component.Component]
//
// ==== export ====
//
// export is a convenience function to export a single component
func export[C component.Component](dis *Distillery) C {
dis.init()
return lifetime.ExportComponent[component.Component, component.Still, C](&dis.lifetime, dis.Still, dis.register)
}
func exportAll[C component.Component](dis *Distillery) []C {
dis.init()
return lifetime.ExportComponents[component.Component, component.Still, C](&dis.lifetime, dis.Still, dis.register)
}
type initFunc = func(context ctx) component.Component

View file

@ -10,7 +10,7 @@ import (
type API struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -38,12 +38,12 @@ type AuthInfo struct {
func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
return &Handler[AuthInfo]{
Config: a.Config,
Auth: a.Dependencies.Auth,
Auth: a.dependencies.Auth,
Methods: []string{"GET"},
Handler: func(s string, r *http.Request) (ai AuthInfo, err error) {
session, _, err := a.Dependencies.Auth.SessionOf(r)
session, _, err := a.dependencies.Auth.SessionOf(r)
ai.User = session.Username()
ai.Token = session.Token
return

View file

@ -15,7 +15,7 @@ import (
type Auth struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
UserDeleteHooks []component.UserDeleteHook
Templating *templating.Templating

View file

@ -17,7 +17,7 @@ import (
type Next struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
Policy *policy.Policy
Instances *instances.Instances
@ -31,13 +31,13 @@ var (
func (next *Next) Routes() component.Routes {
return component.Routes{
Prefix: "/next/",
Decorator: next.Dependencies.Auth.Require(true, scopes.ScopeUserValid, nil),
Decorator: next.dependencies.Auth.Require(true, scopes.ScopeUserValid, nil),
}
}
// Next returns a url that will forward authorized users to the given slug and path
func (next *Next) Next(context context.Context, slug, path string) (string, error) {
wisski, err := next.Dependencies.Instances.WissKI(context, slug)
wisski, err := next.dependencies.Instances.WissKI(context, slug)
if err != nil {
return "", err
}
@ -62,7 +62,7 @@ func (next *Next) getInstance(r *http.Request) (wisski *wisski.WissKI, path stri
}
// fetch the instance from the database
wisski, err = next.Dependencies.Instances.WissKI(r.Context(), slug)
wisski, err = next.dependencies.Instances.WissKI(r.Context(), slug)
if err != nil {
return nil, "", err
}
@ -80,13 +80,13 @@ func (next *Next) HandleRoute(ctx context.Context, path string) (http.Handler, e
}
// get the user
user, _, err := next.Dependencies.Auth.SessionOf(r)
user, _, err := next.dependencies.Auth.SessionOf(r)
if err != nil {
return "", 0, err
}
// check if they have a grant
grant, err := next.Dependencies.Policy.Has(r.Context(), user.User.User, instance.Slug)
grant, err := next.dependencies.Policy.Has(r.Context(), user.User.User, instance.Slug)
if err == policy.ErrNoAccess {
return "", 0, httpx.ErrForbidden
}

View file

@ -21,7 +21,7 @@ import (
type UserPanel struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
Templating *templating.Templating
Policy *policy.Policy
@ -42,14 +42,14 @@ func (panel *UserPanel) Routes() component.Routes {
return component.Routes{
Prefix: "/user/",
CSRF: true,
Decorator: panel.Dependencies.Auth.Require(false, scopes.ScopeUserValid, nil),
Decorator: panel.dependencies.Auth.Require(false, scopes.ScopeUserValid, nil),
}
}
func (panel *UserPanel) Menu(r *http.Request) []component.MenuItem {
title := "Login"
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if user != nil && err == nil {
title = user.User.User
}
@ -137,7 +137,7 @@ func (panel *UserPanel) HandleRoute(ctx context.Context, route string) (http.Han
}
// ensure that the user is logged in!
return panel.Dependencies.Auth.Protect(router, false, scopes.ScopeUserValid, nil), nil
return panel.dependencies.Auth.Protect(router, false, scopes.ScopeUserValid, nil), nil
}
type userFormContext struct {
@ -158,7 +158,7 @@ func (panel *UserPanel) UserFormContext(tpl *templating.Template[userFormContext
return func(ctx httpx.FormContext, r *http.Request) any {
uctx := userFormContext{FormContext: ctx}
if user, err := panel.Dependencies.Auth.UserOfSession(r); err == nil {
if user, err := panel.dependencies.Auth.UserOfSession(r); err == nil {
uctx.User = &user.User
}
return tpl.Context(r, uctx, funcs...)

View file

@ -32,7 +32,7 @@ var (
)
func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
tpl := passwordTemplate.Prepare(panel.Dependencies.Templating)
tpl := passwordTemplate.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
Fields: []field.Field{
@ -53,7 +53,7 @@ func (panel *UserPanel) routePassword(ctx context.Context) http.Handler {
return struct{}{}, errPasswordsNotIdentical
}
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
return struct{}{}, err
}

View file

@ -46,7 +46,7 @@ type SSHTemplateContext struct {
func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
tpl := sshTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuSSH,
@ -57,7 +57,7 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
)
return tpl.HTMLHandler(func(r *http.Request) (sc SSHTemplateContext, err error) {
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
return sc, err
}
@ -66,7 +66,7 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
sc.Port = panel.Config.Listen.SSHPort
// pick the first domain that the user has access to as an example
grants, err := panel.Dependencies.Policy.User(r.Context(), user.User.User)
grants, err := panel.dependencies.Policy.User(r.Context(), user.User.User)
if err != nil && len(grants) > 0 {
sc.Slug = grants[0].Slug
} else {
@ -74,12 +74,12 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
}
sc.Hostname = panel.Config.HTTP.HostFromSlug(sc.Slug)
sc.Keys, err = panel.Dependencies.Keys.Keys(r.Context(), user.User.User)
sc.Keys, err = panel.dependencies.Keys.Keys(r.Context(), user.User.User)
if err != nil {
return sc, err
}
sc.Services = panel.Dependencies.SSH2.Intercepts()
sc.Services = panel.dependencies.SSH2.Intercepts()
return sc, nil
})
@ -100,7 +100,7 @@ func (panel *UserPanel) sshDeleteRoute(ctx context.Context) http.Handler {
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
}
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
logger.Err(err).Str("action", "delete ssh key").Msg("failed to get current user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
@ -114,7 +114,7 @@ func (panel *UserPanel) sshDeleteRoute(ctx context.Context) http.Handler {
return
}
if err := panel.Dependencies.Keys.Remove(r.Context(), user.User.User, key); err != nil {
if err := panel.dependencies.Keys.Remove(r.Context(), user.User.User, key); err != nil {
logger.Err(err).Str("action", "delete ssh key").Msg("failed to delete key")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
@ -140,7 +140,7 @@ type addKeyResult struct {
func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
tpl := sshAddTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuSSH,
@ -159,7 +159,7 @@ func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
RenderTemplateContext: templating.FormTemplateContext(tpl),
Validate: func(r *http.Request, values map[string]string) (ak addKeyResult, err error) {
ak.User, err = panel.Dependencies.Auth.UserOfSession(r)
ak.User, err = panel.dependencies.Auth.UserOfSession(r)
if err != nil || ak.User == nil {
return ak, errInvalidUser
}
@ -181,7 +181,7 @@ func (panel *UserPanel) sshAddRoute(ctx context.Context) http.Handler {
RenderSuccess: func(ak addKeyResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
// add the key to the user
if err := panel.Dependencies.Keys.Add(r.Context(), ak.User.User.User, ak.Comment, ak.Key); err != nil {
if err := panel.dependencies.Keys.Add(r.Context(), ak.User.User.User, ak.Comment, ak.Key); err != nil {
return errAddKey
}
// everything went fine, redirect the user back to the user page!

View file

@ -34,7 +34,7 @@ type TokenTemplateContext struct {
func (panel *UserPanel) tokensRoute(ctx context.Context) http.Handler {
tpl := tokensTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
@ -46,7 +46,7 @@ func (panel *UserPanel) tokensRoute(ctx context.Context) http.Handler {
return tpl.HTMLHandler(func(r *http.Request) (tc TokenTemplateContext, err error) {
// list the user
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil || user == nil {
return tc, err
}
@ -54,7 +54,7 @@ func (panel *UserPanel) tokensRoute(ctx context.Context) http.Handler {
tc.Domain = template.URL(panel.Config.HTTP.JoinPath().String())
// get the tokens
tc.Tokens, err = panel.Dependencies.Tokens.Tokens(r.Context(), user.User.User)
tc.Tokens, err = panel.dependencies.Tokens.Tokens(r.Context(), user.User.User)
return tc, err
})
}
@ -67,7 +67,7 @@ func (panel *UserPanel) tokensDeleteRoute(ctx context.Context) http.Handler {
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
}
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
logger.Err(err).Str("action", "delete token").Msg("failed to get current user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
@ -81,7 +81,7 @@ func (panel *UserPanel) tokensDeleteRoute(ctx context.Context) http.Handler {
return
}
if err := panel.Dependencies.Tokens.Remove(r.Context(), user.User.User, id); err != nil {
if err := panel.dependencies.Tokens.Remove(r.Context(), user.User.User, id); err != nil {
logger.Err(err).Str("action", "delete token").Msg("failed to delete token")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
@ -122,7 +122,7 @@ type TokenCreateContext struct {
func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
tplForm := tokensAddTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
@ -131,7 +131,7 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
)
tplDone := tokenCreateTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
@ -149,7 +149,7 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
RenderTemplateContext: templating.FormTemplateContext(tplForm),
Validate: func(r *http.Request, values map[string]string) (at addTokenResult, err error) {
at.User, err = panel.Dependencies.Auth.UserOfSession(r)
at.User, err = panel.dependencies.Auth.UserOfSession(r)
if err != nil || at.User == nil {
return at, errInvalidUser
}
@ -166,7 +166,7 @@ func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
RenderSuccess: func(at addTokenResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
// add the key to the user
tok, err := panel.Dependencies.Tokens.Add(r.Context(), at.User.User.User, at.Description, at.Scopes)
tok, err := panel.dependencies.Tokens.Add(r.Context(), at.User.User.User, at.Description, at.Scopes)
if err != nil {
return err
}

View file

@ -24,7 +24,7 @@ var totpEnable = templating.Parse[userFormContext](
)
func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
tpl := totpEnable.Prepare(panel.Dependencies.Templating)
tpl := totpEnable.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
Fields: []field.Field{
@ -33,7 +33,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
FieldTemplate: field.PureCSSFieldTemplate,
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
},
@ -43,7 +43,7 @@ func (panel *UserPanel) routeTOTPEnable(ctx context.Context) http.Handler {
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
password := values["password"]
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
return struct{}{}, err
}
@ -90,7 +90,7 @@ type totpEnrollContext struct {
func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
tpl := totpEnrollTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTOTPEnable,
@ -105,11 +105,11 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
FieldTemplate: field.PureCSSFieldTemplate,
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
return struct{}{}, err == nil && user != nil && user.IsTOTPEnabled()
},
RenderTemplateContext: func(context httpx.FormContext, r *http.Request) any {
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
ctx := totpEnrollContext{
userFormContext: userFormContext{
@ -136,7 +136,7 @@ func (panel *UserPanel) routeTOTPEnroll(ctx context.Context) http.Handler {
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
password, otp := values["password"], values["otp"]
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
return struct{}{}, err
}
@ -174,7 +174,7 @@ var totpDisableTemplate = templating.Parse[userFormContext](
)
func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
tpl := totpDisableTemplate.Prepare(panel.Dependencies.Templating)
tpl := totpDisableTemplate.Prepare(panel.dependencies.Templating)
return &httpx.Form[struct{}]{
Fields: []field.Field{
@ -184,7 +184,7 @@ func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
FieldTemplate: field.PureCSSFieldTemplate,
SkipForm: func(r *http.Request) (data struct{}, skip bool) {
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
return struct{}{}, err == nil && user != nil && !user.IsTOTPEnabled()
},
RenderTemplate: tpl.Template(),
@ -193,7 +193,7 @@ func (panel *UserPanel) routeTOTPDisable(ctx context.Context) http.Handler {
Validate: func(r *http.Request, values map[string]string) (struct{}, error) {
password, otp := values["password"], values["otp"]
user, err := panel.Dependencies.Auth.UserOfSession(r)
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil {
return struct{}{}, err
}

View file

@ -52,7 +52,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
}
tpl := userTemplate.Prepare(
panel.Dependencies.Templating,
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
),
@ -61,12 +61,12 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (uc userContext, funcs []templating.FlagFunc, err error) {
// find the user
uc.AuthUser, err = panel.Dependencies.Auth.UserOfSession(r)
uc.AuthUser, err = panel.dependencies.Auth.UserOfSession(r)
if err != nil || uc.AuthUser == nil {
return uc, nil, err
}
uc.ShowAdminURLs = panel.Dependencies.Auth.CheckScope("", scopes.ScopeUserAdmin, r) == nil
uc.ShowAdminURLs = panel.dependencies.Auth.CheckScope("", scopes.ScopeUserAdmin, r) == nil
// replace the totp action in the menu
var totpAction component.MenuItem
@ -81,7 +81,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
}
// find the grants
grants, err := panel.Dependencies.Policy.User(r.Context(), uc.AuthUser.User.User)
grants, err := panel.dependencies.Policy.User(r.Context(), uc.AuthUser.User.User)
if err != nil {
return uc, nil, err
}
@ -90,7 +90,7 @@ func (panel *UserPanel) routeUser(ctx context.Context) http.Handler {
for i, grant := range grants {
uc.Grants[i].Grant = grant
url, err := panel.Dependencies.Next.Next(r.Context(), grant.Slug, "/")
url, err := panel.dependencies.Next.Next(r.Context(), grant.Slug, "/")
if err != nil {
return uc, nil, err
}

View file

@ -27,7 +27,7 @@ func (policy *Policy) Set(ctx context.Context, grant models.Grant) error {
// check that the referenced user exists!
{
_, err := policy.Dependencies.Auth.User(ctx, grant.User)
_, err := policy.dependencies.Auth.User(ctx, grant.User)
if err != nil {
return err
}

View file

@ -14,7 +14,7 @@ import (
type Policy struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
Auth *auth.Auth
}
@ -29,10 +29,10 @@ var (
func (pol *Policy) TableInfo() component.TableInfo {
return component.TableInfo{
Name: models.GrantTable,
Model: reflectx.MakeType[models.Grant](),
Model: reflectx.TypeFor[models.Grant](),
}
}
func (pol *Policy) table(ctx context.Context) (*gorm.DB, error) {
return pol.Dependencies.SQL.QueryTable(ctx, pol)
return pol.dependencies.SQL.QueryTable(ctx, pol)
}

View file

@ -26,8 +26,8 @@ func (auth *Auth) Scopes() map[component.Scope]component.ScopeInfo {
// getScopeMap return a (cached version of) all scopes
func (auth *Auth) getScopeMap() map[component.Scope]scopeMapEntry {
return auth.scopeMap.Get(func() map[component.Scope]scopeMapEntry {
mp := make(map[component.Scope]scopeMapEntry, len(auth.Dependencies.ScopeProviders))
for _, p := range auth.Dependencies.ScopeProviders {
mp := make(map[component.Scope]scopeMapEntry, len(auth.dependencies.ScopeProviders))
for _, p := range auth.dependencies.ScopeProviders {
info := p.Scope()
mp[info.Scope] = scopeMapEntry{
Provider: p,

View file

@ -9,7 +9,7 @@ import (
type AdminLoggedIn struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -32,6 +32,6 @@ func (*AdminLoggedIn) Scope() component.ScopeInfo {
}
func (al *AdminLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
_, user, err := al.Dependencies.Auth.SessionOf(r)
_, user, err := al.dependencies.Auth.SessionOf(r)
return user != nil && user.IsAdmin() && user.IsTOTPEnabled(), err
}

View file

@ -9,7 +9,7 @@ import (
type ListInstancesScope struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -32,6 +32,6 @@ func (*ListInstancesScope) Scope() component.ScopeInfo {
}
func (lis *ListInstancesScope) HasScope(param string, r *http.Request) (bool, error) {
_, user, err := lis.Dependencies.Auth.SessionOf(r)
_, user, err := lis.dependencies.Auth.SessionOf(r)
return user != nil, err
}

View file

@ -9,7 +9,7 @@ import (
type Never struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}

View file

@ -9,7 +9,7 @@ import (
type ListNewsScope struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -32,6 +32,6 @@ func (*ListNewsScope) Scope() component.ScopeInfo {
}
func (lns *ListNewsScope) HasScope(param string, r *http.Request) (bool, error) {
_, user, err := lns.Dependencies.Auth.SessionOf(r)
_, user, err := lns.dependencies.Auth.SessionOf(r)
return user != nil, err
}

View file

@ -9,7 +9,7 @@ import (
type ResolverScope struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -32,6 +32,6 @@ func (*ResolverScope) Scope() component.ScopeInfo {
}
func (rs *ResolverScope) HasScope(param string, r *http.Request) (bool, error) {
_, user, err := rs.Dependencies.Auth.SessionOf(r)
_, user, err := rs.dependencies.Auth.SessionOf(r)
return user != nil, err
}

View file

@ -9,7 +9,7 @@ import (
type UserLoggedIn struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -31,6 +31,6 @@ func (*UserLoggedIn) Scope() component.ScopeInfo {
}
func (iu *UserLoggedIn) HasScope(param string, r *http.Request) (bool, error) {
_, user, err := iu.Dependencies.Auth.SessionOf(r)
_, user, err := iu.dependencies.Auth.SessionOf(r)
return user != nil, err
}

View file

@ -52,7 +52,7 @@ func (auth *Auth) SessionOf(r *http.Request) (session component.SessionInfo, use
// To check the user of a token or session, use SessionOf.
func (auth *Auth) UserOfToken(r *http.Request) (user *AuthUser, err error) {
// get the token object
token, err := auth.Dependencies.Tokens.TokenOf(r)
token, err := auth.dependencies.Tokens.TokenOf(r)
if token == nil {
return nil, err
}
@ -173,7 +173,7 @@ var errLoginFailed = errors.New("login failed")
// authLogin implements a view to login a user
func (auth *Auth) authLogin(ctx context.Context) http.Handler {
tpl := loginTemplate.Prepare(
auth.Dependencies.Templating,
auth.dependencies.Templating,
func(flags templating.Flags, r *http.Request) templating.Flags {
flags.Crumbs = []component.MenuItem{
{Title: "Login", Path: template.URL(r.URL.RequestURI())},

View file

@ -17,7 +17,7 @@ import (
type Tokens struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
}
}
@ -30,12 +30,12 @@ var (
func (tok *Tokens) TableInfo() component.TableInfo {
return component.TableInfo{
Name: models.TokensTable,
Model: reflectx.MakeType[models.Token](),
Model: reflectx.TypeFor[models.Token](),
}
}
func (tok *Tokens) table(ctx context.Context) (*gorm.DB, error) {
return tok.Dependencies.SQL.QueryTable(ctx, tok)
return tok.dependencies.SQL.QueryTable(ctx, tok)
}
func (tok *Tokens) OnUserDelete(ctx context.Context, user *models.User) error {

View file

@ -25,14 +25,14 @@ var ErrUserNotFound = errors.New("user not found")
func (auth *Auth) TableInfo() component.TableInfo {
return component.TableInfo{
Name: models.UserTable,
Model: reflectx.MakeType[models.User](),
Model: reflectx.TypeFor[models.User](),
}
}
// Users returns all users in the database
func (auth *Auth) Users(ctx context.Context) (users []*AuthUser, err error) {
// query the user table
table, err := auth.Dependencies.SQL.QueryTable(ctx, auth)
table, err := auth.dependencies.SQL.QueryTable(ctx, auth)
if err != nil {
return
}
@ -65,7 +65,7 @@ func (auth *Auth) User(ctx context.Context, name string) (user *AuthUser, err er
}
// return the user
table, err := auth.Dependencies.SQL.QueryTable(ctx, auth)
table, err := auth.dependencies.SQL.QueryTable(ctx, auth)
if err != nil {
return
}
@ -96,7 +96,7 @@ func (auth *Auth) User(ctx context.Context, name string) (user *AuthUser, err er
// The user is not associated to any WissKIs, and has no password set.
func (auth *Auth) CreateUser(ctx context.Context, name string) (user *AuthUser, err error) {
// return the user
table, err := auth.Dependencies.SQL.QueryTable(ctx, auth)
table, err := auth.dependencies.SQL.QueryTable(ctx, auth)
if err != nil {
return
}
@ -323,7 +323,7 @@ func (au *AuthUser) MakeRegular(ctx context.Context) error {
// Save saves the given user in the database
func (au *AuthUser) Save(ctx context.Context) error {
table, err := au.auth.Dependencies.SQL.QueryTable(ctx, au.auth)
table, err := au.auth.dependencies.SQL.QueryTable(ctx, au.auth)
if err != nil {
return err
}
@ -332,13 +332,13 @@ func (au *AuthUser) Save(ctx context.Context) error {
// Delete deletes the user from the database
func (au *AuthUser) Delete(ctx context.Context) error {
table, err := au.auth.Dependencies.SQL.QueryTable(ctx, au.auth)
table, err := au.auth.dependencies.SQL.QueryTable(ctx, au.auth)
if err != nil {
return err
}
// run all the user delete hooks
for _, c := range au.auth.Dependencies.UserDeleteHooks {
for _, c := range au.auth.dependencies.UserDeleteHooks {
if err := c.OnUserDelete(ctx, &au.User); err != nil {
return err
}

View file

@ -43,15 +43,13 @@ func (cb *Base) getBase() *Base {
// Init initialzes a new componeont Component with the provided still.
// Init is only initended to be used within a lifetime.Lifetime[Component,Still].
func Init(component Component, core Still) Component {
func Init(component Component, core Still) {
base := component.getBase() // pointer to a struct
base.Still = core
tp := reflect.TypeOf(component).Elem()
base.name = strings.ToLower(tp.Name())
base.id = tp.PkgPath() + "." + tp.Name()
return component
}
func (cb Base) Name() string {

View file

@ -5,6 +5,7 @@ import (
"fmt"
"io"
"path/filepath"
"strings"
"time"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
@ -75,7 +76,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp
defer done()
// create a new status display
backups := exporter.Dependencies.Backupable
backups := exporter.dependencies.Backupable
backup.ComponentErrors = make(map[string]error, len(backups))
// Component backup tasks
@ -124,7 +125,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp
}
// list all instances
wissKIs, err := exporter.Dependencies.Instances.All(ctx)
wissKIs, err := exporter.dependencies.Instances.All(ctx)
if err != nil {
backup.InstanceListErr = err
return nil
@ -159,8 +160,8 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp
}.Use(st, wissKIs)
// sort the instances
slices.SortFunc(backup.InstanceSnapshots, func(a, b Snapshot) bool {
return a.Instance.Slug < b.Instance.Slug
slices.SortFunc(backup.InstanceSnapshots, func(a, b Snapshot) int {
return strings.Compare(a.Instance.Slug, b.Instance.Slug)
})
return nil

View file

@ -21,7 +21,7 @@ import (
// Exporter manages snapshots and backups
type Exporter struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
Instances *instances.Instances
ExporterLogger *logger.Logger

View file

@ -11,7 +11,7 @@ import (
type Pathbuilders struct {
component.Base
Dependencies struct {
dependencies struct {
Instances *instances.Instances
}
}
@ -26,7 +26,7 @@ func (Pathbuilders) SnapshotName() string { return "pathbuilders" }
func (pbs *Pathbuilders) Snapshot(wisski models.Instance, scontext *component.StagingContext) error {
return scontext.AddDirectory(".", func(ctx context.Context) error {
builders, err := pbs.Dependencies.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil)
builders, err := pbs.dependencies.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil)
if err != nil {
return err
}

View file

@ -56,7 +56,7 @@ type export interface {
// Parts lists all available snapshot parts
func (exporter *Exporter) Parts() []string {
return collection.MapSlice(exporter.Dependencies.Snapshotable, func(c component.Snapshotable) string { return c.SnapshotName() })
return collection.MapSlice(exporter.dependencies.Snapshotable, func(c component.Snapshotable) string { return c.SnapshotName() })
}
const (
@ -172,7 +172,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta
// write out the log entry
entry.Path = stagingDir
entry.Packed = false
exporter.Dependencies.ExporterLogger.Add(ctx, entry)
exporter.dependencies.ExporterLogger.Add(ctx, entry)
fmt.Fprintf(progress, "Wrote %s\n", stagingDir)
return nil
@ -200,7 +200,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta
logging.LogMessage(progress, "Writing Log Entry")
entry.Path = archivePath
entry.Packed = true
exporter.Dependencies.ExporterLogger.Add(ctx, entry)
exporter.dependencies.ExporterLogger.Add(ctx, entry)
// and we're done!
return nil

View file

@ -17,7 +17,7 @@ import (
// Logger is responsible for logging backups and snapshots
type Logger struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
}
}
@ -28,7 +28,7 @@ var (
func (*Logger) TableInfo() component.TableInfo {
return component.TableInfo{
Model: reflectx.MakeType[models.Export](),
Model: reflectx.TypeFor[models.Export](),
Name: models.ExportTable,
}
}
@ -50,7 +50,7 @@ func (log *Logger) For(ctx context.Context, slug string) (exports []models.Expor
// Log retrieves (and prunes) all entries in the snapshot log.
func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
// query the table!
table, err := log.Dependencies.SQL.QueryTable(ctx, log)
table, err := log.dependencies.SQL.QueryTable(ctx, log)
if err != nil {
return nil, err
}
@ -82,7 +82,7 @@ func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
// AddToExportLog adds the provided export to the log.
func (log *Logger) Add(ctx context.Context, export models.Export) error {
// find the table
table, err := log.Dependencies.SQL.QueryTable(ctx, log)
table, err := log.dependencies.SQL.QueryTable(ctx, log)
if err != nil {
return err
}

View file

@ -52,6 +52,6 @@ func (exporter *Exporter) PruneExports(ctx context.Context, progress io.Writer)
}
// prune the snapshot log!
_, err = exporter.Dependencies.ExporterLogger.Log(ctx)
_, err = exporter.dependencies.ExporterLogger.Log(ctx)
return err
}

View file

@ -113,8 +113,8 @@ func (exporter *Exporter) NewSnapshot(ctx context.Context, instance *wisski.Wiss
// Also sets up snapshot.partsRunning and snapshot.partsStopped.
// sends a warning about unknown parts into the logger in context.
func (snapshots *Exporter) resolveParts(ctx context.Context, parts []string, snapshot *Snapshot) {
partMap := make(map[string]component.Snapshotable, len(snapshots.Dependencies.Snapshotable))
for _, part := range snapshots.Dependencies.Snapshotable {
partMap := make(map[string]component.Snapshotable, len(snapshots.dependencies.Snapshotable))
for _, part := range snapshots.dependencies.Snapshotable {
partMap[part.SnapshotName()] = part
}

View file

@ -19,7 +19,7 @@ import (
// Instances manages multiple WissKI Instances.
type Instances struct {
component.Base
Dependencies struct {
dependencies struct {
Malt *malt.Malt
SQL *sql.SQL
@ -41,7 +41,7 @@ var errSQL = exit.Error{
// use uses the non-nil wisski instance with this instances
func (instances *Instances) use(wisski *wisski.WissKI) {
wisski.Liquid.Malt = instances.Dependencies.Malt
wisski.Liquid.Malt = instances.dependencies.Malt
}
// WissKI returns the WissKI with the provided slug, if it exists.
@ -51,12 +51,12 @@ func (instances *Instances) WissKI(ctx context.Context, slug string) (wissKI *wi
return nil, ErrWissKINotFound
}
sql := instances.Dependencies.SQL
sql := instances.dependencies.SQL
if err := sql.WaitQueryTable(ctx); err != nil {
return nil, err
}
table, err := sql.QueryTable(ctx, instances.Dependencies.InstanceTable)
table, err := sql.QueryTable(ctx, instances.dependencies.InstanceTable)
if err != nil {
return nil, err
}
@ -91,12 +91,12 @@ func (instances *Instances) Instance(ctx context.Context, instance models.Instan
// Has checks if a WissKI with the provided slug exists inside the database.
// It does not perform any checks on the WissKI itself.
func (instances *Instances) Has(ctx context.Context, slug string) (ok bool, err error) {
sql := instances.Dependencies.SQL
sql := instances.dependencies.SQL
if err := sql.WaitQueryTable(ctx); err != nil {
return false, err
}
table, err := sql.QueryTable(ctx, instances.Dependencies.InstanceTable)
table, err := sql.QueryTable(ctx, instances.dependencies.InstanceTable)
if err != nil {
return false, err
}
@ -135,13 +135,13 @@ func (instances *Instances) Load(ctx context.Context, slugs ...string) ([]*wissk
// find finds instances based on the provided query
func (instances *Instances) find(ctx context.Context, order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) {
sql := instances.Dependencies.SQL
sql := instances.dependencies.SQL
if err := sql.WaitQueryTable(ctx); err != nil {
return nil, err
}
// open the bookkeeping table
table, err := sql.QueryTable(ctx, instances.Dependencies.InstanceTable)
table, err := sql.QueryTable(ctx, instances.dependencies.InstanceTable)
if err != nil {
return nil, err
}

View file

@ -15,16 +15,16 @@ import (
type Malt struct {
component.Base
SQL *sql.SQL `auto:"true"`
InstanceTable *sql.InstanceTable `auto:"true"`
LockTable *sql.LockTable `auto:"true"`
SQL *sql.SQL `inject:"true"`
InstanceTable *sql.InstanceTable `inject:"true"`
LockTable *sql.LockTable `inject:"true"`
TS *triplestore.Triplestore `auto:"true"`
Meta *meta.Meta `auto:"true"`
ExporterLog *logger.Logger `auto:"true"`
Policy *policy.Policy `auto:"true"`
TS *triplestore.Triplestore `inject:"true"`
Meta *meta.Meta `inject:"true"`
ExporterLog *logger.Logger `inject:"true"`
Policy *policy.Policy `inject:"true"`
Docker *docker.Docker `auto:"true"`
Docker *docker.Docker `inject:"true"`
Keys *sshkeys.SSHKeys `auto:"true"`
Keys *sshkeys.SSHKeys `inject:"true"`
}

View file

@ -16,7 +16,7 @@ import (
// Purger purges instances from the distillery
type Purger struct {
component.Base
Dependencies struct {
dependencies struct {
Instances *instances.Instances
Provisionable []component.Provisionable
}
@ -35,10 +35,10 @@ var errPurgeGeneric = exit.Error{
// The instance does not have to exist; in which case the resources are also deleted.
func (purger *Purger) Purge(ctx context.Context, out io.Writer, slug string) error {
logging.LogMessage(out, "Checking bookkeeping table")
instance, err := purger.Dependencies.Instances.WissKI(ctx, slug)
instance, err := purger.dependencies.Instances.WissKI(ctx, slug)
if err == instances.ErrWissKINotFound {
fmt.Fprintln(out, "Not found in bookkeeping table, assuming defaults")
instance, err = purger.Dependencies.Instances.Create(slug, models.System{})
instance, err = purger.dependencies.Instances.Create(slug, models.System{})
}
if err != nil {
return errPurgeNoDetails.WithMessageF(err)
@ -59,7 +59,7 @@ func (purger *Purger) Purge(ctx context.Context, out io.Writer, slug string) err
// purge all the instance specific resources
if err := logging.LogOperation(func() error {
domain := instance.Domain()
for _, pc := range purger.Dependencies.Provisionable {
for _, pc := range purger.dependencies.Provisionable {
logging.LogMessage(out, "Purging %s resources", pc.Name())
err := pc.Purge(ctx, instance.Instance, domain)
if err != nil {

View file

@ -48,8 +48,8 @@ func (mi MenuItem) ReplaceWith(new MenuItem, items []MenuItem) bool {
return false
}
func MenuItemSort(a, b MenuItem) bool {
return a.Priority < b.Priority
func MenuItemSort(a, b MenuItem) int {
return int(a.Priority) - int(b.Priority)
}
type MenuPriority int

View file

@ -12,7 +12,7 @@ import (
// Component meta is responsible for managing metadata per WissKI Instance
type Meta struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
}
@ -27,7 +27,7 @@ var (
func (*Meta) TableInfo() component.TableInfo {
return component.TableInfo{
Model: reflectx.MakeType[models.Metadatum](),
Model: reflectx.TypeFor[models.Metadatum](),
Name: models.MetadataTable,
}
}
@ -51,7 +51,7 @@ func (meta *Meta) Storage(slug string) *Storage {
// create a new storage
meta.sc[slug] = &Storage{
Slug: slug,
sql: meta.Dependencies.SQL,
sql: meta.dependencies.SQL,
table: meta,
}
return meta.sc[slug]

View file

@ -17,7 +17,7 @@ import (
type Provision struct {
component.Base
Dependencies struct {
dependencies struct {
Instances *instances.Instances
Provisionable []component.Provisionable
}
@ -44,7 +44,7 @@ var ErrInstanceAlreadyExists = errors.New("instance with provided slug already e
func (pv *Provision) Validate(flags Flags) error {
// check the slug
if _, err := pv.Dependencies.Instances.IsValidSlug(flags.Slug); err != nil {
if _, err := pv.dependencies.Instances.IsValidSlug(flags.Slug); err != nil {
return err
}
return nil
@ -54,7 +54,7 @@ func (pv *Provision) Validate(flags Flags) error {
func (pv *Provision) Provision(progress io.Writer, ctx context.Context, flags Flags) (*wisski.WissKI, error) {
// check that it doesn't already exist
logging.LogMessage(progress, "Provisioning new WissKI instance %s", flags.Slug)
if exists, err := pv.Dependencies.Instances.Has(ctx, flags.Slug); err != nil || exists {
if exists, err := pv.dependencies.Instances.Has(ctx, flags.Slug); err != nil || exists {
return nil, ErrInstanceAlreadyExists
}
@ -62,7 +62,7 @@ func (pv *Provision) Provision(progress io.Writer, ctx context.Context, flags Fl
fmt.Fprintf(progress, "%#v", flags)
// make it in-memory
instance, err := pv.Dependencies.Instances.Create(flags.Slug, flags.System)
instance, err := pv.dependencies.Instances.Create(flags.Slug, flags.System)
if err != nil {
return nil, err
}
@ -93,7 +93,7 @@ func (pv *Provision) Provision(progress io.Writer, ctx context.Context, flags Fl
// create all the resources!
if err := logging.LogOperation(func() error {
domain := instance.Domain()
for _, pc := range pv.Dependencies.Provisionable {
for _, pc := range pv.dependencies.Provisionable {
logging.LogMessage(progress, "Provisioning %s resources", pc.Name())
err := pc.Provision(ctx, instance.Instance, domain)
if err != nil {

View file

@ -13,7 +13,7 @@ import (
type API struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
Resolver *Resolver
}
@ -33,7 +33,7 @@ func (api *API) Routes() component.Routes {
func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
return &api.Handler[string]{
Config: a.Config,
Auth: a.Dependencies.Auth,
Auth: a.dependencies.Auth,
Methods: []string{"GET"},
@ -43,7 +43,7 @@ func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error
if uri == "" {
return "", httpx.ErrBadRequest
}
target := a.Dependencies.Resolver.Target(uri)
target := a.dependencies.Resolver.Target(uri)
if target == "" {
return "", httpx.ErrNotFound
}

View file

@ -21,7 +21,7 @@ func (resolver *Resolver) Cron(ctx context.Context) error {
// AllPrefixes returns a list of all prefixes from the server.
// Prefixes may be cached on the server
func (resolver *Resolver) AllPrefixes(ctx context.Context) (map[string]string, error) {
instances, err := resolver.Dependencies.Instances.All(ctx)
instances, err := resolver.dependencies.Instances.All(ctx)
if err != nil {
return nil, err
}

View file

@ -24,7 +24,7 @@ import (
type Resolver struct {
component.Base
Dependencies struct {
dependencies struct {
Instances *instances.Instances
Templating *templating.Templating
Auth *auth.Auth
@ -71,7 +71,7 @@ var (
func (resolver *Resolver) HandleRoute(ctx context.Context, route string) (http.Handler, error) {
// get the resolver template
tpl := resolverTemplate.Prepare(
resolver.Dependencies.Templating,
resolver.dependencies.Templating,
templating.Crumbs(
menuResolver,
),
@ -103,7 +103,7 @@ func (resolver *Resolver) HandleRoute(ctx context.Context, route string) (http.H
IndexContext: context,
}
if resolver.Dependencies.Auth.CheckScope("", scopes.ScopeUserValid, r) != nil {
if resolver.dependencies.Auth.CheckScope("", scopes.ScopeUserValid, r) != nil {
ctx.IndexContext.Prefixes = nil
}
httpx.WriteHTML(tpl.Context(r, ctx), nil, t, "", w, r)

View file

@ -12,7 +12,6 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
"github.com/julienschmidt/httprouter"
"github.com/rs/zerolog"
"github.com/tkw1536/pkglib/lifetime"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
"github.com/tkw1536/pkglib/httpx"
@ -20,7 +19,7 @@ import (
type Admin struct {
component.Base
Dependencies struct {
dependencies struct {
Fetchers []component.DistilleryFetcher
Instances *instances.Instances
@ -33,8 +32,6 @@ type Admin struct {
Sockets *socket.Sockets
}
Analytics *lifetime.Analytics
}
var (
@ -47,12 +44,12 @@ func (admin *Admin) Routes() component.Routes {
return component.Routes{
Prefix: "/admin/",
CSRF: true,
Decorator: admin.Dependencies.Auth.Require(false, scopes.ScopeUserAdmin, nil),
Decorator: admin.dependencies.Auth.Require(false, scopes.ScopeUserAdmin, nil),
}
}
func (admin *Admin) Menu(r *http.Request) []component.MenuItem {
if admin.Dependencies.Auth.CheckScope("", scopes.ScopeUserAdmin, r) != nil {
if admin.dependencies.Auth.CheckScope("", scopes.ScopeUserAdmin, r) != nil {
return nil
}
return []component.MenuItem{
@ -65,8 +62,7 @@ func (admin *Admin) Menu(r *http.Request) []component.MenuItem {
}
var (
menuAdmin = component.MenuItem{Title: "Admin", Path: "/admin/"}
menuComponents = component.MenuItem{Title: "Components", Path: "/admin/components/", Priority: component.SmallButton}
menuAdmin = component.MenuItem{Title: "Admin", Path: "/admin/"}
menuUsers = component.MenuItem{Title: "Users", Path: "/admin/users/"}
menuUserCreate = component.MenuItem{Title: "Create User", Path: "/admin/users/create/"}
@ -121,18 +117,6 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
router.Handler(http.MethodPost, route+"users/impersonate", admin.usersImpersonateHandler(ctx))
router.Handler(http.MethodPost, route+"users/unsetpassword", admin.usersUnsetPasswordHandler(ctx))
// add a handler for the component page
{
components := admin.components(ctx)
router.Handler(http.MethodGet, route+"components", components)
}
// add a handler for the ingredients page
{
ingredients := admin.ingredients(ctx)
router.Handler(http.MethodGet, route+"ingredients/:slug", ingredients)
}
// add a handler for the instance page
{
instance := admin.instance(ctx)
@ -167,7 +151,7 @@ func (admin *Admin) loginHandler(ctx context.Context) http.Handler {
}
// get the instance
instance, err := admin.Dependencies.Instances.WissKI(r.Context(), r.PostFormValue("slug"))
instance, err := admin.dependencies.Instances.WissKI(r.Context(), r.PostFormValue("slug"))
if err != nil {
return "", 0, httpx.ErrNotFound
}

View file

@ -1,83 +0,0 @@
package admin
import (
"context"
"html/template"
"net/http"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
"github.com/julienschmidt/httprouter"
"github.com/tkw1536/pkglib/httpx"
"github.com/tkw1536/pkglib/lifetime"
_ "embed"
)
//go:embed "html/anal.html"
var analHTML []byte
var analTemplate = templating.Parse[analContext](
"anal.html", analHTML, nil,
templating.Assets(assets.AssetsAdmin),
)
type analContext struct {
templating.RuntimeFlags
Analytics lifetime.Analytics
}
func (admin *Admin) components(ctx context.Context) http.Handler {
tpl := analTemplate.Prepare(
admin.Dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuInstances,
menuComponents,
),
templating.Title("Components"),
)
return tpl.HTMLHandler(func(r *http.Request) (ac analContext, err error) {
ac.Analytics = *admin.Analytics
return
})
}
func (admin *Admin) ingredients(ctx context.Context) http.Handler {
tpl := analTemplate.Prepare(
admin.Dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuInstances,
menuInstance,
menuIngredients,
),
)
return tpl.HTMLHandlerWithFlags(func(r *http.Request) (ac analContext, funcs []templating.FlagFunc, err error) {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
// find the instance itself!
instance, err := admin.Dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return ac, nil, httpx.ErrNotFound
}
if err != nil {
return ac, nil, err
}
funcs = []templating.FlagFunc{
templating.ReplaceCrumb(menuInstance, component.MenuItem{Title: "Instance", Path: template.URL("/admin/instance/" + slug)}),
templating.ReplaceCrumb(menuIngredients, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")}),
templating.Title(instance.Name() + " - Ingredients"),
}
// and get the components
ac.Analytics = *instance.Info().Analytics
return
})
}

View file

@ -44,7 +44,7 @@ type grantsContext struct {
func (admin *Admin) grants(ctx context.Context) http.Handler {
tpl := grantsTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuInstances,
@ -100,13 +100,13 @@ func (admin *Admin) postGrants(r *http.Request) (gc grantsContext, funcs []templ
if delete {
// delete the user grant
err := admin.Dependencies.Policy.Remove(r.Context(), distilleryUser, slug)
err := admin.dependencies.Policy.Remove(r.Context(), distilleryUser, slug)
if err != nil {
return gc, nil, err
}
} else {
// update the grant
err := admin.Dependencies.Policy.Set(r.Context(), models.Grant{
err := admin.dependencies.Policy.Set(r.Context(), models.Grant{
User: distilleryUser,
Slug: slug,
@ -127,7 +127,7 @@ func (admin *Admin) postGrants(r *http.Request) (gc grantsContext, funcs []templ
func (gc *grantsContext) 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)
gc.instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return nil, httpx.ErrNotFound
}
@ -146,12 +146,12 @@ func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (funcs
}
func (gc *grantsContext) useGrants(r *http.Request, admin *Admin) (err error) {
gc.Grants, err = admin.Dependencies.Policy.Instance(r.Context(), gc.Instance.Slug)
gc.Grants, err = admin.dependencies.Policy.Instance(r.Context(), gc.Instance.Slug)
if err != nil {
return err
}
users, err := admin.Dependencies.Auth.Users(r.Context())
users, err := admin.dependencies.Auth.Users(r.Context())
if err != nil {
return err
}

View file

@ -1,139 +0,0 @@
<div class="pure-u-1-1">
<h2 id="structs">Structs</h2>
</div>
{{ range $name, $comp := .Analytics.Components }}
<div class="pure-u-1-1" id="{{ $name }}">
<div class="padding">
<div class="overflow">
<table class="pure-table pure-table-bordered">
<thead>
<tr>
<th colspan="3">
{{ $name }}
</th>
</tr>
</thead>
<tbody>
{{ range .Groups }}
<tr>
<td>
Implements
</td>
<td colspan="2">
<code><a href="#{{.}}">{{ . }}</a></code><br />
</td>
</tr>
{{ end }}
{{ range $name, $comp := .CFields }}
<tr>
<td>Component Pointer</td>
<td>
<code>{{ $name }}</code>
</td>
<td>
<code><a href="#{{ $comp }}">{{ $comp }}</a></code>
</td>
</tr>
{{ end }}
{{ range $name, $comp := .DCFields }}
<tr>
<td>Component Pointer</td>
<td>
<code>Dependencies/{{ $name }}</code>
</td>
<td>
<code><a href="#{{ $comp }}">{{ $comp }}</a></code>
</td>
</tr>
{{ end }}
{{ range $name, $iface := .IFields }}
<tr>
<td>Interface Slice</td>
<td>
<code>{{ $name }}</code>
</td>
<td>
<code><a href="#{{ $iface }}">[]{{ $iface }}</a></code>
</td>
</tr>
{{ end }}
{{ range $name, $iface := .DIFields }}
<tr>
<td>Interface Slice</td>
<td>
<code>Dependencies/{{ $name }}</code>
</td>
<td>
<code><a href="#{{ $iface }}">[]{{ $iface }}</a></code>
</td>
</tr>
{{ end }}
{{ range $name, $sig := $comp.Methods }}
<tr>
<td>
Method
</td>
<td>
<code>{{ $name }}</code>
</td>
<td>
<code>{{ $sig }}</code>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
</div>
{{ end }}
<div class="pure-u-1-1">
<h2 id="interfaces">Interfaces</h2>
</div>
{{ range $name, $group := .Analytics.Groups }}
<div class="pure-u-1-1" id="{{ $name }}">
<div class="padding">
<div class="overflow">
<table class="pure-table pure-table-bordered">
<thead>
<tr>
<th colspan="3">
{{ $name }}
</th>
</tr>
</thead>
<tbody>
{{ range $name, $sig := $group.Methods }}
<tr>
<td>
Method
</td>
<td>
<code>{{ $name }}</code>
</td>
<td>
<code>{{ $sig }}</code>
</td>
</tr>
{{ end }}
{{ range $group.Components }}
<tr>
<td>
Implemented By
</td>
<td colspan="2">
<code><a href="#{{.}}">{{ . }}</a></code>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
{{ end }}

View file

@ -21,7 +21,7 @@ func (admin *Admin) Status(ctx context.Context, QuickInformation bool) (target s
group.Go(func() error {
// list all the instances
all, err := admin.Dependencies.Instances.All(ctx)
all, err := admin.dependencies.Instances.All(ctx)
if err != nil {
return err
}
@ -47,7 +47,7 @@ func (admin *Admin) Status(ctx context.Context, QuickInformation bool) (target s
flags := component.FetcherFlags{
Context: ctx,
}
for _, o := range admin.Dependencies.Fetchers {
for _, o := range admin.dependencies.Fetchers {
o := o
group.Go(func() error {
return o.Fetch(flags, &target)
@ -109,11 +109,10 @@ type indexContext struct {
func (admin *Admin) index(ctx context.Context) http.Handler {
tpl := indexTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Actions(
menuUsers,
menuInstances,
menuComponents,
),
)
@ -125,7 +124,7 @@ func (admin *Admin) index(ctx context.Context) http.Handler {
func (admin *Admin) instances(ctx context.Context) http.Handler {
tpl := instancesTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuInstances,

View file

@ -34,7 +34,7 @@ type instanceContext struct {
func (admin *Admin) instance(ctx context.Context) http.Handler {
tpl := instanceTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuInstances,
@ -51,7 +51,7 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
// find the instance itself!
instance, err := admin.Dependencies.Instances.WissKI(r.Context(), slug)
instance, err := admin.dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return ic, nil, httpx.ErrNotFound
}
@ -70,7 +70,6 @@ func (admin *Admin) instance(ctx context.Context) http.Handler {
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.ReplaceAction(menuIngredients, component.MenuItem{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton}),
templating.Title(instance.Slug),
}

View file

@ -12,7 +12,7 @@ import (
func (admin *Admin) instanceProvision(ctx context.Context) http.Handler {
tpl := instanceSystemTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Title("Provision New Instance"),
templating.Assets(assets.AssetsAdminProvision),

View file

@ -48,7 +48,7 @@ func (isc *instanceSystemContext) prepare(rebuild bool) {
func (admin *Admin) instanceRebuild(ctx context.Context) http.Handler {
tpl := instanceSystemTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Title("Rebuild Instance"),
templating.Assets(assets.AssetsAdminRebuild),
@ -65,7 +65,7 @@ func (admin *Admin) instanceRebuild(ctx context.Context) http.Handler {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
var instance *wisski.WissKI
instance, err = admin.Dependencies.Instances.WissKI(r.Context(), slug)
instance, err = admin.dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return isc, nil, httpx.ErrNotFound
}

View file

@ -17,7 +17,7 @@ func (sockets *Sockets) Actions() ActionMap {
return map[string]Action{
// generic actions
"backup": sockets.Generic(scopes.ScopeUserAdmin, "", 0, func(ctx context.Context, sockets *Sockets, in io.Reader, out io.Writer, params ...string) error {
return sockets.Dependencies.Exporter.MakeExport(
return sockets.dependencies.Exporter.MakeExport(
ctx,
out,
exporter.ExportTask{
@ -35,7 +35,7 @@ func (sockets *Sockets) Actions() ActionMap {
return err
}
instance, err := sockets.Dependencies.Provision.Provision(
instance, err := sockets.dependencies.Provision.Provision(
out,
ctx,
flags,
@ -54,7 +54,7 @@ func (sockets *Sockets) Actions() ActionMap {
// instance-specific actions!
"snapshot": sockets.Instance(scopes.ScopeUserAdmin, "", 0, func(ctx context.Context, socket *Sockets, instance *wisski.WissKI, in io.Reader, out io.Writer, params ...string) error {
return socket.Dependencies.Exporter.MakeExport(
return socket.dependencies.Exporter.MakeExport(
ctx,
out,
exporter.ExportTask{
@ -86,7 +86,7 @@ func (sockets *Sockets) Actions() ActionMap {
return instance.Barrel().Stack().Down(ctx, out)
}),
"purge": sockets.Instance(scopes.ScopeUserAdmin, "", 0, func(ctx context.Context, sockets *Sockets, instance *wisski.WissKI, in io.Reader, out io.Writer, params ...string) error {
return sockets.Dependencies.Purger.Purge(ctx, out, instance.Slug)
return sockets.dependencies.Purger.Purge(ctx, out, instance.Slug)
}),
"never": sockets.Generic(scopes.ScopeNever, "", 0, func(ctx context.Context, sockets *Sockets, in io.Reader, out io.Writer, params ...string) error {
panic("never called")

View file

@ -23,7 +23,7 @@ type Sockets struct {
actions lazy.Lazy[ActionMap]
Dependencies struct {
dependencies struct {
Provision *provision.Provision
Instances *instances.Instances
Exporter *exporter.Exporter
@ -40,7 +40,7 @@ func (socket *Sockets) Routes() component.Routes {
return component.Routes{
Prefix: "/api/v1/ws",
Exact: true,
Decorator: socket.Dependencies.Auth.Require(true, scopes.ScopeUserValid, nil),
Decorator: socket.dependencies.Auth.Require(true, scopes.ScopeUserValid, nil),
}
}
@ -54,7 +54,7 @@ func (sockets *Sockets) HandleRoute(ctx context.Context, path string) (http.Hand
// Serve handles a connection to the websocket api
func (socket *Sockets) Serve(conn httpx.WebSocketConnection) {
// handle the websocket connection!
name, err := socket.actions.Get(socket.Actions).Handle(socket.Dependencies.Auth, conn)
name, err := socket.actions.Get(socket.Actions).Handle(socket.dependencies.Auth, conn)
if err != nil {
zerolog.Ctx(conn.Context()).Err(err).Str("name", name).Msg("Error handling websocket")
}
@ -80,7 +80,7 @@ func (sockets *Sockets) Instance(scope component.Scope, scopeParam string, numPa
NumParams: numParams + 1,
Handle: func(ctx context.Context, in io.Reader, out io.Writer, params ...string) error {
instance, err := sockets.Dependencies.Instances.WissKI(ctx, params[0])
instance, err := sockets.dependencies.Instances.WissKI(ctx, params[0])
if err != nil {
return err
}

View file

@ -33,7 +33,7 @@ type usersContext struct {
func (admin *Admin) users(ctx context.Context) http.Handler {
tpl := usersTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuUsers,
@ -45,7 +45,7 @@ func (admin *Admin) users(ctx context.Context) http.Handler {
return tpl.HTMLHandler(func(r *http.Request) (uc usersContext, err error) {
uc.Error = r.URL.Query().Get("error")
uc.Users, err = admin.Dependencies.Auth.Users(r.Context())
uc.Users, err = admin.dependencies.Auth.Users(r.Context())
return
})
}
@ -72,7 +72,7 @@ type createUserResult struct {
func (admin *Admin) createUser(ctx context.Context) http.Handler {
tpl := userCreateTemplate.Prepare(
admin.Dependencies.Templating,
admin.dependencies.Templating,
templating.Crumbs(
menuAdmin,
menuUsers,
@ -102,7 +102,7 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
}
// check the password policy
err = admin.Dependencies.Auth.CheckPasswordPolicy(cu.Passsword, cu.User)
err = admin.dependencies.Auth.CheckPasswordPolicy(cu.Passsword, cu.User)
if err != nil {
return cu, err
}
@ -112,7 +112,7 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
RenderSuccess: func(cu createUserResult, values map[string]string, w http.ResponseWriter, r *http.Request) error {
// create the user
user, err := admin.Dependencies.Auth.CreateUser(r.Context(), cu.User)
user, err := admin.dependencies.Auth.CreateUser(r.Context(), cu.User)
if err != nil {
return err
}
@ -151,14 +151,14 @@ func (admin *Admin) useraction(ctx context.Context, name string, action func(r *
}
username := r.PostFormValue("user")
user, err := admin.Dependencies.Auth.User(r.Context(), username)
user, err := admin.dependencies.Auth.User(r.Context(), username)
if err != nil {
logger.Err(err).Str("action", name).Msg("failed to get user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
}
me, err := admin.Dependencies.Auth.UserOfSession(r)
me, err := admin.dependencies.Auth.UserOfSession(r)
if err != nil {
logger.Err(err).Str("action", name).Msg("failed to get current user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
@ -241,7 +241,7 @@ func (admin *Admin) usersImpersonateHandler(ctx context.Context) http.Handler {
}
username := r.PostFormValue("user")
user, err := admin.Dependencies.Auth.User(r.Context(), username)
user, err := admin.dependencies.Auth.User(r.Context(), username)
if err != nil {
logger.Err(err).Str("action", "impersonate").Msg("failed to get user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
@ -249,7 +249,7 @@ func (admin *Admin) usersImpersonateHandler(ctx context.Context) http.Handler {
}
// login the user into the session of the provided user
if err := admin.Dependencies.Auth.Login(w, r, user); err != nil {
if err := admin.dependencies.Auth.Login(w, r, user); err != nil {
logger.Err(err).Str("action", "impersonate").Msg("failed to login user")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return

View file

@ -16,7 +16,7 @@ import (
type Cron struct {
component.Base
Dependencies struct {
dependencies struct {
Tasks []component.Cronable
}
}
@ -52,11 +52,11 @@ func (control *Cron) Listen(ctx context.Context) (<-chan struct{}, func()) {
// Once should not be called concurrently with Cron.
func (control *Cron) Once(ctx context.Context) {
var wg sync.WaitGroup
wg.Add(len(control.Dependencies.Tasks))
wg.Add(len(control.dependencies.Tasks))
zerolog.Ctx(ctx).Info().Time("time", time.Now()).Msg("Starting Cron")
for _, task := range control.Dependencies.Tasks {
for _, task := range control.dependencies.Tasks {
go func(task component.Cronable) {
defer wg.Done()

View file

@ -12,7 +12,7 @@ import (
type Home struct {
component.Base
Dependencies struct {
dependencies struct {
ListInstances *list.ListInstances
Templating *templating.Templating
}
@ -55,7 +55,7 @@ func (home *Home) HandleRoute(ctx context.Context, route string) (http.Handler,
}
func (home *Home) serveWissKI(w http.ResponseWriter, slug string, r *http.Request) {
if _, ok := home.Dependencies.ListInstances.Names()[slug]; !ok {
if _, ok := home.dependencies.ListInstances.Names()[slug]; !ok {
// Get(nil) guaranteed to work by precondition
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "WissKI %q not found\n", slug)

View file

@ -51,7 +51,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
title := home.Config.Home.Title
tpl := publicTemplate.Prepare(
home.Dependencies.Templating,
home.dependencies.Templating,
// set title and menu item
templating.Title(title),
templating.Crumbs(
@ -59,7 +59,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
),
)
about := home.Dependencies.Templating.GetCustomizable(aboutTemplate)
about := home.dependencies.Templating.GetCustomizable(aboutTemplate)
return tpl.HTMLHandler(func(r *http.Request) (pc publicContext, err error) {
// only act on the root path!
@ -72,7 +72,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
// prepare about
pc.aboutContext.Logo = logoHTML
pc.aboutContext.Instances = home.Dependencies.ListInstances.Infos()
pc.aboutContext.Instances = home.dependencies.ListInstances.Infos()
pc.aboutContext.SelfRedirect = home.Config.Home.SelfRedirect.String()
// render the about template
@ -85,7 +85,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
pc.About = template.HTML(builder.String())
// check if we should show the list of WissKIs
pc.ListEnabled = home.Dependencies.ListInstances.ShouldShowList(r)
pc.ListEnabled = home.dependencies.ListInstances.ShouldShowList(r)
// title of the list
pc.ListTitle = home.Config.Home.List.Title

View file

@ -15,7 +15,7 @@ import (
type Legal struct {
component.Base
Dependencies struct {
dependencies struct {
Static *assets.Static
Templating *templating.Templating
}
@ -59,7 +59,7 @@ var (
func (legal *Legal) HandleRoute(ctx context.Context, route string) (http.Handler, error) {
tpl := legalTemplate.Prepare(
legal.Dependencies.Templating,
legal.dependencies.Templating,
templating.Crumbs(
menuLegal,
),

View file

@ -15,7 +15,7 @@ import (
// API implements an API to list all instances
type API struct {
component.Base
Dependencies struct {
dependencies struct {
ListInstances *ListInstances
Auth *auth.Auth
}
@ -42,15 +42,15 @@ type APISystem struct {
func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
return &api.Handler[[]APISystem]{
Config: a.Config,
Auth: a.Dependencies.Auth,
Auth: a.dependencies.Auth,
Methods: []string{"GET"},
Scope: scopes.ScopeInstanceDirectory,
Handler: func(s string, r *http.Request) ([]APISystem, error) {
var statuses []status.WissKI
if a.Dependencies.ListInstances.ShouldShowList(r) {
statuses = a.Dependencies.ListInstances.infos.Get(nil)
if a.dependencies.ListInstances.ShouldShowList(r) {
statuses = a.dependencies.ListInstances.infos.Get(nil)
}
if len(statuses) == 0 {

View file

@ -19,7 +19,7 @@ type ListInstances struct {
names lazy.Lazy[map[string]struct{}] // instance names
infos lazy.Lazy[[]status.WissKI] // list of home instances (updated via cron)
Dependencies struct {
dependencies struct {
Auth *auth.Auth
Instances *instances.Instances
}
@ -42,7 +42,7 @@ func (li *ListInstances) ShouldShowList(r *http.Request) bool {
return allowPrivate
}
_, user, _ := li.Dependencies.Auth.SessionOf(r)
_, user, _ := li.dependencies.Auth.SessionOf(r)
if user == nil {
return allowPublic
} else {
@ -82,7 +82,7 @@ func (li *ListInstances) Cron(ctx context.Context) (err error) {
// getNames returns the names of the given instances
func (li *ListInstances) getNames(ctx context.Context) (map[string]struct{}, error) {
wissKIs, err := li.Dependencies.Instances.All(ctx)
wissKIs, err := li.dependencies.Instances.All(ctx)
if err != nil {
return nil, err
}
@ -97,7 +97,7 @@ func (li *ListInstances) getNames(ctx context.Context) (map[string]struct{}, err
// getInfos returns the names of the given instances
func (li *ListInstances) getInfos(ctx context.Context) ([]status.WissKI, error) {
// find all the WissKIs
wissKIs, err := li.Dependencies.Instances.All(ctx)
wissKIs, err := li.dependencies.Instances.All(ctx)
if err != nil {
return nil, err
}

View file

@ -12,7 +12,7 @@ import (
type API struct {
component.Base
Dependencies struct {
dependencies struct {
Auth *auth.Auth
}
}
@ -31,7 +31,7 @@ func (api *API) Routes() component.Routes {
func (a *API) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
return &api.Handler[[]Item]{
Config: a.Config,
Auth: a.Dependencies.Auth,
Auth: a.dependencies.Auth,
Methods: []string{"GET"},

View file

@ -21,7 +21,7 @@ import (
type News struct {
component.Base
Dependencies struct {
dependencies struct {
Templating *templating.Templating
}
}
@ -104,8 +104,8 @@ func Items() ([]Item, error) {
}
}
slices.SortFunc(items, func(a, b Item) bool {
return !a.Date.Before(b.Date)
slices.SortFunc(items, func(a, b Item) int {
return a.Date.Compare(b.Date)
})
return items, nil
@ -132,7 +132,7 @@ var (
// HandleRoute returns the handler for the requested path
func (news *News) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
tpl := newsTemplate.Prepare(
news.Dependencies.Templating,
news.dependencies.Templating,
templating.Crumbs(
menuNews,
),

View file

@ -20,7 +20,7 @@ import (
// Server represents the running control server.
type Server struct {
component.Base
Dependencies struct {
dependencies struct {
Routeables []component.Routeable
Cronables []component.Cronable
@ -66,7 +66,7 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
csrfProtector := server.csrf()
// iterate over all the handler
for _, s := range server.Dependencies.Routeables {
for _, s := range server.dependencies.Routeables {
routes := s.Routes()
zerolog.Ctx(ctx).Info().
Str("Name", s.Name()).

View file

@ -34,7 +34,7 @@ func (server *Server) Stack() component.StackWithResources {
"SELF_OVERRIDES_FILE": server.Config.Paths.OverridesJSON,
"SELF_RESOLVER_BLOCK_FILE": server.Config.Paths.ResolverBlocks,
"CUSTOM_ASSETS_PATH": server.Dependencies.Templating.CustomAssetsPath(),
"CUSTOM_ASSETS_PATH": server.dependencies.Templating.CustomAssetsPath(),
},
CopyContextFiles: []string{bootstrap.Executable},

View file

@ -40,7 +40,7 @@ type RuntimeFlags struct {
CSRF template.HTML // csrf data (if any)
}
var runtimeFlagsName = reflectx.MakeType[RuntimeFlags]().Name()
var runtimeFlagsName = reflectx.TypeFor[RuntimeFlags]().Name()
// Clone clones this flags
func (flags Flags) Clone() Flags {

View file

@ -18,7 +18,7 @@ func (tpl *Templating) buildMenu(r *http.Request) []component.MenuItem {
// get the static menu items, and then return all the regular ones
var items []component.MenuItem
for _, m := range tpl.Dependencies.Menuable {
for _, m := range tpl.dependencies.Menuable {
items = append(items, m.Menu(r)...)
}
for i, item := range items {
@ -31,8 +31,8 @@ func (tpl *Templating) buildMenu(r *http.Request) []component.MenuItem {
// Menu returns a list of menu items provided by routeables
func (tpl *Templating) Menu(r *http.Request) []component.MenuItem {
return tpl.menu.Get(func() []component.MenuItem {
items := make([]component.MenuItem, 0, len(tpl.Dependencies.Routeables))
for _, route := range tpl.Dependencies.Routeables {
items := make([]component.MenuItem, 0, len(tpl.dependencies.Routeables))
for _, route := range tpl.dependencies.Routeables {
routes := route.Routes()
if routes.MenuTitle == "" {
continue

View file

@ -21,7 +21,7 @@ type Parsed[C any] struct {
// If base is not nil, every template associated with the base template is copied into the given template.
// Functions will be applied on creation time to represent the context for the given template.
func Parse[C any](name string, source []byte, base *template.Template, funcs ...FlagFunc) Parsed[C] {
tp := reflectx.MakeType[C]()
tp := reflectx.TypeFor[C]()
// determine if we have an embedded field in the struct
var hasEmbed bool

View file

@ -8,7 +8,7 @@ import (
// Templating implements templating customization
type Templating struct {
component.Base
Dependencies struct {
dependencies struct {
Routeables []component.Routeable
Menuable []component.Menuable
}

View file

@ -18,7 +18,7 @@ func (*SQL) BackupName() string {
// Backup makes a backup of all SQL databases into the path dest.
func (sql *SQL) Backup(scontext *component.StagingContext) error {
return scontext.AddFile("", func(ctx context.Context, file io.Writer) error {
code := sql.Stack().Exec(ctx, stream.NewIOStream(file, scontext.Progress(), nil, 0), "sql", SQlDumpExecutable, "--all-databases")()
code := sql.Stack().Exec(ctx, stream.NewIOStream(file, scontext.Progress(), nil), "sql", SQlDumpExecutable, "--all-databases")()
if code != 0 {
return errSQLBackup
}

View file

@ -23,7 +23,7 @@ func (sql *SQL) Snapshot(wisski models.Instance, scontext *component.StagingCont
// SnapshotDB makes a backup of the sql database into dest.
func (sql *SQL) SnapshotDB(ctx context.Context, progress io.Writer, dest io.Writer, database string) error {
code := sql.Stack().Exec(ctx, stream.NewIOStream(dest, progress, nil, 0), "sql", SQlDumpExecutable, "--databases", database)()
code := sql.Stack().Exec(ctx, stream.NewIOStream(dest, progress, nil), "sql", SQlDumpExecutable, "--databases", database)()
if code != 0 {
return errSQLBackup
}

View file

@ -11,7 +11,7 @@ import (
type SQL struct {
component.Base
Dependencies struct {
dependencies struct {
Tables []component.Table
}

View file

@ -18,7 +18,7 @@ var (
func (*InstanceTable) TableInfo() component.TableInfo {
return component.TableInfo{
Model: reflectx.MakeType[models.Instance](),
Model: reflectx.TypeFor[models.Instance](),
Name: models.InstanceTable,
}
}
@ -33,7 +33,7 @@ var (
func (*LockTable) TableInfo() component.TableInfo {
return component.TableInfo{
Model: reflectx.MakeType[models.Lock](),
Model: reflectx.TypeFor[models.Lock](),
Name: models.LockTable,
}
}

View file

@ -104,7 +104,7 @@ func (sql *SQL) Update(ctx context.Context, progress io.Writer) error {
// migrate all of the tables!
return logging.LogOperation(func() error {
for _, table := range sql.Dependencies.Tables {
for _, table := range sql.dependencies.Tables {
info := table.TableInfo()
logging.LogMessage(progress, "migrating %q table", table.Name())
db, err := sql.queryTable(ctx, false, info.Name)

View file

@ -19,7 +19,7 @@ func (ssh2 *SSH2) Routes() component.Routes {
func (ssh2 *SSH2) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// fetch the global keys
gkeys, err := ssh2.Dependencies.Keys.Admin(r.Context())
gkeys, err := ssh2.dependencies.Keys.Admin(r.Context())
if err != nil {
httpx.TextInterceptor.Intercept(w, r, err)
return
@ -33,7 +33,7 @@ func (ssh2 *SSH2) HandleRoute(ctx context.Context, path string) (http.Handler, e
}
// fetch the instance
instance, err := ssh2.Dependencies.Instances.WissKI(r.Context(), slug)
instance, err := ssh2.dependencies.Instances.WissKI(r.Context(), slug)
if err != nil {
httpx.TextInterceptor.Intercept(w, r, httpx.ErrNotFound)
return

View file

@ -52,7 +52,7 @@ func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool {
// grab the global permissions
{
globalKeys, err := ssh2.Dependencies.Keys.Admin(ctx)
globalKeys, err := ssh2.dependencies.Keys.Admin(ctx)
if err != nil {
return false
}
@ -62,7 +62,7 @@ func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool {
// grab permissions for each instance
{
instances, err := ssh2.Dependencies.Instances.All(ctx)
instances, err := ssh2.dependencies.Instances.All(ctx)
if err != nil {
return false
}

View file

@ -11,7 +11,7 @@ import (
type SSH2 struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
Instances *instances.Instances
Auth *auth.Auth

View file

@ -11,7 +11,7 @@ import (
type SSHKeys struct {
component.Base
Dependencies struct {
dependencies struct {
SQL *sql.SQL
Auth *auth.Auth
}
@ -25,7 +25,7 @@ var (
// Admin returns the set of administrative ssh keys.
// These are ssh keys associated to distillery admin users.
func (k *SSHKeys) Admin(ctx context.Context) (keys []ssh.PublicKey, err error) {
users, err := k.Dependencies.Auth.Users(ctx)
users, err := k.dependencies.Auth.Users(ctx)
if err != nil {
return nil, err
}

View file

@ -11,7 +11,7 @@ import (
func (ssh2 *SSHKeys) TableInfo() component.TableInfo {
return component.TableInfo{
Model: reflectx.MakeType[models.Keys](),
Model: reflectx.TypeFor[models.Keys](),
Name: models.KeysTable,
}
}
@ -24,7 +24,7 @@ func (ssh2 *SSHKeys) Keys(ctx context.Context, user string) ([]models.Keys, erro
}
// get the table
table, err := ssh2.Dependencies.SQL.QueryTable(ctx, ssh2)
table, err := ssh2.dependencies.SQL.QueryTable(ctx, ssh2)
if err != nil {
return nil, err
}
@ -44,7 +44,7 @@ func (ssh2 *SSHKeys) Keys(ctx context.Context, user string) ([]models.Keys, erro
func (ssh2 *SSHKeys) Add(ctx context.Context, user string, comment string, key ssh.PublicKey) error {
// check that the given user exists
{
_, err := ssh2.Dependencies.Auth.User(ctx, user)
_, err := ssh2.dependencies.Auth.User(ctx, user)
if err != nil {
return err
}
@ -76,7 +76,7 @@ func (ssh2 *SSHKeys) Add(ctx context.Context, user string, comment string, key s
mk.SetPublicKey(key)
// get the table
table, err := ssh2.Dependencies.SQL.QueryTable(ctx, ssh2)
table, err := ssh2.dependencies.SQL.QueryTable(ctx, ssh2)
if err != nil {
return err
}
@ -107,7 +107,7 @@ func (ssh2 *SSHKeys) Remove(ctx context.Context, user string, key ssh.PublicKey)
}
// query the table again
table, err := ssh2.Dependencies.SQL.QueryTable(ctx, ssh2)
table, err := ssh2.dependencies.SQL.QueryTable(ctx, ssh2)
if err != nil {
return nil
}
@ -118,7 +118,7 @@ func (ssh2 *SSHKeys) Remove(ctx context.Context, user string, key ssh.PublicKey)
func (ssh2 *SSHKeys) OnUserDelete(ctx context.Context, user *models.User) error {
// get the table
table, err := ssh2.Dependencies.SQL.QueryTable(ctx, ssh2)
table, err := ssh2.dependencies.SQL.QueryTable(ctx, ssh2)
if err != nil {
return err
}

View file

@ -59,6 +59,29 @@ type Distillery struct {
lifetimeInit sync.Once
}
//
// INIT & EXPORT
//
func (dis *Distillery) init() {
dis.lifetimeInit.Do(func() {
dis.lifetime.Init = func(c component.Component, s component.Still) {
component.Init(c, s)
}
dis.lifetime.Register = dis.allComponents
})
}
func export[C component.Component](dis *Distillery) C {
dis.init()
return lifetime.Export[C](&dis.lifetime, dis.Still)
}
func exportAll[C component.Component](dis *Distillery) []C {
dis.init()
return lifetime.ExportSlice[C](&dis.lifetime, dis.Still)
}
//
// PUBLIC COMPONENT GETTERS
//
@ -119,92 +142,87 @@ func (dis *Distillery) Purger() *purger.Purger {
// THESE SHOULD NEVER BE CALLED DIRECTLY
//
func (dis *Distillery) allComponents() []initFunc {
return []initFunc{
auto[*docker.Docker],
auto[*binder.Binder],
auto[*web.Web],
func (dis *Distillery) allComponents(context *lifetime.RegisterContext[component.Component, component.Still]) {
lifetime.Place[*docker.Docker](context)
lifetime.Place[*binder.Binder](context)
lifetime.Place[*web.Web](context)
manual(func(ts *triplestore.Triplestore) {
ts.BaseURL = "http://" + dis.Upstream.TriplestoreAddr()
ts.PollInterval = time.Second
}),
lifetime.Register(context, func(ts *triplestore.Triplestore, _ component.Still) {
ts.BaseURL = "http://" + dis.Upstream.TriplestoreAddr()
ts.PollInterval = time.Second
})
manual(func(sql *sql.SQL) {
sql.ServerURL = dis.Upstream.SQLAddr()
sql.PollInterval = time.Second
}),
auto[*sql.LockTable],
auto[*sql.InstanceTable],
lifetime.Register(context, func(sql *sql.SQL, _ component.Still) {
sql.ServerURL = dis.Upstream.SQLAddr()
sql.PollInterval = time.Second
})
lifetime.Place[*sql.LockTable](context)
lifetime.Place[*sql.InstanceTable](context)
manual(func(s *solr.Solr) {
s.BaseURL = dis.Upstream.SolrAddr()
s.PollInterval = time.Second
}),
lifetime.Register(context, func(s *solr.Solr, _ component.Still) {
s.BaseURL = dis.Upstream.SolrAddr()
s.PollInterval = time.Second
})
// auth
auto[*auth.Auth],
auto[*policy.Policy],
auto[*panel.UserPanel],
auto[*next.Next],
auto[*tokens.Tokens],
// auth
lifetime.Place[*auth.Auth](context)
lifetime.Place[*policy.Policy](context)
lifetime.Place[*panel.UserPanel](context)
lifetime.Place[*next.Next](context)
lifetime.Place[*tokens.Tokens](context)
//scopes
auto[*scopes.Never],
auto[*scopes.UserLoggedIn],
auto[*scopes.AdminLoggedIn],
auto[*scopes.ListInstancesScope],
auto[*scopes.ListNewsScope],
auto[*scopes.ResolverScope],
//scopes
lifetime.Place[*scopes.Never](context)
lifetime.Place[*scopes.UserLoggedIn](context)
lifetime.Place[*scopes.AdminLoggedIn](context)
lifetime.Place[*scopes.ListInstancesScope](context)
lifetime.Place[*scopes.ListNewsScope](context)
lifetime.Place[*scopes.ResolverScope](context)
// instances
auto[*instances.Instances],
auto[*meta.Meta],
auto[*malt.Malt],
auto[*provision.Provision],
// instances
lifetime.Place[*instances.Instances](context)
lifetime.Place[*meta.Meta](context)
lifetime.Place[*malt.Malt](context)
lifetime.Place[*provision.Provision](context)
// Purger
auto[*purger.Purger],
// Purger
lifetime.Place[*purger.Purger](context)
// Snapshots
auto[*exporter.Exporter],
auto[*logger.Logger],
auto[*exporter.Config],
auto[*exporter.Bookkeeping],
auto[*exporter.Filesystem],
auto[*exporter.Pathbuilders],
// Snapshots
lifetime.Place[*exporter.Exporter](context)
lifetime.Place[*logger.Logger](context)
lifetime.Place[*exporter.Config](context)
lifetime.Place[*exporter.Bookkeeping](context)
lifetime.Place[*exporter.Filesystem](context)
lifetime.Place[*exporter.Pathbuilders](context)
// ssh server
auto[*ssh2.SSH2],
auto[*sshkeys.SSHKeys],
// ssh server
lifetime.Place[*ssh2.SSH2](context)
lifetime.Place[*sshkeys.SSHKeys](context)
// Control server
auto[*server.Server],
// Control server
lifetime.Place[*server.Server](context)
auto[*home.Home],
auto[*list.ListInstances],
manual(func(resolver *resolver.Resolver) {
resolver.RefreshInterval = time.Minute
}),
manual(func(admin *admin.Admin) {
admin.Analytics = &dis.lifetime.Analytics
}),
auto[*socket.Sockets],
auto[*legal.Legal],
auto[*news.News],
lifetime.Place[*home.Home](context)
lifetime.Place[*list.ListInstances](context)
lifetime.Register(context, func(resolver *resolver.Resolver, _ component.Still) {
resolver.RefreshInterval = time.Minute
})
lifetime.Place[*admin.Admin](context) // TODO: Remove analytics
lifetime.Place[*socket.Sockets](context)
lifetime.Place[*legal.Legal](context)
lifetime.Place[*news.News](context)
auto[*assets.Static],
auto[*logo.Logo],
auto[*templating.Templating],
lifetime.Place[*assets.Static](context)
lifetime.Place[*logo.Logo](context)
lifetime.Place[*templating.Templating](context)
// Cron
auto[*cron.Cron],
// Cron
lifetime.Place[*cron.Cron](context)
// API
auto[*api.API],
auto[*list.API],
auto[*list.API],
auto[*news.API],
auto[*resolver.API],
}
// API
lifetime.Place[*api.API](context)
lifetime.Place[*list.API](context)
lifetime.Place[*news.API](context)
lifetime.Place[*resolver.API](context)
}