diff --git a/conference.go b/conference.go index ce79ae0..8452393 100644 --- a/conference.go +++ b/conference.go @@ -478,14 +478,7 @@ func ReadPosts(ctxt ui.AmContext) (string, any, error) { comm := ctxt.CurrentCommunity() conf := ctxt.GetScratch("currentConference").(*database.Conference) myLevel := ctxt.GetScratch("levelInConference").(uint16) - var topic *database.Topic = nil - if rawTopic, err := strconv.ParseInt(ctxt.URLParam("topic"), 10, 16); err == nil { - topic, err = database.AmGetTopicByNumber(ctxt.Ctx(), conf, int16(rawTopic)) - } - if topic == nil { - ctxt.SetRC(http.StatusNotFound) - return ui.ErrorPage(ctxt, fmt.Errorf("topic not found: %s", ctxt.URLParam("topic"))) - } + topic := ctxt.GetScratch("currentTopic").(*database.Topic) // Determine the range of posts to display. The "pin" is the post number after which we display the horizontal line separating old and new posts. lastRead, err := topic.GetLastRead(ctxt.Ctx(), ctxt.CurrentUser()) @@ -642,17 +635,9 @@ func PostInTopic(ctxt ui.AmContext) (string, any, error) { comm := ctxt.CurrentCommunity() conf := ctxt.GetScratch("currentConference").(*database.Conference) level := ctxt.GetScratch("levelInConference").(uint16) + topic := ctxt.GetScratch("currentTopic").(*database.Topic) - var topic *database.Topic = nil - if rawTopic, err := strconv.ParseInt(ctxt.URLParam("topic"), 10, 16); err == nil { - topic, err = database.AmGetTopicByNumber(ctxt.Ctx(), conf, int16(rawTopic)) - } - if topic == nil { - ctxt.SetRC(http.StatusNotFound) - return ui.ErrorPage(ctxt, fmt.Errorf("topic not found: %s", ctxt.URLParam("topic"))) - } - - urlStem := fmt.Sprintf("/comm/%s/conf/%s/r/%d", comm.Alias, ctxt.URLParam("confid"), topic.Number) + urlStem := fmt.Sprintf("/comm/%s/conf/%s/r/%d", comm.Alias, ctxt.GetScratch("currentAlias"), topic.Number) if ctxt.FormFieldIsSet("cancel") { return "redirect", urlStem, nil } diff --git a/main.go b/main.go index a47c5ad..172183a 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,7 @@ func setupEcho() *echo.Echo { fn := ui.AmWrap(NotImplPage) e.GET("/TODO/*", fn) e.POST("/TODO/*", fn) - e.GET("/img/*", ui.AmWrap(ui.AmServeImage)) + e.GET("/img/*", ui.AmServeImage) e.GET("/static/*", ui.AmStaticFileHandler()) e.GET("/go/:postlink", fn) @@ -98,8 +98,8 @@ func setupEcho() *echo.Echo { confGroup.GET("", ui.AmWrap(Topics)) confGroup.GET("/new_topic", ui.AmWrap(NewTopicForm)) confGroup.POST("/new_topic", ui.AmWrap(NewTopic)) - confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts)) - confGroup.POST("/r/:topic", ui.AmWrap(PostInTopic)) + confGroup.GET("/r/:topic", ui.AmWrap(ReadPosts), ui.SetTopic) + confGroup.POST("/r/:topic", ui.AmWrap(PostInTopic), ui.SetTopic) return e } diff --git a/ui/images.go b/ui/images.go index 6907199..4a250d0 100644 --- a/ui/images.go +++ b/ui/images.go @@ -28,6 +28,7 @@ import ( "git.erbosoft.com/amy/amsterdam/database" "github.com/disintegration/imaging" + "github.com/labstack/echo/v4" ) //go:embed static_images/* @@ -55,14 +56,12 @@ func mimeTypeFromFilename(filename string) string { /* AmServeImage serves an image from internal storage. * Parameters: - * ctxt - The AmContext for the request. + * c - The Echo context for this request. * Returns: - * Type of content to be rendered - * Content to be rendered - * Standard Go error return + * Standard Go error return. */ -func AmServeImage(ctxt AmContext) (string, any, error) { - components := strings.SplitAfter(ctxt.URLPath(), "/") +func AmServeImage(c echo.Context) error { + components := strings.SplitAfter(c.Request().URL.Path, "/") var err error = nil if len(components) == 4 { switch components[2] { @@ -70,27 +69,24 @@ func AmServeImage(ctxt AmContext) (string, any, error) { var b []byte b, err = static_images.ReadFile(filepath.Join("static_images", components[3])) if err == nil { - ctxt.SetOutputType(mimeTypeFromFilename(components[3])) - return "bytes", b, nil + return c.Blob(http.StatusOK, mimeTypeFromFilename(components[3]), b) } case "store/": var id int id, err = strconv.Atoi(components[3]) if err == nil { var img *database.ImageStore - img, err = database.AmLoadImage(ctxt.Ctx(), int32(id)) + img, err = database.AmLoadImage(c.Request().Context(), int32(id)) if err == nil { - ctxt.SetOutputType(img.MimeType) - return "bytes", img.Data, nil + return c.Blob(http.StatusOK, img.MimeType, img.Data) } } } } - ctxt.SetRC(http.StatusNotFound) if err == nil { - err = fmt.Errorf("image not found: %s", ctxt.URLPath()) + err = fmt.Errorf("image not found: %s", c.Request().URL.Path) } - return ErrorPage(ctxt, err) + return c.String(http.StatusNotFound, err.Error()) } /* AmProcessUploadedImage takes an image and resizes it to a specified size, returning its data. diff --git a/ui/middleware.go b/ui/middleware.go index 91f0176..c8b4c0d 100644 --- a/ui/middleware.go +++ b/ui/middleware.go @@ -12,8 +12,10 @@ package ui import ( "errors" + "fmt" "net/http" "net/url" + "strconv" "git.erbosoft.com/amy/amsterdam/config" "git.erbosoft.com/amy/amsterdam/database" @@ -119,6 +121,7 @@ func ValidateConference(next echo.HandlerFunc) echo.HandlerFunc { } } +// SetConference is middleware that sets the conference context based on the URL. func SetConference(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { ctxt := AmContextFromEchoContext(c) @@ -140,3 +143,22 @@ func SetConference(next echo.HandlerFunc) echo.HandlerFunc { return next(c) } } + +// SetTopic is middleware that sets the topic context based on the URL. +func SetTopic(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + ctxt := AmContextFromEchoContext(c) + conf := ctxt.GetScratch("currentConference").(*database.Conference) + + var topic *database.Topic = nil + if rawTopic, err := strconv.ParseInt(ctxt.URLParam("topic"), 10, 16); err == nil { + topic, err = database.AmGetTopicByNumber(ctxt.Ctx(), conf, int16(rawTopic)) + } + if topic == nil { + ctxt.SetRC(http.StatusNotFound) + return middlewareErrorPage(c, ctxt, fmt.Errorf("topic not found: %s", ctxt.URLParam("topic"))) + } + ctxt.SetScratch("currentTopic", topic) + return next(c) + } +}