Blog search function
This commit is contained in:
parent
898f82fb79
commit
ede472a128
|
@ -2,27 +2,35 @@ package controllers
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"git.kirsle.net/apps/gophertype/pkg/models"
|
||||
"git.kirsle.net/apps/gophertype/pkg/responses"
|
||||
"git.kirsle.net/apps/gophertype/pkg/session"
|
||||
)
|
||||
|
||||
// BlogSearch at "/blog/search" for searching blog entries.
|
||||
func BlogSearch(w http.ResponseWriter, r *http.Request) {
|
||||
// var (
|
||||
// query = r.FormValue("q")
|
||||
// pageStr = r.FormValue("page")
|
||||
// page int
|
||||
// )
|
||||
var (
|
||||
query = r.FormValue("q")
|
||||
pageStr = r.FormValue("page")
|
||||
page int
|
||||
)
|
||||
|
||||
// if a, err := strconv.Atoi(pageStr); err == nil {
|
||||
// page = a
|
||||
// }
|
||||
if a, err := strconv.Atoi(pageStr); err == nil {
|
||||
page = a
|
||||
}
|
||||
|
||||
// pp, err := models.Posts.SearchPosts(query, page, 20)
|
||||
pp, err := models.Posts.SearchPosts(query, page, 24)
|
||||
if err != nil {
|
||||
session.FlashError(w, r, "Error searching posts: %s", err)
|
||||
responses.Redirect(w, r, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// v := responses.NewTemplateVars(w, r)
|
||||
// v.V["post"] = post
|
||||
v := responses.NewTemplateVars(w, r)
|
||||
v.V["posts"] = pp
|
||||
v.V["search"] = query
|
||||
|
||||
// // Render the body.
|
||||
// v.V["rendered"] = post.HTML()
|
||||
|
||||
// responses.RenderTemplate(w, r, "_builtin/blog/view-post.gohtml", v)
|
||||
responses.RenderTemplate(w, r, "_builtin/blog/search.gohtml", v)
|
||||
}
|
||||
|
|
|
@ -144,6 +144,50 @@ func (m postMan) GetIndexPosts(privacy string, page, perPage int) (PagedPosts, e
|
|||
return pp, r.Error
|
||||
}
|
||||
|
||||
// SearchPosts does a full text search over posts (public only).
|
||||
func (m postMan) SearchPosts(search string, page, perPage int) (PagedPosts, error) {
|
||||
var pp = PagedPosts{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
}
|
||||
|
||||
if pp.Page < 1 {
|
||||
pp.Page = 1
|
||||
}
|
||||
if pp.PerPage <= 0 {
|
||||
pp.PerPage = 20
|
||||
}
|
||||
|
||||
var like = fmt.Sprintf("%%%s%%", search)
|
||||
|
||||
query := DB.Preload("Author").Preload("Tags").
|
||||
Where("privacy = 'public' AND body ILIKE ?", like).
|
||||
Order("sticky desc, created_at desc")
|
||||
|
||||
// Count the total number of rows for paging purposes.
|
||||
query.Model(&Post{}).Count(&pp.Total)
|
||||
|
||||
// Query the paginated slice of results.
|
||||
r := query.
|
||||
Offset((pp.Page - 1) * pp.PerPage).
|
||||
Limit(pp.PerPage).
|
||||
Find(&pp.Posts)
|
||||
|
||||
pp.Pages = int(math.Ceil(float64(pp.Total) / float64(pp.PerPage)))
|
||||
if pp.Page < pp.Pages {
|
||||
pp.NextPage = pp.Page + 1
|
||||
}
|
||||
if pp.Page > 1 {
|
||||
pp.PreviousPage = pp.Page - 1
|
||||
}
|
||||
|
||||
if err := pp.CountComments(); err != nil {
|
||||
console.Error("PagedPosts.CountComments: %s", err)
|
||||
}
|
||||
|
||||
return pp, r.Error
|
||||
}
|
||||
|
||||
// GetPostsByTag gets posts by a certain tag.
|
||||
func (m postMan) GetPostsByTag(tag, privacy string, page, perPage int) (PagedPosts, error) {
|
||||
var pp = PagedPosts{
|
||||
|
|
84
pvt-www/_builtin/blog/search.gohtml
Normal file
84
pvt-www/_builtin/blog/search.gohtml
Normal file
|
@ -0,0 +1,84 @@
|
|||
{{ define "title" }}Search Results: {{.V.search}}{{ end }}
|
||||
{{ define "content" }}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1>Search Results</h1>
|
||||
|
||||
{{ $Pager := .V.posts }}
|
||||
|
||||
<p>
|
||||
<em>{{ $Pager.Total}} results found for:</em> {{.V.search}}
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8">
|
||||
<span class="tag is-secondary" title="{{ $Pager.Total }} total posts">
|
||||
Page {{ $Pager.Page }} of {{ $Pager.Pages }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
{{ if $Pager.PreviousPage }}
|
||||
<a href="?q={{ .V.search }}&page={{ $Pager.PreviousPage }}" class="button has-text-dark is-small is-light">Previous</a>
|
||||
{{ end }}
|
||||
{{ if $Pager.NextPage }}
|
||||
<a href="?q={{ .V.search }}&page={{ $Pager.NextPage }}" class="button has-text-dark is-small is-primary">Next page</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns is-multiline">
|
||||
{{ range .V.posts.Posts }}
|
||||
<div class="column is-one-quarter mb-4">
|
||||
<div class="card" title="{{ .Title }}">
|
||||
<div class="card-image">
|
||||
<figure class="image is-4by3">
|
||||
{{ if .Thumbnail }}
|
||||
<a href="/{{ .Fragment }}">
|
||||
<img src="/static.thumb{{ .Thumbnail }}"
|
||||
style="object-fit: cover"
|
||||
loading="lazy">
|
||||
</a>
|
||||
{{ else }}
|
||||
<div class="has-text-centered is-size-1 pt-6">
|
||||
<i class="fa fa-blog"></i>
|
||||
</div>
|
||||
{{ end }}
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content py-3 px-4">
|
||||
<a href="/{{ .Fragment }}">{{ .Title }}</a><br>
|
||||
<small class="blog-meta">
|
||||
{{ .CreatedAt.Format "Jan 02 2006" }}
|
||||
{{ if ne .Privacy "public" }}
|
||||
<span class="blog-{{ .Privacy }}">[{{ .Privacy }}]</span>
|
||||
{{ end }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<span class="tag is-secondary" title="{{ $Pager.Total }} total posts">
|
||||
Page {{ $Pager.Page }} of {{ $Pager.Pages }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="column is-narrow">
|
||||
{{ if $Pager.PreviousPage }}
|
||||
<a href="?q={{ .V.search }}&page={{ $Pager.PreviousPage }}" class="button has-text-dark is-small is-light">Previous</a>
|
||||
{{ end }}
|
||||
{{ if $Pager.NextPage }}
|
||||
<a href="?q={{ .V.search }}&page={{ $Pager.NextPage }}" class="button has-text-dark is-small is-primary">Next page</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ end }}
|
Loading…
Reference in New Issue
Block a user