Skip to content

Commit

Permalink
Merge pull request #5 from jesusangelm/pagination_and_some_improvements
Browse files Browse the repository at this point in the history
add basic pagination
  • Loading branch information
jesusangelm authored Jan 22, 2024
2 parents 0b2d86d + cfa79fc commit e9e3176
Show file tree
Hide file tree
Showing 12 changed files with 455 additions and 149 deletions.
92 changes: 92 additions & 0 deletions cmd/web/categories_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package main

import (
"errors"
"net/http"
"strconv"

"github.com/julienschmidt/httprouter"
"jesusmarin.dev/galeria/internal/data"
"jesusmarin.dev/galeria/internal/validator"
)

// home handler for root route
func (app *application) listCategories(w http.ResponseWriter, r *http.Request) {
var input struct {
Name string
data.Filters
}

v := validator.New()
qs := r.URL.Query() // To get filter parameters from the QueryString

input.Name = app.readString(qs, "name", "")
input.Filters.Page = app.readInt(qs, "page", 1, v)
input.Filters.PageSize = app.readInt(qs, "page_size", 6, v)
input.Filters.Sort = app.readString(qs, "sort", "-created_at")
input.Filters.SortSafeList = []string{
"id", "name", "created_at", "-id", "-name", "-created_at",
}

if data.ValidateFilters(v, input.Filters); !v.Valid() {
app.notFound(w)
return
}

categories, metadata, err := app.models.Categories.List(input.Name, input.Filters)
if err != nil {
app.serverError(w, err)
}

templatedata := app.newTemplateData(r)
templatedata.Categories = categories
templatedata.Metadata = metadata

app.render(w, http.StatusOK, "home.tmpl", templatedata)
}

func (app *application) categoryShow(w http.ResponseWriter, r *http.Request) {
var input struct {
Name string
data.Filters
}

v := validator.New()
qs := r.URL.Query() // To get filter parameters from the QueryString

input.Filters.Page = app.readInt(qs, "page", 1, v)
input.Filters.PageSize = app.readInt(qs, "page_size", 6, v)
input.Filters.Sort = app.readString(qs, "sort", "-created_at")
input.Filters.SortSafeList = []string{
"id", "name", "created_at", "-id", "-name", "-created_at",
}

if data.ValidateFilters(v, input.Filters); !v.Valid() {
app.notFound(w)
return
}

params := httprouter.ParamsFromContext(r.Context())

id, err := strconv.Atoi(params.ByName("id"))
if err != nil || id < 1 {
app.notFound(w)
return
}

category, metadata, err := app.models.Categories.Get(int64(id), input.Filters)
if err != nil {
if errors.Is(err, data.ErrRecordNotFound) {
app.notFound(w)
} else {
app.serverError(w, err)
}
return
}

data := app.newTemplateData(r)
data.Category = category
data.Metadata = metadata

app.render(w, http.StatusOK, "category_view.tmpl", data)
}
108 changes: 0 additions & 108 deletions cmd/web/handlers.go

This file was deleted.

41 changes: 41 additions & 0 deletions cmd/web/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import (
"bytes"
"fmt"
"net/http"
"net/url"
"runtime/debug"
"strconv"
"strings"
"time"

"jesusmarin.dev/galeria/internal/validator"
)

// Helper that write an error message and stack trace to the errorLog.
Expand Down Expand Up @@ -63,3 +68,39 @@ func (app *application) render(w http.ResponseWriter, status int, page string, d

buf.WriteTo(w)
}

func (app *application) readString(qs url.Values, key string, defaultValue string) string {
s := qs.Get(key)

if s == "" {
return defaultValue
}

return s
}

func (app *application) readCSV(qs url.Values, key string, defaultValue []string) []string {
csv := qs.Get(key)

if csv == "" {
return defaultValue
}

return strings.Split(csv, ",")
}

func (app *application) readInt(qs url.Values, key string, defaultValue int, v *validator.Validator) int {
s := qs.Get(key)

if s == "" {
return defaultValue
}

i, err := strconv.Atoi(s)
if err != nil {
v.AddError(key, "must be an integer value")
return defaultValue
}

return i
}
42 changes: 42 additions & 0 deletions cmd/web/images_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"io"
"log"
"net/http"

"github.com/julienschmidt/httprouter"
)

func (app *application) images(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())

key := params.ByName("key")
if key == "" {
app.notFound(w)
return
}

imageUrl := app.s3Manager.GetFileUrl(key)

resp, err := http.Get(imageUrl)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
app.notFound(w)
return
}

contentType := resp.Header.Get("Content-Type")

w.Header().Set("Content-Type", contentType)
w.Header().Set("Cache-Control", "max-age=3155695200, public")
_, err = io.Copy(w, resp.Body)
if err != nil {
log.Fatal(err)
app.serverError(w, err)
}
}
35 changes: 35 additions & 0 deletions cmd/web/items_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"errors"
"net/http"
"strconv"

"github.com/julienschmidt/httprouter"
"jesusmarin.dev/galeria/internal/data"
)

func (app *application) itemShow(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())

id, err := strconv.Atoi(params.ByName("id"))
if err != nil || id < 1 {
app.notFound(w)
return
}

item, err := app.models.Items.Get(int64(id))
if err != nil {
if errors.Is(err, data.ErrRecordNotFound) {
app.notFound(w)
} else {
app.serverError(w, err)
}
return
}

data := app.newTemplateData(r)
data.Item = item

app.render(w, http.StatusOK, "item_view.tmpl", data)
}
2 changes: 1 addition & 1 deletion cmd/web/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func (app *application) routes() http.Handler {
router.HandlerFunc(http.MethodGet, "/images/:key", app.images)

// Routes definition
router.HandlerFunc(http.MethodGet, "/", app.home)
router.HandlerFunc(http.MethodGet, "/", app.listCategories)
router.HandlerFunc(http.MethodGet, "/category/:id", app.categoryShow)
router.HandlerFunc(http.MethodGet, "/item/:id", app.itemShow)

Expand Down
11 changes: 11 additions & 0 deletions cmd/web/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type templateData struct {
Categories []*data.Category
Item *data.Item
Items []*data.Item
Metadata data.Metadata
}

// Create a humanDate function which returns a nicely formatted string
Expand All @@ -26,11 +27,21 @@ func humanDate(t time.Time) string {
return t.Format("02 jan 2006 at 15:04")
}

func add(a, b int) int {
return a + b
}

func sust(a, b int) int {
return a - b
}

// Initialize a template.FuncMap object and store it in a global variable. This is
// essentially a string-keyed map which acts as a lookup between the names of our
// custom template functions and the functions themselves.
var functions = template.FuncMap{
"humanDate": humanDate,
"add": add,
"sust": sust,
}

// function for read and copy all .tmpl templates in a map variable stored in memory.
Expand Down
Loading

0 comments on commit e9e3176

Please sign in to comment.