Skip to content
Snippets Groups Projects
Commit 8b4354da authored by jensilo's avatar jensilo
Browse files

add automatic copy after parse safe

parent e9667002
No related branches found
No related tags found
No related merge requests found
......@@ -5,3 +5,5 @@ package eiffel
type Cfg struct {
Output OutputCfg `toml:"output"`
}
// TODO add tests for service, web and output
......@@ -6,6 +6,7 @@ import (
"github.com/google/uuid"
"github.com/org-harmony/harmony/src/app/template"
"github.com/org-harmony/harmony/src/app/template/parser"
"github.com/org-harmony/harmony/src/app/user"
"github.com/org-harmony/harmony/src/core/validation"
"net/http"
"strings"
......@@ -152,3 +153,55 @@ func SegmentMapToSegments(segments map[string]string) []parser.ParsingSegment {
return parsingSegments
}
// CopyAfterParseSetting returns whether the checkbox for copying after parsing should be rendered as checked.
// If the checkbox is checked in the request, the setting will be set to "on" in the session.
// If the checkbox is not checked in the request, the setting will be set to "off" in the session if it is not an initial request.
// If the initial request flag is set to true, the setting will not be changed and the request not read.
//
// Initial request means that the request initially loaded the form because in that case the setting should not be changed,
// as initially the value from the form will always be empty. Then only the value from the session is used.
// TODO add tests for this
func CopyAfterParseSetting(request *http.Request, sessionStore user.SessionRepository, init bool) bool {
session, err := user.SessionFromRequest(request, sessionStore)
if err != nil {
return false
}
copyAfterParse, err := session.Setting("eiffel.CopyAfterParse")
requestCopyAfterParse := ""
if !init {
err := request.ParseForm()
if err != nil {
return false
}
requestCopyAfterParse = request.FormValue("copyAfterParse")
}
if err != nil && requestCopyAfterParse == "" {
return false
}
if requestCopyAfterParse == "on" {
session.AddSetting("eiffel.CopyAfterParse", "on")
err := sessionStore.Write(request.Context(), session.ID, session)
if err != nil {
return false
}
return true
}
if requestCopyAfterParse == "" && !init {
session.AddSetting("eiffel.CopyAfterParse", "off")
err := sessionStore.Write(request.Context(), session.ID, session)
if err != nil {
return false
}
return false
}
return copyAfterParse == "on"
}
......@@ -83,6 +83,7 @@ type OutputFormData struct {
OutputFile string
}
// RegisterController registers the controllers as well as the navigation and event listeners.
func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
cfg := Cfg{}
util.Ok(config.C(&cfg, config.From("eiffel"), config.Validate(appCtx.Validator)))
......@@ -154,6 +155,7 @@ func registerNavigation(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
func eiffelElicitationPage(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
templateRepository := util.UnwrapType[template.Repository](appCtx.Repository(template.RepositoryName))
sessionStore := util.UnwrapType[user.SessionRepository](appCtx.Repository(user.SessionRepositoryName))
return web.NewController(appCtx, webCtx, func(io web.IO) error {
templateID := web.URLParam(io.Request(), "templateID")
......@@ -172,6 +174,8 @@ func eiffelElicitationPage(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
true,
)
formData.CopyAfterParse = CopyAfterParseSetting(io.Request(), sessionStore, true)
return renderElicitationPage(io, formData, nil, []error{err})
})
}
......@@ -227,6 +231,7 @@ func searchTemplate(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
func elicitationTemplate(appCtx *hctx.AppCtx, webCtx *web.Ctx, defaultFirstVariant bool) http.Handler {
templateRepository := util.UnwrapType[template.Repository](appCtx.Repository(template.RepositoryName))
sessionStore := util.UnwrapType[user.SessionRepository](appCtx.Repository(user.SessionRepositoryName))
return web.NewController(appCtx, webCtx, func(io web.IO) error {
templateID := web.URLParam(io.Request(), "templateID")
......@@ -247,6 +252,8 @@ func elicitationTemplate(appCtx *hctx.AppCtx, webCtx *web.Ctx, defaultFirstVaria
return io.InlineError(err)
}
formData.CopyAfterParse = CopyAfterParseSetting(io.Request(), sessionStore, true)
io.Response().Header().Set("HX-Push-URL", fmt.Sprintf("/eiffel/%s/%s", templateID, formData.VariantKey))
return io.Render(
......@@ -260,6 +267,7 @@ func elicitationTemplate(appCtx *hctx.AppCtx, webCtx *web.Ctx, defaultFirstVaria
func parseRequirement(appCtx *hctx.AppCtx, webCtx *web.Ctx, cfg Cfg) http.Handler {
templateRepository := util.UnwrapType[template.Repository](appCtx.Repository(template.RepositoryName))
sessionStore := util.UnwrapType[user.SessionRepository](appCtx.Repository(user.SessionRepositoryName))
return web.NewController(appCtx, webCtx, func(io web.IO) error {
request := io.Request()
......@@ -326,6 +334,8 @@ func parseRequirement(appCtx *hctx.AppCtx, webCtx *web.Ctx, cfg Cfg) http.Handle
}
}
formData.CopyAfterParse = CopyAfterParseSetting(request, sessionStore, false)
return io.Render(web.NewFormData(formData, s, err), "eiffel.elicitation.form", "eiffel/_form-elicitation.go.html")
})
}
......
......@@ -5,6 +5,7 @@ import (
"github.com/org-harmony/harmony/src/core/web"
)
// RegisterController registers the home controller and navigation.
func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
registerNavigation(appCtx, webCtx)
......
......@@ -18,13 +18,8 @@ var (
ErrTemplateConfigIncomplete = validation.Error{Msg: "template.new.config-incomplete"}
)
// RegisterController registers the controllers and navigation for the template module.
func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
// TODO how can a lot of this be simplified? It's a lot of boilerplate code.
// Especially templating and error handling. Also, the handling of HTMX request and partial page loads
// does not really seem to be unified. As of right now, I am not fully satisfied with this.
// Maybe it would be helpful to write a PoC focussing fully on the UI/UX first and then adapt the backend to it.
// In this approach it could also be helpful to fully decouple all the rendering logic from the business logic.
registerNavigation(appCtx, webCtx)
router := webCtx.Router.With(user.LoggedInMiddleware(appCtx))
......@@ -39,7 +34,6 @@ func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx) {
router.Get("/template-set/{id}/list", templateListController(appCtx, webCtx).ServeHTTP)
router.Get("/template-set/{id}/new", templateNewController(appCtx, webCtx).ServeHTTP)
router.Post("/template-set/{id}/new", templateNewSaveController(appCtx, webCtx).ServeHTTP)
router.Get("/template/{id}/edit", templateEditPageController(appCtx, webCtx).ServeHTTP)
router.Put("/template/{id}", templateEditSaveController(appCtx, webCtx).ServeHTTP)
router.Delete("/template/{id}", templateDeleteController(appCtx, webCtx).ServeHTTP)
......
......@@ -161,3 +161,28 @@ func (s *Session) IsHardExpired() bool {
return false
}
// AddSetting adds a setting to the session. Settings are stored in the SessionMeta.Settings map.
// If the map is nil it will be initialized.
func (s *Session) AddSetting(key, value string) {
if s.Meta.Settings == nil {
s.Meta.Settings = make(map[string]string)
}
s.Meta.Settings[key] = value
}
// Setting returns the value for the given key from the SessionMeta.Settings map.
// If the map is nil or the key is not present it returns an error.
func (s *Session) Setting(key string) (string, error) {
if s.Meta.Settings == nil {
return "", errors.New("setting not found")
}
value, ok := s.Meta.Settings[key]
if !ok {
return "", errors.New("setting not found")
}
return value, nil
}
......@@ -116,6 +116,7 @@
<div class="accordion-body">
<div class="form-check">
<input form="eiffelElicitationForm" class="form-check-input" role="button"
autocomplete="off"
type="checkbox" name="copyAfterParse" id="copyAfterParse"
{{ if .Data.Form.CopyAfterParse }}checked{{ end }}/>
<label class="form-check-label" for="copyAfterParse" role="button">
......
......@@ -4,10 +4,6 @@
{{ $parsingResult := .Data.Form.ParsingResult }}
{{ $segments := .Data.Form.SegmentMap }}
{{/*
TODO save copy to clipboard setting to user session
*/}}
<h4>{{ t "eiffel.elicitation.form.title" }}</h4>
<form hx-post="/eiffel/elicitation/{{ .Data.Form.TemplateID }}/{{ .Data.Form.VariantKey }}"
hx-target=".eiffel-elicitation-template-variant-form"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment