1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-17 10:56:24 -07:00
gochan/pkg/building/building.go

202 lines
6 KiB
Go
Raw Normal View History

package building
import (
"errors"
"fmt"
"io"
"os"
"path"
2022-10-31 12:41:17 -07:00
"regexp"
"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/serverutil"
)
2022-10-31 12:41:17 -07:00
var (
bbcodeTagRE = regexp.MustCompile(`\[/?[^\[\]\s]+\]`)
)
type recentPost struct {
Board string
URL string
ThumbURL string
2022-12-21 15:34:22 -08:00
Filename string
2022-10-31 12:41:17 -07:00
FileDeleted bool
MessageSample string
}
func getRecentPosts() ([]recentPost, error) {
siteCfg := config.GetSiteConfig()
query := `SELECT
DBPREFIXposts.id,
DBPREFIXposts.message_raw,
(SELECT dir FROM DBPREFIXboards WHERE id = t.board_id) AS dir,
COALESCE(
(SELECT filename FROM DBPREFIXfiles WHERE DBPREFIXfiles.post_id = DBPREFIXposts.id`
if !siteCfg.RecentPostsWithNoFile {
query += ` AND filename != '' AND filename != 'deleted'`
}
query += ` ORDER BY DBPREFIXfiles.id DESC LIMIT 1), ''),
op.id
FROM
DBPREFIXposts
LEFT JOIN (
SELECT id, board_id FROM DBPREFIXthreads
) t ON t.id = DBPREFIXposts.thread_id
LEFT JOIN (
SELECT post_id, filename FROM DBPREFIXfiles
) f on f.post_id = DBPREFIXposts.id
INNER JOIN (
SELECT id, thread_id FROM DBPREFIXposts WHERE is_top_post
) op ON op.thread_id = DBPREFIXposts.thread_id
WHERE DBPREFIXposts.is_deleted = FALSE`
query += " LIMIT " + strconv.Itoa(siteCfg.MaxRecentPosts)
2022-10-31 12:41:17 -07:00
rows, err := gcsql.QuerySQL(query)
if err != nil {
return nil, err
}
defer rows.Close()
var recentPosts []recentPost
for rows.Next() {
var post recentPost
var id, topPostID string
var message, boardDir, filename string
err = rows.Scan(&id, &message, &boardDir, &filename, &topPostID)
2022-10-31 12:41:17 -07:00
if err != nil {
return nil, err
}
if filename == "" && !siteCfg.RecentPostsWithNoFile {
continue
}
message = bbcodeTagRE.ReplaceAllString(message, "")
if len(message) > 40 {
message = message[:37] + "..."
}
post = recentPost{
Board: boardDir,
URL: config.WebPath(boardDir, "res", topPostID+".html") + "#" + id,
ThumbURL: config.WebPath(boardDir, "thumb", gcutil.GetThumbnailPath("post", filename)),
2022-12-21 15:34:22 -08:00
Filename: filename,
2022-10-31 12:41:17 -07:00
FileDeleted: filename == "deleted",
MessageSample: message,
}
recentPosts = append(recentPosts, post)
}
return recentPosts, nil
}
// BuildFrontPage builds the front page using templates/front.html
func BuildFrontPage() error {
errEv := gcutil.LogError(nil).
Str("template", "front")
defer errEv.Discard()
err := gctemplates.InitTemplates("front")
if err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Error loading front page template: " + err.Error())
}
criticalCfg := config.GetSystemCriticalConfig()
os.Remove(path.Join(criticalCfg.DocumentRoot, "index.html"))
2022-12-31 17:29:57 -08:00
frontFile, err := os.OpenFile(path.Join(criticalCfg.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, config.GC_FILE_MODE)
if err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Failed opening front page for writing: " + err.Error())
}
defer frontFile.Close()
if err = config.TakeOwnershipOfFile(frontFile); err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Failed setting file ownership for front page: " + err.Error())
}
2022-10-31 12:41:17 -07:00
var recentPostsArr []recentPost
siteCfg := config.GetSiteConfig()
2022-10-31 12:41:17 -07:00
recentPostsArr, err = getRecentPosts()
2020-05-23 19:40:29 +02:00
if err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Failed loading recent posts: " + err.Error())
}
if err = serverutil.MinifyTemplate(gctemplates.FrontPage, map[string]interface{}{
"siteConfig": siteCfg,
"sections": gcsql.AllSections,
"boards": gcsql.AllBoards,
"boardConfig": config.GetBoardConfig(""),
"recentPosts": recentPostsArr,
}, frontFile, "text/html"); err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Failed executing front page template: " + err.Error())
}
return nil
}
// BuildPageHeader is a convenience function for automatically generating the top part
// of every normal HTML page
2022-08-01 16:08:57 -07:00
func BuildPageHeader(writer io.Writer, pageTitle string, board string, misc map[string]interface{}) error {
phMap := map[string]interface{}{
"pageTitle": pageTitle,
"siteConfig": config.GetSiteConfig(),
"sections": gcsql.AllSections,
"boards": gcsql.AllBoards,
"boardConfig": config.GetBoardConfig(board),
2022-08-01 16:08:57 -07:00
}
for k, val := range misc {
phMap[k] = val
}
return serverutil.MinifyTemplate(gctemplates.PageHeader, phMap, writer, "text/html")
}
// BuildPageFooter is a convenience function for automatically generating the bottom
// of every normal HTML page
func BuildPageFooter(writer io.Writer) (err error) {
return serverutil.MinifyTemplate(gctemplates.PageFooter,
map[string]interface{}{}, writer, "text/html")
}
// BuildJS minifies (if enabled) consts.js, which is built from a template
func BuildJS() error {
// build consts.js from template
err := gctemplates.InitTemplates("js")
errEv := gcutil.LogError(nil).Str("building", "consts.js")
defer errEv.Discard()
if err != nil {
errEv.Err(err).Caller().Send()
return errors.New("Error loading consts.js template:" + err.Error())
}
boardCfg := config.GetBoardConfig("")
criticalCfg := config.GetSystemCriticalConfig()
constsJSPath := path.Join(criticalCfg.DocumentRoot, "js", "consts.js")
2022-12-31 17:29:57 -08:00
constsJSFile, err := os.OpenFile(constsJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, config.GC_FILE_MODE)
if err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("error opening consts.js for writing: %s", err.Error())
}
defer constsJSFile.Close()
if err = config.TakeOwnershipOfFile(constsJSFile); err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("unable to update file ownership for consts.js: %s", err.Error())
}
if err = serverutil.MinifyTemplate(gctemplates.JsConsts,
map[string]interface{}{
"styles": boardCfg.Styles,
"defaultStyle": boardCfg.DefaultStyle,
"timezone": criticalCfg.TimeZone,
},
constsJSFile, "text/javascript"); err != nil {
errEv.Err(err).Caller().Send()
return fmt.Errorf("error building consts.js: %s", err.Error())
}
return nil
}