diff --git a/backend/blog.go b/backend/blog.go index a2d9e7f..59ae230 100644 --- a/backend/blog.go +++ b/backend/blog.go @@ -322,3 +322,44 @@ func (h *ApiHandler) ServeBlogPostUnpublish(writer http.ResponseWriter, request WriteResponse(writer, http.StatusOK, map[string]interface{}{}) } + +func (h *ApiHandler) ServeBlogTagsGet(writer http.ResponseWriter, request *http.Request) { + query := request.URL.Query() + + var err error + var offset int + var limit int + + offsetStr := query.Get("offset") + if offsetStr == "" { + offset = 0 + } else { + offset, err = strconv.Atoi(offsetStr) + if err != nil || offset < 0 { + WriteError(writer, http.StatusBadRequest, "invalid offset", nil) + return + } + } + + limitStr := query.Get("limit") + if limitStr == "" { + limit = 50 + } else { + limit, err = strconv.Atoi(limitStr) + if err != nil || limit <= 0 || limit > 100 { + WriteError(writer, http.StatusBadRequest, "invalid limit", nil) + return + } + } + + tags, total, err := h.db.GetBlogTags(IsAuthorized(request), offset, limit) + if err != nil { + WriteError(writer, http.StatusInternalServerError, "failed to query database", err) + return + } + + WriteResponse(writer, http.StatusOK, map[string]interface{}{ + "tags": tags, + "total": total, + }) +} diff --git a/backend/db.go b/backend/db.go index 7967f04..8d2dfa5 100644 --- a/backend/db.go +++ b/backend/db.go @@ -322,6 +322,54 @@ func (db *Database) SetBlogArticleStatus(id int64, status ArticleStatus) error { return nil } +func (db *Database) GetBlogTags(showAll bool, offset int, limit int) ([]string, int64, error) { + filter := "" + filterArgs := make([]interface{}, 0) + + if !showAll { + filter = " WHERE blog_article.status = ?" + filterArgs = append(filterArgs, ArticleStatusPublished) + } + + args := make([]interface{}, 0, len(filterArgs)*2+2) + args = append(args, filterArgs...) + args = append(args, filterArgs...) + args = append(args, limit) + args = append(args, offset) + + joins := " INNER JOIN blog_article_to_tag ON blog_article_to_tag.tag_id = blog_tag.id" + + " INNER JOIN blog_article ON blog_article.id = blog_article_to_tag.article_id" + + rows, err := db.db.Query( + "SELECT blog_tag.name, (SELECT COUNT(*) FROM blog_tag"+joins+filter+") FROM blog_tag"+joins+filter+" LIMIT ? OFFSET ?", + args..., + ) + if err != nil { + return nil, 0, err + } + + tags := make([]string, 0) + total := int64(0) + + for rows.Next() { + var name string + err := rows.Scan(&name, &total) + if err != nil { + _ = rows.Close() + return nil, 0, err + } + + tags = append(tags, name) + } + + err = rows.Close() + if err != nil { + return nil, 0, err + } + + return tags, total, nil +} + func migrate(db *sql.DB, rootPassword string) error { tx, err := db.Begin() if err != nil { diff --git a/backend/main.go b/backend/main.go index e6998ef..53cddf4 100644 --- a/backend/main.go +++ b/backend/main.go @@ -50,6 +50,9 @@ func main() { mux.Handle("POST /api/blog/{id}/unpublish", apiHandler.ProcessAuth(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { apiHandler.ServeBlogPostUnpublish(writer, request) }), true)) + mux.Handle("GET /api/blog/tags", apiHandler.ProcessAuth(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + apiHandler.ServeBlogTagsGet(writer, request) + }), false)) mux.HandleFunc("POST /api/login", func(writer http.ResponseWriter, request *http.Request) { apiHandler.ServeLoginPost(writer, request) })