1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-19 08:26:23 -07:00

Refactor thread and post data structures to include IsSpoilered and update related queries and templates (still a WIP)

This commit is contained in:
Eggbertx 2025-04-21 17:10:42 -07:00
parent 6ba9b40894
commit 83f8601334
16 changed files with 63 additions and 60 deletions

View file

@ -41,7 +41,7 @@ func (*Pre2021Migrator) migratePost(tx *sql.Tx, post *migrationPost, errEv *zero
Locked: post.locked,
Stickied: post.stickied,
Anchored: post.autosage,
Cyclic: false,
Cyclical: false,
}
if post.oldParentID == 0 {
// migrating post was a thread OP, create the row in the threads table

View file

@ -4,7 +4,7 @@
"FirstPage": ["index.html","firstrun.html","1.html"],
"Username": "",
"UseFastCGI": false,
"DebugMode": false,
"LogLevel": "debug",
"DocumentRoot": "html",
"TemplateDir": "templates",

View file

@ -79,9 +79,10 @@ func BuildBoardPages(board *gcsql.Board, errEv *zerolog.Event) error {
postCfg := config.GetBoardConfig(board.Dir).PostConfig
for _, thread := range threads {
catalogThread := catalogThreadData{
Post: opMap[thread.ID],
Locked: boolToInt(thread.Locked),
Stickied: boolToInt(thread.Stickied),
Post: opMap[thread.ID],
Locked: boolToInt(thread.Locked),
Stickied: boolToInt(thread.Stickied),
IsSpoilered: boolToInt(thread.IsSpoilered),
}
errEv.Int("threadID", thread.ID)
if catalogThread.Images, err = thread.GetReplyFileCount(); err != nil {

View file

@ -19,6 +19,7 @@ type catalogThreadData struct {
OmittedPosts int `json:"omitted_posts"` // posts in the thread but not shown on the board page
OmittedImages int `json:"omitted_images"` // uploads in the thread but not shown on the board page
Stickied int `json:"sticky"`
IsSpoilered int `json:"spoilered"`
Locked int `json:"closed"`
Posts []*Post `json:"-"`
uploads []gcsql.Upload
@ -43,7 +44,7 @@ func (catalog *boardCatalog) fillPages(threadsPerPage int, threads []catalogThre
remainder := len(threads) % threadsPerPage
currentThreadIndex := 0
var i int
for i = 0; i < catalog.numPages; i++ {
for i = range catalog.numPages {
catalog.pages = append(catalog.pages,
catalogPage{
PageNum: i + 1,
@ -63,10 +64,7 @@ func (catalog *boardCatalog) fillPages(threadsPerPage int, threads []catalogThre
}
func getBoardTopPosts(board string) ([]*Post, error) {
const query = `SELECT id, thread_id, ip, name, tripcode, is_secure_tripcode, email, subject, created_on,
last_modified, parent_id, last_bump, message, message_raw, board_id, dir, original_filename, filename,
checksum, filesize, tw, th, width, height, locked, stickied, cyclical, flag, country, is_deleted
FROM DBPREFIXv_building_posts WHERE id = parent_id AND dir = ?`
const query = buildingPostsBaseQuery + "WHERE id = parent_id AND dir = ?"
var posts []*Post
err := QueryPosts(query, []any{board}, func(p *Post) error {

View file

@ -17,6 +17,13 @@ import (
"github.com/gochan-org/gochan/pkg/posting/uploads"
)
const (
buildingPostsBaseQuery = `SELECT id, thread_id, ip, name, tripcode, is_secure_tripcode, email, subject, created_on,
last_modified, parent_id, last_bump, message, message_raw, board_id, dir, original_filename, filename,
checksum, filesize, tw, th, width, height, spoiler_file, locked, stickied, cyclical, spoiler_thread, flag, country, is_deleted
FROM DBPREFIXv_building_posts `
)
func truncateString(msg string, limit int, ellipsis bool) string {
if len(msg) > limit {
if ellipsis {
@ -32,8 +39,8 @@ type PostUploadBase struct {
OriginalFilename string `json:"filename"`
ThumbnailWidth int `json:"tn_w"`
ThumbnailHeight int `json:"tn_h"`
uploadPath string
SpoilerFile int `json:"spoiler"`
uploadPath string
}
func (p *PostUploadBase) HasEmbed() bool {
@ -71,11 +78,12 @@ type Post struct {
BoardDir string `json:"-"`
IP net.IP `json:"-"`
PostUploadBase
Checksum string `json:"md5"`
Extension string `json:"extension"`
Filesize int `json:"fsize"`
UploadWidth int `json:"w"`
UploadHeight int `json:"h"`
Checksum string `json:"md5"`
Extension string `json:"extension"`
Filesize int `json:"fsize"`
UploadWidth int `json:"w"`
UploadHeight int `json:"h"`
LastModified string `json:"last_modified"`
Country geoip.Country `json:"-"`
thread gcsql.Thread
@ -169,7 +177,11 @@ func (p *Post) Stickied() bool {
}
func (p *Post) Cyclic() bool {
return p.thread.Cyclic
return p.thread.Cyclical
}
func (p *Post) SpoilerThread() bool {
return p.thread.IsSpoilered
}
// Select all from v_building_posts (and queries with the same columns) and call the callback function on each Post
@ -199,9 +211,9 @@ func QueryPosts(query string, params []any, cb func(*Post) error) error {
&post.Name, &post.Tripcode, &post.IsSecureTripcode, &post.Email, &post.Subject, &post.CreatedOn,
&post.LastModified, &post.ParentID, &lastBump, &post.Message, &post.MessageRaw, &post.BoardID,
&post.BoardDir, &post.OriginalFilename, &post.Filename, &post.Checksum, &post.Filesize,
&post.ThumbnailWidth, &post.ThumbnailHeight, &post.UploadWidth, &post.UploadHeight,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclic, &post.Country.Flag, &post.Country.Name,
&post.IsDeleted)
&post.ThumbnailWidth, &post.ThumbnailHeight, &post.UploadWidth, &post.UploadHeight, &post.SpoilerFile,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclical, &post.thread.IsSpoilered,
&post.Country.Flag, &post.Country.Name, &post.IsDeleted)
if err = rows.Scan(dest...); err != nil {
return err
@ -224,10 +236,7 @@ func QueryPosts(query string, params []any, cb func(*Post) error) error {
}
func GetBuildablePostsByIP(ip string, limit int) ([]*Post, error) {
query := `SELECT id, thread_id, ip, name, tripcode, is_secure_tripcode, email, subject, created_on, last_modified,
parent_id, last_bump, message, message_raw, board_id, dir, original_filename, filename, checksum, filesize,
tw, th, width, height, locked, stickied, cyclical, flag, country, is_deleted
FROM DBPREFIXv_building_posts WHERE ip = PARAM_ATON ORDER BY id DESC`
query := buildingPostsBaseQuery + "WHERE ip = PARAM_ATON ORDER BY id DESC"
if limit > 0 {
query += " LIMIT " + strconv.Itoa(limit)
}
@ -241,10 +250,7 @@ func GetBuildablePostsByIP(ip string, limit int) ([]*Post, error) {
}
func getThreadPosts(thread *gcsql.Thread) ([]*Post, error) {
const query = `SELECT id, thread_id, ip, name, tripcode, is_secure_tripcode, email, subject, created_on,
last_modified, parent_id, last_bump, message, message_raw, board_id, dir, original_filename, filename,
checksum, filesize, tw, th, width, height, locked, stickied, cyclical, flag, country, is_deleted
FROM DBPREFIXv_building_posts WHERE thread_id = ? ORDER BY id ASC`
const query = buildingPostsBaseQuery + "WHERE thread_id = ? ORDER BY id ASC"
var posts []*Post
err := QueryPosts(query, []any{thread.ID}, func(p *Post) error {
posts = append(posts, p)
@ -254,10 +260,7 @@ func getThreadPosts(thread *gcsql.Thread) ([]*Post, error) {
}
func GetRecentPosts(boardid int, limit int) ([]*Post, error) {
query := `SELECT id, thread_id, ip, name, tripcode, is_secure_tripcode, email, subject, created_on, last_modified,
parent_id, last_bump, message, message_raw, board_id, dir, original_filename, filename, checksum, filesize,
tw, th, width, height, locked, stickied, cyclical, flag, country, is_deleted
FROM DBPREFIXv_building_posts`
query := buildingPostsBaseQuery
var args []any
if boardid > 0 {

View file

@ -408,7 +408,7 @@ func (board *Board) GetThreads(onlyNotDeleted bool, orderLastByBump bool, sticki
var thread Thread
err = rows.Scan(
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored,
&thread.Cyclic, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclical, &thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
)
if err != nil {
return threads, err

View file

@ -422,20 +422,19 @@ func (p *Post) Insert(bumpThread bool, thread *Thread, force bool, requestOption
// already inserted
return ErrorPostAlreadySent
}
insertSQL := `INSERT INTO DBPREFIXposts
const insertSQL = `INSERT INTO DBPREFIXposts
(thread_id, is_top_post, ip, created_on, name, tripcode, is_secure_tripcode, is_role_signature, email, subject,
message, message_raw, password, flag, country)
VALUES(?,?,PARAM_ATON,CURRENT_TIMESTAMP,?,?,?,?,?,?,?,?,?,?,?)`
bumpSQL := `UPDATE DBPREFIXthreads SET last_bump = CURRENT_TIMESTAMP WHERE id = ?`
const bumpSQL = `UPDATE DBPREFIXthreads SET last_bump = CURRENT_TIMESTAMP WHERE id = ?`
if p.ThreadID == 0 {
// thread doesn't exist yet, this is a new post
p.IsTopPost = true
var threadID int
if err = CreateThread(opts, thread); err != nil {
return err
}
p.ThreadID = threadID
p.ThreadID = thread.ID
} else {
if !force {
var threadIsLocked bool

View file

@ -279,7 +279,7 @@ type Thread struct {
Locked bool // sql: locked
Stickied bool // sql: stickied
Anchored bool // sql: anchored
Cyclic bool // sql: cyclical
Cyclical bool // sql: cyclical
IsSpoilered bool // sql: is_spoilered
LastBump time.Time // sql: last_bump
DeletedAt time.Time // sql: deleted_at

View file

@ -9,7 +9,7 @@ import (
const (
selectThreadsBaseSQL = `SELECT
id, board_id, locked, stickied, anchored, cyclical, last_bump, deleted_at, is_deleted
id, board_id, locked, stickied, anchored, cyclical, is_spoilered, last_bump, deleted_at, is_deleted
FROM DBPREFIXthreads `
)
@ -22,7 +22,7 @@ var (
// CreateThread creates a new thread in the database with the given board ID and statuses
func CreateThread(requestOptions *RequestOptions, thread *Thread) (err error) {
const lockedQuery = `SELECT locked FROM DBPREFIXboards WHERE id = ?`
const insertQuery = `INSERT INTO DBPREFIXthreads (board_id, locked, stickied, anchored, cyclical) VALUES (?,?,?,?,?)`
const insertQuery = `INSERT INTO DBPREFIXthreads (board_id, locked, stickied, anchored, cyclical, is_spoilered) VALUES (?,?,?,?,?,?)`
var boardIsLocked bool
if err = QueryRow(requestOptions, lockedQuery, []any{&thread.BoardID}, []any{&boardIsLocked}); err != nil {
return err
@ -30,7 +30,7 @@ func CreateThread(requestOptions *RequestOptions, thread *Thread) (err error) {
if boardIsLocked {
return ErrBoardIsLocked
}
if _, err = Exec(requestOptions, insertQuery, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic); err != nil {
if _, err = Exec(requestOptions, insertQuery, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical, &thread.IsSpoilered); err != nil {
return err
}
return QueryRow(requestOptions, "SELECT MAX(id) FROM DBPREFIXthreads", nil, []any{&thread.ID})
@ -41,8 +41,8 @@ func GetThread(threadID int) (*Thread, error) {
const query = selectThreadsBaseSQL + `WHERE id = ?`
thread := new(Thread)
err := QueryRow(nil, query, []any{threadID}, []any{
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical,
&thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
return thread, err
}
@ -52,8 +52,8 @@ func GetPostThread(opID int) (*Thread, error) {
const query = selectThreadsBaseSQL + `WHERE id = (SELECT thread_id FROM DBPREFIXposts WHERE id = ? LIMIT 1)`
thread := new(Thread)
err := QueryRow(nil, query, []any{opID}, []any{
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical,
&thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
if errors.Is(err, sql.ErrNoRows) {
err = ErrThreadDoesNotExist
@ -90,7 +90,7 @@ func GetThreadsWithBoardID(boardID int, onlyNotDeleted bool) ([]Thread, error) {
var thread Thread
if err = rows.Scan(
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored,
&thread.Cyclic, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclical, &thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
); err != nil {
return threads, err
}
@ -217,7 +217,7 @@ func (t *Thread) UpdateAttribute(attribute string, value bool) error {
case "anchored":
t.Anchored = value
case "cyclic":
t.Cyclic = value
t.Cyclical = value
default:
return fmt.Errorf("invalid thread attribute %q", attribute)
}

View file

@ -456,11 +456,11 @@ func threadAttrsCallback(_ http.ResponseWriter, request *http.Request, _ *gcsql.
} else if request.FormValue("uncyclic") != "" {
attr = "cyclic"
newVal = false
doChange = thread.Cyclic != newVal
doChange = thread.Cyclical != newVal
} else if request.FormValue("cyclic") != "" {
attr = "cyclic"
newVal = true
doChange = thread.Cyclic != newVal
doChange = thread.Cyclical != newVal
}
if attr != "" && doChange {

View file

@ -36,7 +36,7 @@ COALESCE(f.thumbnail_width, 0) AS tw,
COALESCE(f.thumbnail_height, 0) AS th,
COALESCE(f.width, 0) AS width,
COALESCE(f.height, 0) AS height,
COALESCE(f.is_spoilered) AS spoiler_file,
COALESCE(f.is_spoilered, FALSE) AS spoiler_file,
t.locked, t.stickied, t.cyclical, t.is_spoilered as spoiler_thread, flag, country, p.is_deleted
FROM DBPREFIXposts p
LEFT JOIN DBPREFIXfiles f ON f.post_id = p.id AND p.is_deleted = FALSE
@ -70,7 +70,7 @@ SELECT DBPREFIXposts.id, DBPREFIXposts.message_raw,
(SELECT dir FROM DBPREFIXboards WHERE id = t.board_id) as dir,
COALESCE(f.filename, '') as filename, op.id as op_id,
COALESCE(f.original_filename, '') as original_filename,
COALESCE(f.is_spoilered) AS spoiler_file
COALESCE(f.is_spoilered, FALSE) AS spoiler_file
FROM DBPREFIXposts
LEFT JOIN DBPREFIXv_thread_board_ids t ON t.id = DBPREFIXposts.thread_id
LEFT JOIN DBPREFIXfiles f on f.post_id = DBPREFIXposts.id

View file

@ -10,7 +10,7 @@
<form action="{{webPath "/util"}}" method="POST" id="main-form">
{{$global := .}}
{{- range $t, $thread := .threads}}{{$op := index $thread.Posts 0}}
<div class="thread">
<div class="thread {{if $thread.IsSpoilered}}spoiler-thread{{end}}">
{{- template "post.html" map "global" $global "board" $.board "post" $op "is_board_page" true "thread" $thread -}}
{{- if gt $thread.OmittedPosts 0 -}}
<b>{{$thread.OmittedPosts}} repl{{if gt $thread.OmittedPosts 1}}ies{{else}}y{{end}}{{if gt $thread.OmittedImages 0}} and {{$thread.OmittedImages}} upload{{if gt $thread.OmittedImages 1}}s{{end}}{{end}} omitted</b><br />

View file

@ -28,7 +28,7 @@
<span class="status-icons">
{{- if $.thread.Locked}}<img src="{{webPath `/static/lock.png`}}" class="locked-icon" alt="Thread locked" title="Thread locked">{{end -}}
{{- if $.thread.Stickied}}<img src="{{webPath `/static/sticky.png`}}" class="sticky-icon" alt="Sticky" title="Sticky">{{end -}}
{{- if $.thread.Cyclic}}<img src="{{webPath `/static/cyclic.png`}}" class="cyclic-icon" alt="Cyclic thread" title="Cyclic thread">{{end -}}
{{- if $.thread.Cyclical}}<img src="{{webPath `/static/cyclic.png`}}" class="cyclic-icon" alt="Cyclic thread" title="Cyclic thread">{{end -}}
</span>
{{if $.is_board_page -}}
[<a href="{{.post.ThreadPath}}">View</a>]

View file

@ -8,7 +8,7 @@
</header><hr />
{{template "postbox.html" .}}<hr />
<form action="{{webPath "/util"}}" method="POST" id="main-form">
<div class="thread" id="{{$.op.ID}}">
<div class="thread {{if $.op.SpoilerThread}}spoiler-thread{{end}}" id="{{$.op.ID}}">
{{$global := .}}
{{- template "post.html" map "global" $global "board" .board "post" .op "thread" $.thread -}}
{{range $reply_num,$reply := .posts -}}

2
vagrant/Vagrantfile vendored
View file

@ -18,6 +18,8 @@ Vagrant.configure("2") do |config|
config.vm.box = BOX
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 4430
config.vm.network "forwarded_port", guest: 4040, host: 4040
config.vm.network :private_network, ip: "192.168.56.3"
config.vm.synced_folder "../", "/vagrant"
config.vm.provider PROVIDER do |provider|

View file

@ -104,17 +104,17 @@ systemctl restart nginx &
wait
mkdir -p /etc/gochan
cp /vagrant/examples/configs/gochan.example.json /etc/gochan/gochan.json
sed -i /etc/gochan/gochan.json \
cp /vagrant/examples/configs/gochan.example.json /vagrant/gochan.json
ln -s /vagrant/gochan.json /etc/gochan/gochan.json
sed -i /vagrant/gochan.json \
-e 's/"Port": 8080/"Port": 9000/' \
-e 's/"UseFastCGI": false/"UseFastCGI": true/' \
-e 's#"DocumentRoot": "html"#"DocumentRoot": "/srv/gochan"#' \
-e 's#"TemplateDir": "templates"#"TemplateDir": "/usr/share/gochan/templates"#' \
-e 's#"LogDir": "log"#"LogDir": "/var/log/gochan"#' \
-e "s/\"DBtype\": .*/\"DBtype\": \"$DBTYPE\",/" \
-e 's/"DebugMode": false/"DebugMode": true/' \
-e 's/"DBpassword": ""/"DBpassword": "gochan"/' \
-e 's/"SiteHost": .*/"SiteHost": "192.168.56.3",/' \
-e 's/"DBpassword": .*/"DBpassword": "gochan",/' \
-e 's/"Verbosity": 0/"Verbosity": 1/'
if [ "$DBTYPE" = "postgresql" ]; then