2020-04-29 17:44:29 -07:00
|
|
|
package building
|
|
|
|
|
|
|
|
import (
|
2020-06-06 09:28:45 -07:00
|
|
|
"errors"
|
2022-09-04 14:27:14 -07:00
|
|
|
"fmt"
|
2022-01-04 17:48:46 -08:00
|
|
|
"io"
|
2020-04-29 17:44:29 -07:00
|
|
|
"os"
|
|
|
|
"path"
|
2022-10-31 12:41:17 -07:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2020-04-29 17:44:29 -07:00
|
|
|
|
|
|
|
"github.com/gochan-org/gochan/pkg/config"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcsql"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gctemplates"
|
2022-09-04 14:27:14 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
2023-07-14 11:04:46 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
2023-01-06 14:38:35 -08:00
|
|
|
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
2020-04-29 17:44:29 -07:00
|
|
|
)
|
|
|
|
|
2022-10-31 12:41:17 -07:00
|
|
|
var (
|
|
|
|
bbcodeTagRE = regexp.MustCompile(`\[/?[^\[\]\s]+\]`)
|
|
|
|
)
|
|
|
|
|
2024-09-09 17:19:56 -07:00
|
|
|
type frontPagePost struct {
|
2022-10-31 12:41:17 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-09-09 17:19:56 -07:00
|
|
|
func getFrontPagePosts() ([]frontPagePost, error) {
|
2022-10-31 12:41:17 -07:00
|
|
|
siteCfg := config.GetSiteConfig()
|
2024-10-15 09:55:41 -07:00
|
|
|
var query string
|
|
|
|
|
|
|
|
if siteCfg.RecentPostsWithNoFile {
|
|
|
|
// get recent posts, including those with no file
|
|
|
|
query = "SELECT * FROM DBPREFIXv_front_page_posts"
|
|
|
|
} else {
|
|
|
|
query = "SELECT * FROM DBPREFIXv_front_page_posts_with_file"
|
2022-12-20 09:28:22 -08:00
|
|
|
}
|
2024-10-15 09:55:41 -07:00
|
|
|
query += " ORDER BY id DESC LIMIT " + strconv.Itoa(siteCfg.MaxRecentPosts)
|
2022-12-20 09:28:22 -08:00
|
|
|
|
2024-06-13 12:23:25 -07:00
|
|
|
rows, cancel, err := gcsql.QueryTimeoutSQL(nil, query)
|
|
|
|
defer cancel()
|
2022-10-31 12:41:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
2024-09-09 17:19:56 -07:00
|
|
|
var recentPosts []frontPagePost
|
2022-10-31 12:41:17 -07:00
|
|
|
for rows.Next() {
|
2024-09-09 17:19:56 -07:00
|
|
|
var post frontPagePost
|
2022-12-13 16:23:16 -08:00
|
|
|
var id, topPostID string
|
2022-12-17 17:38:56 -08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
message = bbcodeTagRE.ReplaceAllString(message, "")
|
|
|
|
if len(message) > 40 {
|
|
|
|
message = message[:37] + "..."
|
|
|
|
}
|
2023-07-14 11:04:46 -07:00
|
|
|
thumbnail, _ := uploads.GetThumbnailFilenames(filename)
|
2024-09-09 17:19:56 -07:00
|
|
|
post = frontPagePost{
|
2022-10-31 12:41:17 -07:00
|
|
|
Board: boardDir,
|
|
|
|
URL: config.WebPath(boardDir, "res", topPostID+".html") + "#" + id,
|
2023-07-14 11:04:46 -07:00
|
|
|
ThumbURL: config.WebPath(boardDir, "thumb", thumbnail),
|
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)
|
|
|
|
}
|
2024-06-13 12:23:25 -07:00
|
|
|
return recentPosts, rows.Close()
|
2022-10-31 12:41:17 -07:00
|
|
|
}
|
|
|
|
|
2020-04-29 17:44:29 -07:00
|
|
|
// BuildFrontPage builds the front page using templates/front.html
|
2020-06-06 09:28:45 -07:00
|
|
|
func BuildFrontPage() error {
|
2022-12-13 12:44:16 -08:00
|
|
|
errEv := gcutil.LogError(nil).
|
|
|
|
Str("template", "front")
|
|
|
|
defer errEv.Discard()
|
2023-12-19 13:32:25 -08:00
|
|
|
err := gctemplates.InitTemplates(gctemplates.FrontPage)
|
2020-04-29 17:44:29 -07:00
|
|
|
if err != nil {
|
2022-12-13 12:44:16 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
2022-09-04 14:27:14 -07:00
|
|
|
return errors.New("Error loading front page template: " + err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
2021-07-11 11:51:29 -07:00
|
|
|
criticalCfg := config.GetSystemCriticalConfig()
|
2024-05-17 10:57:23 -07:00
|
|
|
frontFile, err := os.OpenFile(path.Join(criticalCfg.DocumentRoot, "index.html"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, config.NormalFileMode)
|
2020-06-06 09:28:45 -07:00
|
|
|
if err != nil {
|
2022-12-13 12:44:16 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
2022-09-04 14:27:14 -07:00
|
|
|
return errors.New("Failed opening front page for writing: " + err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2022-12-31 01:51:14 -08:00
|
|
|
if err = config.TakeOwnershipOfFile(frontFile); err != nil {
|
|
|
|
errEv.Err(err).Caller().Send()
|
|
|
|
return errors.New("Failed setting file ownership for front page: " + err.Error())
|
|
|
|
}
|
|
|
|
|
2024-09-09 17:19:56 -07:00
|
|
|
var recentPostsArr []frontPagePost
|
2021-07-11 16:30:39 -07:00
|
|
|
siteCfg := config.GetSiteConfig()
|
2024-09-09 17:19:56 -07:00
|
|
|
recentPostsArr, err = getFrontPagePosts()
|
2020-05-23 19:40:29 +02:00
|
|
|
if err != nil {
|
2022-12-13 12:44:16 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
2022-09-04 14:27:14 -07:00
|
|
|
return errors.New("Failed loading recent posts: " + err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
2021-03-25 14:42:46 -07:00
|
|
|
if err = serverutil.MinifyTemplate(gctemplates.FrontPage, map[string]interface{}{
|
2022-12-22 12:58:18 -08:00
|
|
|
"siteConfig": siteCfg,
|
|
|
|
"sections": gcsql.AllSections,
|
|
|
|
"boards": gcsql.AllBoards,
|
|
|
|
"boardConfig": config.GetBoardConfig(""),
|
|
|
|
"recentPosts": recentPostsArr,
|
2020-04-29 17:44:29 -07:00
|
|
|
}, frontFile, "text/html"); err != nil {
|
2022-12-13 12:44:16 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
2022-09-04 14:27:14 -07:00
|
|
|
return errors.New("Failed executing front page template: " + err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
2024-02-06 12:30:18 -08:00
|
|
|
return frontFile.Close()
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2022-01-04 17:48:46 -08:00
|
|
|
// 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{}{
|
2022-12-22 12:58:18 -08:00
|
|
|
"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")
|
2022-01-04 17:48:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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,
|
2023-01-04 23:13:59 -08:00
|
|
|
map[string]interface{}{}, writer, "text/html")
|
2022-01-04 17:48:46 -08:00
|
|
|
}
|
|
|
|
|
2020-07-27 18:19:56 -07:00
|
|
|
// BuildJS minifies (if enabled) consts.js, which is built from a template
|
2020-06-06 09:28:45 -07:00
|
|
|
func BuildJS() error {
|
2020-04-29 17:44:29 -07:00
|
|
|
// build consts.js from template
|
2023-12-19 13:32:25 -08:00
|
|
|
err := gctemplates.InitTemplates(gctemplates.JsConsts)
|
2022-12-31 01:51:14 -08:00
|
|
|
errEv := gcutil.LogError(nil).Str("building", "consts.js")
|
|
|
|
defer errEv.Discard()
|
2020-07-27 18:19:56 -07:00
|
|
|
if err != nil {
|
2022-12-31 01:51:14 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
2022-09-04 14:27:14 -07:00
|
|
|
return errors.New("Error loading consts.js template:" + err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
2021-07-11 16:30:39 -07:00
|
|
|
|
|
|
|
boardCfg := config.GetBoardConfig("")
|
|
|
|
criticalCfg := config.GetSystemCriticalConfig()
|
|
|
|
constsJSPath := path.Join(criticalCfg.DocumentRoot, "js", "consts.js")
|
2024-05-17 10:57:23 -07:00
|
|
|
constsJSFile, err := os.OpenFile(constsJSPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, config.NormalFileMode)
|
2020-06-06 09:28:45 -07:00
|
|
|
if err != nil {
|
2022-12-31 01:51:14 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
|
|
|
return fmt.Errorf("error opening consts.js for writing: %s", err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2022-12-31 01:51:14 -08:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
|
2023-06-16 08:42:17 -07:00
|
|
|
if err = serverutil.MinifyTemplate(gctemplates.JsConsts, map[string]any{
|
|
|
|
"styles": boardCfg.Styles,
|
|
|
|
"defaultStyle": boardCfg.DefaultStyle,
|
|
|
|
"webroot": criticalCfg.WebRoot,
|
|
|
|
"timezone": criticalCfg.TimeZone,
|
2024-08-03 17:05:55 -07:00
|
|
|
"fileTypes": boardCfg.AllowOtherExtensions,
|
2023-06-16 08:42:17 -07:00
|
|
|
}, constsJSFile, "text/javascript"); err != nil {
|
2022-12-31 01:51:14 -08:00
|
|
|
errEv.Err(err).Caller().Send()
|
|
|
|
return fmt.Errorf("error building consts.js: %s", err.Error())
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
2024-02-06 12:30:18 -08:00
|
|
|
return constsJSFile.Close()
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|