diff --git a/pkg/controllers/posts.go b/pkg/controllers/posts.go index 081ef6f..10016e4 100644 --- a/pkg/controllers/posts.go +++ b/pkg/controllers/posts.go @@ -26,6 +26,11 @@ func init() { Methods: []string{"GET"}, Handler: BlogIndex(models.Public, false), }) + glue.Register(glue.Endpoint{ + Path: "/tagged", + Methods: []string{"GET"}, + Handler: TagIndex, + }) glue.Register(glue.Endpoint{ Path: "/tagged/{tag}", Methods: []string{"GET"}, @@ -158,6 +163,18 @@ func PartialBlogIndex(r *http.Request, tag, privacy string) template.HTML { return template.HTML(html.String()) } +// TagIndex for "/tagged" to return all tags sorted by popularity. +func TagIndex(w http.ResponseWriter, r *http.Request) { + // If not logged in, only summarize public post tags. + var public = !authentication.LoggedIn(r) + + tags := models.SummarizeTags(public) + + v := responses.NewTemplateVars(w, r) + v.V["tags"] = tags + responses.RenderTemplate(w, r, "_builtin/blog/tags.gohtml", v) +} + // EditPost at "/blog/edit" func EditPost(w http.ResponseWriter, r *http.Request) { v := responses.NewTemplateVars(w, r) diff --git a/pkg/models/posts.go b/pkg/models/posts.go index fa1abb6..3497052 100644 --- a/pkg/models/posts.go +++ b/pkg/models/posts.go @@ -48,13 +48,6 @@ type PagedPosts struct { PreviousPage int } -// TaggedPost associates tags to their posts. -type TaggedPost struct { - ID uint `gorm:"primary_key"` - Tag string - PostID uint // foreign key to Post -} - // New creates a new Post model. func (m postMan) New() Post { return Post{ diff --git a/pkg/models/tags.go b/pkg/models/tags.go new file mode 100644 index 0000000..d5c7abb --- /dev/null +++ b/pkg/models/tags.go @@ -0,0 +1,57 @@ +package models + +import ( + "git.kirsle.net/apps/gophertype/pkg/console" +) + +// TaggedPost associates tags to their posts. +type TaggedPost struct { + ID uint `gorm:"primary_key"` + Tag string + PostID uint // foreign key to Post +} + +// SummarizeTags returns the list of all tags ordered by frequency used. +// public: true for public view, don't count tags on private posts. +func SummarizeTags(public bool) []TagSummary { + var result []TagSummary + + query := DB.Table("tagged_posts"). + Select("tagged_posts.tag, count(tagged_posts.post_id) AS count"). + Joins("JOIN posts ON posts.id = tagged_posts.post_id"). + Group("tagged_posts.tag"). + Order("count desc") + + if public { + query = query.Where("posts.privacy = ?", Public) + } + + rows, err := query.Rows() + if err != nil { + console.Error("SummarizeTags: query.Rows: %s", err) + } + + for rows.Next() { + var ( + tagName string + count int + ) + + if err := rows.Scan(&tagName, &count); err != nil { + console.Error("SummarizeTags: rows.Scan: %s", err) + } + + result = append(result, TagSummary{ + Tag: tagName, + Count: count, + }) + } + + return result +} + +// TagSummary holds the result for SummarizeTags +type TagSummary struct { + Tag string + Count int +} diff --git a/pvt-www/.layout.gohtml b/pvt-www/.layout.gohtml index bb53691..6ee4723 100644 --- a/pvt-www/.layout.gohtml +++ b/pvt-www/.layout.gohtml @@ -32,6 +32,9 @@
Sorted by most frequently used:
+ +