diff --git a/render/render.go b/build/build.go
similarity index 68%
rename from render/render.go
rename to build/build.go
index ba6c84fb7..10675c60d 100644
--- a/render/render.go
+++ b/build/build.go
@@ -1,12 +1,12 @@
/*
-Package render contains render objects, which are passed to HTML templates
+Package build contains build objects, which are passed to HTML templates
to generate HTML pages. Render objects wrap a specific model object,
providing some safety against direct access to protected data. Render
objects also include additional methods to query related records in the
-database. For example, the "Stream" renderer has queries for `Ancestors`,
+database. For example, the "Stream" builder has queries for `Ancestors`,
`Parent`, `Siblings`, and `Children` streams.
This package also contains implementations for all the action steps available
to template designers.
*/
-package render
+package build
diff --git a/render/renderer_.go b/build/builder_.go
similarity index 60%
rename from render/renderer_.go
rename to build/builder_.go
index 3372e0bfa..424327d6a 100644
--- a/render/renderer_.go
+++ b/build/builder_.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"html/template"
@@ -13,10 +13,10 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Renderer safely wraps model objects for consumption by an html Template
-type Renderer interface {
+// Builder safely wraps model objects for consumption by an html Template
+type Builder interface {
- // Render is the main entry-point for templates to use a Renderer
+ // Render is the main entry-point for templates to use a Builder
Render() (template.HTML, error) // Render function outputs an HTML template
View(string) (template.HTML, error) // Render function outputs an HTML template
@@ -24,17 +24,17 @@ type Renderer interface {
Host() string // String representation of the protocol + hostname
Protocol() string // String representation of the HTTP protocol to use when addressing this record (http:// or https://)
Hostname() string // Hostname for this server
- Token() string // URL Token of the record being rendered
+ Token() string // URL Token of the record being builded
NavigationID() string // ID of the Top-Level item to highlight in the navigation.
PageTitle() string // Human-friendly title to put at the top of the page.
Summary() string // Human-friendly summary to put at the top of the page (maybe)
- Permalink() string // Permanent link to the record being rendered
+ Permalink() string // Permanent link to the record being builded
BasePath() string // URL Path of the root of this object, without any additional actions.
URL() string // Complete URL of the requested page
QueryParam(string) string // Query parameter of the requested page
SetQueryParam(string, string) // Sets a queryString parameter
ActionID() string // Token that identifies the action requested via the URL.
- Action() model.Action // The pipeline action to be taken by this renderer
+ Action() model.Action // The pipeline action to be taken by this builder
IsAuthenticated() bool // Returns TRUE if the user is signed in
IsPartialRequest() bool // Returns TRUE if this is an HTMX request for a page fragment
UserCan(string) bool // Returns TRUE if the signed-in user has access to the named action
@@ -52,21 +52,21 @@ type Renderer interface {
GetContent() template.HTML
SetContent(string)
- factory() Factory // The service factory
- request() *http.Request // The original http.Request that we are responding to
- response() http.ResponseWriter // The original http.ResponseWriter that we are responding to
- authorization() model.Authorization // The user's authorization data from the context
- service() service.ModelService // The abstracted ModelService the backs this Renderer
- templateRole() string // Returns the role that the current template plays in the system. Used for choosing child template.
- template() model.Template // The template used for this renderer (if any)
- objectType() string // The type of object being rendered
- schema() schema.Schema // Schema to use to validate this Object
- object() data.Object // Model Object being rendered
- objectID() primitive.ObjectID // MongoDB ObjectID of the Object being rendered
- getUser() (model.User, error) // Retrieves the currently-logged-in user
- lookupProvider() form.LookupProvider // Retrieves the LookupProvider for this user
- debug() // Outputs debug information to the console
- clone(action string) (Renderer, error) // Creates a new Renderer with the same type and object, but a different action
+ factory() Factory // The service factory
+ request() *http.Request // The original http.Request that we are responding to
+ response() http.ResponseWriter // The original http.ResponseWriter that we are responding to
+ authorization() model.Authorization // The user's authorization data from the context
+ service() service.ModelService // The abstracted ModelService the backs this Builder
+ templateRole() string // Returns the role that the current template plays in the system. Used for choosing child template.
+ template() model.Template // The template used for this builder (if any)
+ objectType() string // The type of object being builded
+ schema() schema.Schema // Schema to use to validate this Object
+ object() data.Object // Model Object being builded
+ objectID() primitive.ObjectID // MongoDB ObjectID of the Object being builded
+ getUser() (model.User, error) // Retrieves the currently-logged-in user
+ lookupProvider() form.LookupProvider // Retrieves the LookupProvider for this user
+ debug() // Outputs debug information to the console
+ clone(action string) (Builder, error) // Creates a new Builder with the same type and object, but a different action
- executeTemplate(io.Writer, string, any) error // The HTML template used by this Renderer
+ executeTemplate(io.Writer, string, any) error // The HTML template used by this Builder
}
diff --git a/render/renderer_admin_block.go b/build/builder_admin_block.go
similarity index 86%
rename from render/renderer_admin_block.go
rename to build/builder_admin_block.go
index 7e0b42563..3bdeca285 100644
--- a/render/renderer_admin_block.go
+++ b/build/builder_admin_block.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -17,23 +17,23 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Rule is a renderer for the admin/rules page
+// Rule is a builder for the admin/rules page
// It can only be accessed by a Domain Owner
type Rule struct {
_rule *model.Rule
Common
}
-// NewRule returns a fully initialized `Rule` renderer.
+// NewRule returns a fully initialized `Rule` builder.
func NewRule(factory Factory, request *http.Request, response http.ResponseWriter, rule *model.Rule, template model.Template, actionID string) (Rule, error) {
- const location = "render.NewRule"
+ const location = "build.NewRule"
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Rule{}, derp.Wrap(err, location, "Error creating common renderer")
+ return Rule{}, derp.Wrap(err, location, "Error creating common builder")
}
// Verify that the user is a Domain Owner
@@ -41,7 +41,7 @@ func NewRule(factory Factory, request *http.Request, response http.ResponseWrite
return Rule{}, derp.NewForbiddenError(location, "Must be domain owner to continue")
}
- // Return the Rule renderer
+ // Return the Rule builder
return Rule{
_rule: rule,
Common: common,
@@ -61,7 +61,7 @@ func (w Rule) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Rule.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Rule.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -74,15 +74,15 @@ func (w Rule) Render() (template.HTML, error) {
// View executes a separate view for this Rule
func (w Rule) View(actionID string) (template.HTML, error) {
- const location = "render.Rule.View"
+ const location = "build.Rule.View"
- renderer, err := NewRule(w._factory, w._request, w._response, w._rule, w._template, actionID)
+ builder, err := NewRule(w._factory, w._request, w._response, w._rule, w._template, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, location, "Error creating Rule renderer")
+ return template.HTML(""), derp.Wrap(err, location, "Error creating Rule builder")
}
- return renderer.Render()
+ return builder.Render()
}
func (w Rule) NavigationID() string {
@@ -129,7 +129,7 @@ func (w Rule) executeTemplate(writer io.Writer, name string, data any) error {
return w._template.HTMLTemplate.ExecuteTemplate(writer, name, data)
}
-func (w Rule) clone(action string) (Renderer, error) {
+func (w Rule) clone(action string) (Builder, error) {
return NewRule(w._factory, w._request, w._response, w._rule, w._template, action)
}
@@ -192,5 +192,5 @@ func (w Rule) ServerWideRules() *QueryBuilder[model.Rule] {
}
func (w Rule) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_admin_rule")
+ log.Debug().Interface("object", w.object()).Msg("builder_admin_rule")
}
diff --git a/render/renderer_admin_domain.go b/build/builder_admin_domain.go
similarity index 87%
rename from render/renderer_admin_domain.go
rename to build/builder_admin_domain.go
index 984dc9574..63e5ed3ca 100644
--- a/render/renderer_admin_domain.go
+++ b/build/builder_admin_domain.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -21,7 +21,7 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Domain is the renderer for the admin/domain page
+// Domain is the builder for the admin/domain page
// It can only be accessed by a Domain Owner
type Domain struct {
_provider *service.Provider
@@ -29,16 +29,16 @@ type Domain struct {
Common
}
-// NewDomain returns a fully initialized `Domain` renderer.
+// NewDomain returns a fully initialized `Domain` builder.
func NewDomain(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, actionID string) (Domain, error) {
- const location = "render.NewDomain"
+ const location = "build.NewDomain"
- // Create the underlying common renderer
+ // Create the underlying common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Domain{}, derp.Wrap(err, location, "Error creating common renderer")
+ return Domain{}, derp.Wrap(err, location, "Error creating common builder")
}
// Verify that the user is a Domain Owner
@@ -46,7 +46,7 @@ func NewDomain(factory Factory, request *http.Request, response http.ResponseWri
return Domain{}, derp.NewForbiddenError(location, "Must be domain owner to continue")
}
- // Create and return the Domain renderer
+ // Create and return the Domain builder
result := Domain{
_provider: factory.Provider(),
Common: common,
@@ -75,7 +75,7 @@ func (w Domain) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Domain.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Domain.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -88,15 +88,15 @@ func (w Domain) Render() (template.HTML, error) {
// View executes a separate view for this Group
func (w Domain) View(actionID string) (template.HTML, error) {
- const location = "render.Domain.View"
+ const location = "build.Domain.View"
- renderer, err := NewDomain(w._factory, w._request, w._response, w._template, actionID)
+ builder, err := NewDomain(w._factory, w._request, w._response, w._template, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, location, "Error creating Group renderer")
+ return template.HTML(""), derp.Wrap(err, location, "Error creating Group builder")
}
- return renderer.Render()
+ return builder.Render()
}
func (w Domain) Token() string {
@@ -149,7 +149,7 @@ func (w Domain) PageTitle() string {
return "Settings"
}
-func (w Domain) clone(action string) (Renderer, error) {
+func (w Domain) clone(action string) (Builder, error) {
return NewDomain(w._factory, w._request, w._response, w._template, action)
}
@@ -214,5 +214,5 @@ func (w Domain) Provider(providerID string) providers.Provider {
return result
}
func (w Domain) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_admin_domain")
+ log.Debug().Interface("object", w.object()).Msg("builder_admin_domain")
}
diff --git a/render/renderer_admin_groups.go b/build/builder_admin_groups.go
similarity index 84%
rename from render/renderer_admin_groups.go
rename to build/builder_admin_groups.go
index 2c5bb09e1..0ee4299fd 100644
--- a/render/renderer_admin_groups.go
+++ b/build/builder_admin_groups.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -17,23 +17,23 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Group is a renderer for the admin/groups page
+// Group is a builder for the admin/groups page
// It can only be accessed by a Domain Owner
type Group struct {
_group *model.Group
Common
}
-// NewGroup returns a fully initialized `Group` renderer.
+// NewGroup returns a fully initialized `Group` builder.
func NewGroup(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, group *model.Group, actionID string) (Group, error) {
- const location = "render.NewGroup"
+ const location = "build.NewGroup"
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Group{}, derp.Wrap(err, location, "Error creating common renderer")
+ return Group{}, derp.Wrap(err, location, "Error creating common builder")
}
// Verify that the user is a Domain Owner
@@ -41,7 +41,7 @@ func NewGroup(factory Factory, request *http.Request, response http.ResponseWrit
return Group{}, derp.NewForbiddenError(location, "Must be domain owner to continue")
}
- // Return the Group renderer
+ // Return the Group builder
return Group{
_group: group,
Common: common,
@@ -61,7 +61,7 @@ func (w Group) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Group.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Group.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -74,15 +74,15 @@ func (w Group) Render() (template.HTML, error) {
// View executes a separate view for this Group
func (w Group) View(actionID string) (template.HTML, error) {
- const location = "render.Group.View"
+ const location = "build.Group.View"
- renderer, err := NewGroup(w._factory, w._request, w._response, w._template, w._group, actionID)
+ builder, err := NewGroup(w._factory, w._request, w._response, w._template, w._group, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, location, "Error creating Group renderer")
+ return template.HTML(""), derp.Wrap(err, location, "Error creating Group builder")
}
- return renderer.Render()
+ return builder.Render()
}
func (w Group) NavigationID() string {
@@ -132,7 +132,7 @@ func (w Group) executeTemplate(writer io.Writer, name string, data any) error {
return w._template.HTMLTemplate.ExecuteTemplate(writer, name, data)
}
-func (w Group) clone(action string) (Renderer, error) {
+func (w Group) clone(action string) (Builder, error) {
return NewGroup(w._factory, w._request, w._response, w._template, w._group, action)
}
@@ -175,5 +175,5 @@ func (w Group) Groups() *QueryBuilder[model.Group] {
}
func (w Group) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_admin_group")
+ log.Debug().Interface("object", w.object()).Msg("builder_admin_group")
}
diff --git a/render/renderer_admin_navigation.go b/build/builder_admin_navigation.go
similarity index 79%
rename from render/renderer_admin_navigation.go
rename to build/builder_admin_navigation.go
index f276ff350..375f734f2 100644
--- a/render/renderer_admin_navigation.go
+++ b/build/builder_admin_navigation.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -16,23 +16,23 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Navigation is a renderer for the admin/navigation page
+// Navigation is a builder for the admin/navigation page
// It can only be accessed by a Domain Owner
type Navigation struct {
_stream *model.Stream
Common
}
-// NewNavigation returns a fully initialized `Navigation` renderer.
+// NewNavigation returns a fully initialized `Navigation` builder.
func NewNavigation(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, stream *model.Stream, actionID string) (Navigation, error) {
- const location = "render.NewGroup"
+ const location = "build.NewGroup"
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Navigation{}, derp.Wrap(err, location, "Error creating common renderer")
+ return Navigation{}, derp.Wrap(err, location, "Error creating common builder")
}
// Verify that the user is a Domain Owner
@@ -40,7 +40,7 @@ func NewNavigation(factory Factory, request *http.Request, response http.Respons
return Navigation{}, derp.NewForbiddenError(location, "Must be domain owner to continue")
}
- // Return the Navigation renderer
+ // Return the Navigation builder
return Navigation{
Common: common,
}, nil
@@ -59,7 +59,7 @@ func (w Navigation) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w.factory(), &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Navigation.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Navigation.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -72,15 +72,15 @@ func (w Navigation) Render() (template.HTML, error) {
// View executes a separate view for this Group
func (w Navigation) View(actionID string) (template.HTML, error) {
- const location = "render.Navigation.View"
+ const location = "build.Navigation.View"
- renderer, err := NewNavigation(w.factory(), w._request, w._response, w._template, w._stream, actionID)
+ builder, err := NewNavigation(w.factory(), w._request, w._response, w._template, w._stream, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, location, "Error creating Group renderer")
+ return template.HTML(""), derp.Wrap(err, location, "Error creating Group builder")
}
- return renderer.Render()
+ return builder.Render()
}
func (w Navigation) Token() string {
@@ -127,10 +127,10 @@ func (w Navigation) executeTemplate(wr io.Writer, name string, data any) error {
return w._template.HTMLTemplate.ExecuteTemplate(wr, name, data)
}
-func (w Navigation) clone(action string) (Renderer, error) {
+func (w Navigation) clone(action string) (Builder, error) {
return NewNavigation(w._factory, w._request, w._response, w._template, w._stream, action)
}
func (w Navigation) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_admin_avigation")
+ log.Debug().Interface("object", w.object()).Msg("builder_admin_avigation")
}
diff --git a/render/renderer_admin_users.go b/build/builder_admin_users.go
similarity index 84%
rename from render/renderer_admin_users.go
rename to build/builder_admin_users.go
index db8b9c483..e171d45ec 100644
--- a/render/renderer_admin_users.go
+++ b/build/builder_admin_users.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -17,23 +17,23 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// User is a renderer for the admin/users page
+// User is a builder for the admin/users page
// It can only be accessed by a Domain Owner
type User struct {
_user *model.User
Common
}
-// NewUser returns a fully initialized `User` renderer.
+// NewUser returns a fully initialized `User` builder.
func NewUser(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, user *model.User, actionID string) (User, error) {
- const location = "render.NewGroup"
+ const location = "build.NewGroup"
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return User{}, derp.Wrap(err, location, "Error creating common renderer")
+ return User{}, derp.Wrap(err, location, "Error creating common builder")
}
// Verify that the user is a Domain Owner
@@ -41,7 +41,7 @@ func NewUser(factory Factory, request *http.Request, response http.ResponseWrite
return User{}, derp.NewForbiddenError(location, "Must be domain owner to continue")
}
- // Return the User renderer
+ // Return the User builder
return User{
_user: user,
Common: common,
@@ -61,7 +61,7 @@ func (w User) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w.factory(), &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.User.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.User.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -74,13 +74,13 @@ func (w User) Render() (template.HTML, error) {
// View executes a separate view for this User
func (w User) View(actionID string) (template.HTML, error) {
- renderer, err := NewUser(w._factory, w._request, w._response, w._template, w._user, actionID)
+ builder, err := NewUser(w._factory, w._request, w._response, w._template, w._user, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, "render.User.View", "Error creating renderer")
+ return template.HTML(""), derp.Wrap(err, "build.User.View", "Error creating builder")
}
- return renderer.Render()
+ return builder.Render()
}
func (w User) NavigationID() string {
@@ -127,7 +127,7 @@ func (w User) executeTemplate(writer io.Writer, name string, data any) error {
return w._template.HTMLTemplate.ExecuteTemplate(writer, name, data)
}
-func (w User) clone(action string) (Renderer, error) {
+func (w User) clone(action string) (Builder, error) {
return NewUser(w._factory, w._request, w._response, w._template, w._user, action)
}
@@ -200,9 +200,9 @@ func (w User) AssignedGroups() ([]model.Group, error) {
groupService := w.factory().Group()
result, err := groupService.ListByIDs(w._user.GroupIDs...)
- return result, derp.Wrap(err, "render.User.AssignedGroups", "Error listing groups", w._user.GroupIDs)
+ return result, derp.Wrap(err, "build.User.AssignedGroups", "Error listing groups", w._user.GroupIDs)
}
func (w User) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_admin_users")
+ log.Debug().Interface("object", w.object()).Msg("builder_admin_users")
}
diff --git a/render/renderer_common.go b/build/builder_common.go
similarity index 90%
rename from render/renderer_common.go
rename to build/builder_common.go
index c9902febc..4517e06db 100644
--- a/render/renderer_common.go
+++ b/build/builder_common.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"html/template"
@@ -21,13 +21,13 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Common provides common rendering functions that are needed by ALL renderers
+// Common provides common building functions that are needed by ALL builders
type Common struct {
_factory Factory // Factory interface is required for locating other services.
_request *http.Request // Pointer to the HTTP request we are serving
_response http.ResponseWriter // ResponseWriter for this request
_authorization model.Authorization // Authorization information for the current user
- _template model.Template // Template to use for this renderer
+ _template model.Template // Template to use for this builder
action model.Action // Action to be performed on the Template
actionID string // Token that identifies the action requested in the URL
@@ -39,7 +39,7 @@ type Common struct {
func NewCommon(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, actionID string) (Common, error) {
- const location = "render.NewCommon"
+ const location = "build.NewCommon"
// Retrieve the user's authorization information
steranko := factory.Steranko()
@@ -52,7 +52,7 @@ func NewCommon(factory Factory, request *http.Request, response http.ResponseWri
return Common{}, derp.NewBadRequestError(location, "Invalid action", actionID)
}
- // Return a new Common renderer
+ // Return a new Common builder
return Common{
_factory: factory,
_request: request,
@@ -67,10 +67,10 @@ func NewCommon(factory Factory, request *http.Request, response http.ResponseWri
}
/******************************************
- * Renderer Interface
+ * Builder Interface
******************************************/
-// context returns request context embedded in this renderer.
+// context returns request context embedded in this builder.
func (w Common) factory() Factory {
return w._factory
}
@@ -87,7 +87,7 @@ func (w Common) authorization() model.Authorization {
return w._authorization
}
-// Action returns the model.Action configured into this renderer
+// Action returns the model.Action configured into this builder
func (w Common) Action() model.Action {
return w.action
}
@@ -192,8 +192,8 @@ func (w Common) Now() int64 {
}
// NavigationID returns the the identifier of the top-most stream in the
-// navigation. The "common" renderer just returns a default value that
-// other renderers should override.
+// navigation. The "common" builder just returns a default value that
+// other builders should override.
func (w Common) NavigationID() string {
return ""
}
@@ -295,7 +295,7 @@ func (w Common) UserName() (string, error) {
user, err := w.getUser()
if err != nil {
- return "", derp.Wrap(err, "render.Stream.UserName", "Error loading User")
+ return "", derp.Wrap(err, "build.Stream.UserName", "Error loading User")
}
return user.DisplayName, nil
@@ -306,7 +306,7 @@ func (w Common) UserImage() (string, error) {
user, err := w.getUser()
if err != nil {
- return "", derp.Wrap(err, "render.Stream.UserAvatar", "Error loading User")
+ return "", derp.Wrap(err, "build.Stream.UserAvatar", "Error loading User")
}
return user.ActivityPubAvatarURL(), nil
@@ -316,12 +316,12 @@ func (w Common) UserImage() (string, error) {
* Misc Helper Methods
******************************************/
-// SubRenderer creates a new renderer for a child object. This function works
+// SubBuilder creates a new builder for a child object. This function works
// with Rule, Folder, Follower, Following, and Stream objects. It will return
// an error if the object is not one of those types.
-func (w Common) SubRenderer(object any) (Renderer, error) {
+func (w Common) SubBuilder(object any) (Builder, error) {
- var result Renderer
+ var result Builder
var err error
switch typed := object.(type) {
@@ -342,11 +342,11 @@ func (w Common) SubRenderer(object any) (Renderer, error) {
result, err = NewModel(w._factory, w._request, w._response, &typed, w._template, w.actionID)
default:
- result, err = nil, derp.NewInternalError("render.Common.SubRenderer", "Invalid object type", object)
+ result, err = nil, derp.NewInternalError("build.Common.SubBuilder", "Invalid object type", object)
}
if err != nil {
- err = derp.Wrap(err, "render.Common.SubRenderer", "Error creating sub-renderer for object", object)
+ err = derp.Wrap(err, "build.Common.SubBuilder", "Error creating sub-builder for object", object)
derp.Report(err)
}
@@ -362,7 +362,7 @@ func (w Common) ActivityStream(url string) streams.Document {
result, err := w._factory.ActivityStream().Load(url)
if err != nil {
- derp.Report(derp.Wrap(err, "render.Common.ActivityStream", "Error loading ActivityStream"))
+ derp.Report(derp.Wrap(err, "build.Common.ActivityStream", "Error loading ActivityStream"))
}
// Search for rules that might add a LABEL to this document.
@@ -412,7 +412,7 @@ func (w Common) GetFollowingID(url string) string {
result, err := followingService.GetFollowingID(w.AuthenticatedID(), url)
if err != nil {
- derp.Report(derp.Wrap(err, "render.Common.GetFollowingID", "Error getting following status", url))
+ derp.Report(derp.Wrap(err, "build.Common.GetFollowingID", "Error getting following status", url))
return ""
}
@@ -427,7 +427,7 @@ func (w Common) lookupProvider() form.LookupProvider {
func (w Common) executeTemplate(writer io.Writer, name string, data any) error {
if err := w._template.HTMLTemplate.ExecuteTemplate(writer, name, data); err != nil {
- return derp.Wrap(err, "render.Common.executeTemplate", "Error executing template", name)
+ return derp.Wrap(err, "build.Common.executeTemplate", "Error executing template", name)
}
return nil
@@ -456,7 +456,7 @@ func (w Common) template() model.Template {
return w._template
}
-// getUser loads/caches the currently-signed-in user to be used by other functions in this renderer
+// getUser loads/caches the currently-signed-in user to be used by other functions in this builder
func (w Common) getUser() (model.User, error) {
userService := w._factory.User()
@@ -465,7 +465,7 @@ func (w Common) getUser() (model.User, error) {
authorization := getAuthorization(steranko, w._request)
if err := userService.LoadByID(authorization.UserID, &result); err != nil {
- return model.User{}, derp.Wrap(err, "render.Common.getUser", "Error loading user from database", authorization.UserID)
+ return model.User{}, derp.Wrap(err, "build.Common.getUser", "Error loading user from database", authorization.UserID)
}
return result, nil
@@ -477,7 +477,7 @@ func (w *Common) getDomain() (model.Domain, error) {
domainService := w._factory.Domain()
if !domainService.Ready() {
- return model.Domain{}, derp.NewInternalError("render.Common.getDomain", "Domain service not ready", nil)
+ return model.Domain{}, derp.NewInternalError("build.Common.getDomain", "Domain service not ready", nil)
}
return domainService.Get(), nil
diff --git a/render/renderer_inbox.go b/build/builder_inbox.go
similarity index 88%
rename from render/renderer_inbox.go
rename to build/builder_inbox.go
index aa3c81da9..b7e265b03 100644
--- a/render/renderer_inbox.go
+++ b/build/builder_inbox.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -23,13 +23,13 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Inbox is a renderer for the @user/inbox page
+// Inbox is a builder for the @user/inbox page
type Inbox struct {
_user *model.User
Common
}
-// NewInbox returns a fully initialized `Inbox` renderer
+// NewInbox returns a fully initialized `Inbox` builder
func NewInbox(factory Factory, request *http.Request, response http.ResponseWriter, user *model.User, actionID string) (Inbox, error) {
// Load the Template
@@ -37,14 +37,14 @@ func NewInbox(factory Factory, request *http.Request, response http.ResponseWrit
template, err := templateService.Load("user-inbox") // TODO: Users should get to select their inbox template
if err != nil {
- return Inbox{}, derp.Wrap(err, "render.NewInbox", "Error loading template")
+ return Inbox{}, derp.Wrap(err, "build.NewInbox", "Error loading template")
}
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Inbox{}, derp.Wrap(err, "render.NewInbox", "Error creating common renderer")
+ return Inbox{}, derp.Wrap(err, "build.NewInbox", "Error creating common builder")
}
return Inbox{
@@ -66,7 +66,7 @@ func (w Inbox) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- return "", derp.ReportAndReturn(derp.Wrap(status.Error, "render.Inbox.Render", "Error generating HTML", w._request.URL.String()))
+ return "", derp.ReportAndReturn(derp.Wrap(status.Error, "build.Inbox.Render", "Error generating HTML", w._request.URL.String()))
}
// Success!
@@ -77,13 +77,13 @@ func (w Inbox) Render() (template.HTML, error) {
// View executes a separate view for this Inbox
func (w Inbox) View(actionID string) (template.HTML, error) {
- renderer, err := NewInbox(w._factory, w._request, w._response, w._user, actionID)
+ builder, err := NewInbox(w._factory, w._request, w._response, w._user, actionID)
if err != nil {
- return template.HTML(""), derp.ReportAndReturn(derp.Wrap(err, "render.Inbox.View", "Error creating Inbox renderer"))
+ return template.HTML(""), derp.ReportAndReturn(derp.Wrap(err, "build.Inbox.View", "Error creating Inbox builder"))
}
- return renderer.Render()
+ return builder.Render()
}
// NavigationID returns the ID to use for highlighing navigation menus
@@ -140,7 +140,7 @@ func (w Inbox) templateRole() string {
return "inbox"
}
-func (w Inbox) clone(action string) (Renderer, error) {
+func (w Inbox) clone(action string) (Builder, error) {
return NewInbox(w._factory, w._request, w._response, w._user, action)
}
@@ -240,14 +240,14 @@ func (w Inbox) FollowingByFolder(token string) ([]model.FollowingSummary, error)
userID := w.AuthenticatedID()
if userID.IsZero() {
- return nil, derp.NewUnauthorizedError("render.Inbox.FollowingByFolder", "Must be signed in to view following")
+ return nil, derp.NewUnauthorizedError("build.Inbox.FollowingByFolder", "Must be signed in to view following")
}
// Get the followingID from the token
followingID, err := primitive.ObjectIDFromHex(token)
if err != nil {
- return nil, derp.Wrap(err, "render.Inbox.FollowingByFolder", "Invalid following ID", token)
+ return nil, derp.Wrap(err, "build.Inbox.FollowingByFolder", "Invalid following ID", token)
}
// Try to load the matching records
@@ -264,7 +264,7 @@ func (w Inbox) FollowingByToken(followingToken string) (model.Following, error)
following := model.NewFollowing()
if err := followingService.LoadByToken(userID, followingToken, &following); err != nil {
- return model.Following{}, derp.Wrap(err, "render.Inbox.FollowingByID", "Error loading following")
+ return model.Following{}, derp.Wrap(err, "build.Inbox.FollowingByID", "Error loading following")
}
return following, nil
@@ -291,7 +291,7 @@ func (w Inbox) RuleByToken(token string) model.Rule {
rule := model.NewRule()
if err := ruleService.LoadByToken(w.AuthenticatedID(), token, &rule); err != nil {
- derp.Report(derp.Wrap(err, "render.Inbox.RuleByToken", "Error loading rule", token))
+ derp.Report(derp.Wrap(err, "build.Inbox.RuleByToken", "Error loading rule", token))
}
return rule
@@ -303,7 +303,7 @@ func (w Inbox) Inbox() (QueryBuilder[model.Message], error) {
userID := w.AuthenticatedID()
if userID.IsZero() {
- return QueryBuilder[model.Message]{}, derp.NewUnauthorizedError("render.Inbox.Inbox", "Must be signed in to view inbox")
+ return QueryBuilder[model.Message]{}, derp.NewUnauthorizedError("build.Inbox.Inbox", "Must be signed in to view inbox")
}
queryString := w._request.URL.Query()
@@ -311,7 +311,7 @@ func (w Inbox) Inbox() (QueryBuilder[model.Message], error) {
folderID, err := primitive.ObjectIDFromHex(queryString.Get("folderId"))
if err != nil {
- return QueryBuilder[model.Message]{}, derp.Wrap(err, "render.Inbox.Inbox", "Invalid folderId", queryString.Get("folderId"))
+ return QueryBuilder[model.Message]{}, derp.Wrap(err, "build.Inbox.Inbox", "Invalid folderId", queryString.Get("folderId"))
}
if queryString.Get("readDate") == "" {
@@ -379,14 +379,14 @@ func (w Inbox) Folders() (model.FolderList, error) {
// User must be authenticated to view any folders
if !w.IsAuthenticated() {
- return result, derp.NewForbiddenError("render.Inbox.Folders", "Not authenticated")
+ return result, derp.NewForbiddenError("build.Inbox.Folders", "Not authenticated")
}
folderService := w._factory.Folder()
folders, err := folderService.QueryByUserID(w.AuthenticatedID())
if err != nil {
- return result, derp.Wrap(err, "render.Inbox.Folders", "Error loading folders")
+ return result, derp.Wrap(err, "build.Inbox.Folders", "Error loading folders")
}
result.Folders = folders
@@ -399,12 +399,12 @@ func (w Inbox) FoldersWithSelection() (model.FolderList, error) {
result, err := w.Folders()
if err != nil {
- return result, derp.Wrap(err, "render.Inbox.FoldersWithSelection", "Error loading folders")
+ return result, derp.Wrap(err, "build.Inbox.FoldersWithSelection", "Error loading folders")
}
// Guarantee that we have at least one folder
if len(result.Folders) == 0 {
- return result, derp.NewInternalError("render.Inbox.FoldersWithSelection", "No folders found", nil)
+ return result, derp.NewInternalError("build.Inbox.FoldersWithSelection", "No folders found", nil)
}
// Find/Mark the Selected FolderID
@@ -438,7 +438,7 @@ func (w Inbox) Message() model.Message {
messageID, err := primitive.ObjectIDFromHex(w._request.URL.Query().Get("messageId"))
if err != nil {
- derp.Report(derp.Wrap(err, "render.Inbox.Message", "Invalid message ID", w._request.URL.Query().Get("messageId")))
+ derp.Report(derp.Wrap(err, "build.Inbox.Message", "Invalid message ID", w._request.URL.Query().Get("messageId")))
return model.NewMessage()
}
@@ -447,7 +447,7 @@ func (w Inbox) Message() model.Message {
message := model.NewMessage()
if err := inboxService.LoadByID(w.AuthenticatedID(), messageID, &message); err != nil {
- derp.Report(derp.Wrap(err, "render.Inbox.Message", "Error loading message", messageID))
+ derp.Report(derp.Wrap(err, "build.Inbox.Message", "Error loading message", messageID))
return model.NewMessage()
}
@@ -623,7 +623,7 @@ func (w Inbox) HasRule(ruleType string, trigger string) model.Rule {
// Retrieve rule record. "Not Found" is acceptable, but "legitimate" errors are not.
// In either case, do not halt the request
if err := ruleService.LoadByTrigger(w._user.UserID, ruleType, trigger, &rule); !derp.NilOrNotFound(err) {
- derp.Report(derp.Wrap(err, "render.Inbox.HasRule", "Error loading rule", ruleType, trigger))
+ derp.Report(derp.Wrap(err, "build.Inbox.HasRule", "Error loading rule", ruleType, trigger))
}
// Return the (possibly empty) Rule record
@@ -631,5 +631,5 @@ func (w Inbox) HasRule(ruleType string, trigger string) model.Rule {
}
func (w Inbox) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_Inbox")
+ log.Debug().Interface("object", w.object()).Msg("builder_Inbox")
}
diff --git a/render/renderer_model.go b/build/builder_model.go
similarity index 83%
rename from render/renderer_model.go
rename to build/builder_model.go
index a6d0c0391..e494c010a 100644
--- a/render/renderer_model.go
+++ b/build/builder_model.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -14,17 +14,17 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Model renders objects from any model service that implements the ModelService interface
+// Model builds objects from any model service that implements the ModelService interface
type Model struct {
_service service.ModelService
_object data.Object
Common
}
-// NewModel returns a fully initialized `Model` renderer.
+// NewModel returns a fully initialized `Model` builder.
func NewModel(factory Factory, request *http.Request, response http.ResponseWriter, object data.Object, template model.Template, actionID string) (Model, error) {
- const location = "render.NewModel"
+ const location = "build.NewModel"
action, ok := template.Action(actionID)
@@ -32,11 +32,11 @@ func NewModel(factory Factory, request *http.Request, response http.ResponseWrit
return Model{}, derp.NewBadRequestError(location, "Invalid action", actionID)
}
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Model{}, derp.Wrap(err, location, "Error creating common renderer")
+ return Model{}, derp.Wrap(err, location, "Error creating common builder")
}
// Check permissions on this model object
@@ -59,7 +59,7 @@ func NewModel(factory Factory, request *http.Request, response http.ResponseWrit
return Model{}, derp.NewInternalError(location, "Invalid model service", object)
}
- // Return the Model renderer
+ // Return the Model builder
return Model{
_service: modelService,
_object: object,
@@ -146,7 +146,7 @@ func (w Model) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Stream.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Stream.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -159,13 +159,13 @@ func (w Model) Render() (template.HTML, error) {
// View executes a separate view for this Stream
func (w Model) View(actionID string) (template.HTML, error) {
- const location = "render.Stream.View"
+ const location = "build.Stream.View"
- // Create a new renderer (this will also validate the user's permissions)
+ // Create a new builder (this will also validate the user's permissions)
subStream, err := NewModel(w._factory, w._request, w._response, w._object, w._template, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, location, "Error creating sub-renderer")
+ return template.HTML(""), derp.Wrap(err, location, "Error creating sub-builder")
}
// Generate HTML template
@@ -179,13 +179,13 @@ func (w Model) setState(stateID string) error {
return nil
}
- return derp.NewInternalError("render.Model.SetState", "Object does not implement model.StateSetter interface", w._object)
+ return derp.NewInternalError("build.Model.SetState", "Object does not implement model.StateSetter interface", w._object)
}
-func (w Model) clone(action string) (Renderer, error) {
+func (w Model) clone(action string) (Builder, error) {
return NewModel(w._factory, w._request, w._response, w._object, w._template, action)
}
func (w Model) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_Model")
+ log.Debug().Interface("object", w.object()).Msg("builder_Model")
}
diff --git a/render/renderer_oAuthAuthorization.go b/build/builder_oAuthAuthorization.go
similarity index 93%
rename from render/renderer_oAuthAuthorization.go
rename to build/builder_oAuthAuthorization.go
index 932dbf977..8e2604bb2 100644
--- a/render/renderer_oAuthAuthorization.go
+++ b/build/builder_oAuthAuthorization.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"strings"
@@ -9,7 +9,7 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// OAuthAuthorization is a lightweight renderer that
+// OAuthAuthorization is a lightweight builder that
// displays UI pages for an OAuth Application.
type OAuthAuthorization struct {
_service *service.OAuthClient
@@ -17,10 +17,10 @@ type OAuthAuthorization struct {
_request model.OAuthAuthorizationRequest
}
-// NewOAuthAuthorization returns a fully initialized/loaded `OAuthAuthorization` renderer
+// NewOAuthAuthorization returns a fully initialized/loaded `OAuthAuthorization` builder
func NewOAuthAuthorization(factory Factory, request model.OAuthAuthorizationRequest) (OAuthAuthorization, error) {
- const location = "render.NewOAuthAuthorization"
+ const location = "build.NewOAuthAuthorization"
// Create the result object
result := OAuthAuthorization{
diff --git a/render/renderer_outbox.go b/build/builder_outbox.go
similarity index 87%
rename from render/renderer_outbox.go
rename to build/builder_outbox.go
index 1cb3e8323..30d8acd32 100644
--- a/render/renderer_outbox.go
+++ b/build/builder_outbox.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -16,13 +16,13 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Outbox renders individual messages from a User's Outbox.
+// Outbox builds individual messages from a User's Outbox.
type Outbox struct {
_user *model.User
Common
}
-// NewOutbox returns a fully initialized `Outbox` renderer.
+// NewOutbox returns a fully initialized `Outbox` builder.
func NewOutbox(factory Factory, request *http.Request, response http.ResponseWriter, user *model.User, actionID string) (Outbox, error) {
// Load the Template
@@ -30,22 +30,22 @@ func NewOutbox(factory Factory, request *http.Request, response http.ResponseWri
template, err := templateService.Load("user-outbox") // Users should get to choose their own outbox template
if err != nil {
- return Outbox{}, derp.Wrap(err, "render.NewOutbox", "Error loading template")
+ return Outbox{}, derp.Wrap(err, "build.NewOutbox", "Error loading template")
}
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Outbox{}, derp.Wrap(err, "render.NewOutbox", "Error creating common renderer")
+ return Outbox{}, derp.Wrap(err, "build.NewOutbox", "Error creating common builder")
}
// Verify that the User's profile is visible
if !isUserVisible(&common._authorization, user) {
- return Outbox{}, derp.NewNotFoundError("render.NewOutbox", "User not found")
+ return Outbox{}, derp.NewNotFoundError("build.NewOutbox", "User not found")
}
- // Return the Outbox renderer
+ // Return the Outbox builder
return Outbox{
_user: user,
Common: common,
@@ -65,7 +65,7 @@ func (w Outbox) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Outbox.Render", "Error generating HTML", w._request.URL.String())
+ err := derp.Wrap(status.Error, "build.Outbox.Render", "Error generating HTML", w._request.URL.String())
derp.Report(err)
return "", err
}
@@ -78,13 +78,13 @@ func (w Outbox) Render() (template.HTML, error) {
// View executes a separate view for this Outbox
func (w Outbox) View(actionID string) (template.HTML, error) {
- renderer, err := NewOutbox(w._factory, w._request, w._response, w._user, actionID)
+ builder, err := NewOutbox(w._factory, w._request, w._response, w._user, actionID)
if err != nil {
- return template.HTML(""), derp.Wrap(err, "render.Outbox.View", "Error creating Outbox renderer")
+ return template.HTML(""), derp.Wrap(err, "build.Outbox.View", "Error creating Outbox builder")
}
- return renderer.Render()
+ return builder.Render()
}
// NavigationID returns the ID to use for highlighing navigation menus
@@ -135,7 +135,7 @@ func (w Outbox) templateRole() string {
return "outbox"
}
-func (w Outbox) clone(action string) (Renderer, error) {
+func (w Outbox) clone(action string) (Builder, error) {
return NewOutbox(w._factory, w._request, w._response, w._user, action)
}
@@ -296,5 +296,5 @@ func (w Outbox) Responses() QueryBuilder[model.Response] {
}
func (w Outbox) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_Outbox")
+ log.Debug().Interface("object", w.object()).Msg("builder_Outbox")
}
diff --git a/render/renderer_stream.go b/build/builder_stream.go
similarity index 87%
rename from render/renderer_stream.go
rename to build/builder_stream.go
index 3eb697d2f..388b10a50 100644
--- a/render/renderer_stream.go
+++ b/build/builder_stream.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -25,7 +25,7 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// Stream wraps a model.Stream object and provides functions that make it easy to render an HTML template with it.
+// Stream wraps a model.Stream object and provides functions that make it easy to build an HTML template with it.
type Stream struct {
_service service.ModelService // Service to use to access streams (could be Stream or StreamDraft)
_stream *model.Stream // The Stream to be displayed
@@ -33,13 +33,13 @@ type Stream struct {
}
/******************************************
- * Stream Renderer Constructors
+ * Stream Builder Constructors
******************************************/
// NewStream creates a new object that can generate HTML for a specific stream/view
func NewStream(factory Factory, request *http.Request, response http.ResponseWriter, template model.Template, stream *model.Stream, actionID string) (Stream, error) {
- const location = "render.NewStream"
+ const location = "build.NewStream"
// Verify the requested action
action, ok := template.Action(actionID)
@@ -48,11 +48,11 @@ func NewStream(factory Factory, request *http.Request, response http.ResponseWri
return Stream{}, derp.ReportAndReturn(derp.NewBadRequestError(location, "Invalid action", template.TemplateID, actionID))
}
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(factory, request, response, template, actionID)
if err != nil {
- return Stream{}, derp.ReportAndReturn(derp.Wrap(err, location, "Error creating common renderer"))
+ return Stream{}, derp.ReportAndReturn(derp.Wrap(err, location, "Error creating common builder"))
}
if !action.UserCan(stream, &common._authorization) {
@@ -79,18 +79,18 @@ func NewStreamWithoutTemplate(factory Factory, request *http.Request, response h
template, err := templateService.Load(stream.TemplateID)
if err != nil {
- return Stream{}, derp.Wrap(err, "render.NewStreamWithoutTemplate", "Error loading Template", stream)
+ return Stream{}, derp.Wrap(err, "build.NewStreamWithoutTemplate", "Error loading Template", stream)
}
// Return a fully populated service
return NewStream(factory, request, response, template, stream, actionID)
}
-// NewStreamFromURI creates a new Stream renderer for the provided request context.
+// NewStreamFromURI creates a new Stream builder for the provided request context.
// IMPORTANT: The stream parameter is expected to be an empty stream in the caller's scope that will be populated by this function.
func NewStreamFromURI(serverFactory ServerFactory, request *http.Request, response http.ResponseWriter, stream *model.Stream, actionID string) (Stream, error) {
- const location = "render.NewStreamFromURI"
+ const location = "build.NewStreamFromURI"
// Locate the requested domain name
factory, err := serverFactory.ByDomainName(request.Host)
@@ -117,7 +117,7 @@ func NewStreamFromURI(serverFactory ServerFactory, request *http.Request, respon
actionID = defaultAction
}
- // Create and return a new renderer
+ // Create and return a new builder
return NewStreamWithoutTemplate(factory, request, response, stream, actionID)
}
@@ -134,7 +134,7 @@ func (w Stream) Render() (template.HTML, error) {
status := Pipeline(w.action.Steps).Get(w._factory, &w, &buffer)
if status.Error != nil {
- err := derp.Wrap(status.Error, "render.Stream.Render", "Error generating HTML")
+ err := derp.Wrap(status.Error, "build.Stream.Render", "Error generating HTML")
derp.Report(err)
return "", err
}
@@ -144,7 +144,7 @@ func (w Stream) Render() (template.HTML, error) {
return template.HTML(buffer.String()), nil
}
-// object returns the model object associated with this renderer
+// object returns the model object associated with this builder
func (w Stream) object() data.Object {
return w._stream
}
@@ -157,7 +157,7 @@ func (w Stream) objectType() string {
return "Stream"
}
-// schema returns the validation schema associated with this renderer
+// schema returns the validation schema associated with this builder
func (w Stream) schema() schema.Schema {
return w._template.Schema
}
@@ -172,7 +172,7 @@ func (w Stream) templateRole() string {
return w._template.TemplateRole
}
-func (w Stream) clone(action string) (Renderer, error) {
+func (w Stream) clone(action string) (Builder, error) {
return NewStream(w._factory, w._request, w._response, w._template, w._stream, action)
}
@@ -183,13 +183,13 @@ func (w Stream) clone(action string) (Renderer, error) {
// View executes a separate view for this Stream
func (w Stream) View(actionID string) (template.HTML, error) {
- const location = "render.Stream.View"
+ const location = "build.Stream.View"
- // Create a new renderer (this will also validate the user's permissions)
+ // Create a new builder (this will also validate the user's permissions)
subStream, err := NewStream(w.factory(), w._request, w._response, w._template, w._stream, actionID)
if err != nil {
- return template.HTML(""), derp.ReportAndReturn(derp.Wrap(err, location, "Error creating sub-renderer"))
+ return template.HTML(""), derp.ReportAndReturn(derp.Wrap(err, location, "Error creating sub-builder"))
}
// Generate HTML template
@@ -200,12 +200,12 @@ func (w Stream) View(actionID string) (template.HTML, error) {
* STREAM DATA
******************************************/
-// StreamID returns the unique ID for the stream being rendered
+// StreamID returns the unique ID for the stream being builded
func (w Stream) StreamID() string {
return w._stream.StreamID.Hex()
}
-// StreamID returns the unique ID for the stream being rendered
+// StreamID returns the unique ID for the stream being builded
func (w Stream) ParentID() string {
return w._stream.ParentID.Hex()
}
@@ -218,12 +218,12 @@ func (w Stream) NavigationID() string {
return w._stream.NavigationID
}
-// PageTitle returns the Label for the stream being rendered
+// PageTitle returns the Label for the stream being builded
func (w Stream) PageTitle() string {
return w._stream.Label
}
-// StateID returns the current state of the stream being rendered
+// StateID returns the current state of the stream being builded
func (w Stream) StateID() string {
return w._stream.StateID
}
@@ -233,7 +233,7 @@ func (w Stream) TemplateID() string {
return w._stream.TemplateID
}
-// Token returns the unique URL token for the stream being rendered
+// Token returns the unique URL token for the stream being builded
func (w Stream) Token() string {
return w._stream.Token
}
@@ -243,17 +243,17 @@ func (w Stream) Document() model.DocumentLink {
return w._stream.DocumentLink()
}
-// Label returns the Label for the stream being rendered
+// Label returns the Label for the stream being builded
func (w Stream) Label() string {
return w._stream.Label
}
-// Summary returns the description of the stream being rendered
+// Summary returns the description of the stream being builded
func (w Stream) Summary() string {
return w._stream.Summary
}
-// SummaryHTML returns the description of the stream being rendered
+// SummaryHTML returns the description of the stream being builded
func (w Stream) SummaryHTML() template.HTML {
return template.HTML(w._stream.Summary)
}
@@ -263,7 +263,7 @@ func (w Stream) ShortSummary() string {
return htmlconv.Summary(w._stream.Summary)
}
-// ImageURL returns the thumbnail image URL of the stream being rendered
+// ImageURL returns the thumbnail image URL of the stream being builded
func (w Stream) ImageURL() string {
return w._stream.ImageURL
}
@@ -311,12 +311,12 @@ func (w Stream) ContentRaw() string {
return w._stream.Content.Raw
}
-// CreateDate returns the CreateDate of the stream being rendered
+// CreateDate returns the CreateDate of the stream being builded
func (w Stream) CreateDate() int64 {
return w._stream.CreateDate
}
-// PublishDate returns the PublishDate of the stream being rendered
+// PublishDate returns the PublishDate of the stream being builded
func (w Stream) PublishDate() int64 {
if w._stream.PublishDate > 0 {
@@ -326,22 +326,22 @@ func (w Stream) PublishDate() int64 {
return w._stream.CreateDate
}
-// UpdateDate returns the UpdateDate of the stream being rendered
+// UpdateDate returns the UpdateDate of the stream being builded
func (w Stream) UpdateDate() int64 {
return w._stream.UpdateDate
}
-// Rank returns the Rank of the stream being rendered
+// Rank returns the Rank of the stream being builded
func (w Stream) Rank() int {
return w._stream.Rank
}
-// Data returns the custom data map of the stream being rendered
+// Data returns the custom data map of the stream being builded
func (w Stream) Data(value string) any {
return w._stream.Data[value]
}
-// HasParent returns TRUE if the stream being rendered has a parend objec
+// HasParent returns TRUE if the stream being builded has a parend objec
func (w Stream) HasParent() bool {
return w._stream.HasParent()
}
@@ -408,10 +408,10 @@ func (w Stream) Widgets(location string) (template.HTML, error) {
buffer.WriteString(`
`)
for _, streamWidget := range list {
if widget, ok := widgetService.Get(streamWidget.Type); ok {
- widgetRenderer := NewWidget(&w, streamWidget)
+ widgetBuilder := NewWidget(&w, streamWidget)
- if err := widget.HTMLTemplate.ExecuteTemplate(&buffer, "widget", widgetRenderer); err != nil {
- derp.Report(derp.Wrap(err, "renderer.Stream.Widgets", "Error executing widget template", widget))
+ if err := widget.HTMLTemplate.ExecuteTemplate(&buffer, "widget", widgetBuilder); err != nil {
+ derp.Report(derp.Wrap(err, "builder.Stream.Widgets", "Error executing widget template", widget))
}
}
}
@@ -427,7 +427,7 @@ func (w Stream) Widgets(location string) (template.HTML, error) {
// Parent returns a Stream containing the parent of the current stream
func (w Stream) Parent(actionID string) (Stream, error) {
- const location = "renderer.Stream.Parent"
+ const location = "builder.Stream.Parent"
var parent model.Stream
@@ -437,13 +437,13 @@ func (w Stream) Parent(actionID string) (Stream, error) {
return Stream{}, derp.Wrap(err, location, "Error loading Parent")
}
- renderer, err := NewStreamWithoutTemplate(w.factory(), w._request, w._response, &parent, actionID)
+ builder, err := NewStreamWithoutTemplate(w.factory(), w._request, w._response, &parent, actionID)
if err != nil {
return Stream{}, derp.Wrap(err, location, "Unable to create new Stream")
}
- return renderer, nil
+ return builder, nil
}
// PrevSibling returns the sibling Stream that immediately preceeds this one, based on the provided sort field
@@ -497,7 +497,7 @@ func (w Stream) getFirstStream(criteria exp.Expression, sortOption option.Option
iterator, err := streamService.List(criteria, sortOption, option.FirstRow())
if err != nil {
- derp.Report(derp.Wrap(err, "renderer.Stream.NextSibling", "Database error"))
+ derp.Report(derp.Wrap(err, "builder.Stream.NextSibling", "Database error"))
return Stream{}
}
@@ -509,7 +509,7 @@ func (w Stream) getFirstStream(criteria exp.Expression, sortOption option.Option
}
}
- // Fall through means no streams are valid. Return an empty renderer instead.
+ // Fall through means no streams are valid. Return an empty builder instead.
return Stream{}
}
@@ -627,7 +627,7 @@ func (w Stream) Ancestors() QueryBuilder[model.StreamSummary] {
streamService := w.factory().Stream()
if err := streamService.LoadParent(w._stream, &parent); err != nil {
- derp.Report(derp.Wrap(err, "renderer.Stream.Ancestors", "Error loading parent"))
+ derp.Report(derp.Wrap(err, "builder.Stream.Ancestors", "Error loading parent"))
}
return w.makeStreamQueryBuilder(exp.Equal("parentId", parent.ParentID))
@@ -694,7 +694,7 @@ func (w Stream) Following() ([]model.Following, error) {
iterator, err := followingService.ListByUserID(w.AuthenticatedID())
if err != nil {
- return result, derp.Wrap(err, "renderer.Stream.Following", "Error listing following")
+ return result, derp.Wrap(err, "builder.Stream.Following", "Error listing following")
}
following := model.NewFollowing()
@@ -742,26 +742,26 @@ func (w Stream) CanCreate() []form.LookupCode {
return templateService.ListByContainer(w._template.TemplateID)
}
-// draftRenderer returns a new render.Stream that is bound to the
+// draftBuilder returns a new build.Stream that is bound to the
// draft service, and a draft copy of the current stream.
-func (w Stream) draftRenderer() (Stream, error) {
+func (w Stream) draftBuilder() (Stream, error) {
var draft model.Stream
draftService := w.factory().StreamDraft()
// Load the draft of the object
if err := draftService.LoadByID(w._stream.StreamID, &draft); err != nil {
- return Stream{}, derp.Wrap(err, "render.Stream.draftRenderer", "Error loading draft")
+ return Stream{}, derp.Wrap(err, "build.Stream.draftBuilder", "Error loading draft")
}
- // Create the underlying Common renderer
+ // Create the underlying Common builder
common, err := NewCommon(w._factory, w._request, w._response, w._template, w.actionID)
if err != nil {
- return Stream{}, derp.Wrap(err, "render.Stream.draftRenderer", "Error creating common renderer")
+ return Stream{}, derp.Wrap(err, "build.Stream.draftBuilder", "Error creating common builder")
}
- // Make a duplicate of this renderer. Same object, template, action settings
+ // Make a duplicate of this builder. Same object, template, action settings
return Stream{
_stream: &draft,
_service: draftService,
@@ -775,5 +775,5 @@ func (w Stream) setState(stateID string) error {
}
func (w Stream) debug() {
- log.Debug().Interface("object", w.object()).Msg("renderer_Stream")
+ log.Debug().Interface("object", w.object()).Msg("builder_Stream")
}
diff --git a/render/renderer_widget.go b/build/builder_widget.go
similarity index 66%
rename from render/renderer_widget.go
rename to build/builder_widget.go
index d72692a2a..8b0502c9a 100644
--- a/render/renderer_widget.go
+++ b/build/builder_widget.go
@@ -1,10 +1,10 @@
-package render
+package build
import (
"github.com/EmissarySocial/emissary/model"
)
-// Widget renderer is created by the "with-widget" action, and
+// Widget builder is created by the "with-widget" action, and
// can execute additional action steps on a widget that is
// embedded in a stream. To save the final result, you must
// call "save" on the stream itself, not within this widget.
@@ -13,9 +13,9 @@ type Widget struct {
*Stream
}
-func NewWidget(renderer *Stream, widget model.StreamWidget) Widget {
+func NewWidget(builder *Stream, widget model.StreamWidget) Widget {
return Widget{
Widget: widget,
- Stream: renderer,
+ Stream: builder,
}
}
diff --git a/render/constants.go b/build/constants.go
similarity index 95%
rename from render/constants.go
rename to build/constants.go
index b351e9a6e..2c5a0009e 100644
--- a/render/constants.go
+++ b/build/constants.go
@@ -1,4 +1,4 @@
-package render
+package build
// ActionMethod enumerates the HTTP methods that can be performed on Actions
type ActionMethod uint8
diff --git a/render/factory.go b/build/factory.go
similarity index 99%
rename from render/factory.go
rename to build/factory.go
index 7fe735d1d..231a96ec1 100644
--- a/render/factory.go
+++ b/build/factory.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"github.com/EmissarySocial/emissary/config"
diff --git a/render/functions.go b/build/functions.go
similarity index 99%
rename from render/functions.go
rename to build/functions.go
index 474411204..63947c6e3 100644
--- a/render/functions.go
+++ b/build/functions.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"encoding/json"
diff --git a/render/functions_test.go b/build/functions_test.go
similarity index 97%
rename from render/functions_test.go
rename to build/functions_test.go
index a7c342c6d..fd5ee7176 100644
--- a/render/functions_test.go
+++ b/build/functions_test.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"html/template"
diff --git a/render/interfaces.go b/build/interfaces.go
similarity index 87%
rename from render/interfaces.go
rename to build/interfaces.go
index 7ce1f358a..44c2507f6 100644
--- a/render/interfaces.go
+++ b/build/interfaces.go
@@ -1,11 +1,11 @@
-package render
+package build
import "github.com/EmissarySocial/emissary/model"
type PipelineHalter interface {
// HaltPipeline optionally allows a step to halt processing of an action pipeline
- HaltPipeline(Renderer) bool
+ HaltPipeline(Builder) bool
}
type DocumentLinker interface {
diff --git a/render/pipeline.go b/build/pipeline.go
similarity index 63%
rename from render/pipeline.go
rename to build/pipeline.go
index 562286521..349b036c1 100644
--- a/render/pipeline.go
+++ b/build/pipeline.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -9,17 +9,17 @@ import (
type Pipeline []step.Step
// Execute switches between GET and POST methods for this pipeline, based on the provided ActionMethod
-func (pipeline Pipeline) Execute(factory Factory, renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineResult {
+func (pipeline Pipeline) Execute(factory Factory, builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineResult {
if actionMethod == ActionMethodGet {
- return pipeline.Get(factory, renderer, buffer)
+ return pipeline.Get(factory, builder, buffer)
}
- return pipeline.Post(factory, renderer, buffer)
+ return pipeline.Post(factory, builder, buffer)
}
// Get runs all of the pipeline steps using the GET method
-func (pipeline Pipeline) Get(factory Factory, renderer Renderer, buffer io.Writer) PipelineResult {
+func (pipeline Pipeline) Get(factory Factory, builder Builder, buffer io.Writer) PipelineResult {
status := NewPipelineResult()
@@ -27,7 +27,7 @@ func (pipeline Pipeline) Get(factory Factory, renderer Renderer, buffer io.Write
for _, step := range pipeline {
// Execute the step and collect the results in the pipeline status
- resultFn := ExecutableStep(step).Get(renderer, buffer)
+ resultFn := ExecutableStep(step).Get(builder, buffer)
if resultFn != nil {
resultFn(&status)
@@ -42,14 +42,14 @@ func (pipeline Pipeline) Get(factory Factory, renderer Renderer, buffer io.Write
}
// Post runs runs all of the pipeline steps using the POST method
-func (pipeline Pipeline) Post(factory Factory, renderer Renderer, buffer io.Writer) PipelineResult {
+func (pipeline Pipeline) Post(factory Factory, builder Builder, buffer io.Writer) PipelineResult {
status := NewPipelineResult()
// Execute all of the steps of the requested action
for _, step := range pipeline {
- resultFn := ExecutableStep(step).Post(renderer, buffer)
+ resultFn := ExecutableStep(step).Post(builder, buffer)
if resultFn != nil {
resultFn(&status)
diff --git a/render/pipeline_behavior.go b/build/pipeline_behavior.go
similarity index 96%
rename from render/pipeline_behavior.go
rename to build/pipeline_behavior.go
index ec50a9fa2..6ea4a52b1 100644
--- a/render/pipeline_behavior.go
+++ b/build/pipeline_behavior.go
@@ -1,4 +1,4 @@
-package render
+package build
type PipelineBehavior func(*PipelineResult)
@@ -22,7 +22,7 @@ func UseResult(newStatus PipelineResult) PipelineBehavior {
}
// AsFullPage sets the FullPage flag on the PipelineResult object, which
-// tells the renderer to NOT include the header/footer from the site theme.
+// tells the builder to NOT include the header/footer from the site theme.
func (exit PipelineBehavior) AsFullPage() PipelineBehavior {
return func(status *PipelineResult) {
if exit != nil {
diff --git a/render/pipeline_result.go b/build/pipeline_result.go
similarity index 98%
rename from render/pipeline_result.go
rename to build/pipeline_result.go
index 0ce0df0b2..fb1f03b27 100644
--- a/render/pipeline_result.go
+++ b/build/pipeline_result.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"encoding/json"
@@ -15,7 +15,7 @@ type PipelineResult struct {
Events mapof.String // Map of events to trigger on the client (via HX-Trigger)
FullPage bool // If true, then this result represents the entire page of content, and should not be wrapped in the global template
Halt bool // If true, then this pipeline should halt execution
- Error error // If present, then there was an error rendering this page
+ Error error // If present, then there was an error building this page
}
func NewPipelineResult() PipelineResult {
diff --git a/render/queryBuilder.go b/build/queryBuilder.go
similarity index 99%
rename from render/queryBuilder.go
rename to build/queryBuilder.go
index 864f4a580..5b350031a 100644
--- a/render/queryBuilder.go
+++ b/build/queryBuilder.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"github.com/EmissarySocial/emissary/model"
diff --git a/render/step_.go b/build/step_.go
similarity index 93%
rename from render/step_.go
rename to build/step_.go
index d57fa0558..ab11bce75 100644
--- a/render/step_.go
+++ b/build/step_.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -7,16 +7,16 @@ import (
)
type Step interface {
- Get(Renderer, io.Writer) PipelineBehavior
- Post(Renderer, io.Writer) PipelineBehavior
+ Get(Builder, io.Writer) PipelineBehavior
+ Post(Builder, io.Writer) PipelineBehavior
}
// ExecutableStep uses an Step object to create a new action
func ExecutableStep(stepInfo step.Step) Step {
// These actual action steps require access to more of the application than is available in the model package.
- // Model objects are only concerned with the data that they contain, and not with the actual rendering of that data.
- // So, we convert the model object into a "render step" that CAN access the rendering context.
+ // Model objects are only concerned with the data that they contain, and not with the actual building of that data.
+ // So, we convert the model object into a "build step" that CAN access the building context.
switch s := stepInfo.(type) {
diff --git a/build/step_AddModelObject.go b/build/step_AddModelObject.go
new file mode 100644
index 000000000..ca6949e2f
--- /dev/null
+++ b/build/step_AddModelObject.go
@@ -0,0 +1,83 @@
+package build
+
+import (
+ "io"
+
+ "github.com/EmissarySocial/emissary/model/step"
+ "github.com/benpate/derp"
+ "github.com/benpate/form"
+)
+
+// StepAddModelObject is an action that can add new model objects of any type
+type StepAddModelObject struct {
+ Form form.Element
+ Defaults []step.Step
+}
+
+// Get displays a modal form that lets users enter data for their new model object.
+func (step StepAddModelObject) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ factory := builder.factory()
+ schema := builder.schema()
+ object := builder.object()
+
+ // First, try to execute any "default" steps so that the object is initialized
+ result := Pipeline(step.Defaults).Get(factory, builder, buffer)
+
+ if result.Halt {
+ result.Error = derp.Wrap(result.Error, "build.StepAddModelObject.Get", "Error executing default steps")
+ return UseResult(result)
+ }
+
+ // Try to build the Form HTML
+ formHTML, err := form.Editor(schema, step.Form, object, builder.lookupProvider())
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepAddModelObject.Get", "Error generating form"))
+ }
+
+ formHTML = WrapForm(builder.URL(), formHTML)
+
+ // Wrap formHTML as a modal dialog
+ // nolint:errcheck
+ io.WriteString(buffer, formHTML)
+ return nil
+}
+
+// Post initializes a new model object, populates it with data from the form, then saves it to the database.
+func (step StepAddModelObject) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ // This finds/creates a new object in the builder
+ factory := builder.factory()
+ request := builder.request()
+ object := builder.object()
+ schema := builder.schema()
+
+ // Execute any "default" steps so that the object is initialized
+ result := Pipeline(step.Defaults).Post(factory, builder, buffer)
+
+ if result.Halt {
+ result.Error = derp.Wrap(result.Error, "build.StepAddModelObject.Post", "Error executing default steps")
+ return UseResult(result)
+ }
+
+ // Parse form information
+ if err := request.ParseForm(); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.AddModelObject.Post", "Error parsing form data"))
+ }
+
+ // Try to set each path from the Form into the builder. Note: schema.Set also converts and validated inputs before setting.
+ for key, value := range request.Form {
+ if err := schema.Set(object, key, value); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.AddModelObject.Post", "Error setting path value", key, value))
+ }
+ }
+
+ // Save the object to the database
+ if err := builder.service().ObjectSave(object, "Created"); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepAddModelObject.Post", "Error saving model object to database"))
+ }
+
+ // Success!
+ return nil
+}
diff --git a/render/step_AddStream.go b/build/step_AddStream.go
similarity index 73%
rename from render/step_AddStream.go
rename to build/step_AddStream.go
index 9608ac340..506c26e64 100644
--- a/render/step_AddStream.go
+++ b/build/step_AddStream.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -25,35 +25,35 @@ type StepAddStream struct {
* GET Methods
******************************************/
-// Get renders the HTML for this step - either a modal template selector, or the embedded edit form
-func (step StepAddStream) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+// Get builds the HTML for this step - either a modal template selector, or the embedded edit form
+func (step StepAddStream) Get(builder Builder, buffer io.Writer) PipelineBehavior {
if step.Style == "inline" {
- if err := step.getInline(renderer, buffer); err != nil {
+ if err := step.getInline(builder, buffer); err != nil {
return Halt().WithError(err)
}
return nil
}
// Fall through to displaying the default "CHOOSER" modal
- if err := step.getChooser(renderer, buffer); err != nil {
+ if err := step.getChooser(builder, buffer); err != nil {
return Halt().WithError(err)
}
return Halt()
}
-// modalAddStream renders an HTML dialog that lists all of the templates that the user can create
+// modalAddStream builds an HTML dialog that lists all of the templates that the user can create
// tempalteIDs is a limiter on the list of valid templates. If it is empty, then all valid templates are displayed.
-func (step StepAddStream) getChooser(renderer Renderer, buffer io.Writer) error {
+func (step StepAddStream) getChooser(builder Builder, buffer io.Writer) error {
// response *echo.Response, templateService *service.Template, iconProvider icon.Provider, title string, buffer io.Writer, url string, parentRole string, allowedTemplateIDs []string) {
- factory := renderer.factory()
- response := renderer.response()
+ factory := builder.factory()
+ response := builder.response()
templateService := factory.Template()
iconProvider := factory.Icons()
- parentRole := step.parentRole(renderer)
+ parentRole := step.parentRole(builder)
templates := templateService.ListByContainerLimited(parentRole, step.TemplateRoles)
@@ -64,7 +64,7 @@ func (step StepAddStream) getChooser(renderer Renderer, buffer io.Writer) error
b.Table().Class("table margin-bottom")
for _, template := range templates {
- b.TR().Role("link").Data("hx-post", renderer.URL()+"?templateId="+template.Value)
+ b.TR().Role("link").Data("hx-post", builder.URL()+"?templateId="+template.Value)
{
b.TD().Class("text-3xl").Style("vertical-align:top").EndBracket()
iconProvider.Write(template.Icon, b)
@@ -89,27 +89,27 @@ func (step StepAddStream) getChooser(renderer Renderer, buffer io.Writer) error
return nil
}
-// getInline renders the HTML for an embedded form
-func (step StepAddStream) getInline(renderer Renderer, buffer io.Writer) error {
+// getInline builds the HTML for an embedded form
+func (step StepAddStream) getInline(builder Builder, buffer io.Writer) error {
- const location = "render.StepAddStream.getInline"
+ const location = "build.StepAddStream.getInline"
// Get prerequisites
- factory := renderer.factory()
+ factory := builder.factory()
templateService := factory.Template()
- containedByRole := step.parentRole(renderer)
+ containedByRole := step.parentRole(builder)
// Find the "selected" template
- optionTemplates, newTemplate, err := step.getBestTemplate(templateService, containedByRole, renderer.QueryParam("templateId"))
+ optionTemplates, newTemplate, err := step.getBestTemplate(templateService, containedByRole, builder.QueryParam("templateId"))
if err != nil {
return derp.Wrap(err, location, "Error getting best template")
}
- iconService := renderer.factory().Icons()
+ iconService := builder.factory().Icons()
- path := renderer.request().URL.Path
- path = replaceActionID(path, renderer.ActionID())
+ path := builder.request().URL.Path
+ path = replaceActionID(path, builder.ActionID())
// Build the HTML for the "embed" widget
b := html.New()
@@ -138,23 +138,23 @@ func (step StepAddStream) getInline(renderer Renderer, buffer io.Writer) error {
b.Close() // DIV
}
- // If there is a child renderer, then render it here
+ // If there is a child builder, then build it here
// Create a new child stream
streamService := factory.Stream()
child := streamService.New()
- // Create a new child renderer
- childRenderer, err := NewStream(factory, renderer.request(), renderer.response(), newTemplate, &child, "create")
- childRenderer.setArguments(renderer.getArguments())
+ // Create a new child builder
+ childBuilder, err := NewStream(factory, builder.request(), builder.response(), newTemplate, &child, "create")
+ childBuilder.setArguments(builder.getArguments())
if err != nil {
- return derp.Wrap(err, location, "Error creating new child stream renderer")
+ return derp.Wrap(err, location, "Error creating new child stream builder")
}
- widgetHTML, err := childRenderer.Render()
+ widgetHTML, err := childBuilder.Render()
if err != nil {
- return derp.Wrap(err, location, "Error rendering new child stream")
+ return derp.Wrap(err, location, "Error building new child stream")
}
b.WriteString(string(widgetHTML))
@@ -172,17 +172,17 @@ func (step StepAddStream) getInline(renderer Renderer, buffer io.Writer) error {
* POST Methods
******************************************/
-func (step StepAddStream) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAddStream) Post(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepAddStream.Post"
+ const location = "build.StepAddStream.Post"
// Collect prerequisites
- factory := renderer.factory()
+ factory := builder.factory()
templateService := factory.Template()
- containedByRole := step.parentRole(renderer)
+ containedByRole := step.parentRole(builder)
// Identify the Template to used for the new Stream
- _, template, err := step.getBestTemplate(templateService, containedByRole, renderer.QueryParam("templateId"))
+ _, template, err := step.getBestTemplate(templateService, containedByRole, builder.QueryParam("templateId"))
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Invalid Template. Check template roles and 'containedBy' values."))
@@ -193,30 +193,30 @@ func (step StepAddStream) Post(renderer Renderer, buffer io.Writer) PipelineBeha
newStream := streamService.New()
// Validate and set the location for the new Stream
- if err := step.setLocation(renderer, &template, &newStream); err != nil {
+ if err := step.setLocation(builder, &template, &newStream); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error getting location for new stream"))
}
// Apply custom stream data from the "with-data" map
- if err := step.setStreamData(renderer, &newStream); err != nil {
+ if err := step.setStreamData(builder, &newStream); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error setting stream data"))
}
// Assign the current user as the author (with silent failure)
- if user, err := renderer.getUser(); err == nil {
+ if user, err := builder.getUser(); err == nil {
newStream.SetAttributedTo(user.PersonLink())
}
- // Create a renderer for the new Stream
- newRenderer, err := NewStream(factory, renderer.request(), renderer.response(), template, &newStream, "create")
- newRenderer.setArguments(renderer.getArguments())
+ // Create a builder for the new Stream
+ newBuilder, err := NewStream(factory, builder.request(), builder.response(), template, &newStream, "create")
+ newBuilder.setArguments(builder.getArguments())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating renderer", newStream))
+ return Halt().WithError(derp.Wrap(err, location, "Error creating builder", newStream))
}
// Run the "create" action for the new stream's template, if possible
- result := Pipeline(newRenderer.Action().Steps).Post(factory, &newRenderer, buffer)
+ result := Pipeline(newBuilder.Action().Steps).Post(factory, &newBuilder, buffer)
result.Error = derp.Wrap(result.Error, location, "Unable to execute 'create' action on stream")
// For "inline" styles, use the result from the child's "create" action
@@ -232,18 +232,18 @@ func (step StepAddStream) Post(renderer Renderer, buffer io.Writer) PipelineBeha
// setLocation returns the ParentIDs to use in for the new stream.
// It returns an error if the template cannot be placed in the pre-determined location.
-func (step StepAddStream) setLocation(renderer Renderer, template *model.Template, newStream *model.Stream) error {
+func (step StepAddStream) setLocation(builder Builder, template *model.Template, newStream *model.Stream) error {
- const location = "render.StepAddStream.setLocation"
+ const location = "build.StepAddStream.setLocation"
- streamService := renderer.factory().Stream()
+ streamService := builder.factory().Stream()
switch step.Location {
// Special case for streams in User's Outbox
case "outbox":
- userID := renderer.AuthenticatedID()
+ userID := builder.AuthenticatedID()
if err := streamService.SetLocationOutbox(template, newStream, userID); err != nil {
return derp.Wrap(err, location, "Error setting location for outbox")
}
@@ -260,14 +260,14 @@ func (step StepAddStream) setLocation(renderer Renderer, template *model.Templat
// Default to "Child" streams
default:
- // Guarantee that the current renderer is a Stream renderer
- streamRenderer, ok := renderer.(*Stream)
+ // Guarantee that the current builder is a Stream builder
+ streamBuilder, ok := builder.(*Stream)
if !ok {
- return derp.NewForbiddenError(location, "Cannot add child stream to non-stream renderer")
+ return derp.NewForbiddenError(location, "Cannot add child stream to non-stream builder")
}
- parent := streamRenderer._stream
+ parent := streamBuilder._stream
if err := streamService.SetLocationChild(template, newStream, parent); err != nil {
return derp.Wrap(err, step.Location, "Error setting location for child")
}
@@ -275,7 +275,7 @@ func (step StepAddStream) setLocation(renderer Renderer, template *model.Templat
}
}
-func (step StepAddStream) setStreamData(renderer Renderer, stream *model.Stream) error {
+func (step StepAddStream) setStreamData(builder Builder, stream *model.Stream) error {
if len(step.WithData) == 0 {
return nil
@@ -284,9 +284,9 @@ func (step StepAddStream) setStreamData(renderer Renderer, stream *model.Stream)
s := schema.New(model.StreamSchema())
for key, valueTemplate := range step.WithData {
- value := executeTemplate(valueTemplate, renderer)
+ value := executeTemplate(valueTemplate, builder)
if err := s.Set(stream, key, value); err != nil {
- return derp.Wrap(err, "render.StepAddStream.setStreamData", "Error setting stream data", key, value)
+ return derp.Wrap(err, "build.StepAddStream.setStreamData", "Error setting stream data", key, value)
}
}
@@ -297,7 +297,7 @@ func (step StepAddStream) setStreamData(renderer Renderer, stream *model.Stream)
// It returns a slice of eligible Templates (as form.LookupCodes), and the selected Template.
func (step StepAddStream) getBestTemplate(templateService *service.Template, containedByRole string, selectedTemplateID string) ([]form.LookupCode, model.Template, error) {
- const location = "render.StepAddStream.getBestTemplate"
+ const location = "build.StepAddStream.getBestTemplate"
// Query all eligible Templates
eligible := templateService.ListByContainerLimited(containedByRole, step.TemplateRoles)
@@ -331,7 +331,7 @@ func (step StepAddStream) getBestTemplate(templateService *service.Template, con
// getBestTemplate_result finishes the job of getBestTemplate by loading the selected Template from the memory-cache
func (step StepAddStream) getBestTemplate_result(templateService *service.Template, eligible []form.LookupCode, templateID string) ([]form.LookupCode, model.Template, error) {
- const location = "render.StepAddStream.getBestTemplate_result"
+ const location = "build.StepAddStream.getBestTemplate_result"
template, err := templateService.Load(templateID)
@@ -342,10 +342,10 @@ func (step StepAddStream) getBestTemplate_result(templateService *service.Templa
return eligible, template, nil
}
-func (step StepAddStream) parentRole(renderer Renderer) string {
+func (step StepAddStream) parentRole(builder Builder) string {
if step.Location == "child" {
- return renderer.templateRole()
+ return builder.templateRole()
}
return step.Location
diff --git a/render/step_AsConfirmation.go b/build/step_AsConfirmation.go
similarity index 67%
rename from render/step_AsConfirmation.go
rename to build/step_AsConfirmation.go
index c1ac3485c..b845cebff 100644
--- a/render/step_AsConfirmation.go
+++ b/build/step_AsConfirmation.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -14,7 +14,7 @@ type StepAsConfirmation struct {
}
// Get displays a modal that asks users to continue or not.
-func (step StepAsConfirmation) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAsConfirmation) Get(builder Builder, buffer io.Writer) PipelineBehavior {
// Modal Content
b := html.New()
@@ -22,13 +22,13 @@ func (step StepAsConfirmation) Get(renderer Renderer, buffer io.Writer) Pipeline
b.Div().Class("margin-bottom").InnerText(step.Message).Close()
b.Div()
- b.Button().Class("primary").Data("hx-post", renderer.URL()).Data("hx-swap", "none").InnerText(step.Submit).Close()
+ b.Button().Class("primary").Data("hx-post", builder.URL()).Data("hx-swap", "none").InnerText(step.Submit).Close()
b.Button().Script("on click trigger closeModal").InnerText("Cancel").Close()
// Done
b.CloseAll()
- modalHTML := WrapModal(renderer.response(), b.String())
+ modalHTML := WrapModal(builder.response(), b.String())
// nolint:errcheck
io.WriteString(buffer, modalHTML)
@@ -36,6 +36,6 @@ func (step StepAsConfirmation) Get(renderer Renderer, buffer io.Writer) Pipeline
}
// Post does nothing. (Other steps in the pipeline will make changes)
-func (step StepAsConfirmation) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepAsConfirmation) Post(builder Builder, _ io.Writer) PipelineBehavior {
return Continue().WithEvent("closeModal", "true")
}
diff --git a/render/step_AsModal.go b/build/step_AsModal.go
similarity index 58%
rename from render/step_AsModal.go
rename to build/step_AsModal.go
index f9d28e408..8dc5132dc 100644
--- a/render/step_AsModal.go
+++ b/build/step_AsModal.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -17,14 +17,14 @@ type StepAsModal struct {
}
// Get displays a form where users can update stream data
-func (step StepAsModal) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAsModal) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepAsModal.Get"
+ const location = "build.StepAsModal.Get"
- // Partial pages only render the modal window. This happens MOST of the time.
- if renderer.IsPartialRequest() {
+ // Partial pages only build the modal window. This happens MOST of the time.
+ if builder.IsPartialRequest() {
- modalContent, status := step.getModalContent(renderer)
+ modalContent, status := step.getModalContent(builder)
if status.Halt {
return UseResult(status)
@@ -48,45 +48,45 @@ func (step StepAsModal) Get(renderer Renderer, buffer io.Writer) PipelineBehavio
return result
}
- // Otherwise, we can render the modal on a page background... IF we have a background view defined.
+ // Otherwise, we can build the modal on a page background... IF we have a background view defined.
if step.Background == "" {
return Halt().WithError(derp.NewBadRequestError(location, "Cannot open this route directly."))
}
- // Full pages render the entire page, including the modal window
- fullPageRenderer, err := renderer.clone(step.Background)
+ // Full pages build the entire page, including the modal window
+ fullPageBuilder, err := builder.clone(step.Background)
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating fullPageRenderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Error creating fullPageBuilder"))
}
// Execute the action pipeline
var partialPage bytes.Buffer
- factory := fullPageRenderer.factory()
- pipeline := Pipeline(fullPageRenderer.Action().Steps)
+ factory := fullPageBuilder.factory()
+ pipeline := Pipeline(fullPageBuilder.Action().Steps)
- status := pipeline.Execute(factory, fullPageRenderer, &partialPage, ActionMethodGet)
+ status := pipeline.Execute(factory, fullPageBuilder, &partialPage, ActionMethodGet)
if status.Error != nil {
- return Halt().WithError(derp.Wrap(status.Error, location, "Error executing action pipeline on fullPageRenderer"))
+ return Halt().WithError(derp.Wrap(status.Error, location, "Error executing action pipeline on fullPageBuilder"))
}
// Copy status values into the Response...
- status.Apply(fullPageRenderer.response())
+ status.Apply(fullPageBuilder.response())
- // Full Page requests require the theme service to wrap the rendered content
+ // Full Page requests require the theme service to wrap the builded content
var fullPage bytes.Buffer
htmlTemplate := factory.Domain().Theme().HTMLTemplate
- fullPageRenderer.SetContent(partialPage.String())
+ fullPageBuilder.SetContent(partialPage.String())
- if err := htmlTemplate.ExecuteTemplate(&fullPage, "page", fullPageRenderer); err != nil {
+ if err := htmlTemplate.ExecuteTemplate(&fullPage, "page", fullPageBuilder); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error executing template"))
}
// Insert the modal into the page
asideBegin := "
"
- modalString, result := step.getModalContent(renderer)
+ modalString, result := step.getModalContent(builder)
fullPageString := strings.Replace(fullPage.String(), asideBegin+asideEnd, asideBegin+modalString+asideEnd, 1)
if _, err := io.WriteString(buffer, fullPageString); err != nil {
@@ -97,28 +97,28 @@ func (step StepAsModal) Get(renderer Renderer, buffer io.Writer) PipelineBehavio
}
// Post updates the stream with approved data from the request body.
-func (step StepAsModal) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAsModal) Post(builder Builder, buffer io.Writer) PipelineBehavior {
// Write inner items
- result := Pipeline(step.SubSteps).Post(renderer.factory(), renderer, buffer)
- result.Error = derp.Wrap(result.Error, "render.StepAsModal.Post", "Error executing subSteps")
+ result := Pipeline(step.SubSteps).Post(builder.factory(), builder, buffer)
+ result.Error = derp.Wrap(result.Error, "build.StepAsModal.Post", "Error executing subSteps")
return UseResult(result).WithEvent("closeModal", "true")
}
-func (step StepAsModal) getModalContent(renderer Renderer) (string, PipelineResult) {
+func (step StepAsModal) getModalContent(builder Builder) (string, PipelineResult) {
- const location = "render.StepAsModal.getModalContent"
+ const location = "build.StepAsModal.getModalContent"
// Write inner items
var buffer bytes.Buffer
- result := Pipeline(step.SubSteps).Get(renderer.factory(), renderer, &buffer)
+ result := Pipeline(step.SubSteps).Get(builder.factory(), builder, &buffer)
result.Error = derp.Wrap(result.Error, location, "Error executing subSteps")
if result.Halt {
return "", result
}
- return WrapModal(renderer.response(), buffer.String(), step.Options...), result
+ return WrapModal(builder.response(), buffer.String(), step.Options...), result
}
diff --git a/render/step_AsTooltip.go b/build/step_AsTooltip.go
similarity index 62%
rename from render/step_AsTooltip.go
rename to build/step_AsTooltip.go
index fb5ffe737..2eb629265 100644
--- a/render/step_AsTooltip.go
+++ b/build/step_AsTooltip.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -14,14 +14,14 @@ type StepAsTooltip struct {
}
// Get displays a form where users can update stream data
-func (step StepAsTooltip) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAsTooltip) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepAsTooltip.Get"
+ const location = "build.StepAsTooltip.Get"
// Write inner items
var tooltipBuffer bytes.Buffer
- result := Pipeline(step.SubSteps).Get(renderer.factory(), renderer, &tooltipBuffer)
+ result := Pipeline(step.SubSteps).Get(builder.factory(), builder, &tooltipBuffer)
result.Error = derp.Wrap(result.Error, location, "Error executing subSteps")
if result.Halt {
@@ -29,7 +29,7 @@ func (step StepAsTooltip) Get(renderer Renderer, buffer io.Writer) PipelineBehav
}
// Wrap the content in a tooltip
- tooltipContent := WrapTooltip(renderer.response(), tooltipBuffer.String())
+ tooltipContent := WrapTooltip(builder.response(), tooltipBuffer.String())
if _, err := io.WriteString(buffer, tooltipContent); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error writing from builder to buffer"))
@@ -43,11 +43,11 @@ func (step StepAsTooltip) UseGlobalWrapper() bool {
}
// Post updates the stream with approved data from the request body.
-func (step StepAsTooltip) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepAsTooltip) Post(builder Builder, buffer io.Writer) PipelineBehavior {
// Write inner items
- result := Pipeline(step.SubSteps).Post(renderer.factory(), renderer, buffer)
- result.Error = derp.Wrap(result.Error, "render.StepAsTooltip.Post", "Error executing subSteps")
+ result := Pipeline(step.SubSteps).Post(builder.factory(), builder, buffer)
+ result.Error = derp.Wrap(result.Error, "build.StepAsTooltip.Post", "Error executing subSteps")
return UseResult(result).WithEvent("closeTooltip", "true")
}
diff --git a/render/step_Delete.go b/build/step_Delete.go
similarity index 62%
rename from render/step_Delete.go
rename to build/step_Delete.go
index 839affd9b..e506f274f 100644
--- a/render/step_Delete.go
+++ b/build/step_Delete.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -16,15 +16,15 @@ type StepDelete struct {
}
// Get displays a customizable confirmation form for the delete
-func (step StepDelete) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepDelete) Get(builder Builder, buffer io.Writer) PipelineBehavior {
b := html.New()
- b.H1().InnerText(executeTemplate(step.Title, renderer)).Close()
- b.Div().Class("margin-bottom").InnerText(executeTemplate(step.Message, renderer)).Close()
+ b.H1().InnerText(executeTemplate(step.Title, builder)).Close()
+ b.Div().Class("margin-bottom").InnerText(executeTemplate(step.Message, builder)).Close()
b.Button().Class("warning").
- Attr("hx-post", renderer.URL()).
+ Attr("hx-post", builder.URL()).
Attr("hx-swap", "none").
Attr("hx-push-url", "false").
InnerText(step.Submit).
@@ -33,7 +33,7 @@ func (step StepDelete) Get(renderer Renderer, buffer io.Writer) PipelineBehavior
b.Button().Script("on click trigger closeModal").InnerText("Cancel").Close()
b.CloseAll()
- modalHTML := WrapModal(renderer.response(), b.String())
+ modalHTML := WrapModal(builder.response(), b.String())
// nolint:errcheck
io.WriteString(buffer, modalHTML)
@@ -42,11 +42,11 @@ func (step StepDelete) Get(renderer Renderer, buffer io.Writer) PipelineBehavior
}
// Post removes the object from the database (likely using a soft-delete, though)
-func (step StepDelete) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepDelete) Post(builder Builder, _ io.Writer) PipelineBehavior {
// Delete the object via the model service.
- if err := renderer.service().ObjectDelete(renderer.object(), "Deleted"); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepDelete.Post", "Error deleting stream"))
+ if err := builder.service().ObjectDelete(builder.object(), "Deleted"); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepDelete.Post", "Error deleting stream"))
}
return Continue().WithEvent("closeModal", "true")
diff --git a/render/step_DeleteAttachments.go b/build/step_DeleteAttachments.go
similarity index 64%
rename from render/step_DeleteAttachments.go
rename to build/step_DeleteAttachments.go
index b5a8ad0a0..2d7b32b5e 100644
--- a/render/step_DeleteAttachments.go
+++ b/build/step_DeleteAttachments.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -7,25 +7,25 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
-// StepDeleteAttachments represents an action that can upload attachments. It can only be used on a StreamRenderer
+// StepDeleteAttachments represents an action that can upload attachments. It can only be used on a StreamBuilder
type StepDeleteAttachments struct {
All bool
}
-func (step StepDeleteAttachments) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepDeleteAttachments) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
-func (step StepDeleteAttachments) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepDeleteAttachments) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "renderer.StepDeleteAttachments.Post"
+ const location = "builder.StepDeleteAttachments.Post"
- factory := renderer.factory()
+ factory := builder.factory()
attachmentService := factory.Attachment()
- objectType := renderer.service().ObjectType()
- objectID := renderer.objectID()
+ objectType := builder.service().ObjectType()
+ objectID := builder.objectID()
if step.All {
@@ -36,7 +36,7 @@ func (step StepDeleteAttachments) Post(renderer Renderer, _ io.Writer) PipelineB
} else {
- attachmentIDString := renderer.QueryParam("attachmentId")
+ attachmentIDString := builder.QueryParam("attachmentId")
attachmentID, err := primitive.ObjectIDFromHex(attachmentIDString)
if err != nil {
@@ -49,7 +49,7 @@ func (step StepDeleteAttachments) Post(renderer Renderer, _ io.Writer) PipelineB
}
// Notify the client
- renderer.response().Header().Set("HX-Trigger", `attachments-updated`)
+ builder.response().Header().Set("HX-Trigger", `attachments-updated`)
return nil
}
diff --git a/render/step_EditConnection.go b/build/step_EditConnection.go
similarity index 64%
rename from render/step_EditConnection.go
rename to build/step_EditConnection.go
index fc17ca9d4..a331aee5c 100644
--- a/render/step_EditConnection.go
+++ b/build/step_EditConnection.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -12,18 +12,18 @@ import (
type StepEditConnection struct{}
-func (step StepEditConnection) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepEditConnection) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepEditConnection.Get"
+ const location = "build.StepEditConnection.Get"
// This step must be run in a Domain admin
- domainRenderer := renderer.(*Domain)
+ domainBuilder := builder.(*Domain)
// Collect parameters and services
- providerID := renderer.QueryParam("provider")
+ providerID := builder.QueryParam("provider")
- client := domainRenderer.Client(providerID)
- adapter := domainRenderer.Provider(providerID)
+ client := domainBuilder.Client(providerID)
+ adapter := domainBuilder.Provider(providerID)
// Try to find a Manual Provider for this Provider
manualProvider, ok := adapter.(providers.ManualProvider)
@@ -43,7 +43,7 @@ func (step StepEditConnection) Get(renderer Renderer, buffer io.Writer) Pipeline
}
// Wrap the form as a ModalForm and return
- formHTML = WrapModalForm(renderer.response(), renderer.URL(), formHTML)
+ formHTML = WrapModalForm(builder.response(), builder.URL(), formHTML)
// nolint:errcheck
buffer.Write([]byte(formHTML))
@@ -51,24 +51,24 @@ func (step StepEditConnection) Get(renderer Renderer, buffer io.Writer) Pipeline
return Halt().AsFullPage()
}
-func (step StepEditConnection) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepEditConnection) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepEditConnection.Post"
+ const location = "build.StepEditConnection.Post"
// This step must be run in a Domain admin
- domainRenderer := renderer.(Domain)
+ domainBuilder := builder.(Domain)
postData := mapof.NewAny()
- if err := bind(renderer.request(), &postData); err != nil {
+ if err := bind(builder.request(), &postData); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error parsing POST data"))
}
// Collect parameters and services
- providerID := renderer.QueryParam("provider")
+ providerID := builder.QueryParam("provider")
- client := domainRenderer.Client(providerID)
- adapter := domainRenderer.Provider(providerID)
+ client := domainBuilder.Client(providerID)
+ adapter := domainBuilder.Provider(providerID)
// Try to find a Manual Provider for this Provider
manualProvider, ok := adapter.(providers.ManualProvider)
@@ -86,21 +86,21 @@ func (step StepEditConnection) Post(renderer Renderer, _ io.Writer) PipelineBeha
}
// Run post-configuration scripts, if any
- if err := adapter.AfterConnect(renderer.factory(), &client); err != nil {
+ if err := adapter.AfterConnect(builder.factory(), &client); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error installing client"))
}
// Prevent nil maps
- if domainRenderer.domain.Clients == nil {
- domainRenderer.domain.Clients = make(set.Map[model.Client])
+ if domainBuilder.domain.Clients == nil {
+ domainBuilder.domain.Clients = make(set.Map[model.Client])
}
- domainRenderer.domain.Clients.Put(client)
+ domainBuilder.domain.Clients.Put(client)
// Try to save the domain object back to the database
- domainService := domainRenderer.domainService()
+ domainService := domainBuilder.domainService()
- if err := domainService.Save(*domainRenderer._domain, "Updated connection"); err != nil {
+ if err := domainService.Save(*domainBuilder._domain, "Updated connection"); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error saving domain object"))
}
diff --git a/build/step_EditContent.go b/build/step_EditContent.go
new file mode 100644
index 000000000..a1297561a
--- /dev/null
+++ b/build/step_EditContent.go
@@ -0,0 +1,73 @@
+package build
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/EmissarySocial/emissary/model"
+ "github.com/benpate/derp"
+ "github.com/benpate/rosetta/mapof"
+)
+
+// StepEditContent represents an action-step that can edit/update Container in a streamDraft.
+type StepEditContent struct {
+ Filename string
+ Format string
+}
+
+func (step StepEditContent) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ if err := builder.executeTemplate(buffer, step.Filename, builder); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepEditContent.Get", "Error executing template"))
+ }
+
+ return nil
+}
+
+func (step StepEditContent) Post(builder Builder, _ io.Writer) PipelineBehavior {
+
+ 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"))
+ }
+
+ // Try to read the content from the request body
+ switch step.Format {
+
+ // EditorJS writes directly to the request body
+ case model.ContentFormatEditorJS:
+ 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"))
+ }
+
+ 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"))
+ }
+
+ rawContent, _ = body.GetStringOK("content")
+ }
+
+ // Set the new Content value in the Stream
+ contentService := builder.factory().Content()
+ stream.Content = contentService.New(step.Format, rawContent)
+
+ // 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"))
+ }
+
+ // Success!
+ return nil
+}
diff --git a/render/step_EditModelObject.go b/build/step_EditModelObject.go
similarity index 60%
rename from render/step_EditModelObject.go
rename to build/step_EditModelObject.go
index d549b84cd..88387f9a5 100644
--- a/render/step_EditModelObject.go
+++ b/build/step_EditModelObject.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -17,14 +17,14 @@ type StepEditModelObject struct {
}
// Get displays a modal form that lets users enter data for their new model object.
-func (step StepEditModelObject) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepEditModelObject) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepEditModelObject.Get"
+ const location = "build.StepEditModelObject.Get"
- schema := renderer.schema()
+ schema := builder.schema()
- // Try to render the Form HTML
- result, err := form.Editor(schema, step.Form, renderer.object(), renderer.lookupProvider())
+ // Try to build the Form HTML
+ result, err := form.Editor(schema, step.Form, builder.object(), builder.lookupProvider())
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error generating form"))
@@ -33,10 +33,10 @@ func (step StepEditModelObject) Get(renderer Renderer, buffer io.Writer) Pipelin
optionStrings := make([]string, 0, len(step.Options))
for _, option := range step.Options {
- optionString := executeTemplate(option, renderer)
+ optionString := executeTemplate(option, builder)
// Remove "delete" options from new objects.
- if renderer.object().IsNew() && strings.HasPrefix(optionString, "delete:") {
+ if builder.object().IsNew() && strings.HasPrefix(optionString, "delete:") {
continue
}
@@ -44,7 +44,7 @@ func (step StepEditModelObject) Get(renderer Renderer, buffer io.Writer) Pipelin
optionStrings = append(optionStrings, optionString)
}
- result = WrapForm(renderer.URL(), result, optionStrings...)
+ result = WrapForm(builder.URL(), result, optionStrings...)
// nolint:errcheck
io.WriteString(buffer, result)
@@ -53,27 +53,27 @@ func (step StepEditModelObject) Get(renderer Renderer, buffer io.Writer) Pipelin
}
// Post initializes a new model object, populates it with data from the form, then saves it to the database.
-func (step StepEditModelObject) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepEditModelObject) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepEditModelObject.Post"
+ const location = "build.StepEditModelObject.Post"
// Get the request body
body := mapof.NewAny()
- if err := bind(renderer.request(), &body); err != nil {
+ if err := bind(builder.request(), &body); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error binding request body"))
}
// Appy request body to the object (limited and validated by the form schema)
- stepForm := form.New(renderer.schema(), step.Form)
- object := renderer.object()
+ stepForm := form.New(builder.schema(), step.Form)
+ object := builder.object()
- if err := stepForm.SetAll(object, body, renderer.lookupProvider()); err != nil {
+ 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))
}
// Save the object to the database
- if err := renderer.service().ObjectSave(object, "Edited"); err != nil {
+ if err := builder.service().ObjectSave(object, "Edited"); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error saving model object to database"))
}
diff --git a/render/step_EditTable.go b/build/step_EditTable.go
similarity index 62%
rename from render/step_EditTable.go
rename to build/step_EditTable.go
index 99af61444..911a97c52 100644
--- a/render/step_EditTable.go
+++ b/build/step_EditTable.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -16,22 +16,22 @@ type StepTableEditor struct {
Form form.Element
}
-func (step StepTableEditor) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepTableEditor) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepTableEditor.Get"
+ const location = "build.StepTableEditor.Get"
var err error
- s := renderer.schema()
- factory := renderer.factory()
+ s := builder.schema()
+ factory := builder.factory()
- targetURL := step.getTargetURL(renderer)
- t := table.New(&s, &step.Form, renderer.object(), step.Path, factory.Icons(), targetURL)
- t.UseLookupProvider(renderer.lookupProvider())
+ targetURL := step.getTargetURL(builder)
+ t := table.New(&s, &step.Form, builder.object(), step.Path, factory.Icons(), targetURL)
+ t.UseLookupProvider(builder.lookupProvider())
t.AllowAll()
- if editRow, ok := convert.IntOk(renderer.QueryParam("edit"), 0); ok {
+ if editRow, ok := convert.IntOk(builder.QueryParam("edit"), 0); ok {
err = t.DrawEdit(editRow, buffer)
- } else if add := renderer.QueryParam("add"); add != "" {
+ } else if add := builder.QueryParam("add"); add != "" {
err = t.DrawAdd(buffer)
} else {
err = t.DrawView(buffer)
@@ -44,21 +44,21 @@ func (step StepTableEditor) Get(renderer Renderer, buffer io.Writer) PipelineBeh
return nil
}
-func (step StepTableEditor) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepTableEditor) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepTableEditor.Post"
+ const location = "build.StepTableEditor.Post"
- s := renderer.schema()
- object := renderer.object()
+ s := builder.schema()
+ object := builder.object()
// Try to get the form post data
body := mapof.NewAny()
- if err := bindBody(renderer.request(), &body); err != nil {
+ if err := bindBody(builder.request(), &body); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Failed to bind body", step))
}
- if edit := renderer.QueryParam("edit"); edit != "" {
+ if edit := builder.QueryParam("edit"); edit != "" {
// Bounds checking
editIndex, ok := convert.IntOk(edit, 0)
@@ -81,7 +81,7 @@ func (step StepTableEditor) Post(renderer Renderer, _ io.Writer) PipelineBehavio
}
// Try to delete an existing record
- } else if delete := renderer.QueryParam("delete"); delete != "" {
+ } else if delete := builder.QueryParam("delete"); delete != "" {
table, err := s.Get(object, step.Path)
@@ -101,20 +101,20 @@ func (step StepTableEditor) Post(renderer Renderer, _ io.Writer) PipelineBehavio
}
// Try to find the schema element for this table control
- if ok := renderer.schema().Remove(renderer.object(), step.Path+"."+delete); !ok {
+ if ok := builder.schema().Remove(builder.object(), step.Path+"."+delete); !ok {
return Halt().WithError(derp.NewInternalError(location, "Failed to remove row from table", step.Path))
}
}
- // Once we're done, re-render the table and send it back to the client
- targetURL := step.getTargetURL(renderer)
+ // Once we're done, re-build the table and send it back to the client
+ targetURL := step.getTargetURL(builder)
- factory := renderer.factory()
- t := table.New(&s, &step.Form, renderer.object(), step.Path, factory.Icons(), targetURL)
- t.UseLookupProvider(renderer.lookupProvider())
+ factory := builder.factory()
+ t := table.New(&s, &step.Form, builder.object(), step.Path, factory.Icons(), targetURL)
+ t.UseLookupProvider(builder.lookupProvider())
t.AllowAll()
- if err := t.DrawView(renderer.response()); err != nil {
+ if err := t.DrawView(builder.response()); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error building HTML"))
}
@@ -122,9 +122,9 @@ func (step StepTableEditor) Post(renderer Renderer, _ io.Writer) PipelineBehavio
}
// getTargetURL returns the URL that the table should use for all of its links
-func (step StepTableEditor) getTargetURL(renderer Renderer) string {
- originalPath := renderer.request().URL.Path
- actionID := renderer.ActionID()
+func (step StepTableEditor) getTargetURL(builder Builder) string {
+ originalPath := builder.request().URL.Path
+ actionID := builder.ActionID()
pathSlice := strings.Split(originalPath, "/")
pathSlice[len(pathSlice)-1] = actionID
return strings.Join(pathSlice, "/")
diff --git a/render/step_EditWidget.go b/build/step_EditWidget.go
similarity index 62%
rename from render/step_EditWidget.go
rename to build/step_EditWidget.go
index b8ecb9f0e..94ebe159c 100644
--- a/render/step_EditWidget.go
+++ b/build/step_EditWidget.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -12,23 +12,23 @@ import (
// StepEditWidget represents an action-step that can update the data.DataMap custom data stored in a Stream
type StepEditWidget struct{}
-func (step StepEditWidget) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepEditWidget) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- widget, streamWidget, _, err := step.common(renderer)
+ widget, streamWidget, _, err := step.common(builder)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditWidget.Get", "Error locating widget"))
+ return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Get", "Error locating widget"))
}
// Render the Form
formHTML, err := form.Editor(widget.Schema, widget.Form, streamWidget.Data, nil)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditWidget.Get", "Error rendering form"))
+ return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Get", "Error building form"))
}
// Wrap the form as a modal and return it to the client
- formHTML = WrapModalForm(renderer.response(), renderer.URL(), formHTML)
+ formHTML = WrapModalForm(builder.response(), builder.URL(), formHTML)
// nolint:errcheck
buffer.Write([]byte(formHTML))
@@ -37,65 +37,65 @@ func (step StepEditWidget) Get(renderer Renderer, buffer io.Writer) PipelineBeha
}
// Post updates the stream with approved data from the request body.
-func (step StepEditWidget) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepEditWidget) Post(builder Builder, _ io.Writer) PipelineBehavior {
// Locate the widget and its configuration
- widget, streamWidget, streamRenderer, err := step.common(renderer)
+ widget, streamWidget, streamBuilder, err := step.common(builder)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditWidget.Post", "Error locating widget"))
+ return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "Error locating widget"))
}
// Get the form post information
formData := mapof.NewAny()
- if err := bind(renderer.request(), &formData); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditWidget.Post", "Error binding form data"))
+ if err := bind(builder.request(), &formData); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "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, "render.StepEditWidget.Post", "Error applying form data to widget"))
+ return Halt().WithError(derp.Wrap(err, "build.StepEditWidget.Post", "Error applying form data to widget"))
}
// Update the stream with the new widget (in the same location)
- streamRenderer._stream.Widgets.Put(streamWidget)
+ streamBuilder._stream.Widgets.Put(streamWidget)
return Continue().WithEvent("closeModal", "true")
}
// common locates the widget and its configuration
-func (step StepEditWidget) common(renderer Renderer) (model.Widget, model.StreamWidget, *Stream, error) {
+func (step StepEditWidget) common(builder Builder) (model.Widget, model.StreamWidget, *Stream, error) {
- const location = "render.StepEditWidget.doStep"
+ const location = "build.StepEditWidget.doStep"
// WithWidget can only be used on a Stream
- streamRenderer, ok := renderer.(*Stream)
+ streamBuilder, ok := builder.(*Stream)
if !ok {
- return model.Widget{}, model.StreamWidget{}, nil, derp.NewInternalError(location, "Renderer is not a StreamRenderer")
+ return model.Widget{}, model.StreamWidget{}, nil, derp.NewInternalError(location, "Builder is not a StreamBuilder")
}
// User must be authenticated to view widget details
- if !streamRenderer.IsAuthenticated() {
+ if !streamBuilder.IsAuthenticated() {
return model.Widget{}, model.StreamWidget{}, nil, derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action")
}
// Get the token from the request
- token := renderer.QueryParam("widgetId")
+ token := builder.QueryParam("widgetId")
if token == "" {
return model.Widget{}, model.StreamWidget{}, nil, derp.NewBadRequestError(location, "Missing required parameter: widgetId")
}
// Try to find the widget in the stream
- streamWidget, ok := streamRenderer._stream.Widgets.Get(token)
+ streamWidget, ok := streamBuilder._stream.Widgets.Get(token)
if !ok {
return model.Widget{}, model.StreamWidget{}, nil, derp.NewBadRequestError(location, "Invalid widgetId", token)
}
- widgetService := streamRenderer.factory().Widget()
+ widgetService := streamBuilder.factory().Widget()
widget, ok := widgetService.Get(streamWidget.Type)
if !ok {
@@ -112,5 +112,5 @@ func (step StepEditWidget) common(renderer Renderer) (model.Widget, model.Stream
return model.Widget{}, model.StreamWidget{}, nil, derp.NewBadRequestError(location, "Widget does not support editing (empty schema)", streamWidget.Type)
}
- return widget, streamWidget, streamRenderer, nil
+ return widget, streamWidget, streamBuilder, nil
}
diff --git a/build/step_Error.go b/build/step_Error.go
new file mode 100644
index 000000000..acab11a64
--- /dev/null
+++ b/build/step_Error.go
@@ -0,0 +1,20 @@
+package build
+
+import (
+ "io"
+
+ "github.com/EmissarySocial/emissary/model/step"
+ "github.com/benpate/derp"
+)
+
+type StepError struct {
+ Original step.Step
+}
+
+func (step StepError) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return Halt().WithError(derp.NewInternalError("build.StepError", "Unrecognized Pipeline Step", "This should never happen", builder.ActionID(), builder.Action(), builder.Action().Steps, builder.object(), step.Original))
+}
+
+func (step StepError) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ return Halt().WithError(derp.NewInternalError("build.StepError", "Unrecognized Pipeline Step", "This should never happen", step.Original))
+}
diff --git a/render/step_ForwardTo.go b/build/step_ForwardTo.go
similarity index 63%
rename from render/step_ForwardTo.go
rename to build/step_ForwardTo.go
index 812ddc2e1..cd52432a2 100644
--- a/render/step_ForwardTo.go
+++ b/build/step_ForwardTo.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -13,17 +13,17 @@ type StepForwardTo struct {
URL *template.Template
}
-func (step StepForwardTo) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepForwardTo) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepForwardTo) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepForwardTo) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepForwardTo.Post"
+ const location = "build.StepForwardTo.Post"
var nextPage bytes.Buffer
- if err := step.URL.Execute(&nextPage, renderer); err != nil {
+ if err := step.URL.Execute(&nextPage, builder); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error evaluating 'url'"))
}
diff --git a/render/step_Halt.go b/build/step_Halt.go
similarity index 53%
rename from render/step_Halt.go
rename to build/step_Halt.go
index e1790d22e..c73b3d882 100644
--- a/render/step_Halt.go
+++ b/build/step_Halt.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -7,11 +7,11 @@ import (
// StepHalt represents an action-step that can save changes to any object
type StepHalt struct{}
-func (step StepHalt) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepHalt) Get(builder Builder, _ io.Writer) PipelineBehavior {
return Halt()
}
// Post saves the object to the database
-func (step StepHalt) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepHalt) Post(builder Builder, _ io.Writer) PipelineBehavior {
return Halt()
}
diff --git a/render/step_IfCondition.go b/build/step_IfCondition.go
similarity index 53%
rename from render/step_IfCondition.go
rename to build/step_IfCondition.go
index 24714a426..a4855005d 100644
--- a/render/step_IfCondition.go
+++ b/build/step_IfCondition.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -18,39 +18,39 @@ type StepIfCondition struct {
}
// Get displays a form where users can update stream data
-func (step StepIfCondition) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepIfCondition) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepIfCondition) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepIfCondition) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
// Get displays a form where users can update stream data
-func (step StepIfCondition) execute(renderer Renderer, buffer io.Writer, method ActionMethod) PipelineBehavior {
+func (step StepIfCondition) execute(builder Builder, buffer io.Writer, method ActionMethod) PipelineBehavior {
- const location = "renderer.StepIfCondition.execute"
+ const location = "builder.StepIfCondition.execute"
- factory := renderer.factory()
+ factory := builder.factory()
- if step.evaluateCondition(renderer) {
- result := Pipeline(step.Then).Execute(factory, renderer, buffer, method)
+ if step.evaluateCondition(builder) {
+ result := Pipeline(step.Then).Execute(factory, builder, buffer, method)
result.Error = derp.Wrap(result.Error, location, "Error executing 'then' sub-steps")
return UseResult(result)
}
- result := Pipeline(step.Otherwise).Get(factory, renderer, buffer)
+ result := Pipeline(step.Otherwise).Get(factory, builder, buffer)
result.Error = derp.Wrap(result.Error, location, "Error executing 'otherwise' sub-steps")
return UseResult(result)
}
// evaluateCondition executes the conditional template and
-func (step StepIfCondition) evaluateCondition(renderer Renderer) bool {
+func (step StepIfCondition) evaluateCondition(builder Builder) bool {
var result bytes.Buffer
- if err := step.Condition.Execute(&result, renderer); err != nil {
+ if err := step.Condition.Execute(&result, builder); err != nil {
return false
}
diff --git a/build/step_InlineError.go b/build/step_InlineError.go
new file mode 100644
index 000000000..8ff8f83dc
--- /dev/null
+++ b/build/step_InlineError.go
@@ -0,0 +1,26 @@
+package build
+
+import (
+ "io"
+ "text/template"
+)
+
+// StepInlineError represents an action-step that can build a Stream into HTML
+type StepInlineError struct {
+ Message *template.Template
+}
+
+// Get builds the Stream HTML to the context
+func (step StepInlineError) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return nil
+}
+
+func (step StepInlineError) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ result := executeTemplate(step.Message, builder)
+
+ if _, err := buffer.Write([]byte(`
` + result + ``)); err != nil {
+ return Halt().WithError(err)
+ }
+
+ return Halt().WithHeader("HX-Reswap", "innerHTML").WithHeader("HX-Retarget", "#htmx-response-message")
+}
diff --git a/build/step_InlineSuccess.go b/build/step_InlineSuccess.go
new file mode 100644
index 000000000..caaa2789a
--- /dev/null
+++ b/build/step_InlineSuccess.go
@@ -0,0 +1,25 @@
+package build
+
+import (
+ "io"
+ "text/template"
+)
+
+// StepInlineSuccess represents an action-step that can build a Stream into HTML
+type StepInlineSuccess struct {
+ Message *template.Template
+}
+
+// Get builds the Stream HTML to the context
+func (step StepInlineSuccess) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return nil
+}
+
+func (step StepInlineSuccess) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ result := executeTemplate(step.Message, builder)
+
+ if _, err := buffer.Write([]byte(`
` + result + ``)); err != nil {
+ return Halt().WithError(err)
+ }
+ return Halt().WithHeader("HX-Reswap", "innerHTML").WithHeader("HX-Retarget", "#htmx-response-message")
+}
diff --git a/render/step_ProcessContent.go b/build/step_ProcessContent.go
similarity index 65%
rename from render/step_ProcessContent.go
rename to build/step_ProcessContent.go
index e7f1fd4f9..65a876cf0 100644
--- a/render/step_ProcessContent.go
+++ b/build/step_ProcessContent.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -15,27 +15,27 @@ type StepProcessContent struct {
AddLinks bool
}
-// Get renders the HTML for this step - either a modal template selector, or the embedded edit form
-func (step StepProcessContent) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+// Get builds the HTML for this step - either a modal template selector, or the embedded edit form
+func (step StepProcessContent) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
-func (step StepProcessContent) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepProcessContent) Post(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepProcessContent.Post"
+ const location = "build.StepProcessContent.Post"
// Require that we are working with a Stream object
- streamRenderer, ok := renderer.(*Stream)
+ streamBuilder, ok := builder.(*Stream)
if !ok {
return Halt().WithError(derp.NewInternalError(location, "step: AddTags can only be used on a Stream"))
}
- factory := streamRenderer.factory()
+ factory := streamBuilder.factory()
streamService := factory.Stream()
contentService := factory.Content()
- stream := streamRenderer._stream
+ stream := streamBuilder._stream
if step.RemoveHTML {
stream.Content.HTML = html.RemoveAnchors(stream.Content.HTML)
diff --git a/build/step_PromoteDraft.go b/build/step_PromoteDraft.go
new file mode 100644
index 000000000..ec9463b21
--- /dev/null
+++ b/build/step_PromoteDraft.go
@@ -0,0 +1,37 @@
+package build
+
+import (
+ "io"
+
+ "github.com/benpate/derp"
+)
+
+// StepStreamPromoteDraft represents an action-step that can copy the Container from a StreamDraft into its corresponding Stream
+type StepStreamPromoteDraft struct {
+ StateID string
+}
+
+func (step StepStreamPromoteDraft) Get(builder Builder, _ io.Writer) PipelineBehavior {
+ return nil
+}
+
+// Post copies relevant information from the draft into the primary stream, then deletes the draft
+func (step StepStreamPromoteDraft) Post(builder Builder, _ io.Writer) PipelineBehavior {
+
+ streamBuilder := builder.(*Stream)
+
+ factory := builder.factory()
+
+ // Try to load the draft from the database, overwriting the stream already in the builder
+ stream, err := factory.StreamDraft().Promote(builder.objectID(), step.StateID)
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, "builder.StepStreamPromoteDraft.Post", "Error publishing draft"))
+ }
+
+ // Push the newly updated stream back to the builder so that subsequent
+ // steps (e.g. publish) can use the correct data.
+ streamBuilder._stream = &stream
+
+ return nil
+}
diff --git a/render/step_Publish.go b/build/step_Publish.go
similarity index 58%
rename from render/step_Publish.go
rename to build/step_Publish.go
index 84444346f..8cc80f0ba 100644
--- a/render/step_Publish.go
+++ b/build/step_Publish.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -10,36 +10,36 @@ import (
// StepPublish represents an action-step that can update a stream's PublishDate with the current time.
type StepPublish struct{}
-func (step StepPublish) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepPublish) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with the current date as the "PublishDate"
-func (step StepPublish) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepPublish) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepPublish.Post"
+ const location = "build.StepPublish.Post"
// Require that the user is signed in to perform this action
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "User is not authenticated", nil))
}
- streamRenderer := renderer.(*Stream)
- factory := streamRenderer.factory()
+ streamBuilder := builder.(*Stream)
+ factory := streamBuilder.factory()
// Try to load the User from the Database
userService := factory.User()
user := model.NewUser()
- if err := userService.LoadByID(streamRenderer.AuthenticatedID(), &user); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error loading user", streamRenderer.AuthenticatedID()))
+ if err := userService.LoadByID(streamBuilder.AuthenticatedID(), &user); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error loading user", streamBuilder.AuthenticatedID()))
}
// Try to Publish the Stream to ActivityPub
streamService := factory.Stream()
- if err := streamService.Publish(&user, streamRenderer._stream); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error publishing stream", streamRenderer._stream))
+ if err := streamService.Publish(&user, streamBuilder._stream); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error publishing stream", streamBuilder._stream))
}
return nil
diff --git a/render/step_RedirectTo.go b/build/step_RedirectTo.go
similarity index 53%
rename from render/step_RedirectTo.go
rename to build/step_RedirectTo.go
index a5638d42c..6d7963a93 100644
--- a/render/step_RedirectTo.go
+++ b/build/step_RedirectTo.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -14,26 +14,26 @@ type StepRedirectTo struct {
URL *template.Template
}
-func (step StepRedirectTo) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer)
+func (step StepRedirectTo) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder)
}
// Post updates the stream with approved data from the request body.
-func (step StepRedirectTo) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- return step.execute(renderer)
+func (step StepRedirectTo) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ return step.execute(builder)
}
// Redirect returns an HTTP 307 Temporary Redirect that works for both GET and POST methods
-func (step StepRedirectTo) execute(renderer Renderer) PipelineBehavior {
+func (step StepRedirectTo) execute(builder Builder) PipelineBehavior {
- const location = "render.StepRedirectTo.execute"
+ const location = "build.StepRedirectTo.execute"
var nextPage bytes.Buffer
- if err := step.URL.Execute(&nextPage, renderer); err != nil {
+ if err := step.URL.Execute(&nextPage, builder); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error evaluating 'url'"))
}
- if err := redirect(renderer.response(), http.StatusTemporaryRedirect, nextPage.String()); err != nil {
+ if err := redirect(builder.response(), http.StatusTemporaryRedirect, nextPage.String()); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error redirecting to new page"))
}
diff --git a/render/step_RefreshPage.go b/build/step_RefreshPage.go
similarity index 62%
rename from render/step_RefreshPage.go
rename to build/step_RefreshPage.go
index 499d13e8a..fa5ac99e2 100644
--- a/render/step_RefreshPage.go
+++ b/build/step_RefreshPage.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -7,12 +7,12 @@ import (
// StepRefreshPage represents an action-step that forwards the user to a new page.
type StepRefreshPage struct{}
-func (step StepRefreshPage) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepRefreshPage) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepRefreshPage) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepRefreshPage) Post(builder Builder, _ io.Writer) PipelineBehavior {
return Continue().
WithEvent("closeModal", "true").
WithEvent("refreshPage", "true")
diff --git a/render/step_ReloadPage.go b/build/step_ReloadPage.go
similarity index 59%
rename from render/step_ReloadPage.go
rename to build/step_ReloadPage.go
index 6e287b316..7ef58ef94 100644
--- a/render/step_ReloadPage.go
+++ b/build/step_ReloadPage.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -7,11 +7,11 @@ import (
// StepReloadPage represents an action-step that forwards the user to a new page.
type StepReloadPage struct{}
-func (step StepReloadPage) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepReloadPage) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepReloadPage) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepReloadPage) Post(builder Builder, _ io.Writer) PipelineBehavior {
return Continue().WithHeader("HX-Refresh", "true")
}
diff --git a/render/step_RemoveEvent.go b/build/step_RemoveEvent.go
similarity index 67%
rename from render/step_RemoveEvent.go
rename to build/step_RemoveEvent.go
index d062919a9..7feee8434 100644
--- a/render/step_RemoveEvent.go
+++ b/build/step_RemoveEvent.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -9,11 +9,11 @@ type StepRemoveEvent struct {
Event string
}
-func (step StepRemoveEvent) Get(_ Renderer, _ io.Writer) PipelineBehavior {
+func (step StepRemoveEvent) Get(_ Builder, _ io.Writer) PipelineBehavior {
return Continue().RemoveEvent(step.Event)
}
// Post updates the stream with approved data from the request body.
-func (step StepRemoveEvent) Post(_ Renderer, _ io.Writer) PipelineBehavior {
+func (step StepRemoveEvent) Post(_ Builder, _ io.Writer) PipelineBehavior {
return Continue().RemoveEvent(step.Event)
}
diff --git a/render/step_Save.go b/build/step_Save.go
similarity index 61%
rename from render/step_Save.go
rename to build/step_Save.go
index 78f3ff4cc..9a8f9fac0 100644
--- a/render/step_Save.go
+++ b/build/step_Save.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,21 +13,21 @@ type StepSave struct {
Comment *template.Template
}
-func (step StepSave) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSave) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post saves the object to the database
-func (step StepSave) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSave) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepSave.Post"
+ const location = "build.StepSave.Post"
- modelService := renderer.service()
- object := renderer.object()
- comment := executeTemplate(step.Comment, renderer)
+ modelService := builder.service()
+ object := builder.object()
+ comment := executeTemplate(step.Comment, builder)
if setter, ok := modelService.(service.AuthorSetter); ok {
- if err := setter.SetAuthor(object, renderer.AuthenticatedID()); err != nil {
+ if err := setter.SetAuthor(object, builder.AuthenticatedID()); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error setting author"))
}
}
diff --git a/build/step_SendEmail.go b/build/step_SendEmail.go
new file mode 100644
index 000000000..0e397bdb1
--- /dev/null
+++ b/build/step_SendEmail.go
@@ -0,0 +1,47 @@
+package build
+
+import (
+ "io"
+
+ "github.com/benpate/derp"
+)
+
+// StepSendEmail represents an action-step that can send a named email to a recipient
+type StepSendEmail struct {
+ Email string
+}
+
+func (step StepSendEmail) Get(_ Builder, _ io.Writer) PipelineBehavior {
+ return nil
+}
+
+// Post saves the object to the database
+func (step StepSendEmail) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ factory := builder.factory()
+ emailService := factory.Email()
+
+ userBuilder, ok := builder.(User)
+
+ if !ok {
+ return Halt().WithError(derp.NewInternalError("build.StepSendEmail.Post", "Invalid Builder", "Builder must be Admin/User"))
+ }
+
+ switch step.Email {
+
+ case "welcome":
+
+ if err := emailService.SendWelcome(userBuilder._user); err != nil {
+ return Halt().WithError(err)
+ }
+
+ case "password-reset":
+ if err := emailService.SendPasswordReset(userBuilder._user); err != nil {
+ return Halt().WithError(err)
+ }
+
+ default:
+ return Halt().WithError(derp.NewInternalError("build.StepSendEmail.Post", "Invalid email name", "Name must be 'welcome' or 'password-reset'"))
+ }
+
+ return nil
+}
diff --git a/build/step_ServerRedirect.go b/build/step_ServerRedirect.go
new file mode 100644
index 000000000..59b8377a2
--- /dev/null
+++ b/build/step_ServerRedirect.go
@@ -0,0 +1,54 @@
+package build
+
+import (
+ "io"
+
+ "github.com/benpate/derp"
+)
+
+// StepServerRedirect represents an action-step that continues building the output stream as
+// a GET request to a new action.
+type StepServerRedirect struct {
+ On string // "get" or "post" or "both"
+ Action string
+}
+
+func (step StepServerRedirect) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ if step.On == "post" {
+ return nil
+ }
+
+ return step.redirect(builder, buffer)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepServerRedirect) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ if step.On == "get" {
+ return nil
+ }
+
+ return step.redirect(builder, builder.response())
+}
+
+// redirect creates a new builder on this object with the requested Action and then continues as a GET request.
+func (step StepServerRedirect) redirect(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ newBuilder, err := builder.clone(step.Action)
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepServerRedirect.Redirect", "Error creating new builder"))
+ }
+
+ result, err := newBuilder.Render()
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepServerRedirect.Redirect", "Error building new page"))
+ }
+
+ if _, err := buffer.Write([]byte(result)); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepServerRedirect.Redirect", "Error writing output buffer"))
+ }
+
+ return nil
+}
diff --git a/render/step_SetData.go b/build/step_SetData.go
similarity index 67%
rename from render/step_SetData.go
rename to build/step_SetData.go
index a95613989..60415362f 100644
--- a/render/step_SetData.go
+++ b/build/step_SetData.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -18,33 +18,33 @@ type StepSetData struct {
Defaults mapof.Any // values to set into the object IFF they are currently empty.
}
-func (step StepSetData) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepSetData) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- if err := step.setURLPaths(renderer); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetData.Get", "Error setting data from URL"))
+ if err := step.setURLPaths(builder); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSetData.Get", "Error setting data from URL"))
}
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepSetData) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSetData) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepSetData.Post"
+ const location = "build.StepSetData.Post"
- if err := step.setURLPaths(renderer); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetData.Get", "Error setting data from URL"))
+ if err := step.setURLPaths(builder); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSetData.Get", "Error setting data from URL"))
}
- object := renderer.object()
- schema := renderer.schema()
+ object := builder.object()
+ schema := builder.schema()
if len(step.FromForm) > 0 {
transaction := mapof.NewAny()
// Collect form POST information
- if err := bindBody(renderer.request(), &transaction); err != nil {
+ if err := bindBody(builder.request(), &transaction); err != nil {
result := derp.Wrap(err, location, "Error binding body", derp.WithCode(http.StatusBadRequest))
return Halt().WithError(result)
}
@@ -60,7 +60,7 @@ func (step StepSetData) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
// Put values from template.json into the stream
for key, value := range step.Values {
- valueString := executeTemplate(value, renderer)
+ valueString := executeTemplate(value, builder)
if err := schema.Set(object, key, valueString); err != nil {
result := derp.Wrap(err, location, "Error setting value from template.json", key, derp.WithCode(http.StatusBadRequest))
return Halt().WithError(result)
@@ -69,7 +69,7 @@ func (step StepSetData) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
// Set default values (only if no value already exists)
for name, value := range step.Defaults {
- currentValue, _ := schema.Get(renderer, name)
+ currentValue, _ := schema.Get(builder, name)
if compare.IsZero(currentValue) {
if err := schema.Set(object, name, value); err != nil {
result := derp.Wrap(err, location, "Error setting default value", name, value, derp.WithCode(http.StatusBadRequest))
@@ -82,16 +82,16 @@ func (step StepSetData) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
return nil
}
-func (step StepSetData) setURLPaths(renderer Renderer) error {
+func (step StepSetData) setURLPaths(builder Builder) error {
if len(step.FromURL) > 0 {
- query := renderer.request().URL.Query()
- schema := renderer.schema()
- object := renderer.object()
+ query := builder.request().URL.Query()
+ schema := builder.schema()
+ object := builder.object()
for _, path := range step.FromURL {
if value := query.Get(path); value != "" {
if err := schema.Set(object, path, value); err != nil {
- result := derp.Wrap(err, "render.StepSetData.setURLPaths", "Error setting data from URL", derp.WithCode(http.StatusBadRequest))
+ result := derp.Wrap(err, "build.StepSetData.setURLPaths", "Error setting data from URL", derp.WithCode(http.StatusBadRequest))
return result
}
}
diff --git a/build/step_SetHeader.go b/build/step_SetHeader.go
new file mode 100644
index 000000000..dc7cd57f1
--- /dev/null
+++ b/build/step_SetHeader.go
@@ -0,0 +1,44 @@
+package build
+
+import (
+ "bytes"
+ "io"
+ "text/template"
+
+ "github.com/benpate/derp"
+)
+
+// StepSetHeader represents an action-step that can update the custom data stored in a Stream
+type StepSetHeader struct {
+ Method string
+ Name string
+ Value *template.Template
+}
+
+func (step StepSetHeader) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ if step.Method == "post" {
+ return nil
+ }
+ return step.setHeader(builder)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepSetHeader) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ if step.Method == "get" {
+ return nil
+ }
+ return step.setHeader(builder)
+}
+
+func (step StepSetHeader) setHeader(builder Builder) PipelineBehavior {
+
+ var value bytes.Buffer
+
+ if err := step.Value.Execute(&value, builder); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSetHeader.Post", "Error executing template", step.Value))
+ }
+
+ builder.response().Header().Set(step.Name, value.String())
+
+ return nil
+}
diff --git a/build/step_SetQueryParam.go b/build/step_SetQueryParam.go
new file mode 100644
index 000000000..ce9a6ed63
--- /dev/null
+++ b/build/step_SetQueryParam.go
@@ -0,0 +1,33 @@
+package build
+
+import (
+ "io"
+ "text/template"
+)
+
+// StepSetQueryParam represents an action-step that sets values to the request query string
+type StepSetQueryParam struct {
+ Values map[string]*template.Template
+}
+
+// Get displays a form where users can update stream data
+func (step StepSetQueryParam) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.Do(builder)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepSetQueryParam) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ return step.Do(builder)
+}
+
+func (step StepSetQueryParam) Do(builder Builder) PipelineBehavior {
+ query := builder.request().URL.Query()
+
+ for key, value := range step.Values {
+ queryValue := executeTemplate(value, builder)
+ query.Set(key, queryValue)
+ }
+
+ builder.request().URL.RawQuery = query.Encode()
+ return nil
+}
diff --git a/build/step_SetRenderData.go b/build/step_SetRenderData.go
new file mode 100644
index 000000000..114b7d566
--- /dev/null
+++ b/build/step_SetRenderData.go
@@ -0,0 +1,30 @@
+package build
+
+import (
+ "io"
+ "text/template"
+)
+
+// StepSetRenderData represents an action-step that sets values to the request query string
+type StepSetRenderData struct {
+ Values map[string]*template.Template
+}
+
+// Get displays a form where users can update stream data
+func (step StepSetRenderData) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.Do(builder)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepSetRenderData) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ return step.Do(builder)
+}
+
+func (step StepSetRenderData) Do(builder Builder) PipelineBehavior {
+ for key, value := range step.Values {
+ queryValue := executeTemplate(value, builder)
+ builder.setString(key, queryValue)
+ }
+
+ return nil
+}
diff --git a/render/step_SetResponse.go b/build/step_SetResponse.go
similarity index 79%
rename from render/step_SetResponse.go
rename to build/step_SetResponse.go
index bedda8276..63a14ddbc 100644
--- a/render/step_SetResponse.go
+++ b/build/step_SetResponse.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -16,30 +16,30 @@ type StepSetResponseTransaction struct {
Exists string `json:"exists" form:"exists"` // If TRUE, then create/update the response. If FALSE, remove it.
}
-func (step StepSetResponse) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepSetResponse) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
-func (step StepSetResponse) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSetResponse) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepSetResponse.Post"
+ const location = "build.StepSetResponse.Post"
transaction := StepSetResponseTransaction{}
// Receive the transaction data
- if err := bind(renderer.request(), &transaction); err != nil {
+ if err := bind(builder.request(), &transaction); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error binding transaction"))
}
// Retrieve the currently authenticated user
- user, err := renderer.getUser()
+ user, err := builder.getUser()
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error getting user"))
}
// Set the value in the database
- responseService := renderer.factory().Response()
+ responseService := builder.factory().Response()
// Create/Update the response
if convert.Bool(transaction.Exists) {
diff --git a/render/step_SetSimpleSharing.go b/build/step_SetSimpleSharing.go
similarity index 80%
rename from render/step_SetSimpleSharing.go
rename to build/step_SetSimpleSharing.go
index 3c0c16b66..c82ee6aaa 100644
--- a/render/step_SetSimpleSharing.go
+++ b/build/step_SetSimpleSharing.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -21,16 +21,16 @@ type StepSetSimpleSharing struct {
Roles []string
}
-func (step StepSetSimpleSharing) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepSetSimpleSharing) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- streamRenderer := renderer.(*Stream)
- model := streamRenderer._stream.SimplePermissionModel()
+ streamBuilder := builder.(*Stream)
+ model := streamBuilder._stream.SimplePermissionModel()
// Try to write form HTML
- formHTML, err := form.Editor(step.schema(), step.form(), model, renderer.lookupProvider())
+ formHTML, err := form.Editor(step.schema(), step.form(), model, builder.lookupProvider())
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetSimpleSharing.Get", "Error rendering form"))
+ return Halt().WithError(derp.Wrap(err, "build.StepSetSimpleSharing.Get", "Error building form"))
}
// Write the rest of the HTML that contains the form
@@ -42,7 +42,7 @@ func (step StepSetSimpleSharing) Get(renderer Renderer, buffer io.Writer) Pipeli
// Form
b.Form("", "").
- Data("hx-post", renderer.URL()).
+ Data("hx-post", builder.URL()).
Data("hx-swap", "none").
Data("hx-push-url", "false").
Script("init send checkFormRules(changed:me as Values)").
@@ -59,15 +59,15 @@ func (step StepSetSimpleSharing) Get(renderer Renderer, buffer io.Writer) Pipeli
return nil
}
-func (step StepSetSimpleSharing) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSetSimpleSharing) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepSetSimpleSharing.Post"
+ const location = "build.StepSetSimpleSharing.Post"
- request := renderer.request()
+ request := builder.request()
// Try to parse the form input
if err := request.ParseForm(); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetSimpleSharing", "Error parsing form input"))
+ return Halt().WithError(derp.Wrap(err, "build.StepSetSimpleSharing", "Error parsing form input"))
}
var groupIDs []primitive.ObjectID
@@ -89,8 +89,8 @@ func (step StepSetSimpleSharing) Post(renderer Renderer, _ io.Writer) PipelineBe
}
// Build the stream criteria
- streamRenderer := renderer.(*Stream)
- stream := streamRenderer._stream
+ streamBuilder := builder.(*Stream)
+ stream := streamBuilder._stream
stream.Permissions = model.NewStreamPermissions()
for _, groupID := range groupIDs {
diff --git a/build/step_SetState.go b/build/step_SetState.go
new file mode 100644
index 000000000..dac585322
--- /dev/null
+++ b/build/step_SetState.go
@@ -0,0 +1,36 @@
+package build
+
+import (
+ "io"
+
+ "github.com/benpate/derp"
+)
+
+// StepSetState represents an action-step that can change a Stream's state
+type StepSetState struct {
+ State string
+}
+
+func (step StepSetState) Get(builder Builder, _ io.Writer) PipelineBehavior {
+ return nil
+}
+
+// Post updates the stream with configured data, and moves the stream to a new state
+func (step StepSetState) Post(builder Builder, _ io.Writer) PipelineBehavior {
+
+ // If the builder is a StateSetter, then try to update the state
+ if setter, ok := builder.(StateSetter); ok {
+
+ // This action may still fail (for instance) if the builder wraps
+ // a model object that is not a `model.StateSetter`
+ if err := setter.setState(step.State); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.stepSetState.Post", "Error setting state"))
+ }
+
+ // Success
+ return nil
+ }
+
+ // Failure (obv)
+ return Halt().WithError(derp.NewInternalError("build.stepSetState.Post", "Builder does not implement StateSetter interface"))
+}
diff --git a/render/step_SetThumbnail.go b/build/step_SetThumbnail.go
similarity index 58%
rename from render/step_SetThumbnail.go
rename to build/step_SetThumbnail.go
index 25e1990fb..d37368106 100644
--- a/render/step_SetThumbnail.go
+++ b/build/step_SetThumbnail.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -11,29 +11,29 @@ type StepSetThumbnail struct {
Path string
}
-func (step StepSetThumbnail) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSetThumbnail) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepSetThumbnail) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSetThumbnail) Post(builder Builder, _ io.Writer) PipelineBehavior {
// Find best icon from attachments
- factory := renderer.factory()
+ factory := builder.factory()
- objectType := renderer.service().ObjectType()
- objectID := renderer.objectID()
- object := renderer.object()
+ objectType := builder.service().ObjectType()
+ objectID := builder.objectID()
+ object := builder.object()
attachments, err := factory.Attachment().QueryByObjectID(objectType, objectID)
if err != nil {
- return Halt().WithError(derp.NewBadRequestError("render.StepSetThumbnail.Post", "Error listing attachments"))
+ return Halt().WithError(derp.NewBadRequestError("build.StepSetThumbnail.Post", "Error listing attachments"))
}
// Scan all attachments and use the first one that is an image.
- schema := renderer.schema()
+ schema := builder.schema()
for _, attachment := range attachments {
if attachment.MimeCategory() == "image" {
@@ -41,17 +41,17 @@ func (step StepSetThumbnail) Post(renderer Renderer, _ io.Writer) PipelineBehavi
// Special case for User objects (this should always be "imageId")
if objectType == "User" {
if err := schema.Set(object, step.Path, attachment.AttachmentID.Hex()); err != nil {
- return Halt().WithError(derp.NewInternalError("render.StepSetThumbnail.Post", "Invalid path for non-user object (A)", step.Path))
+ return Halt().WithError(derp.NewInternalError("build.StepSetThumbnail.Post", "Invalid path for non-user object (A)", step.Path))
}
return nil
}
// Standard path for all other records
- imageURL := renderer.Permalink()
+ imageURL := builder.Permalink()
imageURL = imageURL + "/attachments/" + attachment.AttachmentID.Hex()
if err := schema.Set(object, step.Path, imageURL); err != nil {
- return Halt().WithError(derp.NewInternalError("render.StepSetThumbnail.Post", "Invalid path for non-user object (B)", step.Path))
+ return Halt().WithError(derp.NewInternalError("build.StepSetThumbnail.Post", "Invalid path for non-user object (B)", step.Path))
}
return nil
}
@@ -59,7 +59,7 @@ func (step StepSetThumbnail) Post(renderer Renderer, _ io.Writer) PipelineBehavi
// Fall through means that we can't find any images. Set the Thumbnail to an empty string.
if err := schema.Set(object, step.Path, ""); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetThumbnail.Post", "Error setting thumbnail"))
+ return Halt().WithError(derp.Wrap(err, "build.StepSetThumbnail.Post", "Error setting thumbnail"))
}
// Success!
diff --git a/render/step_Sort.go b/build/step_Sort.go
similarity index 52%
rename from render/step_Sort.go
rename to build/step_Sort.go
index 4fc8789a1..74ccb240a 100644
--- a/render/step_Sort.go
+++ b/build/step_Sort.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -15,20 +15,20 @@ type StepSort struct {
Message string
}
-func (step StepSort) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSort) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepSort) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSort) Post(builder Builder, _ io.Writer) PipelineBehavior {
var transaction struct {
Keys []string `form:"keys"`
}
// Collect form POST information
- if err := bind(renderer.request(), &transaction); err != nil {
- return Halt().WithError(derp.NewBadRequestError("render.StepSort.Post", "Error binding body"))
+ if err := bind(builder.request(), &transaction); err != nil {
+ return Halt().WithError(derp.NewBadRequestError("build.StepSort.Post", "Error binding body"))
}
for index, id := range transaction.Keys {
@@ -40,26 +40,26 @@ func (step StepSort) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSort.Post", "Invalid objectId", id))
+ return Halt().WithError(derp.Wrap(err, "build.StepSort.Post", "Invalid objectId", id))
}
criteria := exp.Equal(step.Keys, objectID)
// Try to load the object from the database
- object, err := renderer.service().ObjectLoad(criteria)
+ object, err := builder.service().ObjectLoad(criteria)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSort.Post", "Error loading object with criteria: ", criteria))
+ return Halt().WithError(derp.Wrap(err, "build.StepSort.Post", "Error loading object with criteria: ", criteria))
}
// Use the object schema to set the new sort rank
- if err := renderer.schema().Set(object, "rank", newRank); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSort.Post", "Error setting new rank", objectID, step.Values, newRank))
+ if err := builder.schema().Set(object, "rank", newRank); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSort.Post", "Error setting new rank", objectID, step.Values, newRank))
}
// Try to save back to the database
- if err := renderer.service().ObjectSave(object, step.Message); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSort.Post", "Error saving record tot he database", object))
+ if err := builder.service().ObjectSave(object, step.Message); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSort.Post", "Error saving record tot he database", object))
}
}
diff --git a/render/step_SortAttachments.go b/build/step_SortAttachments.go
similarity index 62%
rename from render/step_SortAttachments.go
rename to build/step_SortAttachments.go
index cf5bedc54..999daecae 100644
--- a/render/step_SortAttachments.go
+++ b/build/step_SortAttachments.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -16,23 +16,23 @@ type StepSortAttachments struct {
Message string
}
-func (step StepSortAttachments) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSortAttachments) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepSortAttachments) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSortAttachments) Post(builder Builder, _ io.Writer) PipelineBehavior {
var transaction struct {
Keys []string `form:"keys"`
}
// Collect form POST information
- if err := bind(renderer.request(), &transaction); err != nil {
- return Halt().WithError(derp.NewBadRequestError("render.StepSortAttachments.Post", "Error binding body"))
+ if err := bind(builder.request(), &transaction); err != nil {
+ return Halt().WithError(derp.NewBadRequestError("build.StepSortAttachments.Post", "Error binding body"))
}
- factory := renderer.factory()
+ factory := builder.factory()
attachmentService := factory.Attachment()
for index, id := range transaction.Keys {
@@ -44,16 +44,16 @@ func (step StepSortAttachments) Post(renderer Renderer, _ io.Writer) PipelineBeh
attachmentID, err := primitive.ObjectIDFromHex(id)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSortAttachments.Post", "Invalid attachmentId", id))
+ return Halt().WithError(derp.Wrap(err, "build.StepSortAttachments.Post", "Invalid attachmentId", id))
}
- criteria := exp.Equal("streamId", renderer.objectID()).
+ criteria := exp.Equal("streamId", builder.objectID()).
AndEqual(step.Keys, attachmentID).
AndEqual("deleteDate", 0)
// Try to load the attachment from the database
if err := attachmentService.Load(criteria, &attachment); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSortAttachments.Post", "Error loading attachment with criteria: ", criteria))
+ return Halt().WithError(derp.Wrap(err, "build.StepSortAttachments.Post", "Error loading attachment with criteria: ", criteria))
}
// If the rank for this attachment has not changed, then don't waste time saving it again.
@@ -65,7 +65,7 @@ func (step StepSortAttachments) Post(renderer Renderer, _ io.Writer) PipelineBeh
// Try to save back to the database
if err := attachmentService.Save(&attachment, step.Message); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSortAttachments.Post", "Error saving record tot he database", attachment))
+ return Halt().WithError(derp.Wrap(err, "build.StepSortAttachments.Post", "Error saving record tot he database", attachment))
}
}
diff --git a/render/step_SortWidgets.go b/build/step_SortWidgets.go
similarity index 69%
rename from render/step_SortWidgets.go
rename to build/step_SortWidgets.go
index 4f7112b59..aef16dd94 100644
--- a/render/step_SortWidgets.go
+++ b/build/step_SortWidgets.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,32 +13,32 @@ import (
// StepSortWidgets represents an action-step that can edit/update Container in a streamDraft.
type StepSortWidgets struct{}
-func (step StepSortWidgets) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepSortWidgets) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
-func (step StepSortWidgets) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepSortWidgets) Post(builder Builder, _ io.Writer) PipelineBehavior {
- streamRenderer, ok := renderer.(*Stream)
+ streamBuilder, ok := builder.(*Stream)
if !ok {
- return Halt().WithError(derp.NewInternalError("render.StepSortWidgets.Post", "edit-widgets can only be used on Stream transaction"))
+ return Halt().WithError(derp.NewInternalError("build.StepSortWidgets.Post", "edit-widgets can only be used on Stream transaction"))
}
// Collect required services
- factory := streamRenderer._factory
+ factory := streamBuilder._factory
widgetService := factory.Widget()
// Collect transaction from form POST
transaction := mapof.NewString()
- if err := bind(renderer.request(), &transaction); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSortWidgets.Post", "Error binding form transaction"))
+ if err := bind(builder.request(), &transaction); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepSortWidgets.Post", "Error binding form transaction"))
}
// Set up some variables
- stream := streamRenderer._stream
- template := streamRenderer.template()
+ stream := streamBuilder._stream
+ template := streamBuilder.template()
newWidgets := model.NewStreamWidgets()
// Find and organize the selected widgets
diff --git a/render/step_TriggerEvent.go b/build/step_TriggerEvent.go
similarity index 58%
rename from render/step_TriggerEvent.go
rename to build/step_TriggerEvent.go
index 412f603d3..9030986c5 100644
--- a/render/step_TriggerEvent.go
+++ b/build/step_TriggerEvent.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -11,12 +11,12 @@ type StepTriggerEvent struct {
Value *template.Template
}
-func (step StepTriggerEvent) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepTriggerEvent) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepTriggerEvent) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- value := executeTemplate(step.Value, renderer)
+func (step StepTriggerEvent) Post(builder Builder, _ io.Writer) PipelineBehavior {
+ value := executeTemplate(step.Value, builder)
return Continue().WithEvent(step.Event, value)
}
diff --git a/render/step_UnPublish.go b/build/step_UnPublish.go
similarity index 58%
rename from render/step_UnPublish.go
rename to build/step_UnPublish.go
index dac43b2bb..459fcda9c 100644
--- a/render/step_UnPublish.go
+++ b/build/step_UnPublish.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -12,36 +12,36 @@ type StepUnPublish struct {
Role string
}
-func (step StepUnPublish) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepUnPublish) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with the current date as the "PublishDate"
-func (step StepUnPublish) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepUnPublish) Post(builder Builder, _ io.Writer) PipelineBehavior {
- const location = "render.StepUnPublish.Post"
+ const location = "build.StepUnPublish.Post"
// Require that the user is signed in to perform this action
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "User is not authenticated", nil))
}
- streamRenderer := renderer.(*Stream)
- factory := streamRenderer.factory()
+ streamBuilder := builder.(*Stream)
+ factory := streamBuilder.factory()
// Try to load the User from the Database
userService := factory.User()
user := model.NewUser()
- if err := userService.LoadByID(streamRenderer.AuthenticatedID(), &user); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error loading user", streamRenderer.AuthenticatedID()))
+ if err := userService.LoadByID(streamBuilder.AuthenticatedID(), &user); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error loading user", streamBuilder.AuthenticatedID()))
}
// Try to Publish the Stream to ActivityPub
streamService := factory.Stream()
- if err := streamService.UnPublish(&user, streamRenderer._stream); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error publishing stream", streamRenderer._stream))
+ if err := streamService.UnPublish(&user, streamBuilder._stream); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error publishing stream", streamBuilder._stream))
}
return nil
diff --git a/render/step_UploadAttachment.go b/build/step_UploadAttachment.go
similarity index 85%
rename from render/step_UploadAttachment.go
rename to build/step_UploadAttachment.go
index b35873f27..105145293 100644
--- a/render/step_UploadAttachment.go
+++ b/build/step_UploadAttachment.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"encoding/json"
@@ -9,19 +9,19 @@ import (
"github.com/benpate/rosetta/mapof"
)
-// StepUploadAttachment represents an action that can upload attachments. It can only be used on a StreamRenderer
+// StepUploadAttachment represents an action that can upload attachments. It can only be used on a StreamBuilder
type StepUploadAttachment struct {
Maximum int
}
-func (step StepUploadAttachment) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepUploadAttachment) Get(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
-func (step StepUploadAttachment) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepUploadAttachment) Post(builder Builder, buffer io.Writer) PipelineBehavior {
// Read the multipart form from the request
- form, err := multipartForm(renderer.request())
+ form, err := multipartForm(builder.request())
if err != nil {
return Halt().WithError(derp.Wrap(err, "handler.StepUploadAttachment.Post", "Error reading multipart form."))
@@ -37,11 +37,11 @@ func (step StepUploadAttachment) Post(renderer Renderer, buffer io.Writer) Pipel
step.Maximum = 1
}
- factory := renderer.factory()
+ factory := builder.factory()
attachmentService := factory.Attachment()
- objectID := renderer.objectID()
- objectType := renderer.service().ObjectType()
+ objectID := builder.objectID()
+ objectType := builder.service().ObjectType()
// Special case: If we're uploading a draft, then we need to attach the document to the parent stream.
if objectType == "StreamDraft" {
@@ -83,12 +83,12 @@ func (step StepUploadAttachment) Post(renderer Renderer, buffer io.Writer) Pipel
response := mapof.Any{
"success": 1,
"file": mapof.Any{
- "url": attachment.CalcURL(renderer.Host()),
+ "url": attachment.CalcURL(builder.Host()),
"height": attachment.Height,
"width": attachment.Width,
},
"data": mapof.Any{
- "filePath": attachment.CalcURL(renderer.Host()),
+ "filePath": attachment.CalcURL(builder.Host()),
},
}
diff --git a/render/step_ViewFeed.go b/build/step_ViewFeed.go
similarity index 64%
rename from render/step_ViewFeed.go
rename to build/step_ViewFeed.go
index 354e303e9..6fb31a1f6 100644
--- a/render/step_ViewFeed.go
+++ b/build/step_ViewFeed.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"encoding/json"
@@ -16,35 +16,35 @@ import (
accept "github.com/timewasted/go-accept-headers"
)
-// StepViewFeed represents an action-step that can render a Stream into HTML
+// StepViewFeed represents an action-step that can build a Stream into HTML
type StepViewFeed struct{}
-// Get renders the Stream HTML to the context
-func (step StepViewFeed) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+// Get builds the Stream HTML to the context
+func (step StepViewFeed) Get(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepViewFeed.Get"
+ const location = "build.StepViewFeed.Get"
- factory := renderer.factory()
+ factory := builder.factory()
// Get all child streams from the database
- children, err := factory.Stream().ListByParent(renderer.objectID())
+ children, err := factory.Stream().ListByParent(builder.objectID())
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error querying child streams"))
}
- mimeType := step.detectMimeType(renderer)
+ mimeType := step.detectMimeType(builder)
// Special case for JSONFeed
if mimeType == model.MimeTypeJSONFeed {
- return step.asJSONFeed(renderer, buffer, children)
+ return step.asJSONFeed(builder, buffer, children)
}
// Initialize the result RSS feed
result := feeds.Feed{
- Title: renderer.PageTitle(),
- Description: renderer.Summary(),
- Link: &feeds.Link{Href: renderer.Permalink()},
+ Title: builder.PageTitle(),
+ Description: builder.Summary(),
+ Link: &feeds.Link{Href: builder.Permalink()},
Author: &feeds.Author{Name: ""},
Created: time.Now(),
}
@@ -78,14 +78,14 @@ func (step StepViewFeed) Get(renderer Renderer, buffer io.Writer) PipelineBehavi
}
}
-func (step StepViewFeed) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepViewFeed) Post(builder Builder, _ io.Writer) PipelineBehavior {
return nil
}
-func (step StepViewFeed) detectMimeType(renderer Renderer) string {
+func (step StepViewFeed) detectMimeType(builder Builder) string {
// First, try to get the format from the query string
- switch renderer.QueryParam("format") {
+ switch builder.QueryParam("format") {
case "json":
return model.MimeTypeJSONFeed
case "atom":
@@ -95,7 +95,7 @@ func (step StepViewFeed) detectMimeType(renderer Renderer) string {
}
// Otherwise, get the format from the "Accept" header
- header := renderer.request().Header
+ header := builder.request().Header
if result, err := accept.Negotiate(header.Get("Accept"), model.MimeTypeJSONFeed, model.MimeTypeAtom, model.MimeTypeRSS, model.MimeTypeXML, model.MimeTypeXMLText); err == nil {
return result
@@ -105,30 +105,30 @@ func (step StepViewFeed) detectMimeType(renderer Renderer) string {
return model.MimeTypeJSONFeed
}
-func (step StepViewFeed) asJSONFeed(renderer Renderer, buffer io.Writer, children data.Iterator) PipelineBehavior {
+func (step StepViewFeed) asJSONFeed(builder Builder, buffer io.Writer, children data.Iterator) PipelineBehavior {
feed := jsonfeed.Feed{
Version: "https://jsonfeed.org/version/1.1",
- Title: renderer.PageTitle(),
- HomePageURL: renderer.Permalink(),
- FeedURL: renderer.Permalink() + "/feed?format=json",
- Description: renderer.Summary(),
+ Title: builder.PageTitle(),
+ HomePageURL: builder.Permalink(),
+ FeedURL: builder.Permalink() + "/feed?format=json",
+ Description: builder.Summary(),
Hubs: []jsonfeed.Hub{
{
Type: "WebSub",
- URL: renderer.Permalink() + "/websub",
+ URL: builder.Permalink() + "/websub",
},
},
}
feed.Items = slice.Map(iterator.Slice(children, model.NewStream), convert.StreamToJsonFeed)
- renderer.response().Header().Add("Content-Type", model.MimeTypeJSONFeed)
+ builder.response().Header().Add("Content-Type", model.MimeTypeJSONFeed)
bytes, err := json.Marshal(feed)
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepViewFeed.asJSONFeed", "Error generating JSONFeed"))
+ return Halt().WithError(derp.Wrap(err, "build.StepViewFeed.asJSONFeed", "Error generating JSONFeed"))
}
// nolint:errcheck
diff --git a/render/step_ViewHTML.go b/build/step_ViewHTML.go
similarity index 65%
rename from render/step_ViewHTML.go
rename to build/step_ViewHTML.go
index e0d9c7ad4..d99a6e15d 100644
--- a/render/step_ViewHTML.go
+++ b/build/step_ViewHTML.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -8,32 +8,32 @@ import (
"github.com/benpate/rosetta/compare"
)
-// StepViewHTML represents an action-step that can render a Stream into HTML
+// StepViewHTML represents an action-step that can build a Stream into HTML
type StepViewHTML struct {
File string
Method string
}
-// Get renders the Stream HTML to the context
-func (step StepViewHTML) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+// Get builds the Stream HTML to the context
+func (step StepViewHTML) Get(builder Builder, buffer io.Writer) PipelineBehavior {
if step.Method != "post" {
- return step.execute(renderer, buffer)
+ return step.execute(builder, buffer)
}
return nil
}
-func (step StepViewHTML) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepViewHTML) Post(builder Builder, buffer io.Writer) PipelineBehavior {
if step.Method != "get" {
- return step.execute(renderer, buffer)
+ return step.execute(builder, buffer)
}
return nil
}
-func (step StepViewHTML) execute(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepViewHTML) execute(builder Builder, buffer io.Writer) PipelineBehavior {
/* TODO: MEDIUM: Re-implement client-side caching later.
Caching leads to problems on INDEX-ONLY pages because you may have added/changed/deleted a child
@@ -43,7 +43,7 @@ func (step StepViewHTML) execute(renderer Renderer, buffer io.Writer) PipelineBe
// Validate If-None-Match Header
if etag := requestHeader.Get("If-None-Match"); etag != "" {
- if etag == renderer.object().ETag() {
+ if etag == builder.object().ETag() {
context.Response().WriteHeader(http.StatusNotModified)
return nil
}
@@ -52,7 +52,7 @@ func (step StepViewHTML) execute(renderer Renderer, buffer io.Writer) PipelineBe
// Validate If-Modified-Since Header
if modifiedSince := requestHeader.Get("If-Modified-Since"); modifiedSince != "" {
if modifiedSinceDate, err := time.Parse(time.RFC3339, modifiedSince); err == nil {
- if modifiedSinceDate.UnixMilli() >= renderer.object().Updated() {
+ if modifiedSinceDate.UnixMilli() >= builder.object().Updated() {
context.Response().WriteHeader(http.StatusNotModified)
return nil
}
@@ -61,7 +61,7 @@ func (step StepViewHTML) execute(renderer Renderer, buffer io.Writer) PipelineBe
*/
// TODO: LOW: We can do a better job with caching. If a page is public, then caching should be public, too.
- header := renderer.response().Header()
+ header := builder.response().Header()
header.Set("Vary", "Cookie, HX-Request")
// header.Set("Cache-Control", "private")
@@ -70,17 +70,17 @@ func (step StepViewHTML) execute(renderer Renderer, buffer io.Writer) PipelineBe
if step.File != "" {
filename = step.File
} else {
- filename = renderer.ActionID()
+ filename = builder.ActionID()
}
- if err := renderer.executeTemplate(buffer, filename, renderer); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepViewHTML.Get", "Error executing template"))
+ if err := builder.executeTemplate(buffer, filename, builder); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepViewHTML.Get", "Error executing template"))
}
// TODO: MEDIUM: Re-implement caching. Will need to automatically compute the "Vary" header.
// If we have a valid object, then try to set ETag headers.
- if object := renderer.object(); compare.NotNil(object) {
+ if object := builder.object(); compare.NotNil(object) {
return Continue().
WithHeader("Last-Modified", time.UnixMilli(object.Updated()).Format(time.RFC3339)).
WithHeader("ETag", object.ETag())
diff --git a/render/step_ViewJSONLD.go b/build/step_ViewJSONLD.go
similarity index 55%
rename from render/step_ViewJSONLD.go
rename to build/step_ViewJSONLD.go
index 6e6eab8cb..209f6344c 100644
--- a/render/step_ViewJSONLD.go
+++ b/build/step_ViewJSONLD.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"encoding/json"
@@ -9,34 +9,34 @@ import (
accept "github.com/timewasted/go-accept-headers"
)
-// StepViewJSONLD represents an action-step that can render a Stream into HTML
+// StepViewJSONLD represents an action-step that can build a Stream into HTML
type StepViewJSONLD struct {
Method string
}
-// Get renders the Stream HTML to the context
-func (step StepViewJSONLD) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+// Get builds the Stream HTML to the context
+func (step StepViewJSONLD) Get(builder Builder, buffer io.Writer) PipelineBehavior {
if step.Method != "post" {
- return step.execute(renderer, buffer)
+ return step.execute(builder, buffer)
}
return nil
}
-func (step StepViewJSONLD) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepViewJSONLD) Post(builder Builder, buffer io.Writer) PipelineBehavior {
if step.Method != "get" {
- return step.execute(renderer, buffer)
+ return step.execute(builder, buffer)
}
return nil
}
-func (step StepViewJSONLD) execute(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepViewJSONLD) execute(builder Builder, buffer io.Writer) PipelineBehavior {
// Try to negotiate the correct content type
- acceptHeader := renderer.request().Header.Get("Accept")
+ acceptHeader := builder.request().Header.Get("Accept")
accept, err := accept.Negotiate(acceptHeader, model.MimeTypeHTML, model.MimeTypeActivityPub, model.MimeTypeJSONLD, model.MimeTypeJSON)
// If there is an error in content negotiation, then no JSON-LD for you
@@ -55,19 +55,19 @@ func (step StepViewJSONLD) execute(renderer Renderer, buffer io.Writer) Pipeline
// JSON-LD FOR YOU!!!!
- // Now, try to get a JSONLDGetter from the renderer
- if getter, ok := renderer.object().(model.JSONLDGetter); ok {
+ // Now, try to get a JSONLDGetter from the builder
+ if getter, ok := builder.object().(model.JSONLDGetter); ok {
// Write the object as JSON
result, err := json.Marshal(getter.GetJSONLD())
if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepViewJSONLD.Get", "Error marshalling JSONLD"))
+ return Halt().WithError(derp.Wrap(err, "build.StepViewJSONLD.Get", "Error marshalling JSONLD"))
}
// Write the JSON to the output buffer
if _, err := buffer.Write(result); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepViewJSONLD.Get", "Error writing JSONLD to buffer"))
+ return Halt().WithError(derp.Wrap(err, "build.StepViewJSONLD.Get", "Error writing JSONLD to buffer"))
}
// Done. Return result as pure JSON.
@@ -75,5 +75,5 @@ func (step StepViewJSONLD) execute(renderer Renderer, buffer io.Writer) Pipeline
}
// If you're here, that means the template designer used step on a non-JSONLDGetter object type. Shame.
- return Halt().WithError(derp.NewNotFoundError("render.StepViewJSONLD.Get", "Object does not implement JSONLDGetter interface"))
+ return Halt().WithError(derp.NewNotFoundError("build.StepViewJSONLD.Get", "Object does not implement JSONLDGetter interface"))
}
diff --git a/render/step_WebSub.go b/build/step_WebSub.go
similarity index 59%
rename from render/step_WebSub.go
rename to build/step_WebSub.go
index 52a8140ba..99520786e 100644
--- a/render/step_WebSub.go
+++ b/build/step_WebSub.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -11,23 +11,23 @@ import (
"github.com/timewasted/go-accept-headers"
)
-// StepWebSub represents an action-step that can render a Stream into HTML
+// StepWebSub represents an action-step that can build a Stream into HTML
type StepWebSub struct {
}
// Get is not required by WebSub. So let's redirect to the primary action.
-func (step StepWebSub) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepWebSub) Get(builder Builder, buffer io.Writer) PipelineBehavior {
// TODO: MEDIUM: This may not jive with the new PipelineBehavior model. Check accordingly.
- newLocation := list.RemoveLast(renderer.URL(), list.DelimiterSlash)
- if err := redirect(renderer.response(), http.StatusSeeOther, newLocation); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepWebSub.Get", "Error writing redirection", newLocation))
+ newLocation := list.RemoveLast(builder.URL(), list.DelimiterSlash)
+ if err := redirect(builder.response(), http.StatusSeeOther, newLocation); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepWebSub.Get", "Error writing redirection", newLocation))
}
return nil
}
// Post accepts a WebSub request, verifies it, and potentially creates a new Follower record.
-func (step StepWebSub) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
+func (step StepWebSub) Post(builder Builder, _ io.Writer) PipelineBehavior {
var transaction struct {
Mode string `form:"hub.mode"`
@@ -37,14 +37,14 @@ func (step StepWebSub) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
LeaseSeconds int `form:"hub.lease_seconds"`
}
- if err := bind(renderer.request(), &transaction); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepWebSub.Post", "Error parsing form data"))
+ if err := bind(builder.request(), &transaction); err != nil {
+ return Halt().WithError(derp.Wrap(err, "build.StepWebSub.Post", "Error parsing form data"))
}
// Try to validate and save the follower via the queue.
- factory := renderer.factory()
+ factory := builder.factory()
- format, err := accept.Negotiate(renderer.request().Header.Get("Accept"), model.MimeTypeJSONFeed, model.MimeTypeAtom, model.MimeTypeRSS, model.MimeTypeXML, model.MimeTypeXMLText)
+ format, err := accept.Negotiate(builder.request().Header.Get("Accept"), model.MimeTypeJSONFeed, model.MimeTypeAtom, model.MimeTypeRSS, model.MimeTypeXML, model.MimeTypeXMLText)
if err != nil {
format = model.MimeTypeJSONFeed
@@ -54,8 +54,8 @@ func (step StepWebSub) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
factory.Queue().Push(service.NewTaskCreateWebSubFollower(
factory.Follower(),
factory.Locator(),
- renderer.objectType(),
- renderer.objectID(),
+ builder.objectType(),
+ builder.objectID(),
format,
transaction.Mode,
transaction.Topic,
@@ -67,7 +67,7 @@ func (step StepWebSub) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
// TODO: MEDIUM: This may not jive with the new PipelineBehavior model. Check accordingly.
// Set Status Code 202 (Accepted) to conform to WebSub spec
// https://www.w3.org/TR/websub/#subscription-response-details
- renderer.response().WriteHeader(202)
+ builder.response().WriteHeader(202)
return nil
}
diff --git a/render/step_WebSub_test.go b/build/step_WebSub_test.go
similarity index 99%
rename from render/step_WebSub_test.go
rename to build/step_WebSub_test.go
index 1259cb178..f47ddc56f 100644
--- a/render/step_WebSub_test.go
+++ b/build/step_WebSub_test.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"testing"
diff --git a/render/step_WithChildren.go b/build/step_WithChildren.go
similarity index 63%
rename from render/step_WithChildren.go
rename to build/step_WithChildren.go
index 119a8aa47..63ead5145 100644
--- a/render/step_WithChildren.go
+++ b/build/step_WithChildren.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,19 +13,19 @@ type StepWithChildren struct {
SubSteps []step.Step
}
-func (step StepWithChildren) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepWithChildren) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
// Post updates the stream with approved data from the request body.
-func (step StepWithChildren) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepWithChildren) Post(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepWithChildren.Post"
+ const location = "build.StepWithChildren.Post"
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
- children, err := factory.Stream().ListByParent(streamRenderer._stream.ParentID)
+ children, err := factory.Stream().ListByParent(streamBuilder._stream.ParentID)
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error listing children"))
@@ -36,15 +36,15 @@ func (step StepWithChildren) Post(renderer Renderer, buffer io.Writer) PipelineB
for children.Next(&child) {
- // Make a renderer with the new child stream
+ // Make a builder with the new child stream
// TODO: LOW: Is "view" really the best action to use here??
- childStream, err := NewStreamWithoutTemplate(streamRenderer.factory(), streamRenderer.request(), streamRenderer.response(), &child, "")
+ childStream, err := NewStreamWithoutTemplate(streamBuilder.factory(), streamBuilder.request(), streamBuilder.response(), &child, "")
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating renderer for child"))
+ return Halt().WithError(derp.Wrap(err, location, "Error creating builder for child"))
}
- // Execute the POST render pipeline on the child
+ // Execute the POST build pipeline on the child
childResult := Pipeline(step.SubSteps).Post(factory, &childStream, buffer)
childResult.Error = derp.Wrap(result.Error, location, "Error executing steps for child")
diff --git a/build/step_WithDraft.go b/build/step_WithDraft.go
new file mode 100644
index 000000000..b66e9f4af
--- /dev/null
+++ b/build/step_WithDraft.go
@@ -0,0 +1,53 @@
+package build
+
+import (
+ "io"
+
+ "github.com/EmissarySocial/emissary/model/step"
+ "github.com/benpate/derp"
+)
+
+// StepWithDraft represents an action-step that can update the data.DataMap custom data stored in a Stream
+type StepWithDraft struct {
+ SubSteps []step.Step
+}
+
+// Get displays a form where users can update stream data
+func (step StepWithDraft) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ const location = "build.StepWithDraft.Get"
+
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
+ draftBuilder, err := streamBuilder.draftBuilder()
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error getting draft builder"))
+ }
+
+ // Execute the POST build pipeline on the parent
+ status := Pipeline(step.SubSteps).Get(factory, &draftBuilder, buffer)
+ status.Error = derp.Wrap(status.Error, location, "Error executing steps on draft")
+
+ return UseResult(status)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepWithDraft) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ const location = "build.StepWithDraft.Post"
+
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
+ draftBuilder, err := streamBuilder.draftBuilder()
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error getting draft builder"))
+ }
+
+ // Execute the POST build pipeline on the parent
+ result := Pipeline(step.SubSteps).Post(factory, &draftBuilder, buffer)
+ result.Error = derp.Wrap(result.Error, location, "Error executing steps on draft")
+
+ return UseResult(result)
+}
diff --git a/render/step_WithFolder.go b/build/step_WithFolder.go
similarity index 51%
rename from render/step_WithFolder.go
rename to build/step_WithFolder.go
index 579e25992..09e2a9b22 100644
--- a/render/step_WithFolder.go
+++ b/build/step_WithFolder.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,33 +13,33 @@ type StepWithFolder struct {
SubSteps []step.Step
}
-func (step StepWithFolder) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithFolder) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepWithFolder) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithFolder) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithFolder) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithFolder) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithFolder.execute"
+ const location = "build.StepWithFolder.execute"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
folderService := factory.Folder()
- folderToken := renderer.QueryParam("folderId")
+ folderToken := builder.QueryParam("folderId")
folder := model.NewFolder()
- folder.UserID = renderer.AuthenticatedID()
+ folder.UserID = builder.AuthenticatedID()
// If we have a real ID, then try to load the folder from the database
if (folderToken != "") && (folderToken != "new") {
- if err := folderService.LoadByToken(renderer.AuthenticatedID(), folderToken, &folder); err != nil {
+ if err := folderService.LoadByToken(builder.AuthenticatedID(), folderToken, &folder); err != nil {
if actionMethod == ActionMethodGet {
return Halt().WithError(derp.Wrap(err, location, "Unable to load Folder", folderToken))
}
@@ -47,15 +47,15 @@ func (step StepWithFolder) execute(renderer Renderer, buffer io.Writer, actionMe
}
}
- // Create a new renderer tied to the Folder record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &folder, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Folder record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &folder, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the POST render pipeline on the child
- result := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the POST build pipeline on the child
+ result := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
result.Error = derp.Wrap(result.Error, location, "Error executing steps for child")
return UseResult(result)
diff --git a/render/step_WithFollower.go b/build/step_WithFollower.go
similarity index 50%
rename from render/step_WithFollower.go
rename to build/step_WithFollower.go
index 6feba266b..736cb1293 100644
--- a/render/step_WithFollower.go
+++ b/build/step_WithFollower.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,48 +13,48 @@ type StepWithFollower struct {
SubSteps []step.Step
}
-func (step StepWithFollower) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithFollower) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepWithFollower) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithFollower) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithFollower) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithFollower) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithFollower.execute"
+ const location = "build.StepWithFollower.execute"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
followerService := factory.Follower()
- followerToken := renderer.QueryParam("followerId")
+ followerToken := builder.QueryParam("followerId")
follower := model.NewFollower()
- follower.ParentID = renderer.AuthenticatedID()
+ follower.ParentID = builder.AuthenticatedID()
// Try to load the Follower record (unless we're creating a NEW record)
if (followerToken != "") && (followerToken != "new") {
- if err := followerService.LoadByToken(renderer.AuthenticatedID(), followerToken, &follower); err != nil {
+ if err := followerService.LoadByToken(builder.AuthenticatedID(), followerToken, &follower); err != nil {
if actionMethod == ActionMethodGet {
return Halt().WithError(derp.Wrap(err, location, "Unable to load Follower via ID", followerToken))
}
}
}
- // Create a new renderer tied to the Follower record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &follower, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Follower record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &follower, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the render pipeline on the Follower record
- result := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the build pipeline on the Follower record
+ result := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
result.Error = derp.Wrap(result.Error, location, "Error executing steps for child")
return UseResult(result)
diff --git a/render/step_WithFollowing.go b/build/step_WithFollowing.go
similarity index 52%
rename from render/step_WithFollowing.go
rename to build/step_WithFollowing.go
index a5e516d07..4c35c952a 100644
--- a/render/step_WithFollowing.go
+++ b/build/step_WithFollowing.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,33 +13,33 @@ type StepWithFollowing struct {
SubSteps []step.Step
}
-func (step StepWithFollowing) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithFollowing) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepWithFollowing) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithFollowing) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithFollowing) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithFollowing) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithFollowing.execute"
+ const location = "build.StepWithFollowing.execute"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
followingService := factory.Following()
- token := renderer.QueryParam("followingId")
+ token := builder.QueryParam("followingId")
following := model.NewFollowing()
- following.UserID = renderer.AuthenticatedID()
+ following.UserID = builder.AuthenticatedID()
// If we have a real ID, then try to load the following from the database
if (token != "") && (token != "new") {
- if err := followingService.LoadByToken(renderer.AuthenticatedID(), token, &following); err != nil {
+ if err := followingService.LoadByToken(builder.AuthenticatedID(), token, &following); err != nil {
if actionMethod == ActionMethodGet {
return Halt().WithError(derp.Wrap(err, location, "Unable to load Following", token))
}
@@ -47,15 +47,15 @@ func (step StepWithFollowing) execute(renderer Renderer, buffer io.Writer, actio
}
}
- // Create a new renderer tied to the Following record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &following, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Following record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &following, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the POST render pipeline on the child
- result := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the POST build pipeline on the child
+ result := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
if result.Error != nil {
return Halt().WithError(derp.Wrap(result.Error, location, "Error executing steps for child"))
diff --git a/render/step_WithMessage.go b/build/step_WithMessage.go
similarity index 56%
rename from render/step_WithMessage.go
rename to build/step_WithMessage.go
index 7c27b5467..3104dc7c2 100644
--- a/render/step_WithMessage.go
+++ b/build/step_WithMessage.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -14,50 +14,50 @@ type StepWithMessage struct {
SubSteps []step.Step
}
-func (step StepWithMessage) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithMessage) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the message with data from the request body.
-func (step StepWithMessage) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithMessage) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithMessage) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithMessage) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithMessage.execute"
+ const location = "build.StepWithMessage.execute"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Parse the MessageID from the query string
- messageID, err := primitive.ObjectIDFromHex(renderer.QueryParam("messageId"))
+ messageID, err := primitive.ObjectIDFromHex(builder.QueryParam("messageId"))
if err != nil {
return Halt().WithError(derp.Wrap(err, location, "MessageID must be a valid hex string"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
inboxService := factory.Inbox()
message := model.NewMessage()
- userID := renderer.AuthenticatedID()
+ userID := builder.AuthenticatedID()
// If we have a real ID, then try to load the message from the database
if err := inboxService.LoadByID(userID, messageID, &message); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Unable to load Message", messageID))
}
- // Create a new renderer tied to the Message record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &message, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Message record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &message, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the POST render pipeline on the child
- result := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the POST build pipeline on the child
+ result := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
result.Error = derp.Wrap(result.Error, location, "Error executing steps for child")
return UseResult(result)
diff --git a/build/step_WithNextSibling.go b/build/step_WithNextSibling.go
new file mode 100644
index 000000000..f72486a80
--- /dev/null
+++ b/build/step_WithNextSibling.go
@@ -0,0 +1,53 @@
+package build
+
+import (
+ "io"
+
+ "github.com/EmissarySocial/emissary/model"
+ "github.com/EmissarySocial/emissary/model/step"
+ "github.com/benpate/derp"
+)
+
+// StepWithNextSibling represents an action-step that can update the data.DataMap custom data stored in a Stream
+type StepWithNextSibling struct {
+ SubSteps []step.Step
+}
+
+func (step StepWithNextSibling) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
+}
+
+// Post executes the subSteps on the parent Stream
+func (step StepWithNextSibling) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
+}
+
+// Post executes the subSteps on the parent Stream
+func (step StepWithNextSibling) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+
+ const location = "build.StepWithNextSibling.Post"
+
+ var sibling model.Stream
+
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
+ stream := streamBuilder._stream
+
+ if err := factory.Stream().LoadNextSibling(stream.ParentID, stream.Rank, &sibling); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error listing parent"))
+ }
+
+ // Make a builder with the new parent stream
+ // TODO: LOW: Is "view" really the best action to use here??
+ siblingBuilder, err := NewStreamWithoutTemplate(streamBuilder.factory(), streamBuilder.request(), streamBuilder.response(), &sibling, "view")
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error creating builder for sibling"))
+ }
+
+ // execute the POST build pipeline on the parent
+ result := Pipeline(step.SubSteps).Execute(factory, &siblingBuilder, buffer, actionMethod)
+ result.Error = derp.Wrap(result.Error, location, "Error executing steps for parent")
+
+ return UseResult(result)
+}
diff --git a/render/step_WithParent.go b/build/step_WithParent.go
similarity index 55%
rename from render/step_WithParent.go
rename to build/step_WithParent.go
index 1f2aa5ee3..512ce6503 100644
--- a/render/step_WithParent.go
+++ b/build/step_WithParent.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,33 +13,33 @@ type StepWithParent struct {
SubSteps []step.Step
}
-func (step StepWithParent) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepWithParent) Get(builder Builder, buffer io.Writer) PipelineBehavior {
return nil
}
// Post executes the subSteps on the parent Stream
-func (step StepWithParent) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
+func (step StepWithParent) Post(builder Builder, buffer io.Writer) PipelineBehavior {
- const location = "render.StepWithParent.Post"
+ const location = "build.StepWithParent.Post"
var parent model.Stream
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
- if err := factory.Stream().LoadByID(streamRenderer._stream.ParentID, &parent); err != nil {
+ if err := factory.Stream().LoadByID(streamBuilder._stream.ParentID, &parent); err != nil {
return Halt().WithError(derp.Wrap(err, location, "Error listing parent"))
}
- // Make a renderer with the new parent stream
+ // Make a builder with the new parent stream
// TODO: LOW: Is "view" really the best action to use here??
- parentStream, err := NewStreamWithoutTemplate(streamRenderer.factory(), streamRenderer.request(), streamRenderer.response(), &parent, "")
+ parentStream, err := NewStreamWithoutTemplate(streamBuilder.factory(), streamBuilder.request(), streamBuilder.response(), &parent, "")
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating renderer for parent"))
+ return Halt().WithError(derp.Wrap(err, location, "Error creating builder for parent"))
}
- // Execute the POST render pipeline on the parent
+ // Execute the POST build pipeline on the parent
result := Pipeline(step.SubSteps).Post(factory, &parentStream, buffer)
result.Error = derp.Wrap(result.Error, location, "Error executing steps for parent")
return UseResult(result)
diff --git a/build/step_WithPrevSibling.go b/build/step_WithPrevSibling.go
new file mode 100644
index 000000000..3e134bf10
--- /dev/null
+++ b/build/step_WithPrevSibling.go
@@ -0,0 +1,52 @@
+package build
+
+import (
+ "io"
+
+ "github.com/EmissarySocial/emissary/model"
+ "github.com/EmissarySocial/emissary/model/step"
+ "github.com/benpate/derp"
+)
+
+// StepWithPrevSibling represents an action-step that can update the data.DataMap custom data stored in a Stream
+type StepWithPrevSibling struct {
+ SubSteps []step.Step
+}
+
+func (step StepWithPrevSibling) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
+}
+
+// Post executes the subSteps on the parent Stream
+func (step StepWithPrevSibling) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
+}
+
+// Post executes the subSteps on the parent Stream
+func (step StepWithPrevSibling) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+
+ const location = "build.StepWithPrevSibling.execute"
+
+ var sibling model.Stream
+
+ factory := builder.factory()
+ streamBuilder := builder.(*Stream)
+ stream := streamBuilder._stream
+
+ if err := factory.Stream().LoadPrevSibling(stream.ParentID, stream.Rank, &sibling); err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error listing parent"))
+ }
+
+ // Make a builder with the new parent stream
+ // TODO: Is "view" really the best action to use here??
+ siblingBuilder, err := NewStreamWithoutTemplate(streamBuilder.factory(), streamBuilder.request(), streamBuilder.response(), &sibling, "view")
+
+ if err != nil {
+ return Halt().WithError(derp.Wrap(err, location, "Error creating builder for sibling"))
+ }
+
+ // Execute the POST build pipeline on the parent
+ result := Pipeline(step.SubSteps).Execute(factory, &siblingBuilder, buffer, actionMethod)
+ result.Error = derp.Wrap(result.Error, location, "Error executing steps for parent")
+ return UseResult(result)
+}
diff --git a/render/step_WithResponse.go b/build/step_WithResponse.go
similarity index 59%
rename from render/step_WithResponse.go
rename to build/step_WithResponse.go
index f09e4a3bb..5b85acac9 100644
--- a/render/step_WithResponse.go
+++ b/build/step_WithResponse.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -14,27 +14,27 @@ type StepWithResponse struct {
SubSteps []step.Step
}
-func (step StepWithResponse) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithResponse) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepWithResponse) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithResponse) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithResponse) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithResponse) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithResponse.doStep"
+ const location = "build.StepWithResponse.doStep"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
responseService := factory.Response()
- responseToken := renderer.QueryParam("responseId")
+ responseToken := builder.QueryParam("responseId")
response := model.NewResponse()
// If we have a real ID, then try to load the response from the database
@@ -49,15 +49,15 @@ func (step StepWithResponse) execute(renderer Renderer, buffer io.Writer, action
}
}
- // Create a new renderer tied to the Response record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &response, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Response record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &response, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the POST render pipeline on the child
- result := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the POST build pipeline on the child
+ result := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
result.Error = derp.Wrap(result.Error, location, "Error executing steps for child")
return UseResult(result)
diff --git a/render/step_WithRule.go b/build/step_WithRule.go
similarity index 50%
rename from render/step_WithRule.go
rename to build/step_WithRule.go
index 9831e8f93..66f28765d 100644
--- a/render/step_WithRule.go
+++ b/build/step_WithRule.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"io"
@@ -13,32 +13,32 @@ type StepWithRule struct {
SubSteps []step.Step
}
-func (step StepWithRule) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
+func (step StepWithRule) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodGet)
}
// Post updates the stream with approved data from the request body.
-func (step StepWithRule) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
+func (step StepWithRule) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+ return step.execute(builder, buffer, ActionMethodPost)
}
-func (step StepWithRule) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
+func (step StepWithRule) execute(builder Builder, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
- const location = "render.StepWithRule.doStep"
+ const location = "build.StepWithRule.doStep"
- if !renderer.IsAuthenticated() {
+ if !builder.IsAuthenticated() {
return Halt().WithError(derp.NewUnauthorizedError(location, "Anonymous user is not authorized to perform this action"))
}
// Collect required services and values
- factory := renderer.factory()
+ factory := builder.factory()
ruleService := factory.Rule()
- ruleToken := renderer.QueryParam("ruleId")
+ ruleToken := builder.QueryParam("ruleId")
rule := model.NewRule()
- rule.UserID = renderer.AuthenticatedID()
+ rule.UserID = builder.AuthenticatedID()
if (ruleToken != "") && (ruleToken != "new") {
- if err := ruleService.LoadByToken(renderer.AuthenticatedID(), ruleToken, &rule); err != nil {
+ if err := ruleService.LoadByToken(builder.AuthenticatedID(), ruleToken, &rule); err != nil {
if actionMethod == ActionMethodGet {
return Halt().WithError(derp.Wrap(err, location, "Unable to load Rule", ruleToken))
}
@@ -46,15 +46,15 @@ func (step StepWithRule) execute(renderer Renderer, buffer io.Writer, actionMeth
}
}
- // Create a new renderer tied to the Rule record
- subRenderer, err := NewModel(factory, renderer.request(), renderer.response(), &rule, renderer.template(), renderer.ActionID())
+ // Create a new builder tied to the Rule record
+ subBuilder, err := NewModel(factory, builder.request(), builder.response(), &rule, builder.template(), builder.ActionID())
if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-renderer"))
+ return Halt().WithError(derp.Wrap(err, location, "Unable to create sub-builder"))
}
- // Execute the POST render pipeline on the child
- reesult := Pipeline(step.SubSteps).Execute(factory, subRenderer, buffer, actionMethod)
+ // Execute the POST build pipeline on the child
+ reesult := Pipeline(step.SubSteps).Execute(factory, subBuilder, buffer, actionMethod)
reesult.Error = derp.Wrap(reesult.Error, location, "Error executing steps for child")
return UseResult(reesult)
diff --git a/build/step_do.go b/build/step_do.go
new file mode 100644
index 000000000..2fae58e95
--- /dev/null
+++ b/build/step_do.go
@@ -0,0 +1,41 @@
+package build
+
+import (
+ "io"
+
+ "github.com/benpate/derp"
+)
+
+// StepDo represents an action-step that sends an HTMX 'forward' to a new page.
+type StepDo struct {
+ Action string
+}
+
+func (step StepDo) Get(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ const location = "build.StepDo.Get"
+
+ action, ok := builder.template().Actions[step.Action]
+
+ if !ok {
+ return Halt().WithError(derp.NewBadRequestError(location, "Action not found", step.Action))
+ }
+
+ result := Pipeline(action.Steps).Get(builder.factory(), builder, buffer)
+ return UseResult(result)
+}
+
+// Post updates the stream with approved data from the request body.
+func (step StepDo) Post(builder Builder, buffer io.Writer) PipelineBehavior {
+
+ const location = "build.StepDo.Post"
+
+ action, ok := builder.template().Actions[step.Action]
+
+ if !ok {
+ return Halt().WithError(derp.NewBadRequestError(location, "Action not found", step.Action))
+ }
+
+ result := Pipeline(action.Steps).Post(builder.factory(), builder, buffer)
+ return UseResult(result)
+}
diff --git a/render/urlvalues_test.go b/build/urlvalues_test.go
similarity index 98%
rename from render/urlvalues_test.go
rename to build/urlvalues_test.go
index 3206cdb7c..60fbdf373 100644
--- a/render/urlvalues_test.go
+++ b/build/urlvalues_test.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
diff --git a/render/utilities.go b/build/utilities.go
similarity index 95%
rename from render/utilities.go
rename to build/utilities.go
index 5784ee3d2..7d478a168 100644
--- a/render/utilities.go
+++ b/build/utilities.go
@@ -1,4 +1,4 @@
-package render
+package build
import (
"bytes"
@@ -26,7 +26,7 @@ func WrapInlineSuccess(response http.ResponseWriter, message any) error {
response.WriteHeader(http.StatusOK)
_, err := response.Write([]byte(`
` + convert.String(message) + ``))
- return derp.Wrap(err, "render.WrapInlineSuccess", "Error writing response", message)
+ return derp.Wrap(err, "build.WrapInlineSuccess", "Error writing response", message)
}
// WrapInlineError sends an error message to the #htmx-response-message element
@@ -39,7 +39,7 @@ func WrapInlineError(response http.ResponseWriter, err error) error {
response.WriteHeader(http.StatusOK)
if _, writeError := response.Write([]byte(`
` + derp.Message(err) + ``)); writeError != nil {
- return derp.Wrap(writeError, "render.WrapInlineError", "Error writing response", err)
+ return derp.Wrap(writeError, "build.WrapInlineError", "Error writing response", err)
}
return nil
@@ -215,7 +215,7 @@ func executeTemplate(template TemplateLike, data any) string {
var buffer bytes.Buffer
if err := template.Execute(&buffer, data); err != nil {
- derp.Report(derp.Wrap(err, "render.executeTemplate", "Error executing template", data))
+ derp.Report(derp.Wrap(err, "build.executeTemplate", "Error executing template", data))
return ""
}
@@ -263,7 +263,7 @@ func bindBody(request *http.Request, result any) error {
func multipartForm(request *http.Request) (*multipart.Form, error) {
if err := request.ParseMultipartForm(32 << 20); err != nil {
- return nil, derp.Wrap(err, "render.multipartForm", "Error parsing multipart form")
+ return nil, derp.Wrap(err, "build.multipartForm", "Error parsing multipart form")
}
return request.MultipartForm, nil
diff --git a/domain/factory.go b/domain/factory.go
index 2ac3222eb..8d2421fbb 100644
--- a/domain/factory.go
+++ b/domain/factory.go
@@ -4,9 +4,9 @@ import (
"context"
"strings"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/config"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/service"
"github.com/EmissarySocial/emissary/tools/set"
"github.com/benpate/data"
@@ -197,7 +197,7 @@ func (factory *Factory) Refresh(domain config.Domain, providers []config.Provide
factory.Theme(),
factory.User(),
factory.Provider(),
- render.FuncMap(factory.Icons()),
+ build.FuncMap(factory.Icons()),
)
// Populate EncryptionKey Service
diff --git a/handler/activitypub_user/profile.go b/handler/activitypub_user/profile.go
index 0cfcc50d8..f81a373ab 100644
--- a/handler/activitypub_user/profile.go
+++ b/handler/activitypub_user/profile.go
@@ -13,7 +13,7 @@ import (
func RenderProfileJSONLD(context echo.Context, factory *domain.Factory, user *model.User) error {
- const location = "handler.activitypub.renderProfileJSONLD"
+ const location = "handler.activitypub.buildProfileJSONLD"
// Try to load the key from the Datbase
keyService := factory.EncryptionKey()
diff --git a/handler/admin.go b/handler/admin.go
index a415a324e..e0bfad063 100644
--- a/handler/admin.go
+++ b/handler/admin.go
@@ -1,9 +1,9 @@
package handler
import (
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/domain"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/rosetta/first"
@@ -14,17 +14,17 @@ import (
// GetAdmin handles GET requests
func GetAdmin(factoryManager *server.Factory) echo.HandlerFunc {
- return renderAdmin(factoryManager, render.ActionMethodGet)
+ return buildAdmin(factoryManager, build.ActionMethodGet)
}
// PostAdmin handles POST/DELETE requests
func PostAdmin(factoryManager *server.Factory) echo.HandlerFunc {
- return renderAdmin(factoryManager, render.ActionMethodPost)
+ return buildAdmin(factoryManager, build.ActionMethodPost)
}
-func renderAdmin(factoryManager *server.Factory, actionMethod render.ActionMethod) echo.HandlerFunc {
+func buildAdmin(factoryManager *server.Factory, actionMethod build.ActionMethod) echo.HandlerFunc {
- const location = "handler.adminRenderer"
+ const location = "handler.adminBuilder"
return func(ctx echo.Context) error {
@@ -43,7 +43,7 @@ func renderAdmin(factoryManager *server.Factory, actionMethod render.ActionMetho
}
// Parse admin parameters
- templateID, actionID, objectID := renderAdmin_ParsePath(ctx)
+ templateID, actionID, objectID := buildAdmin_ParsePath(ctx)
// Try to load the Template
templateService := factory.Template()
@@ -53,19 +53,19 @@ func renderAdmin(factoryManager *server.Factory, actionMethod render.ActionMetho
return err
}
- // Locate and populate the renderer
- renderer, err := renderAdmin_GetRenderer(factory, sterankoContext, template, actionID, objectID)
+ // Locate and populate the builder
+ builder, err := buildAdmin_GetBuilder(factory, sterankoContext, template, actionID, objectID)
if err != nil {
- return derp.Wrap(err, location, "Error generating renderer")
+ return derp.Wrap(err, location, "Error generating builder")
}
// Success!!
- return renderHTML(factory, sterankoContext, renderer, actionMethod)
+ return buildHTML(factory, sterankoContext, builder, actionMethod)
}
}
-func renderAdmin_ParsePath(ctx echo.Context) (string, string, primitive.ObjectID) {
+func buildAdmin_ParsePath(ctx echo.Context) (string, string, primitive.ObjectID) {
// First parameter is always the templateID
templateID := first.String(ctx.Param("param1"), "domain")
@@ -82,11 +82,11 @@ func renderAdmin_ParsePath(ctx echo.Context) (string, string, primitive.ObjectID
return templateID, actionID, primitive.NilObjectID
}
-func renderAdmin_GetRenderer(factory *domain.Factory, ctx *steranko.Context, template model.Template, actionID string, objectID primitive.ObjectID) (render.Renderer, error) {
+func buildAdmin_GetBuilder(factory *domain.Factory, ctx *steranko.Context, template model.Template, actionID string, objectID primitive.ObjectID) (build.Builder, error) {
- const location = "handler.renderAdmin_GetRenderer"
+ const location = "handler.buildAdmin_GetBuilder"
- // Create the correct renderer for this controller
+ // Create the correct builder for this controller
switch template.Model {
case "rule":
@@ -101,10 +101,10 @@ func renderAdmin_GetRenderer(factory *domain.Factory, ctx *steranko.Context, tem
}
}
- return render.NewRule(factory, ctx.Request(), ctx.Response(), &rule, template, actionID)
+ return build.NewRule(factory, ctx.Request(), ctx.Response(), &rule, template, actionID)
case "domain":
- return render.NewDomain(factory, ctx.Request(), ctx.Response(), template, actionID)
+ return build.NewDomain(factory, ctx.Request(), ctx.Response(), template, actionID)
case "group":
group := model.NewGroup()
@@ -116,7 +116,7 @@ func renderAdmin_GetRenderer(factory *domain.Factory, ctx *steranko.Context, tem
}
}
- return render.NewGroup(factory, ctx.Request(), ctx.Response(), template, &group, actionID)
+ return build.NewGroup(factory, ctx.Request(), ctx.Response(), template, &group, actionID)
case "stream":
stream := model.NewStream()
@@ -128,7 +128,7 @@ func renderAdmin_GetRenderer(factory *domain.Factory, ctx *steranko.Context, tem
}
}
- return render.NewNavigation(factory, ctx.Request(), ctx.Response(), template, &stream, actionID)
+ return build.NewNavigation(factory, ctx.Request(), ctx.Response(), template, &stream, actionID)
case "user":
user := model.NewUser()
@@ -140,7 +140,7 @@ func renderAdmin_GetRenderer(factory *domain.Factory, ctx *steranko.Context, tem
}
}
- return render.NewUser(factory, ctx.Request(), ctx.Response(), template, &user, actionID)
+ return build.NewUser(factory, ctx.Request(), ctx.Response(), template, &user, actionID)
default:
return nil, derp.NewNotFoundError(location, "Template MODEL must be one of: 'rule', 'domain', 'group', 'stream', or 'user'", template.Model)
diff --git a/handler/attachment.go b/handler/attachment.go
index e0f7af1dc..50dfbce00 100644
--- a/handler/attachment.go
+++ b/handler/attachment.go
@@ -3,8 +3,8 @@ package handler
import (
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/rosetta/list"
@@ -61,8 +61,8 @@ func GetAttachment(factoryManager *server.Factory) echo.HandlerFunc {
}
// Try to find the action requested by the user. This also enforces user permissions...
- if _, err := render.NewStreamWithoutTemplate(factory, ctx.Request(), ctx.Response(), &stream, "view"); err != nil {
- return derp.Wrap(err, location, "Cannot create renderer")
+ if _, err := build.NewStreamWithoutTemplate(factory, ctx.Request(), ctx.Response(), &stream, "view"); err != nil {
+ return derp.Wrap(err, location, "Cannot create builder")
}
// Retrieve the file from the mediaserver
diff --git a/handler/html.go b/handler/html.go
index 9a1165436..6b8a35229 100644
--- a/handler/html.go
+++ b/handler/html.go
@@ -4,22 +4,22 @@ import (
"bytes"
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/domain"
- "github.com/EmissarySocial/emissary/render"
"github.com/benpate/derp"
"github.com/labstack/echo/v4"
)
-// renderHTML collects the logic to render complete vs. partial HTML pages.
-func renderHTML(factory *domain.Factory, ctx echo.Context, renderer render.Renderer, actionMethod render.ActionMethod) error {
+// buildHTML collects the logic to build complete vs. partial HTML pages.
+func buildHTML(factory *domain.Factory, ctx echo.Context, builder build.Builder, actionMethod build.ActionMethod) error {
- const location = "handler.renderHTML"
+ const location = "handler.buildHTML"
var partialPage bytes.Buffer
// Execute the action pipeline
- pipeline := render.Pipeline(renderer.Action().Steps)
+ pipeline := build.Pipeline(builder.Action().Steps)
- status := pipeline.Execute(factory, renderer, &partialPage, actionMethod)
+ status := pipeline.Execute(factory, builder, &partialPage, actionMethod)
if status.Error != nil {
return derp.Wrap(status.Error, location, "Error executing action pipeline")
@@ -29,17 +29,17 @@ func renderHTML(factory *domain.Factory, ctx echo.Context, renderer render.Rende
status.Apply(ctx.Response())
// Partial page requests can be completed here.
- if renderer.IsPartialRequest() || status.FullPage {
+ if builder.IsPartialRequest() || status.FullPage {
return ctx.HTML(status.GetStatusCode(), partialPage.String())
}
- // Full Page requests require the theme service to wrap the rendered content
+ // Full Page requests require the theme service to wrap the builded content
htmlTemplate := factory.Domain().Theme().HTMLTemplate
- renderer.SetContent(partialPage.String())
+ builder.SetContent(partialPage.String())
var fullPage bytes.Buffer
- if err := htmlTemplate.ExecuteTemplate(&fullPage, "page", renderer); err != nil {
- return derp.Wrap(err, location, "Error rendering full-page content")
+ if err := htmlTemplate.ExecuteTemplate(&fullPage, "page", builder); err != nil {
+ return derp.Wrap(err, location, "Error building full-page content")
}
return ctx.HTML(http.StatusOK, fullPage.String())
diff --git a/handler/inbox.go b/handler/inbox.go
index 46daed832..e2a1d7872 100644
--- a/handler/inbox.go
+++ b/handler/inbox.go
@@ -1,8 +1,8 @@
package handler
import (
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/rosetta/first"
@@ -12,18 +12,18 @@ import (
// GetInbox handles GET requests
func GetInbox(serverFactory *server.Factory) echo.HandlerFunc {
- return renderInbox(serverFactory, render.ActionMethodGet)
+ return buildInbox(serverFactory, build.ActionMethodGet)
}
// PostInbox handles POST/DELETE requests
func PostInbox(serverFactory *server.Factory) echo.HandlerFunc {
- return renderInbox(serverFactory, render.ActionMethodPost)
+ return buildInbox(serverFactory, build.ActionMethodPost)
}
-// renderInbox is the common Inbox handler for both GET and POST requests
-func renderInbox(serverFactory *server.Factory, actionMethod render.ActionMethod) echo.HandlerFunc {
+// buildInbox is the common Inbox handler for both GET and POST requests
+func buildInbox(serverFactory *server.Factory, actionMethod build.ActionMethod) echo.HandlerFunc {
- const location = "handler.renderInbox"
+ const location = "handler.buildInbox"
return func(context echo.Context) error {
@@ -55,16 +55,16 @@ func renderInbox(serverFactory *server.Factory, actionMethod render.ActionMethod
actionID := first.String(context.Param("action"), "inbox")
if ok, err := handleJSONLD(context, &user); ok {
- return derp.Wrap(err, location, "Error rendering JSON-LD")
+ return derp.Wrap(err, location, "Error building JSON-LD")
}
- renderer, err := render.NewInbox(factory, context.Request(), context.Response(), &user, actionID)
+ builder, err := build.NewInbox(factory, context.Request(), context.Response(), &user, actionID)
if err != nil {
- return derp.Wrap(err, location, "Error creating renderer")
+ return derp.Wrap(err, location, "Error creating builder")
}
- // Forward to the standard page renderer to complete the job
- return renderHTML(factory, sterankoContext, renderer, actionMethod)
+ // Forward to the standard page builder to complete the job
+ return buildHTML(factory, sterankoContext, builder, actionMethod)
}
}
diff --git a/handler/oauth-server.go b/handler/oauth-server.go
index 621155dd8..a1a109bb6 100644
--- a/handler/oauth-server.go
+++ b/handler/oauth-server.go
@@ -4,8 +4,8 @@ import (
"net/http"
"net/url"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/EmissarySocial/emissary/service"
"github.com/benpate/derp"
@@ -35,17 +35,17 @@ func GetOAuthAuthorization(serverFactory *server.Factory) echo.HandlerFunc {
return derp.NewInternalError(location, "Invalid Domain.")
}
- // Load the OAuth Renderer
- renderer, err := render.NewOAuthAuthorization(factory, transaction)
+ // Load the OAuth Builder
+ builder, err := build.NewOAuthAuthorization(factory, transaction)
if err != nil {
- return derp.Wrap(err, location, "Error Generating Renderer")
+ return derp.Wrap(err, location, "Error Generating Builder")
}
// Render the template
template := factory.Domain().Theme().HTMLTemplate
- if err := template.ExecuteTemplate(ctx.Response(), "oauth", renderer); err != nil {
+ if err := template.ExecuteTemplate(ctx.Response(), "oauth", builder); err != nil {
return derp.Wrap(err, location, "Error executing template")
}
diff --git a/handler/outbox.go b/handler/outbox.go
index dcecd4260..11d7549fe 100644
--- a/handler/outbox.go
+++ b/handler/outbox.go
@@ -3,9 +3,9 @@ package handler
import (
"net/http"
+ "github.com/EmissarySocial/emissary/build"
activitypub "github.com/EmissarySocial/emissary/handler/activitypub_user"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/mediaserver"
@@ -17,12 +17,12 @@ import (
// GetOutbox handles GET requests
func GetOutbox(serverFactory *server.Factory) echo.HandlerFunc {
- return renderOutbox(serverFactory, render.ActionMethodGet)
+ return buildOutbox(serverFactory, build.ActionMethodGet)
}
// PostOutbox handles POST/DELETE requests
func PostOutbox(serverFactory *server.Factory) echo.HandlerFunc {
- return renderOutbox(serverFactory, render.ActionMethodPost)
+ return buildOutbox(serverFactory, build.ActionMethodPost)
}
func GetProfileAvatar(serverFactory *server.Factory) echo.HandlerFunc {
@@ -89,10 +89,10 @@ func GetProfileAvatar(serverFactory *server.Factory) echo.HandlerFunc {
}
}
-// renderOutbox is the common Outbox handler for both GET and POST requests
-func renderOutbox(serverFactory *server.Factory, actionMethod render.ActionMethod) echo.HandlerFunc {
+// buildOutbox is the common Outbox handler for both GET and POST requests
+func buildOutbox(serverFactory *server.Factory, actionMethod build.ActionMethod) echo.HandlerFunc {
- const location = "handler.renderOutbox"
+ const location = "handler.buildOutbox"
return func(context echo.Context) error {
@@ -122,7 +122,7 @@ func renderOutbox(serverFactory *server.Factory, actionMethod render.ActionMetho
}
if !isUserVisible(sterankoContext, &user) {
- return derp.NewNotFoundError("handler.renderOutbox", "User not found")
+ return derp.NewNotFoundError("handler.buildOutbox", "User not found")
}
if isJSONLDRequest(sterankoContext) {
@@ -133,17 +133,17 @@ func renderOutbox(serverFactory *server.Factory, actionMethod render.ActionMetho
actionID := first.String(context.Param("action"), "view")
if ok, err := handleJSONLD(context, &user); ok {
- return derp.Wrap(err, location, "Error rendering JSON-LD")
+ return derp.Wrap(err, location, "Error building JSON-LD")
}
- renderer, err := render.NewOutbox(factory, context.Request(), context.Response(), &user, actionID)
+ builder, err := build.NewOutbox(factory, context.Request(), context.Response(), &user, actionID)
if err != nil {
- return derp.Wrap(err, location, "Error creating renderer")
+ return derp.Wrap(err, location, "Error creating builder")
}
- // Forward to the standard page renderer to complete the job
- return renderHTML(factory, sterankoContext, renderer, actionMethod)
+ // Forward to the standard page builder to complete the job
+ return buildHTML(factory, sterankoContext, builder, actionMethod)
}
}
diff --git a/handler/qrcode.go b/handler/qrcode.go
index 3303c180d..be97744cf 100644
--- a/handler/qrcode.go
+++ b/handler/qrcode.go
@@ -14,7 +14,7 @@ import (
type StepQRCode struct {
}
-// Get renders the Stream HTML to the context
+// Get builds the Stream HTML to the context
func GetQRCode(fm *server.Factory) echo.HandlerFunc {
return func(ctx echo.Context) error {
@@ -32,14 +32,14 @@ func GetQRCode(fm *server.Factory) echo.HandlerFunc {
qrc, err := qrcode.New(url)
if err != nil {
- return derp.Wrap(err, "render.StepQRCode.Get", "Error generating QR Code")
+ return derp.Wrap(err, "build.StepQRCode.Get", "Error generating QR Code")
}
w := standard.NewWithWriter(AsWriteCloser{ctx.Response().Writer})
// "save" file to the writer
if err := qrc.Save(w); err != nil {
- return derp.Wrap(err, "render.StepQRCode.Get", "Error writing image")
+ return derp.Wrap(err, "build.StepQRCode.Get", "Error writing image")
}
return nil
diff --git a/handler/setup_domain.go b/handler/setup_domain.go
index 76e45b521..357ab19e1 100644
--- a/handler/setup_domain.go
+++ b/handler/setup_domain.go
@@ -4,9 +4,9 @@ import (
_ "embed"
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/config"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/form"
@@ -45,7 +45,7 @@ func SetupDomainGet(factory *server.Factory) echo.HandlerFunc {
return derp.Wrap(err, "handler.SetupDomainGet", "Error generating form")
}
- result := render.WrapModalForm(ctx.Response(), "/domains/"+domain.DomainID, formHTML)
+ result := build.WrapModalForm(ctx.Response(), "/domains/"+domain.DomainID, formHTML)
return ctx.HTML(200, result)
}
@@ -64,24 +64,24 @@ func SetupDomainPost(factory *server.Factory) echo.HandlerFunc {
input := mapof.Any{}
if err := (&echo.DefaultBinder{}).BindBody(ctx, &input); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error binding form input"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error binding form input"))
}
s := schema.New(config.DomainSchema())
if err := s.SetAll(&domain, input); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error setting config values"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error setting config values"))
}
if err := s.Validate(&domain); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error validating config values"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error validating config values"))
}
if err := factory.PutDomain(domain); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error saving domain"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "handler.SetupDomainPost", "Error saving domain"))
}
- render.CloseModal(ctx)
+ build.CloseModal(ctx)
return ctx.NoContent(http.StatusOK)
}
}
@@ -99,7 +99,7 @@ func SetupDomainDelete(factory *server.Factory) echo.HandlerFunc {
}
// Close the modal and return OK
- render.RefreshPage(ctx)
+ build.RefreshPage(ctx)
return ctx.NoContent(http.StatusOK)
}
}
diff --git a/handler/setup_oauth.go b/handler/setup_oauth.go
index fb737c156..6280f8cb2 100644
--- a/handler/setup_oauth.go
+++ b/handler/setup_oauth.go
@@ -4,8 +4,8 @@ import (
"html/template"
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/config"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/EmissarySocial/emissary/tools/dataset"
"github.com/EmissarySocial/emissary/tools/set"
@@ -51,7 +51,7 @@ func SetupOAuthGet(factory *server.Factory, templates *template.Template) echo.H
}
// Wrap the form in a modal dialog
- result := render.WrapModalForm(ctx.Response(), "/oauth/"+oAuthProviderID, formHTML)
+ result := build.WrapModalForm(ctx.Response(), "/oauth/"+oAuthProviderID, formHTML)
return ctx.HTML(200, result)
}
@@ -104,7 +104,7 @@ func SetupOAuthPost(factory *server.Factory, templates *template.Template) echo.
}
// Success!
- render.CloseModal(ctx)
+ build.CloseModal(ctx)
return ctx.NoContent(http.StatusOK)
}
}
diff --git a/handler/setup_server.go b/handler/setup_server.go
index 2a77a2ff0..5c9a5b441 100644
--- a/handler/setup_server.go
+++ b/handler/setup_server.go
@@ -6,8 +6,8 @@ import (
"net/http"
"time"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/form"
@@ -30,17 +30,17 @@ func SetupPageGet(factory *server.Factory, templates *template.Template, templat
if useWrapper {
if err := templates.ExecuteTemplate(ctx.Response().Writer, "_header.html", config); err != nil {
- derp.Report(render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error rendering index page")))
+ derp.Report(build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error building index page")))
}
}
if err := templates.ExecuteTemplate(ctx.Response().Writer, templateID, config); err != nil {
- derp.Report(render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error rendering index page")))
+ derp.Report(build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error building index page")))
}
if useWrapper {
if err := templates.ExecuteTemplate(ctx.Response().Writer, "_footer.html", config); err != nil {
- derp.Report(render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error rendering index page")))
+ derp.Report(build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.getIndex", "Error building index page")))
}
}
@@ -81,7 +81,7 @@ func SetupServerGet(factory *server.Factory) echo.HandlerFunc {
}
// Return the form
- return ctx.HTML(http.StatusOK, render.WrapForm(uri, result, "cancel-button:hide"))
+ return ctx.HTML(http.StatusOK, build.WrapForm(uri, result, "cancel-button:hide"))
}
}
@@ -93,7 +93,7 @@ func SetupServerPost(factory *server.Factory) echo.HandlerFunc {
data := mapof.NewAny()
if err := ctx.Bind(&data); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverPost", "Error parsing form data"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverPost", "Error parsing form data"))
}
// Data schema and UI schema
@@ -106,7 +106,7 @@ func SetupServerPost(factory *server.Factory) echo.HandlerFunc {
element, asTable, err := getSetupForm(section)
if err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverTable", "Invalid table name"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverTable", "Invalid table name"))
}
// Write Table-formatted forms.
@@ -115,12 +115,12 @@ func SetupServerPost(factory *server.Factory) echo.HandlerFunc {
// Apply the changes to the configuration
if err := widget.Do(ctx.Request().URL, data); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverTable", "Error saving form data"))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverTable", "Error saving form data"))
}
// Try to save the configuration to the persistent storage
if err := factory.UpdateConfig(config); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.postServer", "Internal error saving config. Try again later."))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.postServer", "Internal error saving config. Try again later."))
}
// Redraw the table
@@ -132,16 +132,16 @@ func SetupServerPost(factory *server.Factory) echo.HandlerFunc {
// Apply the changes to the configuration
if err := form.SetAll(&config, data, nil); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverPost", "Error saving form data", data))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.serverPost", "Error saving form data", data))
}
// Try to save the configuration to the persistent storage
if err := factory.UpdateConfig(config); err != nil {
- return render.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.postServer", "Internal error saving config. Try again later."))
+ return build.WrapInlineError(ctx.Response(), derp.Wrap(err, "setup.postServer", "Internal error saving config. Try again later."))
}
// Success!
- return render.WrapInlineSuccess(ctx.Response(), "Record Updated at: "+time.Now().Format(time.TimeOnly))
+ return build.WrapInlineSuccess(ctx.Response(), "Record Updated at: "+time.Now().Format(time.TimeOnly))
}
}
diff --git a/handler/setup_users.go b/handler/setup_users.go
index 027a40869..bd240a0c2 100644
--- a/handler/setup_users.go
+++ b/handler/setup_users.go
@@ -5,10 +5,10 @@ import (
"html/template"
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/config"
"github.com/EmissarySocial/emissary/domain"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/rosetta/mapof"
@@ -33,11 +33,11 @@ func SetupDomainUsersGet(serverFactory *server.Factory, templates *template.Temp
modal, err := displayDomainUsersModal(domainConfig, factory, templates)
if err != nil {
- return derp.Wrap(err, location, "Error rendering modal")
+ return derp.Wrap(err, location, "Error building modal")
}
// Wrap it as a modal
- return ctx.HTML(http.StatusOK, render.WrapModal(ctx.Response(), modal, "class:large"))
+ return ctx.HTML(http.StatusOK, build.WrapModal(ctx.Response(), modal, "class:large"))
}
}
@@ -81,7 +81,7 @@ func SetupDomainUserPost(serverFactory *server.Factory, templates *template.Temp
modal, err := displayDomainUsersModal(domainConfig, factory, templates)
if err != nil {
- return derp.Wrap(err, location, "Error rendering modal")
+ return derp.Wrap(err, location, "Error building modal")
}
return ctx.HTML(http.StatusOK, modal)
@@ -151,7 +151,7 @@ func SetupDomainUserDelete(serverFactory *server.Factory, templates *template.Te
modal, err := displayDomainUsersModal(domainConfig, factory, templates)
if err != nil {
- return derp.Wrap(err, location, "Error rendering modal")
+ return derp.Wrap(err, location, "Error building modal")
}
return ctx.HTML(http.StatusOK, modal)
diff --git a/handler/signin.go b/handler/signin.go
index b00225e5d..8b4ae6086 100644
--- a/handler/signin.go
+++ b/handler/signin.go
@@ -162,7 +162,7 @@ func GetResetCode(serverFactory *server.Factory) echo.HandlerFunc {
return derp.Wrap(err, "handler.GetResetCode", "Error loading user")
}
- // Try to render the HTML response
+ // Try to build the HTML response
template := factory.Domain().Theme().HTMLTemplate
object := mapof.Any{
diff --git a/handler/startup.go b/handler/startup.go
index d00ad4e1d..fa52ceaf3 100644
--- a/handler/startup.go
+++ b/handler/startup.go
@@ -3,7 +3,7 @@ package handler
import (
"net/http"
- "github.com/EmissarySocial/emissary/render"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/benpate/rosetta/first"
@@ -32,7 +32,7 @@ func GetStartup(serverFactory *server.Factory) echo.HandlerFunc {
return derp.NewUnauthorizedError(location, "Unauthorized")
}
- // Collect parameters to render
+ // Collect parameters to build
templateService := factory.Template()
template, err := templateService.LoadAdmin("startup")
@@ -42,18 +42,18 @@ func GetStartup(serverFactory *server.Factory) echo.HandlerFunc {
actionID := first.String(ctx.Param("action"), "page")
- // Get a Renderer for this page (also authenticates admin permissions)
- renderer, err := render.NewDomain(factory, ctx.Request(), ctx.Response(), template, actionID)
+ // Get a Builder for this page (also authenticates admin permissions)
+ builder, err := build.NewDomain(factory, ctx.Request(), ctx.Response(), template, actionID)
if err != nil {
- return derp.Wrap(err, location, "Error creating renderer")
+ return derp.Wrap(err, location, "Error creating builder")
}
// Render the HTML page.
- result, err := renderer.Render()
+ result, err := builder.Render()
if err != nil {
- return derp.Wrap(err, location, "Error rendering page")
+ return derp.Wrap(err, location, "Error building page")
}
// Return the HTML page to the browser
diff --git a/handler/stream.go b/handler/stream.go
index d58655d48..f250dcd63 100644
--- a/handler/stream.go
+++ b/handler/stream.go
@@ -3,9 +3,9 @@ package handler
import (
"net/http"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/handler/activitypub_stream"
"github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/server"
"github.com/benpate/derp"
"github.com/labstack/echo/v4"
@@ -22,25 +22,25 @@ func GetStream(serverFactory *server.Factory) echo.HandlerFunc {
return activitypub_stream.GetJSONLD(serverFactory)(ctx)
}
- // Otherwise, just render the stream normally
- return renderStream(serverFactory, render.ActionMethodGet)(ctx)
+ // Otherwise, just build the stream normally
+ return buildStream(serverFactory, build.ActionMethodGet)(ctx)
}
}
// GetStreamWithAction handles GET requests with a specified action
func GetStreamWithAction(serverFactory *server.Factory) echo.HandlerFunc {
- return renderStream(serverFactory, render.ActionMethodGet)
+ return buildStream(serverFactory, build.ActionMethodGet)
}
// PostStreamWithAction handles POST requests with a specified action
func PostStreamWithAction(serverFactory *server.Factory) echo.HandlerFunc {
- return renderStream(serverFactory, render.ActionMethodPost)
+ return buildStream(serverFactory, build.ActionMethodPost)
}
-// renderStream is the common Stream handler for both GET and POST requests
-func renderStream(serverFactory *server.Factory, actionMethod render.ActionMethod) echo.HandlerFunc {
+// buildStream is the common Stream handler for both GET and POST requests
+func buildStream(serverFactory *server.Factory, actionMethod build.ActionMethod) echo.HandlerFunc {
- const location = "handler.renderStream"
+ const location = "handler.buildStream"
return func(ctx echo.Context) error {
@@ -71,23 +71,23 @@ func renderStream(serverFactory *server.Factory, actionMethod render.ActionMetho
actionID := getActionID(ctx)
if ok, err := handleJSONLD(ctx, streamService.JSONLDGetter(&stream)); ok {
- return derp.Wrap(err, location, "Error rendering JSON-LD")
+ return derp.Wrap(err, location, "Error building JSON-LD")
}
- renderer, err := render.NewStreamWithoutTemplate(factory, ctx.Request(), ctx.Response(), &stream, actionID)
+ builder, err := build.NewStreamWithoutTemplate(factory, ctx.Request(), ctx.Response(), &stream, actionID)
if err != nil {
- return derp.Wrap(err, location, "Error creating Renderer")
+ return derp.Wrap(err, location, "Error creating Builder")
}
// Add webmention link header per:
// https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
- if actionMethod == render.ActionMethodGet {
+ if actionMethod == build.ActionMethodGet {
ctx.Response().Header().Set("Link", "/.webmention; rel=\"webmention\"")
}
- if err := renderHTML(factory, ctx, &renderer, actionMethod); err != nil {
- return derp.Wrap(err, location, "Error rendering page")
+ if err := buildHTML(factory, ctx, &builder, actionMethod); err != nil {
+ return derp.Wrap(err, location, "Error building page")
}
return nil
diff --git a/model/message.go b/model/message.go
index 325b21154..29a9792b3 100644
--- a/model/message.go
+++ b/model/message.go
@@ -106,7 +106,7 @@ func (message Message) NotRead() bool {
// SetState implements the model.StateSetter interface, and
// updates the message.StateID by wrapping the MarkXXX() methods.
// This method is primarily used by HTML templates in the
-// render pipeline. Services and handlers written in Go should
+// build pipeline. Services and handlers written in Go should
// probably use MarkRead(), MarkUnread(), etc. directly.
func (message *Message) SetState(stateID string) {
diff --git a/model/step/addModelObject.go b/model/step/addModelObject.go
index ec04bd159..c80df4dd1 100644
--- a/model/step/addModelObject.go
+++ b/model/step/addModelObject.go
@@ -36,5 +36,5 @@ func NewAddModelObject(stepInfo mapof.Any) (AddModelObject, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step AddModelObject) AmStep() {}
diff --git a/model/step/addStream.go b/model/step/addStream.go
index 5b60903f3..2d94efec8 100644
--- a/model/step/addStream.go
+++ b/model/step/addStream.go
@@ -55,5 +55,5 @@ func NewAddStream(stepInfo mapof.Any) (AddStream, error) {
return result, nil
}
-// AmStep is here to verify that this struct is a render pipeline step
+// AmStep is here to verify that this struct is a build pipeline step
func (step AddStream) AmStep() {}
diff --git a/model/step/asConfirmation.go b/model/step/asConfirmation.go
index b58f8df23..b0ad83b76 100644
--- a/model/step/asConfirmation.go
+++ b/model/step/asConfirmation.go
@@ -22,5 +22,5 @@ func NewAsConfirmation(stepInfo mapof.Any) (AsConfirmation, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step AsConfirmation) AmStep() {}
diff --git a/model/step/asModal.go b/model/step/asModal.go
index de19ac53b..83be8bfc7 100644
--- a/model/step/asModal.go
+++ b/model/step/asModal.go
@@ -28,5 +28,5 @@ func NewAsModal(stepInfo mapof.Any) (AsModal, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step AsModal) AmStep() {}
diff --git a/model/step/asTooltip.go b/model/step/asTooltip.go
index 7ea3c47f5..66927a19a 100644
--- a/model/step/asTooltip.go
+++ b/model/step/asTooltip.go
@@ -24,5 +24,5 @@ func NewAsTooltip(stepInfo mapof.Any) (AsTooltip, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step AsTooltip) AmStep() {}
diff --git a/model/step/delete.go b/model/step/delete.go
index 750d742a4..5cb466e5f 100644
--- a/model/step/delete.go
+++ b/model/step/delete.go
@@ -37,5 +37,5 @@ func NewDelete(stepInfo mapof.Any) (Delete, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Delete) AmStep() {}
diff --git a/model/step/deleteAttachments.go b/model/step/deleteAttachments.go
index 49c95788a..7ca98bb47 100644
--- a/model/step/deleteAttachments.go
+++ b/model/step/deleteAttachments.go
@@ -2,7 +2,7 @@ package step
import "github.com/benpate/rosetta/mapof"
-// DeleteAttachments represents an action that can upload attachments. It can only be used on a StreamRenderer
+// DeleteAttachments represents an action that can upload attachments. It can only be used on a StreamBuilder
type DeleteAttachments struct {
All bool
}
@@ -14,5 +14,5 @@ func NewDeleteAttachments(stepInfo mapof.Any) (DeleteAttachments, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step DeleteAttachments) AmStep() {}
diff --git a/model/step/do.go b/model/step/do.go
index 2cfb5b5ab..eb6e65230 100644
--- a/model/step/do.go
+++ b/model/step/do.go
@@ -16,5 +16,5 @@ func NewDo(stepInfo mapof.Any) (Do, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Do) AmStep() {}
diff --git a/model/step/editConnection.go b/model/step/editConnection.go
index ebdf0c281..fbbfa6173 100644
--- a/model/step/editConnection.go
+++ b/model/step/editConnection.go
@@ -9,5 +9,5 @@ func NewEditConnection(stepInfo mapof.Any) (EditConnection, error) {
return EditConnection{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step EditConnection) AmStep() {}
diff --git a/model/step/editContent.go b/model/step/editContent.go
index 6cbeb1195..218379844 100644
--- a/model/step/editContent.go
+++ b/model/step/editContent.go
@@ -19,5 +19,5 @@ func NewEditContent(stepInfo mapof.Any) (EditContent, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step EditContent) AmStep() {}
diff --git a/model/step/editModelObject.go b/model/step/editModelObject.go
index 5e8f92de2..b2bb55846 100644
--- a/model/step/editModelObject.go
+++ b/model/step/editModelObject.go
@@ -44,5 +44,5 @@ func NewEditModelObject(stepInfo mapof.Any) (EditModelObject, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step EditModelObject) AmStep() {}
diff --git a/model/step/editTable.go b/model/step/editTable.go
index 72e26bca7..2f0435704 100644
--- a/model/step/editTable.go
+++ b/model/step/editTable.go
@@ -27,5 +27,5 @@ func NewTableEditor(stepInfo mapof.Any) (TableEditor, error) {
}, nil
}
-// AmStep is here to verify that this struct is a render pipeline step
+// AmStep is here to verify that this struct is a build pipeline step
func (step TableEditor) AmStep() {}
diff --git a/model/step/editWidget.go b/model/step/editWidget.go
index fb9ab3dc1..b63d650ec 100644
--- a/model/step/editWidget.go
+++ b/model/step/editWidget.go
@@ -5,7 +5,7 @@ import (
)
// EditWidget represents an action-step that locates an existing widget and
-// creates a renderer for it.
+// creates a builder for it.
type EditWidget struct{}
// NewEditWidget returns a fully initialized EditWidget object
@@ -13,5 +13,5 @@ func NewEditWidget(stepInfo mapof.Any) (EditWidget, error) {
return EditWidget{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step EditWidget) AmStep() {}
diff --git a/model/step/forwardTo.go b/model/step/forwardTo.go
index 9da0b010e..df2f8b4b1 100644
--- a/model/step/forwardTo.go
+++ b/model/step/forwardTo.go
@@ -28,5 +28,5 @@ func NewForwardTo(stepInfo mapof.Any) (ForwardTo, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ForwardTo) AmStep() {}
diff --git a/model/step/halt.go b/model/step/halt.go
index 05058ff81..15c51143d 100644
--- a/model/step/halt.go
+++ b/model/step/halt.go
@@ -12,5 +12,5 @@ func NewHalt(stepInfo mapof.Any) (Halt, error) {
return Halt{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Halt) AmStep() {}
diff --git a/model/step/ifCondition.go b/model/step/ifCondition.go
index e10aad91d..586daa0f4 100644
--- a/model/step/ifCondition.go
+++ b/model/step/ifCondition.go
@@ -46,5 +46,5 @@ func NewIfCondition(stepInfo mapof.Any) (IfCondition, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step IfCondition) AmStep() {}
diff --git a/model/step/inlineError.go b/model/step/inlineError.go
index b2cfe5016..1b2acf9b6 100644
--- a/model/step/inlineError.go
+++ b/model/step/inlineError.go
@@ -25,5 +25,5 @@ func NewInlineError(stepInfo mapof.Any) (InlineError, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step InlineError) AmStep() {}
diff --git a/model/step/inlineSuccess.go b/model/step/inlineSuccess.go
index e13e94a83..63b111c0c 100644
--- a/model/step/inlineSuccess.go
+++ b/model/step/inlineSuccess.go
@@ -25,5 +25,5 @@ func NewInlineSuccess(stepInfo mapof.Any) (InlineSuccess, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step InlineSuccess) AmStep() {}
diff --git a/model/step/processContent.go b/model/step/processContent.go
index f99f34b07..cecbe67de 100644
--- a/model/step/processContent.go
+++ b/model/step/processContent.go
@@ -21,5 +21,5 @@ func NewProcessContent(stepInfo mapof.Any) (ProcessContent, error) {
}, nil
}
-// AmStep is here to verify that this struct is a render pipeline step
+// AmStep is here to verify that this struct is a build pipeline step
func (step ProcessContent) AmStep() {}
diff --git a/model/step/promoteDraft.go b/model/step/promoteDraft.go
index 8a5117c66..472555013 100644
--- a/model/step/promoteDraft.go
+++ b/model/step/promoteDraft.go
@@ -16,5 +16,5 @@ func NewStreamPromoteDraft(stepInfo mapof.Any) (StreamPromoteDraft, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step StreamPromoteDraft) AmStep() {}
diff --git a/model/step/publish.go b/model/step/publish.go
index ac03d96e6..6a4d00d06 100644
--- a/model/step/publish.go
+++ b/model/step/publish.go
@@ -10,5 +10,5 @@ func NewPublish(stepInfo mapof.Any) (Publish, error) {
return Publish{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Publish) AmStep() {}
diff --git a/model/step/redirectTo.go b/model/step/redirectTo.go
index eb1872824..0ccb16cae 100644
--- a/model/step/redirectTo.go
+++ b/model/step/redirectTo.go
@@ -28,5 +28,5 @@ func NewRedirectTo(stepInfo mapof.Any) (RedirectTo, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step RedirectTo) AmStep() {}
diff --git a/model/step/refreshPage.go b/model/step/refreshPage.go
index e77aa7446..d7f0f0bee 100644
--- a/model/step/refreshPage.go
+++ b/model/step/refreshPage.go
@@ -10,5 +10,5 @@ func NewRefreshPage(stepInfo mapof.Any) (RefreshPage, error) {
return RefreshPage{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step RefreshPage) AmStep() {}
diff --git a/model/step/reloadPage.go b/model/step/reloadPage.go
index 004e5d33a..7774695b1 100644
--- a/model/step/reloadPage.go
+++ b/model/step/reloadPage.go
@@ -10,5 +10,5 @@ func NewReloadPage(stepInfo mapof.Any) (ReloadPage, error) {
return ReloadPage{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ReloadPage) AmStep() {}
diff --git a/model/step/removeEvent.go b/model/step/removeEvent.go
index 939fb3c62..9f2472cca 100644
--- a/model/step/removeEvent.go
+++ b/model/step/removeEvent.go
@@ -17,5 +17,5 @@ func NewRemoveEvent(stepInfo mapof.Any) (RemoveEvent, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step RemoveEvent) AmStep() {}
diff --git a/model/step/save.go b/model/step/save.go
index fc80335b9..8d4367e61 100644
--- a/model/step/save.go
+++ b/model/step/save.go
@@ -26,5 +26,5 @@ func NewSave(stepInfo mapof.Any) (Save, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Save) AmStep() {}
diff --git a/model/step/sendEmail.go b/model/step/sendEmail.go
index 7b29bace7..afd6419e0 100644
--- a/model/step/sendEmail.go
+++ b/model/step/sendEmail.go
@@ -16,5 +16,5 @@ func NewSendEmail(stepInfo mapof.Any) (SendEmail, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SendEmail) AmStep() {}
diff --git a/model/step/serverRedirect.go b/model/step/serverRedirect.go
index 248a046a8..099deca07 100644
--- a/model/step/serverRedirect.go
+++ b/model/step/serverRedirect.go
@@ -20,5 +20,5 @@ func NewServerRedirect(stepInfo mapof.Any) (ServerRedirect, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ServerRedirect) AmStep() {}
diff --git a/model/step/setData.go b/model/step/setData.go
index a0573c65f..904f898c1 100644
--- a/model/step/setData.go
+++ b/model/step/setData.go
@@ -38,5 +38,5 @@ func NewSetData(stepInfo mapof.Any) (SetData, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetData) AmStep() {}
diff --git a/model/step/setHeader.go b/model/step/setHeader.go
index e3b91de12..f4ec0fb55 100644
--- a/model/step/setHeader.go
+++ b/model/step/setHeader.go
@@ -31,5 +31,5 @@ func NewSetHeader(stepInfo mapof.Any) (SetHeader, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetHeader) AmStep() {}
diff --git a/model/step/setQueryParam.go b/model/step/setQueryParam.go
index 81f8bc932..26e731e3a 100644
--- a/model/step/setQueryParam.go
+++ b/model/step/setQueryParam.go
@@ -34,5 +34,5 @@ func NewSetQueryParam(stepInfo mapof.Any) (SetQueryParam, error) {
return result, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetQueryParam) AmStep() {}
diff --git a/model/step/setRenderData.go b/model/step/setRenderData.go
index c43c4655d..420a0cff9 100644
--- a/model/step/setRenderData.go
+++ b/model/step/setRenderData.go
@@ -8,7 +8,7 @@ import (
"github.com/benpate/rosetta/mapof"
)
-// SetRenderData represents an action-step that can update the custom data stored in a renderer
+// SetRenderData represents an action-step that can update the custom data stored in a builder
type SetRenderData struct {
Values map[string]*template.Template // values to set directly into the object
}
@@ -34,5 +34,5 @@ func NewSetRenderData(stepInfo mapof.Any) (SetRenderData, error) {
return result, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetRenderData) AmStep() {}
diff --git a/model/step/setResponse.go b/model/step/setResponse.go
index 317c496de..a0b2a255f 100644
--- a/model/step/setResponse.go
+++ b/model/step/setResponse.go
@@ -11,5 +11,5 @@ func NewSetResponse(stepInfo mapof.Any) (SetResponse, error) {
return SetResponse{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetResponse) AmStep() {}
diff --git a/model/step/setSimpleSharing.go b/model/step/setSimpleSharing.go
index 72986e45e..7d2f03f3e 100644
--- a/model/step/setSimpleSharing.go
+++ b/model/step/setSimpleSharing.go
@@ -22,5 +22,5 @@ func NewSetSimpleSharing(stepInfo mapof.Any) (SetSimpleSharing, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetSimpleSharing) AmStep() {}
diff --git a/model/step/setState.go b/model/step/setState.go
index ae4399151..b0199b880 100644
--- a/model/step/setState.go
+++ b/model/step/setState.go
@@ -14,5 +14,5 @@ func NewSetState(stepInfo mapof.Any) (SetState, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetState) AmStep() {}
diff --git a/model/step/setThumbnail.go b/model/step/setThumbnail.go
index fd19fb0fd..2bda2f631 100644
--- a/model/step/setThumbnail.go
+++ b/model/step/setThumbnail.go
@@ -13,5 +13,5 @@ func NewSetThumbnail(stepInfo mapof.Any) (SetThumbnail, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SetThumbnail) AmStep() {}
diff --git a/model/step/sort.go b/model/step/sort.go
index eb7707b98..2da663cdf 100644
--- a/model/step/sort.go
+++ b/model/step/sort.go
@@ -21,5 +21,5 @@ func NewSort(stepInfo mapof.Any) (Sort, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step Sort) AmStep() {}
diff --git a/model/step/sortAttachments.go b/model/step/sortAttachments.go
index c3c303759..76bf3e0de 100644
--- a/model/step/sortAttachments.go
+++ b/model/step/sortAttachments.go
@@ -21,5 +21,5 @@ func NewSortAttachments(stepInfo mapof.Any) (SortAttachments, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SortAttachments) AmStep() {}
diff --git a/model/step/sortWidgets.go b/model/step/sortWidgets.go
index bac72b4ca..f92446d2a 100644
--- a/model/step/sortWidgets.go
+++ b/model/step/sortWidgets.go
@@ -12,5 +12,5 @@ func NewSortWidgets(stepInfo mapof.Any) (SortWidgets, error) {
return SortWidgets{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step SortWidgets) AmStep() {}
diff --git a/model/step/step.go b/model/step/step.go
index 3802beef5..602efc462 100644
--- a/model/step/step.go
+++ b/model/step/step.go
@@ -1,5 +1,5 @@
-// Package Step encapsulates the DATA required for each pipeline step in the renderer.
-// This package does not contain any rendering functions (that's in /render) but these
+// Package Step encapsulates the DATA required for each pipeline step in the builder.
+// This package does not contain any building functions (that's in /build) but these
// objects know how to parse and "compile" raw data into the arguments required to execute
// each step.
package step
@@ -199,7 +199,7 @@ func New(stepInfo mapof.Any) (Step, error) {
return nil, derp.NewInternalError("model.step.New", "Unrecognized step type", stepInfo)
}
-// NewPipeline parses a series of render steps into a new array
+// NewPipeline parses a series of build steps into a new array
func NewPipeline[T ~map[string]any](stepInfo []T) ([]Step, error) {
const location = "model.step.NewPipeline"
diff --git a/model/step/triggerEvent.go b/model/step/triggerEvent.go
index ac1a79d14..a74a7ec7d 100644
--- a/model/step/triggerEvent.go
+++ b/model/step/triggerEvent.go
@@ -28,5 +28,5 @@ func NewTriggerEvent(stepInfo mapof.Any) (TriggerEvent, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step TriggerEvent) AmStep() {}
diff --git a/model/step/unPublish.go b/model/step/unPublish.go
index 7257bbd83..89d697f50 100644
--- a/model/step/unPublish.go
+++ b/model/step/unPublish.go
@@ -14,5 +14,5 @@ func NewUnPublish(stepInfo mapof.Any) (UnPublish, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step UnPublish) AmStep() {}
diff --git a/model/step/uploadAttachment.go b/model/step/uploadAttachment.go
index ff991e25b..f8c35fbc6 100644
--- a/model/step/uploadAttachment.go
+++ b/model/step/uploadAttachment.go
@@ -2,7 +2,7 @@ package step
import "github.com/benpate/rosetta/mapof"
-// UploadAttachment represents an action that can upload attachments. It can only be used on a StreamRenderer
+// UploadAttachment represents an action that can upload attachments. It can only be used on a StreamBuilder
type UploadAttachment struct {
Maximum int
}
@@ -14,5 +14,5 @@ func NewUploadAttachment(stepInfo mapof.Any) (UploadAttachment, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step UploadAttachment) AmStep() {}
diff --git a/model/step/viewFeed.go b/model/step/viewFeed.go
index ee120f421..525e48145 100644
--- a/model/step/viewFeed.go
+++ b/model/step/viewFeed.go
@@ -2,7 +2,7 @@ package step
import "github.com/benpate/rosetta/mapof"
-// ViewFeed represents an action-step that can render a Stream into HTML
+// ViewFeed represents an action-step that can build a Stream into HTML
type ViewFeed struct {
}
@@ -12,5 +12,5 @@ func NewViewFeed(stepInfo mapof.Any) (ViewFeed, error) {
return ViewFeed{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ViewFeed) AmStep() {}
diff --git a/model/step/viewHTML.go b/model/step/viewHTML.go
index 8767f616b..ea19b137c 100644
--- a/model/step/viewHTML.go
+++ b/model/step/viewHTML.go
@@ -5,7 +5,7 @@ import (
"github.com/benpate/rosetta/mapof"
)
-// ViewHTML represents an action-step that can render a Stream into HTML
+// ViewHTML represents an action-step that can build a Stream into HTML
type ViewHTML struct {
File string
Method string
@@ -20,5 +20,5 @@ func NewViewHTML(stepInfo mapof.Any) (ViewHTML, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ViewHTML) AmStep() {}
diff --git a/model/step/viewJSONLD.go b/model/step/viewJSONLD.go
index fe00e1643..5ca73a1d8 100644
--- a/model/step/viewJSONLD.go
+++ b/model/step/viewJSONLD.go
@@ -5,7 +5,7 @@ import (
"github.com/benpate/rosetta/mapof"
)
-// ViewJSONLD represents an action-step that can render a Stream into HTML
+// ViewJSONLD represents an action-step that can build a Stream into HTML
type ViewJSONLD struct {
Method string
}
@@ -18,5 +18,5 @@ func NewViewJSONLD(stepInfo mapof.Any) (ViewJSONLD, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step ViewJSONLD) AmStep() {}
diff --git a/model/step/webSub.go b/model/step/webSub.go
index 10aac5a64..2cb7f4a86 100644
--- a/model/step/webSub.go
+++ b/model/step/webSub.go
@@ -2,7 +2,7 @@ package step
import "github.com/benpate/rosetta/mapof"
-// WebSub represents an action-step that can render a Stream into HTML
+// WebSub represents an action-step that can build a Stream into HTML
type WebSub struct {
}
@@ -11,5 +11,5 @@ func NewWebSub(stepInfo mapof.Any) (WebSub, error) {
return WebSub{}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WebSub) AmStep() {}
diff --git a/model/step/withChildren.go b/model/step/withChildren.go
index aec01a787..563e6dd5c 100644
--- a/model/step/withChildren.go
+++ b/model/step/withChildren.go
@@ -27,5 +27,5 @@ func NewWithChildren(stepInfo mapof.Any) (WithChildren, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithChildren) AmStep() {}
diff --git a/model/step/withDraft.go b/model/step/withDraft.go
index 3b2af6d0c..2ce473b1c 100644
--- a/model/step/withDraft.go
+++ b/model/step/withDraft.go
@@ -14,7 +14,7 @@ type WithDraft struct {
// NewWithDraft returns a fully initialized WithDraft object
func NewWithDraft(stepInfo mapof.Any) (WithDraft, error) {
- const location = "render.NewWithDraft"
+ const location = "build.NewWithDraft"
subSteps, err := NewPipeline(convert.SliceOfMap(stepInfo["steps"]))
@@ -27,5 +27,5 @@ func NewWithDraft(stepInfo mapof.Any) (WithDraft, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithDraft) AmStep() {}
diff --git a/model/step/withFolder.go b/model/step/withFolder.go
index 7b29db178..49ca22763 100644
--- a/model/step/withFolder.go
+++ b/model/step/withFolder.go
@@ -27,5 +27,5 @@ func NewWithFolder(stepInfo mapof.Any) (WithFolder, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithFolder) AmStep() {}
diff --git a/model/step/withFollower.go b/model/step/withFollower.go
index 50a84b341..8b94e266c 100644
--- a/model/step/withFollower.go
+++ b/model/step/withFollower.go
@@ -27,5 +27,5 @@ func NewWithFollower(stepInfo mapof.Any) (WithFollower, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithFollower) AmStep() {}
diff --git a/model/step/withFollowing.go b/model/step/withFollowing.go
index eb190918b..b8dcd927c 100644
--- a/model/step/withFollowing.go
+++ b/model/step/withFollowing.go
@@ -27,5 +27,5 @@ func NewWithFollowing(stepInfo mapof.Any) (WithFollowing, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithFollowing) AmStep() {}
diff --git a/model/step/withMessage.go b/model/step/withMessage.go
index 6402c3c61..ffcaf2d67 100644
--- a/model/step/withMessage.go
+++ b/model/step/withMessage.go
@@ -27,5 +27,5 @@ func NewWithMessage(stepInfo mapof.Any) (WithMessage, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithMessage) AmStep() {}
diff --git a/model/step/withNextSibling.go b/model/step/withNextSibling.go
index cf194bd43..43f2a1c8f 100644
--- a/model/step/withNextSibling.go
+++ b/model/step/withNextSibling.go
@@ -27,5 +27,5 @@ func NewWithNextSibling(stepInfo mapof.Any) (WithNextSibling, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithNextSibling) AmStep() {}
diff --git a/model/step/withParent.go b/model/step/withParent.go
index d5b38426c..73bb6f08d 100644
--- a/model/step/withParent.go
+++ b/model/step/withParent.go
@@ -14,7 +14,7 @@ type WithParent struct {
// NewWithParent returns a fully initialized WithParent object
func NewWithParent(stepInfo mapof.Any) (WithParent, error) {
- const location = "render.NewWithParent"
+ const location = "build.NewWithParent"
subSteps, err := NewPipeline(convert.SliceOfMap(stepInfo["steps"]))
@@ -27,5 +27,5 @@ func NewWithParent(stepInfo mapof.Any) (WithParent, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithParent) AmStep() {}
diff --git a/model/step/withPrevSibling.go b/model/step/withPrevSibling.go
index 4a898a6e7..faf983794 100644
--- a/model/step/withPrevSibling.go
+++ b/model/step/withPrevSibling.go
@@ -27,5 +27,5 @@ func NewWithPrevSibling(stepInfo mapof.Any) (WithPrevSibling, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithPrevSibling) AmStep() {}
diff --git a/model/step/withResponse.go b/model/step/withResponse.go
index 6f2f0bf09..3f3e0e41b 100644
--- a/model/step/withResponse.go
+++ b/model/step/withResponse.go
@@ -27,5 +27,5 @@ func NewWithResponse(stepInfo mapof.Any) (WithResponse, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithResponse) AmStep() {}
diff --git a/model/step/withRule.go b/model/step/withRule.go
index e5d16508f..85de15157 100644
--- a/model/step/withRule.go
+++ b/model/step/withRule.go
@@ -27,5 +27,5 @@ func NewWithRule(stepInfo mapof.Any) (WithRule, error) {
}, nil
}
-// AmStep is here only to verify that this struct is a render pipeline step
+// AmStep is here only to verify that this struct is a build pipeline step
func (step WithRule) AmStep() {}
diff --git a/model/stream.go b/model/stream.go
index 2a653c3a7..2dec62f79 100644
--- a/model/stream.go
+++ b/model/stream.go
@@ -22,7 +22,7 @@ type Stream struct {
ParentIDs id.Slice `json:"parentIds" bson:"parentIds"` // List of all parent IDs, including the current parent. This is used to generate "breadcrumbs" for the Stream.
Rank int `json:"rank" bson:"rank"` // If Template uses a custom sort order, then this is the value used to determine the position of this Stream.
NavigationID string `json:"navigationId" bson:"navigationId"` // Unique identifier of the "top-level" Stream that this record falls within.
- TemplateID string `json:"templateId" bson:"templateId"` // Unique identifier (name) of the Template to use when rendering this Stream in HTML.
+ TemplateID string `json:"templateId" bson:"templateId"` // Unique identifier (name) of the Template to use when building this Stream in HTML.
ParentTemplateID string `json:"parentTemplateId" bson:"parentTemplateId"` // Unique identifier (name) of the parent's Template.
StateID string `json:"stateId" bson:"stateId"` // Unique identifier of the State this Stream is in. This is used to populate the State information from the Template service at load time.
SocialRole string `json:"socialRole,omitempty" bson:"socialRole,omitempty"` // Role to use for this Stream in social integrations (Article, Note, Image, etc)
@@ -34,7 +34,7 @@ type Stream struct {
Summary string `json:"summary,omitempty" bson:"summary,omitempty"` // Brief summary of the document
ImageURL string `json:"imageUrl,omitempty" bson:"imageUrl,omitempty"` // URL of the cover image for this document's image
Content Content `json:"content,omitempty" bson:"content,omitempty"` // Body content object for this Stream.
- Widgets set.Slice[StreamWidget] `json:"widgets,omitempty" bson:"widgets,omitempty"` // Additional widgets to include when rendering this Stream.
+ Widgets set.Slice[StreamWidget] `json:"widgets,omitempty" bson:"widgets,omitempty"` // Additional widgets to include when building this Stream.
Tags sliceof.Object[Tag] `json:"tags,omitempty" bson:"tags,omitempty"` // List of tags that are associated with this document
Data mapof.Any `json:"data,omitempty" bson:"data,omitempty"` // Set of data to populate into the Template. This is validated by the JSON-Schema of the Template.
AttributedTo PersonLink `json:"attributedTo,omitempty" bson:"attributedTo,omitempty"` // List of people who are attributed to this document
diff --git a/model/streamSummary.go b/model/streamSummary.go
index 595300c0b..6281dd8de 100644
--- a/model/streamSummary.go
+++ b/model/streamSummary.go
@@ -10,12 +10,12 @@ type StreamSummary struct {
ObjectID primitive.ObjectID `json:"streamId" bson:"_id"` // Unique identifier of this Stream. (NOT USED PUBLICLY)
ParentObjectID primitive.ObjectID `json:"parentId" bson:"parentId"` // Unique identifier of the "parent" stream. (NOT USED PUBLICLY)
Token string `json:"token" bson:"token"` // Unique value that identifies this element in the URL
- TemplateID string `json:"templateId" bson:"templateId"` // Unique identifier (name) of the Template to use when rendering this Stream in HTML.
+ TemplateID string `json:"templateId" bson:"templateId"` // Unique identifier (name) of the Template to use when building this Stream in HTML.
URL string `json:"url,omitempty" bson:"url,omitempty"` // URL of the original document
Label string `json:"label,omitempty" bson:"label,omitempty"` // Label/Title of the document
Summary string `json:"summary,omitempty" bson:"summary,omitempty"` // Brief summary of the document
Content Content `json:"content,omitempty" bson:"content,omitempty"` // Content of the document
- Data mapof.Any `json:"data,omitempty" bson:"data,omitempty"` // Additional data that is specific to the Template used to render this Stream
+ Data mapof.Any `json:"data,omitempty" bson:"data,omitempty"` // Additional data that is specific to the Template used to build this Stream
ImageURL string `json:"imageUrl,omitempty" bson:"imageUrl,omitempty"` // URL of the cover image for this document's image
AttributedTo PersonLink `json:"attributedTo,omitempty" bson:"attributedTo,omitempty"` // List of people who are attributed to this document
InReplyTo string `json:"inReplyTo,omitempty" bson:"inReplyTo,omitempty"` // If this stream is a reply to another stream or web page, then this links to the original document.
diff --git a/model/streamWidget.go b/model/streamWidget.go
index c6b798abd..cb87ad211 100644
--- a/model/streamWidget.go
+++ b/model/streamWidget.go
@@ -12,7 +12,7 @@ type StreamWidget struct {
Label string `json:"label" bson:"label"`
Data mapof.Any `json:"data" bson:"data"`
- // These values are not stored in the database, but injected during rendering
+ // These values are not stored in the database, but injected during building
Stream *Stream `json:"-" bson:"-"`
Widget Widget `json:"-" bson:"-"`
}
diff --git a/model/template.go b/model/template.go
index 50a50e93b..736fc4066 100644
--- a/model/template.go
+++ b/model/template.go
@@ -12,7 +12,7 @@ import (
"github.com/benpate/rosetta/sliceof"
)
-// Template represents an HTML template used for rendering Streams
+// Template represents an HTML template used for building Streams
type Template struct {
TemplateID string `json:"templateId" bson:"templateId"` // Internal name/token other objects (like streams) will use to reference this Template.
URL string `json:"url" bson:"url"` // URL where this template is published
diff --git a/model/theme.go b/model/theme.go
index 3a59e69bd..085047421 100644
--- a/model/theme.go
+++ b/model/theme.go
@@ -10,7 +10,7 @@ import (
"github.com/benpate/rosetta/mapof"
)
-// Theme represents an HTML template used for rendering all hard-coded application elements (but not dynamic streams)
+// Theme represents an HTML template used for building all hard-coded application elements (but not dynamic streams)
type Theme struct {
ThemeID string `json:"themeID" bson:"themeID"` // Internal name/token other objects (like streams) will use to reference this Theme.
Extends []string `json:"extends" bson:"extends"` // List of other themes that this theme extends
diff --git a/render/step_AddModelObject.go b/render/step_AddModelObject.go
deleted file mode 100644
index cd1fb870d..000000000
--- a/render/step_AddModelObject.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/EmissarySocial/emissary/model/step"
- "github.com/benpate/derp"
- "github.com/benpate/form"
-)
-
-// StepAddModelObject is an action that can add new model objects of any type
-type StepAddModelObject struct {
- Form form.Element
- Defaults []step.Step
-}
-
-// Get displays a modal form that lets users enter data for their new model object.
-func (step StepAddModelObject) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- factory := renderer.factory()
- schema := renderer.schema()
- object := renderer.object()
-
- // First, try to execute any "default" steps so that the object is initialized
- result := Pipeline(step.Defaults).Get(factory, renderer, buffer)
-
- if result.Halt {
- result.Error = derp.Wrap(result.Error, "render.StepAddModelObject.Get", "Error executing default steps")
- return UseResult(result)
- }
-
- // Try to render the Form HTML
- formHTML, err := form.Editor(schema, step.Form, object, renderer.lookupProvider())
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepAddModelObject.Get", "Error generating form"))
- }
-
- formHTML = WrapForm(renderer.URL(), formHTML)
-
- // Wrap formHTML as a modal dialog
- // nolint:errcheck
- io.WriteString(buffer, formHTML)
- return nil
-}
-
-// Post initializes a new model object, populates it with data from the form, then saves it to the database.
-func (step StepAddModelObject) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- // This finds/creates a new object in the renderer
- factory := renderer.factory()
- request := renderer.request()
- object := renderer.object()
- schema := renderer.schema()
-
- // Execute any "default" steps so that the object is initialized
- result := Pipeline(step.Defaults).Post(factory, renderer, buffer)
-
- if result.Halt {
- result.Error = derp.Wrap(result.Error, "render.StepAddModelObject.Post", "Error executing default steps")
- return UseResult(result)
- }
-
- // Parse form information
- if err := request.ParseForm(); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.AddModelObject.Post", "Error parsing form data"))
- }
-
- // Try to set each path from the Form into the renderer. Note: schema.Set also converts and validated inputs before setting.
- for key, value := range request.Form {
- if err := schema.Set(object, key, value); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.AddModelObject.Post", "Error setting path value", key, value))
- }
- }
-
- // Save the object to the database
- if err := renderer.service().ObjectSave(object, "Created"); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepAddModelObject.Post", "Error saving model object to database"))
- }
-
- // Success!
- return nil
-}
diff --git a/render/step_EditContent.go b/render/step_EditContent.go
deleted file mode 100644
index 46c099e32..000000000
--- a/render/step_EditContent.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package render
-
-import (
- "bytes"
- "io"
-
- "github.com/EmissarySocial/emissary/model"
- "github.com/benpate/derp"
- "github.com/benpate/rosetta/mapof"
-)
-
-// StepEditContent represents an action-step that can edit/update Container in a streamDraft.
-type StepEditContent struct {
- Filename string
- Format string
-}
-
-func (step StepEditContent) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- if err := renderer.executeTemplate(buffer, step.Filename, renderer); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditContent.Get", "Error executing template"))
- }
-
- return nil
-}
-
-func (step StepEditContent) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
-
- var rawContent string
-
- // Require that we're working with a Stream
- stream, ok := renderer.object().(*model.Stream)
-
- if !ok {
- return Halt().WithError(derp.NewInternalError("render.StepEditContent.Post", "step: EditContent can only be used on a Stream"))
- }
-
- // Try to read the content from the request body
- switch step.Format {
-
- // EditorJS writes directly to the request body
- case model.ContentFormatEditorJS:
- var buffer bytes.Buffer
-
- if _, err := io.Copy(&buffer, renderer.request().Body); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditContent.Post", "Error reading request data"))
- }
-
- rawContent = buffer.String()
-
- // All other types are a Form post
- default:
-
- body := mapof.NewAny()
- if err := bind(renderer.request(), &body); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditContent.Post", "Error parsing request data"))
- }
-
- rawContent, _ = body.GetStringOK("content")
- }
-
- // Set the new Content value in the Stream
- contentService := renderer.factory().Content()
- stream.Content = contentService.New(step.Format, rawContent)
-
- // Try to save the object back to the database
- if err := renderer.service().ObjectSave(stream, "Content edited"); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepEditContent.Post", "Error saving stream"))
- }
-
- // Success!
- return nil
-}
diff --git a/render/step_Error.go b/render/step_Error.go
deleted file mode 100644
index acbcbc08c..000000000
--- a/render/step_Error.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/EmissarySocial/emissary/model/step"
- "github.com/benpate/derp"
-)
-
-type StepError struct {
- Original step.Step
-}
-
-func (step StepError) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return Halt().WithError(derp.NewInternalError("render.StepError", "Unrecognized Pipeline Step", "This should never happen", renderer.ActionID(), renderer.Action(), renderer.Action().Steps, renderer.object(), step.Original))
-}
-
-func (step StepError) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- return Halt().WithError(derp.NewInternalError("render.StepError", "Unrecognized Pipeline Step", "This should never happen", step.Original))
-}
diff --git a/render/step_InlineError.go b/render/step_InlineError.go
deleted file mode 100644
index 33494af0d..000000000
--- a/render/step_InlineError.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package render
-
-import (
- "io"
- "text/template"
-)
-
-// StepInlineError represents an action-step that can render a Stream into HTML
-type StepInlineError struct {
- Message *template.Template
-}
-
-// Get renders the Stream HTML to the context
-func (step StepInlineError) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return nil
-}
-
-func (step StepInlineError) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- result := executeTemplate(step.Message, renderer)
-
- if _, err := buffer.Write([]byte(`
` + result + ``)); err != nil {
- return Halt().WithError(err)
- }
-
- return Halt().WithHeader("HX-Reswap", "innerHTML").WithHeader("HX-Retarget", "#htmx-response-message")
-}
diff --git a/render/step_InlineSuccess.go b/render/step_InlineSuccess.go
deleted file mode 100644
index 021d67c25..000000000
--- a/render/step_InlineSuccess.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package render
-
-import (
- "io"
- "text/template"
-)
-
-// StepInlineSuccess represents an action-step that can render a Stream into HTML
-type StepInlineSuccess struct {
- Message *template.Template
-}
-
-// Get renders the Stream HTML to the context
-func (step StepInlineSuccess) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return nil
-}
-
-func (step StepInlineSuccess) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- result := executeTemplate(step.Message, renderer)
-
- if _, err := buffer.Write([]byte(`
` + result + ``)); err != nil {
- return Halt().WithError(err)
- }
- return Halt().WithHeader("HX-Reswap", "innerHTML").WithHeader("HX-Retarget", "#htmx-response-message")
-}
diff --git a/render/step_PromoteDraft.go b/render/step_PromoteDraft.go
deleted file mode 100644
index 77e994beb..000000000
--- a/render/step_PromoteDraft.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/benpate/derp"
-)
-
-// StepStreamPromoteDraft represents an action-step that can copy the Container from a StreamDraft into its corresponding Stream
-type StepStreamPromoteDraft struct {
- StateID string
-}
-
-func (step StepStreamPromoteDraft) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
- return nil
-}
-
-// Post copies relevant information from the draft into the primary stream, then deletes the draft
-func (step StepStreamPromoteDraft) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
-
- streamRenderer := renderer.(*Stream)
-
- factory := renderer.factory()
-
- // Try to load the draft from the database, overwriting the stream already in the renderer
- stream, err := factory.StreamDraft().Promote(renderer.objectID(), step.StateID)
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, "renderer.StepStreamPromoteDraft.Post", "Error publishing draft"))
- }
-
- // Push the newly updated stream back to the renderer so that subsequent
- // steps (e.g. publish) can use the correct data.
- streamRenderer._stream = &stream
-
- return nil
-}
diff --git a/render/step_SendEmail.go b/render/step_SendEmail.go
deleted file mode 100644
index 8363fcc68..000000000
--- a/render/step_SendEmail.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/benpate/derp"
-)
-
-// StepSendEmail represents an action-step that can send a named email to a recipient
-type StepSendEmail struct {
- Email string
-}
-
-func (step StepSendEmail) Get(_ Renderer, _ io.Writer) PipelineBehavior {
- return nil
-}
-
-// Post saves the object to the database
-func (step StepSendEmail) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- factory := renderer.factory()
- emailService := factory.Email()
-
- userRenderer, ok := renderer.(User)
-
- if !ok {
- return Halt().WithError(derp.NewInternalError("render.StepSendEmail.Post", "Invalid Renderer", "Renderer must be Admin/User"))
- }
-
- switch step.Email {
-
- case "welcome":
-
- if err := emailService.SendWelcome(userRenderer._user); err != nil {
- return Halt().WithError(err)
- }
-
- case "password-reset":
- if err := emailService.SendPasswordReset(userRenderer._user); err != nil {
- return Halt().WithError(err)
- }
-
- default:
- return Halt().WithError(derp.NewInternalError("render.StepSendEmail.Post", "Invalid email name", "Name must be 'welcome' or 'password-reset'"))
- }
-
- return nil
-}
diff --git a/render/step_ServerRedirect.go b/render/step_ServerRedirect.go
deleted file mode 100644
index 768585d21..000000000
--- a/render/step_ServerRedirect.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/benpate/derp"
-)
-
-// StepServerRedirect represents an action-step that continues rendering the output stream as
-// a GET request to a new action.
-type StepServerRedirect struct {
- On string // "get" or "post" or "both"
- Action string
-}
-
-func (step StepServerRedirect) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- if step.On == "post" {
- return nil
- }
-
- return step.redirect(renderer, buffer)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepServerRedirect) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- if step.On == "get" {
- return nil
- }
-
- return step.redirect(renderer, renderer.response())
-}
-
-// redirect creates a new renderer on this object with the requested Action and then continues as a GET request.
-func (step StepServerRedirect) redirect(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- newRenderer, err := renderer.clone(step.Action)
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepServerRedirect.Redirect", "Error creating new renderer"))
- }
-
- result, err := newRenderer.Render()
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepServerRedirect.Redirect", "Error rendering new page"))
- }
-
- if _, err := buffer.Write([]byte(result)); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepServerRedirect.Redirect", "Error writing output buffer"))
- }
-
- return nil
-}
diff --git a/render/step_SetHeader.go b/render/step_SetHeader.go
deleted file mode 100644
index e1a719641..000000000
--- a/render/step_SetHeader.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package render
-
-import (
- "bytes"
- "io"
- "text/template"
-
- "github.com/benpate/derp"
-)
-
-// StepSetHeader represents an action-step that can update the custom data stored in a Stream
-type StepSetHeader struct {
- Method string
- Name string
- Value *template.Template
-}
-
-func (step StepSetHeader) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- if step.Method == "post" {
- return nil
- }
- return step.setHeader(renderer)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepSetHeader) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- if step.Method == "get" {
- return nil
- }
- return step.setHeader(renderer)
-}
-
-func (step StepSetHeader) setHeader(renderer Renderer) PipelineBehavior {
-
- var value bytes.Buffer
-
- if err := step.Value.Execute(&value, renderer); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.StepSetHeader.Post", "Error executing template", step.Value))
- }
-
- renderer.response().Header().Set(step.Name, value.String())
-
- return nil
-}
diff --git a/render/step_SetQueryParam.go b/render/step_SetQueryParam.go
deleted file mode 100644
index 042272a11..000000000
--- a/render/step_SetQueryParam.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package render
-
-import (
- "io"
- "text/template"
-)
-
-// StepSetQueryParam represents an action-step that sets values to the request query string
-type StepSetQueryParam struct {
- Values map[string]*template.Template
-}
-
-// Get displays a form where users can update stream data
-func (step StepSetQueryParam) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.Do(renderer)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepSetQueryParam) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- return step.Do(renderer)
-}
-
-func (step StepSetQueryParam) Do(renderer Renderer) PipelineBehavior {
- query := renderer.request().URL.Query()
-
- for key, value := range step.Values {
- queryValue := executeTemplate(value, renderer)
- query.Set(key, queryValue)
- }
-
- renderer.request().URL.RawQuery = query.Encode()
- return nil
-}
diff --git a/render/step_SetRenderData.go b/render/step_SetRenderData.go
deleted file mode 100644
index fbeabd207..000000000
--- a/render/step_SetRenderData.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package render
-
-import (
- "io"
- "text/template"
-)
-
-// StepSetRenderData represents an action-step that sets values to the request query string
-type StepSetRenderData struct {
- Values map[string]*template.Template
-}
-
-// Get displays a form where users can update stream data
-func (step StepSetRenderData) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.Do(renderer)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepSetRenderData) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
- return step.Do(renderer)
-}
-
-func (step StepSetRenderData) Do(renderer Renderer) PipelineBehavior {
- for key, value := range step.Values {
- queryValue := executeTemplate(value, renderer)
- renderer.setString(key, queryValue)
- }
-
- return nil
-}
diff --git a/render/step_SetState.go b/render/step_SetState.go
deleted file mode 100644
index f405e4e00..000000000
--- a/render/step_SetState.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/benpate/derp"
-)
-
-// StepSetState represents an action-step that can change a Stream's state
-type StepSetState struct {
- State string
-}
-
-func (step StepSetState) Get(renderer Renderer, _ io.Writer) PipelineBehavior {
- return nil
-}
-
-// Post updates the stream with configured data, and moves the stream to a new state
-func (step StepSetState) Post(renderer Renderer, _ io.Writer) PipelineBehavior {
-
- // If the renderer is a StateSetter, then try to update the state
- if setter, ok := renderer.(StateSetter); ok {
-
- // This action may still fail (for instance) if the renderer wraps
- // a model object that is not a `model.StateSetter`
- if err := setter.setState(step.State); err != nil {
- return Halt().WithError(derp.Wrap(err, "render.stepSetState.Post", "Error setting state"))
- }
-
- // Success
- return nil
- }
-
- // Failure (obv)
- return Halt().WithError(derp.NewInternalError("render.stepSetState.Post", "Renderer does not implement StateSetter interface"))
-}
diff --git a/render/step_WithDraft.go b/render/step_WithDraft.go
deleted file mode 100644
index 0697681ee..000000000
--- a/render/step_WithDraft.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/EmissarySocial/emissary/model/step"
- "github.com/benpate/derp"
-)
-
-// StepWithDraft represents an action-step that can update the data.DataMap custom data stored in a Stream
-type StepWithDraft struct {
- SubSteps []step.Step
-}
-
-// Get displays a form where users can update stream data
-func (step StepWithDraft) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- const location = "render.StepWithDraft.Get"
-
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
- draftRenderer, err := streamRenderer.draftRenderer()
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error getting draft renderer"))
- }
-
- // Execute the POST render pipeline on the parent
- status := Pipeline(step.SubSteps).Get(factory, &draftRenderer, buffer)
- status.Error = derp.Wrap(status.Error, location, "Error executing steps on draft")
-
- return UseResult(status)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepWithDraft) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- const location = "render.StepWithDraft.Post"
-
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
- draftRenderer, err := streamRenderer.draftRenderer()
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error getting draft renderer"))
- }
-
- // Execute the POST render pipeline on the parent
- result := Pipeline(step.SubSteps).Post(factory, &draftRenderer, buffer)
- result.Error = derp.Wrap(result.Error, location, "Error executing steps on draft")
-
- return UseResult(result)
-}
diff --git a/render/step_WithNextSibling.go b/render/step_WithNextSibling.go
deleted file mode 100644
index 4f775d229..000000000
--- a/render/step_WithNextSibling.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/model/step"
- "github.com/benpate/derp"
-)
-
-// StepWithNextSibling represents an action-step that can update the data.DataMap custom data stored in a Stream
-type StepWithNextSibling struct {
- SubSteps []step.Step
-}
-
-func (step StepWithNextSibling) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
-}
-
-// Post executes the subSteps on the parent Stream
-func (step StepWithNextSibling) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
-}
-
-// Post executes the subSteps on the parent Stream
-func (step StepWithNextSibling) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
-
- const location = "render.StepWithNextSibling.Post"
-
- var sibling model.Stream
-
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
- stream := streamRenderer._stream
-
- if err := factory.Stream().LoadNextSibling(stream.ParentID, stream.Rank, &sibling); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error listing parent"))
- }
-
- // Make a renderer with the new parent stream
- // TODO: LOW: Is "view" really the best action to use here??
- siblingRenderer, err := NewStreamWithoutTemplate(streamRenderer.factory(), streamRenderer.request(), streamRenderer.response(), &sibling, "view")
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating renderer for sibling"))
- }
-
- // execute the POST render pipeline on the parent
- result := Pipeline(step.SubSteps).Execute(factory, &siblingRenderer, buffer, actionMethod)
- result.Error = derp.Wrap(result.Error, location, "Error executing steps for parent")
-
- return UseResult(result)
-}
diff --git a/render/step_WithPrevSibling.go b/render/step_WithPrevSibling.go
deleted file mode 100644
index 09aab811f..000000000
--- a/render/step_WithPrevSibling.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/EmissarySocial/emissary/model"
- "github.com/EmissarySocial/emissary/model/step"
- "github.com/benpate/derp"
-)
-
-// StepWithPrevSibling represents an action-step that can update the data.DataMap custom data stored in a Stream
-type StepWithPrevSibling struct {
- SubSteps []step.Step
-}
-
-func (step StepWithPrevSibling) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodGet)
-}
-
-// Post executes the subSteps on the parent Stream
-func (step StepWithPrevSibling) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
- return step.execute(renderer, buffer, ActionMethodPost)
-}
-
-// Post executes the subSteps on the parent Stream
-func (step StepWithPrevSibling) execute(renderer Renderer, buffer io.Writer, actionMethod ActionMethod) PipelineBehavior {
-
- const location = "render.StepWithPrevSibling.execute"
-
- var sibling model.Stream
-
- factory := renderer.factory()
- streamRenderer := renderer.(*Stream)
- stream := streamRenderer._stream
-
- if err := factory.Stream().LoadPrevSibling(stream.ParentID, stream.Rank, &sibling); err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error listing parent"))
- }
-
- // Make a renderer with the new parent stream
- // TODO: Is "view" really the best action to use here??
- siblingRenderer, err := NewStreamWithoutTemplate(streamRenderer.factory(), streamRenderer.request(), streamRenderer.response(), &sibling, "view")
-
- if err != nil {
- return Halt().WithError(derp.Wrap(err, location, "Error creating renderer for sibling"))
- }
-
- // Execute the POST render pipeline on the parent
- result := Pipeline(step.SubSteps).Execute(factory, &siblingRenderer, buffer, actionMethod)
- result.Error = derp.Wrap(result.Error, location, "Error executing steps for parent")
- return UseResult(result)
-}
diff --git a/render/step_do.go b/render/step_do.go
deleted file mode 100644
index ffe043232..000000000
--- a/render/step_do.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package render
-
-import (
- "io"
-
- "github.com/benpate/derp"
-)
-
-// StepDo represents an action-step that sends an HTMX 'forward' to a new page.
-type StepDo struct {
- Action string
-}
-
-func (step StepDo) Get(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- const location = "render.StepDo.Get"
-
- action, ok := renderer.template().Actions[step.Action]
-
- if !ok {
- return Halt().WithError(derp.NewBadRequestError(location, "Action not found", step.Action))
- }
-
- result := Pipeline(action.Steps).Get(renderer.factory(), renderer, buffer)
- return UseResult(result)
-}
-
-// Post updates the stream with approved data from the request body.
-func (step StepDo) Post(renderer Renderer, buffer io.Writer) PipelineBehavior {
-
- const location = "render.StepDo.Post"
-
- action, ok := renderer.template().Actions[step.Action]
-
- if !ok {
- return Halt().WithError(derp.NewBadRequestError(location, "Action not found", step.Action))
- }
-
- result := Pipeline(action.Steps).Post(renderer.factory(), renderer, buffer)
- return UseResult(result)
-}
diff --git a/server.go b/server.go
index 7c9308bad..d260c03dc 100644
--- a/server.go
+++ b/server.go
@@ -242,9 +242,9 @@ func makeStandardRoutes(factory *server.Factory, e *echo.Echo) {
e.DELETE("/:stream", handler.PostStreamWithAction(factory))
// Hard-coded routes for additional stream services
- e.GET("/:stream/attachments/:attachment", handler.GetAttachment(factory)) // TODO: LOW: Can Stream Attachments be moved into a custom render step?
- e.GET("/:stream/sse", handler.ServerSentEvent(factory)) // TODO: LOW: Can SSE be moved into a custom render step?
- e.GET("/:stream/qrcode", handler.GetQRCode(factory)) // TODO: LOW: Can QR Codes be moved into a custom render step?
+ e.GET("/:stream/attachments/:attachment", handler.GetAttachment(factory)) // TODO: LOW: Can Stream Attachments be moved into a custom build step?
+ e.GET("/:stream/sse", handler.ServerSentEvent(factory)) // TODO: LOW: Can SSE be moved into a custom build step?
+ e.GET("/:stream/qrcode", handler.GetQRCode(factory)) // TODO: LOW: Can QR Codes be moved into a custom build step?
// Profile Pages
// NOTE: these are rewritten from /@:userId by the rewrite middleware
diff --git a/server/factory.go b/server/factory.go
index e2b648827..00ea7066e 100644
--- a/server/factory.go
+++ b/server/factory.go
@@ -7,9 +7,9 @@ import (
"strings"
"sync"
+ "github.com/EmissarySocial/emissary/build"
"github.com/EmissarySocial/emissary/config"
"github.com/EmissarySocial/emissary/domain"
- "github.com/EmissarySocial/emissary/render"
"github.com/EmissarySocial/emissary/service"
"github.com/EmissarySocial/emissary/tools/ascache"
"github.com/EmissarySocial/emissary/tools/ascacherules"
@@ -498,7 +498,7 @@ func (factory *Factory) Widget() *service.Widget {
// FuncMap returns the global funcMap (used by all templates)
func (factory *Factory) FuncMap() template.FuncMap {
- return render.FuncMap(factory.Icons())
+ return build.FuncMap(factory.Icons())
}
// Icons returns the global icon collection
diff --git a/service/outbox_publish.go b/service/outbox_publish.go
index 3437cc76e..0a4bcdf97 100644
--- a/service/outbox_publish.go
+++ b/service/outbox_publish.go
@@ -107,7 +107,7 @@ func (service Outbox) sendNotifications_WebSub(parentType string, parentID primi
// sendNotifications_WebMention sends WebMention updates to external websites that are
// mentioned in this stream. This is here (and not in the outbox service)
-// because we need to render the content in order to discover outbound links.
+// because we need to build the content in order to discover outbound links.
func (service *Outbox) sendNotifications_WebMention(activity mapof.Any) {
// Locate the object ID for this acticity