Skip to content

Commit

Permalink
Refactor Echo Bind
Browse files Browse the repository at this point in the history
- no longer using `context.Bind` on maps -- only structs
- now using new funtion `formdata.Parse` for other form values
- refactor some comments/logs/error messages
  • Loading branch information
benpate committed Jan 7, 2025
1 parent 91e7186 commit 5d8e0e2
Show file tree
Hide file tree
Showing 28 changed files with 468 additions and 242 deletions.
14 changes: 6 additions & 8 deletions build/step_EditConnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/EmissarySocial/emissary/service/providers"
"github.com/benpate/derp"
"github.com/benpate/rosetta/mapof"
)

type StepEditConnection struct{}
Expand Down Expand Up @@ -62,12 +61,6 @@ func (step StepEditConnection) Post(builder Builder, _ io.Writer) PipelineBehavi
// This step must be run in a Domain admin
domainBuilder := builder.(Domain)

postData := mapof.NewAny()

if err := bind(builder.request(), &postData); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing POST data"))
}

// Collect parameters and services
providerID := builder.QueryParam("providerId")

Expand All @@ -92,8 +85,13 @@ func (step StepEditConnection) Post(builder Builder, _ io.Writer) PipelineBehavi
// Retrieve the custom form for this Manual Provider
form := manualProvider.ManualConfig()

// Parse the data in the Form post
if err := builder.request().ParseForm(); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing form body"))
}

// Apply the form data to the domain object
if err := form.SetAll(&connection, postData, nil); err != nil {
if err := form.SetURLValues(&connection, builder.request().Form, nil); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error updating domain object form"))
}

Expand Down
23 changes: 14 additions & 9 deletions build/step_EditContent.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"io"

"github.com/EmissarySocial/emissary/model"
"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/rosetta/mapof"
)

// StepEditContent is a Step that can edit/update Container in a streamDraft.
Expand All @@ -18,9 +18,11 @@ type StepEditContent struct {

func (step StepEditContent) Get(builder Builder, buffer io.Writer) PipelineBehavior {

const location = "build.StepEditContent.Get"

if step.Filename != "" {
if err := builder.execute(buffer, step.Filename, builder); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditContent.Get", "Error executing template"))
return Halt().WithError(derp.Wrap(err, location, "Error executing template"))
}
}

Expand All @@ -29,13 +31,15 @@ func (step StepEditContent) Get(builder Builder, buffer io.Writer) PipelineBehav

func (step StepEditContent) Post(builder Builder, _ io.Writer) PipelineBehavior {

const location = "build.StepEditContent.Post"

var rawContent string

// Require that we're working with a Stream
stream, ok := builder.object().(*model.Stream)

if !ok {
return Halt().WithError(derp.NewInternalError("build.StepEditContent.Post", "step: EditContent can only be used on a Stream"))
return Halt().WithError(derp.NewInternalError(location, "step: EditContent can only be used on a Stream"))
}

// Try to read the content from the request body
Expand All @@ -46,20 +50,21 @@ func (step StepEditContent) Post(builder Builder, _ io.Writer) PipelineBehavior
var buffer bytes.Buffer

if _, err := io.Copy(&buffer, builder.request().Body); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditContent.Post", "Error reading request data"))
return Halt().WithError(derp.Wrap(err, location, "Error reading request data"))
}

rawContent = buffer.String()

// All other types are a Form post
default:

body := mapof.NewAny()
if err := bind(builder.request(), &body); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditContent.Post", "Error parsing request data"))
value, err := formdata.Parse(builder.request())

if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing request data"))
}

rawContent = body.GetString(step.Fieldname)
rawContent = value.Get(step.Fieldname)
}

// Set the new Content value in the Stream
Expand All @@ -68,7 +73,7 @@ func (step StepEditContent) Post(builder Builder, _ io.Writer) PipelineBehavior

// Try to save the object back to the database
if err := builder.service().ObjectSave(stream, "Content edited"); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditContent.Post", "Error saving stream"))
return Halt().WithError(derp.Wrap(err, location, "Error saving stream"))
}

// Success!
Expand Down
14 changes: 7 additions & 7 deletions build/step_EditModelObject.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"strings"
"text/template"

"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/form"
"github.com/benpate/rosetta/mapof"
)

// StepEditModelObject is an action that can add new sub-streams to the domain.
Expand Down Expand Up @@ -58,19 +58,19 @@ func (step StepEditModelObject) Post(builder Builder, _ io.Writer) PipelineBehav

const location = "build.StepEditModelObject.Post"

// Get the request body
body := mapof.NewAny()
// Get the request data
values, err := formdata.Parse(builder.request())

if err := bind(builder.request(), &body); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error binding request body"))
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing form values"))
}

// Appy request body to the object (limited and validated by the form schema)
stepForm := form.New(builder.schema(), step.getForm(builder))
object := builder.object()

if err := stepForm.SetAll(object, body, builder.lookupProvider()); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error applying request body to model object", body))
if err := stepForm.SetURLValues(object, values, builder.lookupProvider()); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error applying request body to model object"))
}

// Success!
Expand Down
7 changes: 4 additions & 3 deletions build/step_EditRegistration.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package build
import (
"io"

"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/EmissarySocial/emissary/tools/random"
"github.com/benpate/derp"
"github.com/benpate/html"
Expand Down Expand Up @@ -119,14 +120,14 @@ func (step StepEditRegistration) Post(builder Builder, _ io.Writer) PipelineBeha
}

// Bind to the form POST data
inputs := mapof.NewAny()
if err := bind(builder.request(), &inputs); err != nil {
inputs, err := formdata.Parse(builder.request())
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error binding form data"))
}

// Use the schema to set the form inputs into a new map
data := mapof.NewString()
if err := registration.Schema.SetAll(&data, inputs); err != nil {
if err := registration.Schema.SetURLValues(&data, inputs); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error updating domain object form"))
}

Expand Down
8 changes: 4 additions & 4 deletions build/step_EditTable.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"io"
"strings"

"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/form"
"github.com/benpate/rosetta/convert"
"github.com/benpate/rosetta/mapof"
"github.com/benpate/table"
)

Expand Down Expand Up @@ -52,9 +52,9 @@ func (step StepTableEditor) Post(builder Builder, _ io.Writer) PipelineBehavior
object := builder.object()

// Try to get the form post data
body := mapof.NewAny()
body, err := formdata.Parse(builder.request())

if err := bindBody(builder.request(), &body); err != nil {
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Failed to bind body", step))
}

Expand All @@ -75,7 +75,7 @@ func (step StepTableEditor) Post(builder Builder, _ io.Writer) PipelineBehavior
for _, field := range step.Form.AllElements() {
path := step.Path + "." + edit + "." + field.Path

if err := s.Set(object, path, body[field.Path]); err != nil {
if err := s.Set(object, path, body.Get(field.Path)); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error setting value in table", object, field.Path, path, body[field.Path]))
}
}
Expand Down
13 changes: 7 additions & 6 deletions build/step_EditTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ import (
"io"

"github.com/EmissarySocial/emissary/model"
"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/form"
"github.com/benpate/html"
"github.com/benpate/rosetta/mapof"
"github.com/benpate/rosetta/slice"
)

// StepEditTemplate is a Step that can delete a Stream from the Domain
// StepEditTemplate is a Step that lets users choose their profile template(s)
type StepEditTemplate struct {
Title string
Paths []string
}

// Get displays a customizable confirmation form for the delete
// Get displays a form where users can select their profile template(s)
func (step StepEditTemplate) Get(builder Builder, buffer io.Writer) PipelineBehavior {

schema := builder.schema()
Expand Down Expand Up @@ -55,7 +56,7 @@ func (step StepEditTemplate) Get(builder Builder, buffer io.Writer) PipelineBeha
return Continue()
}

// Post removes the object from the database (likely using a soft-delete, though)
// Post updates a User's profile template(s)
func (step StepEditTemplate) Post(builder Builder, _ io.Writer) PipelineBehavior {

const location = "build.StepEditTemplate.Post"
Expand All @@ -64,17 +65,17 @@ func (step StepEditTemplate) Post(builder Builder, _ io.Writer) PipelineBehavior
object := builder.object()

// Collect inputs from the form
transaction := make(map[string]string)
transaction, err := formdata.Parse(builder.request())

if err := bind(builder.request(), &transaction); err != nil {
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing form"))
}

// Multiple Templates may be specified. So, for each new value...
for _, path := range step.Paths {

// Find the new TemplateID
newTemplateID := transaction[path]
newTemplateID := transaction.Get(path)

// Scan all allowed records
if step.isTemplateAllowed(builder, path, newTemplateID) {
Expand Down
20 changes: 11 additions & 9 deletions build/step_EditWidget.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"io"

"github.com/EmissarySocial/emissary/model"
"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/form"
"github.com/benpate/rosetta/mapof"
)

// StepEditWidget is a Step that can update the data.DataMap custom data stored in a Stream
// StepEditWidget is a Step that displays a form for editing Widgets.
type StepEditWidget struct{}

func (step StepEditWidget) Get(builder Builder, buffer io.Writer) PipelineBehavior {
Expand All @@ -36,26 +36,28 @@ func (step StepEditWidget) Get(builder Builder, buffer io.Writer) PipelineBehavi
return nil
}

// Post updates the stream with approved data from the request body.
// Post updates a Widget's configuration data.
func (step StepEditWidget) Post(builder Builder, _ io.Writer) PipelineBehavior {

const location = "build.StepEditWidget.Post"

// Locate the widget and its configuration
widget, streamWidget, streamBuilder, err := step.common(builder)

if err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "Error locating widget"))
return Halt().WithError(derp.Wrap(err, location, "Error locating widget"))
}

// Get the form post information
formData := mapof.NewAny()
if err := bind(builder.request(), &formData); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "Error binding form data"))
values, err := formdata.Parse(builder.request())
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error binding form data"))
}

// Apply the form data to the widget
f := form.New(widget.Schema, widget.Form)
if err := f.SetAll(&streamWidget.Data, formData, nil); err != nil {
return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "Error applying form data to widget"))
if err := f.SetURLValues(&streamWidget.Data, values, nil); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error applying form data to widget"))
}

// Update the stream with the new widget (in the same location)
Expand Down
7 changes: 4 additions & 3 deletions build/step_SetData.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"text/template"

"github.com/EmissarySocial/emissary/tools/formdata"
"github.com/benpate/derp"
"github.com/benpate/rosetta/compare"
"github.com/benpate/rosetta/mapof"
Expand Down Expand Up @@ -66,10 +67,10 @@ func (step StepSetData) Post(builder Builder, _ io.Writer) PipelineBehavior {

if len(step.FromForm) > 0 {

transaction := mapof.NewAny()

// Collect form POST information
if err := bindBody(builder.request(), &transaction); err != nil {
transaction, err := formdata.Parse(builder.request())

if err != nil {
result := derp.Wrap(err, location, "Error binding body", derp.WithCode(http.StatusBadRequest))
return Halt().WithError(result)
}
Expand Down
Loading

0 comments on commit 5d8e0e2

Please sign in to comment.