lessmore/node/ssr.go

278 lines
5.5 KiB
Go

package node
import (
"encoding/json"
"net/http"
"regexp"
"strings"
"time"
"strconv"
"gitea.difrex.ru/Umbrella/fetcher/i2es"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
)
const (
quotesRE = `^(\w+)?>(.*)$`
)
type ssr struct {
es ESConf
templatesDir string
}
func newSSR(templatesDir string, es ESConf) *ssr {
return &ssr{
es: es,
templatesDir: templatesDir,
}
}
type PageData struct {
Echoes []echo
CurrentPage string
PageNum int
Posts []i2es.ESDoc
ShowPaginator bool
}
func (p *PageData) GetDate(date string) string {
d, err := strconv.ParseInt(date, 0, 64)
if err != nil {
return err.Error()
}
return time.Unix(d, 0).UTC().Format("02 Jan 06 15:04 MST")
}
func (p *PageData) Inc() int {
return p.PageNum + 1
}
func (p *PageData) Dec() int {
return p.PageNum - 1
}
func (p *PageData) RenderMessage(message string) (msg string) {
return parseQuotes(message)
}
func parseQuotes(message string) string {
var parsed []string
r, err := regexp.Compile(quotesRE)
if err != nil {
log.Error(err)
return message
}
for _, line := range strings.Split(message, "\n") {
if r.MatchString(line) {
author := r.FindAllStringSubmatch(line, 1)
quote := "<figure class=\"text-end\"><blockquote class=\"blockquote quote\"><small>" + author[0][2] + "</small></blockquote>"
if len(author) > 0 && author[0][1] != "" {
quote += `<figcaption class="blockquote-footer">` + author[0][1] + `</figcaption>`
}
quote += "</figure>"
parsed = append(parsed, quote)
} else {
parsed = append(parsed, line)
}
}
return strings.Join(parsed, "\n")
}
func (s *ssr) newPageData(page string, posts []i2es.ESDoc, num int, showPaginator bool) *PageData {
return &PageData{
Echoes: s.es.GetEchoesList(),
Posts: posts,
CurrentPage: page,
PageNum: num,
ShowPaginator: showPaginator,
}
}
func (s *ssr) ssrRootHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("root")
if err != nil {
log.Error(err)
return
}
posts := s.es.GetLatestPosts(50)
for i := range posts {
posts[i].Message = parseQuotes(posts[i].Message)
}
if err := tpl.Execute(w, s.newPageData("feed", posts, 1, true)); err != nil {
log.Error(err)
}
}
func (s *ssr) ssrForumHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("forum")
if err != nil {
log.Error(err)
return
}
vars := mux.Vars(r)
var num int
if _, ok := vars["page"]; ok {
num = getPageNum(mux.Vars(r)["page"])
}
bcVal := r.URL.Query().Get("year")
bc, _ := strconv.ParseBool(bcVal)
if bc {
if err := tpl.Execute(w, s.newPageData("forum", s.es.GetThreadsYear(num), num, false)); err != nil {
log.Error(err)
}
return
}
if err := tpl.Execute(w, s.newPageData("forum", s.es.GetThreads(num), num, true)); err != nil {
log.Error(err)
}
}
func (s *ssr) threadViewHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("thread")
if err != nil {
log.Error(err)
return
}
topicid, ok := mux.Vars(r)["topicid"]
if !ok {
log.Warn("empty topicid")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("error: empty topicid"))
return
}
posts := s.es.GetTopic(topicid)
thread := "nil"
if len(posts) > 0 {
thread = posts[0].Subg
}
for i := range posts {
posts[i].Message = parseQuotes(posts[i].Message)
}
if err := tpl.Execute(w, s.newPageData(thread, posts, 1, true)); err != nil {
log.Error(err)
}
}
func getPageNum(page string) int {
i, err := strconv.ParseInt(page, 0, 64)
if err != nil {
log.Error(err)
return 1
}
if i < 1 {
return 1
}
return int(i)
}
func (s *ssr) echoViewHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("echo")
if err != nil {
log.Error(err)
return
}
vars := mux.Vars(r)
echo, ok := vars["echo"]
if !ok {
log.Warn("empty echo")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("error: empty echo"))
return
}
page := 1
if _, ok := vars["page"]; ok {
page = getPageNum(vars["page"])
}
bcVal := r.URL.Query().Get("year")
bc, _ := strconv.ParseBool(bcVal)
if bc {
if err := tpl.Execute(w, s.newPageData("forum", s.es.GetThreadsYear(page, echo), page, false)); err != nil {
log.Error(err)
}
return
}
if err := tpl.Execute(w, s.newPageData(echo, s.es.GetThreads(page, echo), page, true)); err != nil {
log.Error(err)
}
}
func (s *ssr) docsFormattingHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("docs_formatting")
if err != nil {
log.Error(err)
return
}
if err := tpl.Execute(w, s.newPageData("docs: formatting", nil, 1, false)); err != nil {
log.Error(err)
}
}
func (s *ssr) singleMessageHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("message")
if err != nil {
log.Error(err)
return
}
msgid, ok := mux.Vars(r)["msgid"]
if !ok {
log.Warn("empty msgid")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("error: empty msgid"))
return
}
if err := tpl.Execute(w, s.newPageData(msgid, s.es.GetMessage(msgid), 1, false)); err != nil {
log.Error(err)
}
}
func (s *ssr) searchHandler(w http.ResponseWriter, r *http.Request) {
tpl, err := s.getTemplate("search")
if err != nil {
log.Error(err)
return
}
q := r.URL.Query().Get("query")
if q != "" {
m, err := json.Marshal(q)
if err != nil {
log.Error(err)
m = []byte("")
}
posts := s.es.DoSearch(string(m))
for i := range posts {
posts[i].Date = parseTime(posts[i].Date)
}
if err := tpl.Execute(w, s.newPageData("search", posts, 1, false)); err != nil {
log.Error(err)
}
}
}