1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-25 09:36:24 -07:00

Refactor threads table, rename cyclical attribute to cyclic for consistency

This commit is contained in:
Eggbertx 2025-05-02 11:47:01 -07:00
parent d7f2995333
commit 305b557e41
24 changed files with 137 additions and 55 deletions

View file

@ -12,7 +12,7 @@ import (
func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *config.SQLConfig, errEv *zerolog.Event) (err error) {
var query string
var dataType string
var cyclicalType string
defer func() {
if a := recover(); a != nil {
errEv.Caller(4).Interface("panic", a).Send()
@ -28,6 +28,7 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
// fix default collation
query = `ALTER DATABASE ` + dbName + ` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci`
if _, err = db.GetBaseDB().ExecContext(ctx, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
@ -35,6 +36,7 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
query = `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE'`
rows, err = db.QueryContextSQL(ctx, nil, query, dbName)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
defer func() {
@ -44,10 +46,12 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
for rows.Next() {
err = rows.Scan(&tableName)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE ` + tableName + ` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
@ -55,21 +59,23 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
return err
}
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXip_ban", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXip_ban", sqlConfig)
if err != nil {
return err
}
if dataType != "" {
if cyclicalType != "" {
// add range_start and range_end columns
query = `ALTER TABLE DBPREFIXip_ban
ADD COLUMN IF NOT EXISTS range_start VARBINARY(16) NOT NULL,
ADD COLUMN IF NOT EXISTS range_end VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
// convert ban IP string to IP range
if rows, err = db.QueryContextSQL(ctx, nil, "SELECT id, ip FROM DBPREFIXip_ban"); err != nil {
errEv.Err(err).Caller().Send()
return err
}
var rangeStart, rangeEnd string
@ -77,6 +83,7 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
var id int
var ipOrCIDR string
if err = rows.Scan(&id, &ipOrCIDR); err != nil {
errEv.Err(err).Caller().Send()
return err
}
if rangeStart, rangeEnd, err = gcutil.ParseIPRange(ipOrCIDR); err != nil {
@ -85,122 +92,168 @@ func updateMysqlDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *confi
query = `UPDATE DBPREFIXip_ban
SET range_start = INET6_ATON(?), range_end = INET6_ATON(?) WHERE id = ?`
if _, err = db.ExecContextSQL(ctx, nil, query, rangeStart, rangeEnd, id); err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE DBPREFIXip_ban DROP COLUMN IF EXISTS ip`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
if err = rows.Close(); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// Convert DBPREFIXposts.ip to from varchar to varbinary
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXposts", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if common.IsStringType(dataType) {
if common.IsStringType(cyclicalType) {
// rename `ip` to a temporary column to then be removed
query = "ALTER TABLE DBPREFIXposts CHANGE ip ip_str varchar(45)"
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE DBPREFIXposts
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
// convert post IP VARCHAR(45) to VARBINARY(16)
query = `UPDATE DBPREFIXposts SET ip = INET6_ATON(ip_str)`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE DBPREFIXposts DROP COLUMN IF EXISTS ip_str`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// Convert DBPREFIXreports.ip to from varchar to varbinary
dataType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXreports", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "ip", "DBPREFIXreports", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if common.IsStringType(dataType) {
if common.IsStringType(cyclicalType) {
// rename `ip` to a temporary column to then be removed
query = "ALTER TABLE DBPREFIXreports CHANGE ip ip_str varchar(45)"
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE DBPREFIXreports
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
// convert report IP VARCHAR(45) to VARBINARY(16)
query = `UPDATE DBPREFIXreports SET ip = INET6_ATON(ip_str)`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
query = `ALTER TABLE DBPREFIXreports DROP COLUMN IF EXISTS ip_str`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// add flag column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, nil, "flag", "DBPREFIXposts", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "flag", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
if cyclicalType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN flag VARCHAR(45) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// add country column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, nil, "country", "DBPREFIXposts", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "country", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
if cyclicalType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN country VARCHAR(80) NOT NULL DEFAULT ''`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// add is_secure_tripcode column to DBPREFIXposts
dataType, err = common.ColumnType(ctx, db, nil, "is_secure_tripcode", "DBPREFIXposts", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "is_secure_tripcode", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
if cyclicalType == "" {
query = `ALTER TABLE DBPREFIXposts ADD COLUMN is_secure_tripcode BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// add spoilered column to DBPREFIXthreads
dataType, err = common.ColumnType(ctx, db, nil, "is_spoilered", "DBPREFIXthreads", sqlConfig)
cyclicalType, err = common.ColumnType(ctx, db, nil, "is_spoilered", "DBPREFIXthreads", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
if cyclicalType == "" {
query = `ALTER TABLE DBPREFIXthreads ADD COLUMN is_spoilered BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
// rename DBPREFIXposts.cyclical to cyclic
cyclicalType, err = common.ColumnType(ctx, db, nil, "cyclical", "DBPREFIXthreads", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
cyclicType, err := common.ColumnType(ctx, db, nil, "cyclic", "DBPREFIXthreads", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if cyclicalType == "" && cyclicType == "" {
query = `ALTER TABLE DBPREFIXthreads ADD COLUMN cyclic BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
} else if cyclicalType != "" {
query = `ALTER TABLE DBPREFIXthreads CHANGE cyclical cyclic BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}

View file

@ -117,5 +117,19 @@ func updatePostgresDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *co
}
}
// rename DBPREFIXposts.cyclical to cyclic
dataType, err = common.ColumnType(ctx, db, nil, "cyclic", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts CHANGE cyclical cyclic BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
return nil
}

View file

@ -135,5 +135,19 @@ func updateSqliteDB(ctx context.Context, dbu *GCDatabaseUpdater, sqlConfig *conf
}
}
// rename DBPREFIXposts.cyclical to cyclic
dataType, err = common.ColumnType(ctx, db, nil, "cyclic", "DBPREFIXposts", sqlConfig)
if err != nil {
errEv.Err(err).Caller().Send()
return err
}
if dataType == "" {
query = `ALTER TABLE DBPREFIXposts CHANGE cyclical cyclic BOOL NOT NULL DEFAULT FALSE`
if _, err = db.ExecContextSQL(ctx, nil, query); err != nil {
errEv.Err(err).Caller().Send()
return err
}
}
return nil
}

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,
Cyclical: false,
Cyclic: false,
}
if post.oldParentID == 0 {
// migrating post was a thread OP, create the row in the threads table

View file

@ -83,7 +83,7 @@ func BuildBoardPages(board *gcsql.Board, errEv *zerolog.Event) error {
Locked: boolToInt(thread.Locked),
Stickied: boolToInt(thread.Stickied),
IsSpoilered: boolToInt(thread.IsSpoilered),
Cyclical: boolToInt(thread.Cyclical),
Cyclic: boolToInt(thread.Cyclic),
}
errEv.Int("threadID", thread.ID)
if catalogThread.Images, err = thread.GetReplyFileCount(); err != nil {

View file

@ -20,7 +20,7 @@ type catalogThreadData struct {
OmittedImages int `json:"omitted_images"` // uploads in the thread but not shown on the board page
Stickied int `json:"sticky"`
IsSpoilered int `json:"spoilered"`
Cyclical int `json:"cyclical"`
Cyclic int `json:"cyclic"`
Locked int `json:"closed"`
Posts []*Post `json:"-"`
uploads []gcsql.Upload

View file

@ -20,7 +20,7 @@ import (
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, banned_message, board_id, dir, original_filename, filename,
checksum, filesize, tw, th, width, height, spoiler_file, locked, stickied, cyclical, spoiler_thread, flag, country, is_deleted
checksum, filesize, tw, th, width, height, spoiler_file, locked, stickied, cyclic, spoiler_thread, flag, country, is_deleted
FROM DBPREFIXv_building_posts `
)
@ -177,7 +177,7 @@ func (p *Post) Stickied() bool {
}
func (p *Post) Cyclic() bool {
return p.thread.Cyclical
return p.thread.Cyclic
}
func (p *Post) SpoilerThread() bool {
@ -213,7 +213,7 @@ func QueryPosts(query string, params []any, cb func(*Post) error) error {
&post.LastModified, &post.ParentID, &lastBump, &post.Message, &post.MessageRaw, &post.BannedMessage,
&post.BoardID, &post.BoardDir, &post.OriginalFilename, &post.Filename, &post.Checksum, &post.Filesize,
&post.ThumbnailWidth, &post.ThumbnailHeight, &post.UploadWidth, &post.UploadHeight, &spoilerFile,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclical, &post.thread.IsSpoilered,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclic, &post.thread.IsSpoilered,
&post.Country.Flag, &post.Country.Name, &post.IsDeleted)
if err = rows.Scan(dest...); err != nil {

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.Cyclical, &thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclic, &thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
)
if err != nil {
return threads, err

View file

@ -21,7 +21,7 @@ import (
const (
// GochanVersionKeyConstant is the key value used in the version table of the database to store and receive the (database) version of base gochan
gochanVersionKeyConstant = "gochan"
DatabaseVersion = 5
DatabaseVersion = 6
UnsupportedSQLVersionMsg = `syntax error in SQL query, confirm you are using a supported driver and SQL server (error text: %s)`
mysqlConnStr = "%s:%s@tcp(%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci"
postgresConnStr = "postgres://%s:%s@%s/%s?sslmode=disable"

View file

@ -348,7 +348,7 @@ func (p *Post) UnlinkUploads(leaveDeletedBox bool, requestOpts ...*RequestOption
// InCyclicThread returns true if the post is in a cyclic thread
func (p *Post) InCyclicThread() (bool, error) {
var cyclic bool
err := QueryRowTimeoutSQL(nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
err := QueryRowTimeoutSQL(nil, "SELECT cyclic FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
if errors.Is(err, sql.ErrNoRows) {
return false, ErrThreadDoesNotExist
}
@ -490,7 +490,7 @@ func (p *Post) CyclicPostsToBePruned() ([]CyclicThreadPost, error) {
defer cancel()
var cyclic bool
err := QueryRowContextSQL(ctx, nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
err := QueryRowContextSQL(ctx, nil, "SELECT cyclic FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
if errors.Is(err, sql.ErrNoRows) {
err = ErrThreadDoesNotExist
}
@ -503,7 +503,7 @@ func (p *Post) CyclicPostsToBePruned() ([]CyclicThreadPost, error) {
}
rows, err := QueryContextSQL(ctx, nil, `SELECT post_id, thread_id, op_id, filename, dir
FROM DBPREFIXv_posts_cyclical_check WHERE thread_id = ? AND post_id <> op_id ORDER BY post_id ASC`, p.ThreadID)
FROM DBPREFIXv_posts_cyclic_check WHERE thread_id = ? AND post_id <> op_id ORDER BY post_id ASC`, p.ThreadID)
if err != nil {
return nil, err
}

View file

@ -11,7 +11,7 @@ import (
)
var (
insertIntoThreadsBase = `INSERT INTO threads \(board_id, locked, stickied, anchored, cyclical, is_spoilered\) VALUES `
insertIntoThreadsBase = `INSERT INTO threads \(board_id, locked, stickied, anchored, cyclic, is_spoilered\) VALUES `
insertIntoThreadsMySQL = insertIntoThreadsBase + `\(\?,\?,\?,\?,\?,\?\)`
insertIntoThreadsPostgres = insertIntoThreadsBase + `\(\$1,\$2,\$3,\$4,\$5,\$6\)`

View file

@ -15,7 +15,7 @@ var (
`CREATE TABLE database_version\(\s+component VARCHAR\(40\) NOT NULL PRIMARY KEY,\s+version INT NOT NULL \)`,
`CREATE TABLE sections\(\s+id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,\s+name TEXT NOT NULL,\s+abbreviation TEXT NOT NULL,\s+position SMALLINT NOT NULL,\s+hidden BOOL NOT NULL \)`,
`CREATE TABLE boards\(\s*id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,\s+section_id BIGINT NOT NULL,\s+uri VARCHAR\(45\) NOT NULL,\s+dir VARCHAR\(45\) NOT NULL,\s+navbar_position SMALLINT NOT NULL,\s+title VARCHAR\(45\) NOT NULL,\s+subtitle VARCHAR\(64\) NOT NULL,\s+description VARCHAR\(64\) NOT NULL,\s+max_file_size INT NOT NULL,\s+max_threads SMALLINT NOT NULL, default_style VARCHAR\(45\) NOT NULL,\s+locked BOOL NOT NULL,\s+created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+anonymous_name VARCHAR\(45\) NOT NULL DEFAULT 'Anonymous',\s+force_anonymous BOOL NOT NULL,\s+autosage_after SMALLINT NOT NULL,\s+no_images_after SMALLINT NOT NULL,\s+max_message_length SMALLINT NOT NULL,\s+min_message_length SMALLINT NOT NULL,\s+allow_embeds BOOL NOT NULL,\s+redirect_to_thread BOOL NOT NULL,\s+require_file BOOL NOT NULL,\s+enable_catalog BOOL NOT NULL,\s+CONSTRAINT boards_section_id_fk\s+FOREIGN KEY\(section_id\) REFERENCES sections\(id\),\s+CONSTRAINT boards_dir_unique UNIQUE\(dir\),\s+CONSTRAINT boards_uri_unique UNIQUE\(uri\)\s*\)`,
`CREATE TABLE threads\(\s*id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclical BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE TABLE threads\(\s*id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclic BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE INDEX thread_deleted_index ON threads\(is_deleted\)`,
`CREATE TABLE posts\(\s+id BIGINT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,\s+thread_id BIGINT NOT NULL,\s+is_top_post BOOL NOT NULL DEFAULT FALSE,\s+ip VARBINARY\(16\) NOT NULL,\s+created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+name VARCHAR\(50\) NOT NULL DEFAULT '',\s+tripcode VARCHAR\(10\) NOT NULL DEFAULT '',\s+is_secure_tripcode BOOL NOT NULL DEFAULT FALSE,\s+is_role_signature BOOL NOT NULL DEFAULT FALSE, email VARCHAR\(50\) NOT NULL DEFAULT '',\s+subject VARCHAR\(100\) NOT NULL DEFAULT '',\s+message TEXT NOT NULL,\s+message_raw TEXT NOT NULL,\s+password TEXT NOT NULL,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+banned_message TEXT,\s+flag VARCHAR\(45\) NOT NULL DEFAULT '',\s+country VARCHAR\(80\) NOT NULL DEFAULT '',\s+CONSTRAINT posts_thread_id_fk\s+FOREIGN KEY\(thread_id\) REFERENCES threads\(id\) ON DELETE CASCADE \)`,
`CREATE INDEX top_post_index ON posts\(is_top_post\)`,
@ -40,7 +40,7 @@ var (
`CREATE TABLE database_version\(\s+component VARCHAR\(40\) NOT NULL PRIMARY KEY,\s+version INT NOT NULL \)`,
`CREATE TABLE sections\(\s+id BIGSERIAL PRIMARY KEY,\s+name TEXT NOT NULL,\s+abbreviation TEXT NOT NULL,\s+position SMALLINT NOT NULL,\s+hidden BOOL NOT NULL \)`,
`CREATE TABLE boards\(\s*id BIGSERIAL PRIMARY KEY,\s+section_id BIGINT NOT NULL,\s+uri VARCHAR\(45\) NOT NULL,\s+dir VARCHAR\(45\) NOT NULL,\s+navbar_position SMALLINT NOT NULL,\s+title VARCHAR\(45\) NOT NULL,\s+subtitle VARCHAR\(64\) NOT NULL,\s+description VARCHAR\(64\) NOT NULL,\s+max_file_size INT NOT NULL,\s+max_threads SMALLINT NOT NULL, default_style VARCHAR\(45\) NOT NULL,\s+locked BOOL NOT NULL,\s+created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+anonymous_name VARCHAR\(45\) NOT NULL DEFAULT 'Anonymous',\s+force_anonymous BOOL NOT NULL,\s+autosage_after SMALLINT NOT NULL,\s+no_images_after SMALLINT NOT NULL,\s+max_message_length SMALLINT NOT NULL,\s+min_message_length SMALLINT NOT NULL,\s+allow_embeds BOOL NOT NULL,\s+redirect_to_thread BOOL NOT NULL,\s+require_file BOOL NOT NULL,\s+enable_catalog BOOL NOT NULL,\s+CONSTRAINT boards_section_id_fk\s+FOREIGN KEY\(section_id\) REFERENCES sections\(id\),\s+CONSTRAINT boards_dir_unique UNIQUE\(dir\),\s+CONSTRAINT boards_uri_unique UNIQUE\(uri\)\s*\)`,
`CREATE TABLE threads\(\s*id BIGSERIAL PRIMARY KEY,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclical BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE TABLE threads\(\s*id BIGSERIAL PRIMARY KEY,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclic BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE INDEX thread_deleted_index ON threads\(is_deleted\)`,
`CREATE TABLE posts\(\s+id BIGSERIAL PRIMARY KEY,\s+thread_id BIGINT NOT NULL,\s+is_top_post BOOL NOT NULL DEFAULT FALSE,\s+ip INET NOT NULL,\s+created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+name VARCHAR\(50\) NOT NULL DEFAULT '',\s+tripcode VARCHAR\(10\) NOT NULL DEFAULT '',\s+is_secure_tripcode BOOL NOT NULL DEFAULT FALSE,\s+is_role_signature BOOL NOT NULL DEFAULT FALSE, email VARCHAR\(50\) NOT NULL DEFAULT '',\s+subject VARCHAR\(100\) NOT NULL DEFAULT '',\s+message TEXT NOT NULL,\s+message_raw TEXT NOT NULL,\s+password TEXT NOT NULL,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+banned_message TEXT,\s+flag VARCHAR\(45\) NOT NULL DEFAULT '',\s+country VARCHAR\(80\) NOT NULL DEFAULT '',\s+CONSTRAINT posts_thread_id_fk\s+FOREIGN KEY\(thread_id\) REFERENCES threads\(id\) ON DELETE CASCADE \)`,
`CREATE INDEX top_post_index ON posts\(is_top_post\)`,
@ -65,7 +65,7 @@ var (
`CREATE TABLE database_version\(\s+component VARCHAR\(40\) NOT NULL PRIMARY KEY,\s+version INT NOT NULL \)`,
`CREATE TABLE sections\(\s+id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\s+name TEXT NOT NULL,\s+abbreviation TEXT NOT NULL,\s+position SMALLINT NOT NULL,\s+hidden BOOL NOT NULL \)`,
`CREATE TABLE boards\(\s*id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\s+section_id BIGINT NOT NULL,\s+uri VARCHAR\(45\) NOT NULL,\s+dir VARCHAR\(45\) NOT NULL,\s+navbar_position SMALLINT NOT NULL,\s+title VARCHAR\(45\) NOT NULL,\s+subtitle VARCHAR\(64\) NOT NULL,\s+description VARCHAR\(64\) NOT NULL,\s+max_file_size INT NOT NULL,\s+max_threads SMALLINT NOT NULL, default_style VARCHAR\(45\) NOT NULL,\s+locked BOOL NOT NULL,\s+created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+anonymous_name VARCHAR\(45\) NOT NULL DEFAULT 'Anonymous',\s+force_anonymous BOOL NOT NULL,\s+autosage_after SMALLINT NOT NULL,\s+no_images_after SMALLINT NOT NULL,\s+max_message_length SMALLINT NOT NULL,\s+min_message_length SMALLINT NOT NULL,\s+allow_embeds BOOL NOT NULL,\s+redirect_to_thread BOOL NOT NULL,\s+require_file BOOL NOT NULL,\s+enable_catalog BOOL NOT NULL,\s+CONSTRAINT boards_section_id_fk\s+FOREIGN KEY\(section_id\) REFERENCES sections\(id\),\s+CONSTRAINT boards_dir_unique UNIQUE\(dir\),\s+CONSTRAINT boards_uri_unique UNIQUE\(uri\)\s*\)`,
`CREATE TABLE threads\(\s*id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclical BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE TABLE threads\(\s*id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\s+board_id BIGINT NOT NULL,\s+locked BOOL NOT NULL DEFAULT FALSE,\s+stickied BOOL NOT NULL DEFAULT FALSE,\s+anchored BOOL NOT NULL DEFAULT FALSE,\s+cyclic BOOL NOT NULL DEFAULT FALSE,\s+is_spoilered BOOL NOT NULL DEFAULT FALSE,\s+last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+CONSTRAINT threads_board_id_fk\s+FOREIGN KEY\(board_id\) REFERENCES boards\(id\) ON DELETE CASCADE\s*\)`,
`CREATE INDEX thread_deleted_index ON threads\(is_deleted\)`,
`CREATE TABLE posts\(\s+id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\s+thread_id BIGINT NOT NULL,\s+is_top_post BOOL NOT NULL DEFAULT FALSE,\s+ip VARCHAR\(45\) NOT NULL,\s+created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+name VARCHAR\(50\) NOT NULL DEFAULT '',\s+tripcode VARCHAR\(10\) NOT NULL DEFAULT '',\s+is_secure_tripcode BOOL NOT NULL DEFAULT FALSE,\s+is_role_signature BOOL NOT NULL DEFAULT FALSE, email VARCHAR\(50\) NOT NULL DEFAULT '',\s+subject VARCHAR\(100\) NOT NULL DEFAULT '',\s+message TEXT NOT NULL,\s+message_raw TEXT NOT NULL,\s+password TEXT NOT NULL,\s+deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\s+is_deleted BOOL NOT NULL DEFAULT FALSE,\s+banned_message TEXT,\s+flag VARCHAR\(45\) NOT NULL DEFAULT '',\s+country VARCHAR\(80\) NOT NULL DEFAULT '',\s+CONSTRAINT posts_thread_id_fk\s+FOREIGN KEY\(thread_id\) REFERENCES threads\(id\) ON DELETE CASCADE \)`,
`CREATE INDEX top_post_index ON posts\(is_top_post\)`,

View file

@ -280,7 +280,7 @@ type Thread struct {
Locked bool // sql: locked
Stickied bool // sql: stickied
Anchored bool // sql: anchored
Cyclical bool // sql: cyclical
Cyclic bool // sql: cyclic
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, is_spoilered, last_bump, deleted_at, is_deleted
id, board_id, locked, stickied, anchored, cyclic, 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, is_spoilered) VALUES (?,?,?,?,?,?)`
const insertQuery = `INSERT INTO DBPREFIXthreads (board_id, locked, stickied, anchored, cyclic, 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.Cyclical, &thread.IsSpoilered); err != nil {
if _, err = Exec(requestOptions, insertQuery, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic, &thread.IsSpoilered); err != nil {
return err
}
return QueryRow(requestOptions, "SELECT MAX(id) FROM DBPREFIXthreads", nil, []any{&thread.ID})
@ -41,7 +41,7 @@ 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.Cyclical,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
return thread, err
@ -52,7 +52,7 @@ 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.Cyclical,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
if errors.Is(err, sql.ErrNoRows) {
@ -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.Cyclical, &thread.IsSpoilered, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclic, &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.Cyclical = value
t.Cyclic = value
default:
return fmt.Errorf("invalid thread attribute %q", attribute)
}

View file

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

View file

@ -1,6 +1,6 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0" version="26.2.9">
<diagram id="TVQ4taKJlGjEfO4J5nL0" name="Page-1">
<mxGraphModel dx="2754" dy="2167" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<mxGraphModel dx="1835" dy="1652" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
@ -771,10 +771,10 @@
<mxCell id="PdcwpANUKP4F5l-W0EyN-188" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" parent="PdcwpANUKP4F5l-W0EyN-187" vertex="1" connectable="0">
<mxGeometry width="56" height="26" as="geometry" />
</mxCell>
<mxCell id="tuHC6-spi_Zi7_7CJrgR-3" value="is_role_signature" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=60;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" vertex="1" parent="PdcwpANUKP4F5l-W0EyN-132">
<mxCell id="tuHC6-spi_Zi7_7CJrgR-3" value="is_role_signature" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=60;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="PdcwpANUKP4F5l-W0EyN-132" vertex="1">
<mxGeometry y="238" width="220" height="26" as="geometry" />
</mxCell>
<mxCell id="tuHC6-spi_Zi7_7CJrgR-4" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" vertex="1" connectable="0" parent="tuHC6-spi_Zi7_7CJrgR-3">
<mxCell id="tuHC6-spi_Zi7_7CJrgR-4" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" parent="tuHC6-spi_Zi7_7CJrgR-3" vertex="1" connectable="0">
<mxGeometry width="56" height="26" as="geometry" />
</mxCell>
<mxCell id="PdcwpANUKP4F5l-W0EyN-189" value="email" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=60;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="PdcwpANUKP4F5l-W0EyN-132" vertex="1">
@ -958,16 +958,16 @@
<mxCell id="g8VmcGA17cuox0www8EO-89" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" parent="g8VmcGA17cuox0www8EO-88" vertex="1" connectable="0">
<mxGeometry width="30" height="26" as="geometry" />
</mxCell>
<mxCell id="g8VmcGA17cuox0www8EO-90" value="cyclical" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=34;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="g8VmcGA17cuox0www8EO-75" vertex="1">
<mxCell id="g8VmcGA17cuox0www8EO-90" value="cyclic" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=34;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="g8VmcGA17cuox0www8EO-75" vertex="1">
<mxGeometry y="160" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="g8VmcGA17cuox0www8EO-91" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" parent="g8VmcGA17cuox0www8EO-90" vertex="1" connectable="0">
<mxGeometry width="30" height="26" as="geometry" />
</mxCell>
<mxCell id="tuHC6-spi_Zi7_7CJrgR-1" value="spoilered" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=34;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" vertex="1" parent="g8VmcGA17cuox0www8EO-75">
<mxCell id="tuHC6-spi_Zi7_7CJrgR-1" value="is_spoilered" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=34;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="g8VmcGA17cuox0www8EO-75" vertex="1">
<mxGeometry y="186" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="tuHC6-spi_Zi7_7CJrgR-2" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" vertex="1" connectable="0" parent="tuHC6-spi_Zi7_7CJrgR-1">
<mxCell id="tuHC6-spi_Zi7_7CJrgR-2" value="" style="shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[];portConstraint=eastwest;part=1;fontSize=12;" parent="tuHC6-spi_Zi7_7CJrgR-1" vertex="1" connectable="0">
<mxGeometry width="30" height="26" as="geometry" />
</mxCell>
<mxCell id="g8VmcGA17cuox0www8EO-86" value="last_bump" style="shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;fillColor=none;spacingLeft=34;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;fontSize=12;" parent="g8VmcGA17cuox0www8EO-75" vertex="1">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 589 KiB

Before After
Before After

View file

@ -54,7 +54,7 @@ CREATE TABLE DBPREFIXthreads(
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
cyclic BOOL NOT NULL DEFAULT FALSE,
is_spoilered BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View file

@ -47,7 +47,7 @@ CREATE TABLE DBPREFIXthreads(
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
cyclic BOOL NOT NULL DEFAULT FALSE,
is_spoilered BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View file

@ -47,7 +47,7 @@ CREATE TABLE DBPREFIXthreads(
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
cyclic BOOL NOT NULL DEFAULT FALSE,
is_spoilered BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View file

@ -47,7 +47,7 @@ CREATE TABLE DBPREFIXthreads(
locked BOOL NOT NULL DEFAULT FALSE,
stickied BOOL NOT NULL DEFAULT FALSE,
anchored BOOL NOT NULL DEFAULT FALSE,
cyclical BOOL NOT NULL DEFAULT FALSE,
cyclic BOOL NOT NULL DEFAULT FALSE,
is_spoilered BOOL NOT NULL DEFAULT FALSE,
last_bump TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View file

@ -8,7 +8,7 @@ DROP VIEW IF EXISTS DBPREFIXv_upload_info;
DROP VIEW IF EXISTS DBPREFIXv_front_page_posts_with_file;
DROP VIEW IF EXISTS DBPREFIXv_front_page_posts;
DROP VIEW IF EXISTS DBPREFIXv_posts_to_delete_file_only;
DROP VIEW IF EXISTS DBPREFIXv_posts_cyclical_check;
DROP VIEW IF EXISTS DBPREFIXv_posts_cyclic_check;
DROP VIEW IF EXISTS DBPREFIXv_posts_to_delete;
DROP VIEW IF EXISTS DBPREFIXv_recent_posts;
DROP VIEW IF EXISTS DBPREFIXv_building_posts;
@ -37,7 +37,7 @@ COALESCE(f.thumbnail_height, 0) AS th,
COALESCE(f.width, 0) AS width,
COALESCE(f.height, 0) AS height,
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
t.locked, t.stickied, t.cyclic, 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
LEFT JOIN DBPREFIXthreads t ON t.id = p.thread_id
@ -58,12 +58,12 @@ CREATE VIEW DBPREFIXv_posts_to_delete_file_only AS
SELECT * FROM DBPREFIXv_posts_to_delete
WHERE filename IS NOT NULL;
CREATE VIEW DBPREFIXv_posts_cyclical_check AS
CREATE VIEW DBPREFIXv_posts_cyclic_check AS
SELECT post_id, d.thread_id, op_id, d.is_top_post, filename, dir
FROM DBPREFIXv_posts_to_delete d
INNER JOIN DBPREFIXposts p ON p.id = post_id
INNER JOIN DBPREFIXthreads t ON d.thread_id = t.id
WHERE p.is_deleted = FALSE AND d.is_top_post = FALSE and t.cyclical = TRUE;
WHERE p.is_deleted = FALSE AND d.is_top_post = FALSE and t.cyclic = TRUE;
CREATE VIEW DBPREFIXv_front_page_posts AS
SELECT DBPREFIXposts.id, DBPREFIXposts.message_raw,

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.Cyclical}}<img src="{{webPath `/static/cyclic.png`}}" class="cyclic-icon" alt="Cyclic thread" title="Cyclic thread">{{end -}}
{{- if $.thread.Cyclic}}<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>]

1
vagrant/Vagrantfile vendored
View file

@ -19,6 +19,7 @@ Vagrant.configure("2") do |config|
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 "forwarded_port", guest: 3306, host: 3306
config.vm.network :private_network, ip: "192.168.56.3"
config.vm.synced_folder "../", "/vagrant"