1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-18 07:36:24 -07:00
gochan/pkg/building/threads.go
2023-01-06 14:38:35 -08:00

143 lines
4.5 KiB
Go

package building
import (
"encoding/json"
"errors"
"fmt"
"os"
"path"
"strconv"
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/server/serverutil"
)
// BuildThreads builds thread(s) given a boardid, or if all = false, also given a threadid.
// if all is set to true, ignore which, otherwise, which = build only specified boardid
// TODO: make it variadic
func BuildThreads(all bool, boardid, threadid int) error {
var threads []gcsql.Post
var err error
if all {
threads, err = gcsql.GetBoardTopPosts(boardid)
} else {
var post *gcsql.Post
post, err = gcsql.GetThreadTopPost(threadid)
threads = []gcsql.Post{*post}
}
if err != nil {
return err
}
for t := range threads {
op := &threads[t]
if err = BuildThreadPages(op); err != nil {
return err
}
}
return nil
}
// BuildThreadPages builds the pages for a thread given the top post. It fails if op is not the top post
func BuildThreadPages(op *gcsql.Post) error {
errEv := gcutil.LogError(nil).
Str("building", "thread").
Int("postid", op.ID).
Int("threadid", op.ThreadID)
defer errEv.Discard()
if !op.IsTopPost {
errEv.Caller().Msg("non-OP passed to BuildThreadPages")
return gcsql.ErrNotTopPost
}
err := gctemplates.InitTemplates("threadpage")
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
var threadPageFile *os.File
board, err := op.GetBoard()
if err != nil {
errEv.Err(err).
Caller().Msg("failed building thread")
return errors.New("failed building thread: " + err.Error())
}
errEv.Str("boardDir", board.Dir)
thread, err := gcsql.GetThread(op.ThreadID)
if err != nil {
errEv.Err(err).
Caller().Msg("Unable to get thread info")
return errors.New("unable to get thread info: " + err.Error())
}
posts, err := getThreadPosts(thread)
if err != nil {
errEv.Err(err).Caller().Send()
return errors.New("failed building thread: " + err.Error())
}
criticalCfg := config.GetSystemCriticalConfig()
os.Remove(path.Join(criticalCfg.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html"))
os.Remove(path.Join(criticalCfg.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".json"))
threadPageFilepath := path.Join(criticalCfg.DocumentRoot, board.Dir, "res", strconv.Itoa(op.ID)+".html")
threadPageFile, err = os.OpenFile(threadPageFilepath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, config.GC_FILE_MODE)
if err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("unable to open /%s/res/%d.html: %s", board.Dir, op.ID, err.Error())
}
defer threadPageFile.Close()
if err = config.TakeOwnershipOfFile(threadPageFile); err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("unable to set file permissions for /%s/res/%d.html: %s", board.Dir, op.ID, err.Error())
}
errEv.Int("op", posts[0].ID)
// render thread page
captchaCfg := config.GetSiteConfig().Captcha
if err = serverutil.MinifyTemplate(gctemplates.ThreadPage, map[string]interface{}{
"boards": gcsql.AllBoards,
"board": board,
"boardConfig": config.GetBoardConfig(board.Dir),
"sections": gcsql.AllSections,
"posts": posts[1:],
"op": posts[0],
"useCaptcha": captchaCfg.UseCaptcha() && !captchaCfg.OnlyNeededForThreads,
"captcha": captchaCfg,
}, threadPageFile, "text/html"); err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("failed building /%s/res/%d threadpage: %s", board.Dir, posts[0].ID, err.Error())
}
// Put together the thread JSON
threadJSONFile, err := os.OpenFile(
path.Join(criticalCfg.DocumentRoot, board.Dir, "res", strconv.Itoa(posts[0].ID)+".json"),
os.O_CREATE|os.O_RDWR|os.O_TRUNC, config.GC_FILE_MODE)
if err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("failed opening /%s/res/%d.json: %s", board.Dir, posts[0].ID, err.Error())
}
defer threadJSONFile.Close()
if err = config.TakeOwnershipOfFile(threadJSONFile); err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("failed setting file permissions for /%s/res/%d.json: %s", board.Dir, posts[0].ID, err.Error())
}
threadMap := make(map[string][]Post)
threadMap["posts"] = posts
threadJSON, err := json.Marshal(threadMap)
if err != nil {
gcutil.LogError(err).Send()
return errors.New("failed to marshal to JSON: " + err.Error())
}
if _, err = threadJSONFile.Write(threadJSON); err != nil {
errEv.Err(err).
Caller().Send()
return fmt.Errorf("failed writing /%s/res/%d.json: %s", board.Dir, posts[0].ID, err.Error())
}
return nil
}