GoBlog/reactions.go

106 lines
2.7 KiB
Go

package main
import (
"encoding/json"
"errors"
"net/http"
"github.com/samber/lo"
"go.goblog.app/app/pkgs/bufferpool"
"go.goblog.app/app/pkgs/contenttype"
)
// Hardcoded for now
var allowedReactions = []string{
"❤️",
"👍",
"🎉",
"😂",
"😱",
}
func (a *goBlog) reactionsEnabled() bool {
return a.cfg.Reactions != nil && a.cfg.Reactions.Enabled
}
const reactionsPostParam = "reactions"
func (a *goBlog) reactionsEnabledForPost(post *post) bool {
return a.reactionsEnabled() && post != nil && post.firstParameter(reactionsPostParam) != "false"
}
func (a *goBlog) postReaction(w http.ResponseWriter, r *http.Request) {
path := r.FormValue("path")
reaction := r.FormValue("reaction")
if path == "" || reaction == "" {
a.serveError(w, r, "", http.StatusBadRequest)
return
}
err := a.saveReaction(reaction, path)
if err != nil {
a.serveError(w, r, "", http.StatusBadRequest)
return
}
}
func (a *goBlog) saveReaction(reaction, path string) error {
// Check if reaction is allowed
if !lo.Contains(allowedReactions, reaction) {
return errors.New("reaction not allowed")
}
// Insert reaction
_, err := a.db.exec("insert into reactions (path, reaction, count) values (?, ?, 1) on conflict (path, reaction) do update set count=count+1", path, reaction)
return err
}
func (a *goBlog) getReactions(w http.ResponseWriter, r *http.Request) {
path := r.FormValue("path")
reactions, err := a.getReactionsFromDatabase(path)
if err != nil {
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
buf := bufferpool.Get()
defer bufferpool.Put(buf)
err = json.NewEncoder(buf).Encode(reactions)
if err != nil {
a.serveError(w, r, "", http.StatusInternalServerError)
return
}
w.Header().Set(contentType, contenttype.JSONUTF8)
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
}
func (a *goBlog) getReactionsFromDatabase(path string) (map[string]int, error) {
sqlBuf := bufferpool.Get()
defer bufferpool.Put(sqlBuf)
sqlArgs := []any{}
sqlBuf.WriteString("select reaction, count from reactions where path=? and reaction in (")
sqlArgs = append(sqlArgs, path)
for i, reaction := range allowedReactions {
if i > 0 {
sqlBuf.WriteString(",")
}
sqlBuf.WriteString("?")
sqlArgs = append(sqlArgs, reaction)
}
sqlBuf.WriteString(") and path not in (select path from post_parameters where parameter=? and value=?)")
sqlArgs = append(sqlArgs, reactionsPostParam, "false")
rows, err := a.db.query(sqlBuf.String(), sqlArgs...)
if err != nil {
return nil, err
}
defer rows.Close()
reactions := map[string]int{}
for rows.Next() {
var reaction string
var count int
err = rows.Scan(&reaction, &count)
if err != nil {
return nil, err
}
reactions[reaction] = count
}
return reactions, nil
}