wisski-cloud-distillery/internal/dis/component/auth/panel/tokens.go
2023-11-02 12:05:13 +01:00

184 lines
4.8 KiB
Go

package panel
import (
"context"
"html/template"
"net/http"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
"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/rs/zerolog"
"github.com/tkw1536/pkglib/httpx"
"github.com/tkw1536/pkglib/httpx/field"
_ "embed"
)
//go:embed "templates/tokens.html"
var tokensHTML []byte
var tokensTemplate = templating.Parse[TokenTemplateContext](
"tokens.html", tokensHTML, nil,
templating.Title("Tokens"),
templating.Assets(assets.AssetsUser),
)
type TokenTemplateContext struct {
templating.RuntimeFlags
Domain template.URL // server base URL
Tokens []models.Token
}
func (panel *UserPanel) tokensRoute(ctx context.Context) http.Handler {
tpl := tokensTemplate.Prepare(
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
),
templating.Actions(
menuTokensAdd,
),
)
return tpl.HTMLHandler(func(r *http.Request) (tc TokenTemplateContext, err error) {
// list the user
user, err := panel.dependencies.Auth.UserOfSession(r)
if err != nil || user == nil {
return tc, err
}
tc.Domain = template.URL(panel.Config.HTTP.JoinPath().String())
// get the tokens
tc.Tokens, err = panel.dependencies.Tokens.Tokens(r.Context(), user.User.User)
return tc, err
})
}
func (panel *UserPanel) tokensDeleteRoute(ctx context.Context) http.Handler {
logger := zerolog.Ctx(ctx)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
logger.Err(err).Str("action", "delete token").Msg("failed to parse form")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
}
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)
return
}
id := r.PostFormValue("id")
if id == "" {
logger.Err(err).Str("action", "delete token").Msg("failed to get token")
httpx.HTMLInterceptor.Fallback.ServeHTTP(w, r)
return
}
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
}
http.Redirect(w, r, string(menuTokens.Path), http.StatusSeeOther)
})
}
//go:embed "templates/tokens_add.html"
var tokensAddHTML []byte
var tokensAddTemplate = templating.ParseForm(
"tokens_add.html", tokensAddHTML, httpx.FormTemplate,
templating.Title("Add Token"),
templating.Assets(assets.AssetsUser),
)
type addTokenResult struct {
User *auth.AuthUser
Description string
Scopes []string
}
//go:embed "templates/token_created.html"
var tokenCreatedHTML []byte
var tokenCreateTemplate = templating.Parse[TokenCreateContext](
"token_created.html", tokenCreatedHTML, httpx.FormTemplate,
templating.Title("Add Token"),
templating.Assets(assets.AssetsUser),
)
type TokenCreateContext struct {
templating.RuntimeFlags
Domain template.URL // server base URL
Token *models.Token
}
func (panel *UserPanel) tokensAddRoute(ctx context.Context) http.Handler {
tplForm := tokensAddTemplate.Prepare(
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
menuTokensAdd,
),
)
tplDone := tokenCreateTemplate.Prepare(
panel.dependencies.Templating,
templating.Crumbs(
menuUser,
menuTokens,
menuTokensAdd,
),
)
return &httpx.Form[addTokenResult]{
Fields: []field.Field{
{Name: "description", Type: field.Text, Label: "Description"},
},
FieldTemplate: field.PureCSSFieldTemplate,
RenderTemplate: tplForm.Template(),
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)
if err != nil || at.User == nil {
return at, errInvalidUser
}
at.Description = values["description"]
if at.Description == "" {
at.Description = "API Key"
}
at.Scopes = nil
return at, nil
},
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)
if err != nil {
return err
}
if err != nil {
return errAddToken
}
// render the created context
return httpx.WriteHTML(tplDone.Context(r, TokenCreateContext{
Domain: template.URL(panel.Config.HTTP.JoinPath().String()),
Token: tok,
}), nil, tplDone.Template(), "", w, r)
},
}
}