mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-09-04 10:06:24 -07:00
Add more Postgres db migration for IP -> INET, split dbtypes into their own files
This commit is contained in:
parent
d294462968
commit
0e34698257
8 changed files with 386 additions and 198 deletions
|
@ -1,6 +1,8 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
@ -14,6 +16,42 @@ var (
|
|||
commentRemover = regexp.MustCompile("--.*\n?")
|
||||
)
|
||||
|
||||
// ColumnType returns a string representation of the column's data type. It does not return an error
|
||||
// if the column does not exist, instead returning an empty string.
|
||||
func ColumnType(db *gcsql.GCDB, tx *sql.Tx, columnName string, tableName string, dbName string, dbType string) (string, error) {
|
||||
var query string
|
||||
var dataType string
|
||||
var err error
|
||||
var params []any
|
||||
switch dbType {
|
||||
case "mysql":
|
||||
query = `SELECT DATA_TYPE FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ? LIMIT 1`
|
||||
params = []any{dbName, tableName, columnName}
|
||||
case "postgresql":
|
||||
query = `SELECT data_type FROM information_schema.columns
|
||||
WHERE (table_schema = ? OR table_schema = 'public')
|
||||
AND table_name = ? AND column_name = ? LIMIT 1`
|
||||
params = []any{dbName, tableName, columnName}
|
||||
case "sqlite3":
|
||||
query = `SELECT type FROM pragma_table_info(?) WHERE name = ?`
|
||||
params = []any{tableName, columnName}
|
||||
default:
|
||||
return "", gcsql.ErrUnsupportedDB
|
||||
}
|
||||
err = db.QueryRowTxSQL(tx, query, params, []any{&dataType})
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return "", nil
|
||||
}
|
||||
return dataType, err
|
||||
}
|
||||
|
||||
// IsStringType returns true if the given column data type is TEXT or VARCHAR
|
||||
func IsStringType(dataType string) bool {
|
||||
lower := strings.ToLower(dataType)
|
||||
return strings.HasPrefix(lower, "varchar") || lower == "text"
|
||||
}
|
||||
|
||||
func RunSQLFile(path string, db *gcsql.GCDB) error {
|
||||
sqlBytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
|
|
|
@ -55,13 +55,9 @@ func (dbu *GCDatabaseUpdater) MigrateDB() (bool, error) {
|
|||
return migrated, err
|
||||
}
|
||||
|
||||
var query string
|
||||
var tableName string
|
||||
var numConstraints int
|
||||
var numColumns int
|
||||
var rangeStart string
|
||||
var rangeEnd string
|
||||
criticalConfig := config.GetSystemCriticalConfig()
|
||||
dbName := criticalConfig.DBname
|
||||
dbType := criticalConfig.DBtype
|
||||
ctx := context.Background()
|
||||
tx, err := dbu.db.BeginTx(ctx, &sql.TxOptions{
|
||||
Isolation: 0,
|
||||
|
@ -70,204 +66,21 @@ func (dbu *GCDatabaseUpdater) MigrateDB() (bool, error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
tx.Rollback()
|
||||
}()
|
||||
defer tx.Rollback()
|
||||
|
||||
switch criticalConfig.DBtype {
|
||||
case "mysql":
|
||||
query = `SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_NAME = 'wordfilters_board_id_fk'
|
||||
AND TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'DBPREFIXwordfilters'`
|
||||
|
||||
if err = dbu.db.QueryRowTxSQL(tx, query, nil, []any{&numConstraints}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numConstraints > 0 {
|
||||
query = `ALTER TABLE DBPREFIXwordfilters DROP FOREIGN KEY wordfilters_board_id_fk`
|
||||
} else {
|
||||
query = ""
|
||||
}
|
||||
query = `SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'DBPREFIXwordfilters'
|
||||
AND COLUMN_NAME = 'board_dirs'`
|
||||
if err = dbu.db.QueryRowTxSQL(tx, query, nil, []any{&numColumns}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numColumns == 0 {
|
||||
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Yay, collation! Everybody loves MySQL's default collation!
|
||||
query = `ALTER DATABASE ` + criticalConfig.DBname + ` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci`
|
||||
if _, err = tx.Exec(query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?`
|
||||
rows, err := dbu.db.QuerySQL(query, criticalConfig.DBname)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
rows.Close()
|
||||
}()
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&tableName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `ALTER TABLE ` + tableName + ` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
|
||||
if _, err = tx.Exec(query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'DBPREFIXip_ban'
|
||||
AND COLUMN_NAME = 'ip'`
|
||||
if err = dbu.db.QueryRowTxSQL(tx, query, nil, []any{&numColumns}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numColumns > 0 {
|
||||
// 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 = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// convert ban IP string to IP range
|
||||
if rows, err = dbu.db.QuerySQL(`SELECT id, ip FROM DBPREFIXip_ban`); err != nil {
|
||||
return false, err
|
||||
}
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ipOrCIDR string
|
||||
if err = rows.Scan(&id, &ipOrCIDR); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rangeStart, rangeEnd, err = gcutil.ParseIPRange(ipOrCIDR); err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `UPDATE DBPREFIXip_ban
|
||||
SET range_start = INET6_ATON(?), range_end = INET6_ATON(?) WHERE id = ?`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query, rangeStart, rangeEnd, id); err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `ALTER TABLE DBPREFIXip_ban DROP COLUMN IF EXISTS ip`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DBPREFIXposts.ip to from varchar to varbinary
|
||||
query = `SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'DBPREFIXposts'
|
||||
AND COLUMN_NAME = 'ip'
|
||||
AND DATA_TYPE = 'varchar'`
|
||||
if err = dbu.db.QueryRowTxSQL(tx, query, nil, []any{&numColumns}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numColumns == 1 {
|
||||
// rename `ip` to a temporary column to then be removed
|
||||
query = `ALTER TABLE DBPREFIXposts CHANGE ip ip_str varchar(45)`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXposts
|
||||
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// convert post IP VARCHAR(45) to VARBINARY(16)
|
||||
query = `UPDATE DBPREFIXposts SET ip = INET6_ATON(ip_str)`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXposts DROP COLUMN IF EXISTS ip_str`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DBPREFIXreports.ip to from varchar to varbinary
|
||||
query = `SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'DBPREFIXreports'
|
||||
AND COLUMN_NAME = 'ip'
|
||||
AND DATA_TYPE = 'varchar'`
|
||||
if err = dbu.db.QueryRowTxSQL(tx, query, nil, []any{&numColumns}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numColumns == 1 {
|
||||
// rename `ip` to a temporary column to then be removed
|
||||
query = `ALTER TABLE DBPREFIXreports CHANGE ip ip_str varchar(45)`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXreports
|
||||
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// convert post IP VARCHAR(45) to VARBINARY(16)
|
||||
query = `UPDATE DBPREFIXreports SET ip = INET6_ATON(ip_str)`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXreports DROP COLUMN IF EXISTS ip_str`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
err = updateMysqlDB(dbu.db, tx, dbName, dbType)
|
||||
case "postgres":
|
||||
_, err = gcsql.ExecSQL(`ALTER TABLE DBPREFIXwordfilters DROP CONSTRAINT IF EXISTS board_id_fk`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN IF NOT EXISTS board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = updatePostgresDB(dbu.db, tx, dbName, dbType)
|
||||
case "sqlite3":
|
||||
_, err = dbu.db.ExecSQL(`PRAGMA foreign_keys = ON`)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
query = `SELECT COUNT(*) FROM PRAGMA_TABLE_INFO('DBPREFIXwordfilters') WHERE name = 'board_dirs'`
|
||||
var numColumns int
|
||||
if err = dbu.db.QueryRowSQL(query, nil, []any{&numColumns}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if numColumns == 0 {
|
||||
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = dbu.db.ExecTxSQL(tx, query); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
err = updateSqliteDB(dbu.db, tx, dbName, dbType)
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
query = `UPDATE DBPREFIXdatabase_version SET version = ? WHERE component = 'gochan'`
|
||||
query := `UPDATE DBPREFIXdatabase_version SET version = ? WHERE component = 'gochan'`
|
||||
_, err = dbu.db.ExecTxSQL(tx, query, latestDatabaseVersion)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
166
cmd/gochan-migration/internal/gcupdate/updatemysql.go
Normal file
166
cmd/gochan-migration/internal/gcupdate/updatemysql.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package gcupdate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
)
|
||||
|
||||
func updateMysqlDB(db *gcsql.GCDB, tx *sql.Tx, dbName string, dbType string) error {
|
||||
var numConstraints int
|
||||
var err error
|
||||
query := `SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE CONSTRAINT_NAME = 'wordfilters_board_id_fk'
|
||||
AND TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'DBPREFIXwordfilters'`
|
||||
|
||||
if err = db.QueryRowTxSQL(tx, query, nil, []any{&numConstraints}); err != nil {
|
||||
return err
|
||||
}
|
||||
if numConstraints > 0 {
|
||||
query = `ALTER TABLE DBPREFIXwordfilters DROP FOREIGN KEY wordfilters_board_id_fk`
|
||||
} else {
|
||||
query = ""
|
||||
}
|
||||
dataType, err := common.ColumnType(db, tx, "board_dirs", "DBPREFIXwordfilters", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dataType == "" {
|
||||
query = `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Yay, collation! Everybody loves MySQL's default collation!
|
||||
query = `ALTER DATABASE ` + dbName + ` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci`
|
||||
if _, err = tx.Exec(query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?`
|
||||
rows, err := db.QuerySQL(query, dbName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
rows.Close()
|
||||
}()
|
||||
var tableName string
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&tableName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query = `ALTER TABLE ` + tableName + ` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
|
||||
if _, err = tx.Exec(query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
dataType, err = common.ColumnType(db, tx, "ip", "DBPREFIXip_ban", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dataType == "" {
|
||||
// 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.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
// convert ban IP string to IP range
|
||||
if rows, err = db.QuerySQL(`SELECT id, ip FROM DBPREFIXip_ban`); err != nil {
|
||||
return err
|
||||
}
|
||||
var rangeStart, rangeEnd string
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var ipOrCIDR string
|
||||
if err = rows.Scan(&id, &ipOrCIDR); err != nil {
|
||||
return err
|
||||
}
|
||||
if rangeStart, rangeEnd, err = gcutil.ParseIPRange(ipOrCIDR); err != nil {
|
||||
return err
|
||||
}
|
||||
query = `UPDATE DBPREFIXip_ban
|
||||
SET range_start = INET6_ATON(?), range_end = INET6_ATON(?) WHERE id = ?`
|
||||
if _, err = db.ExecTxSQL(tx, query, rangeStart, rangeEnd, id); err != nil {
|
||||
return err
|
||||
}
|
||||
query = `ALTER TABLE DBPREFIXip_ban DROP COLUMN IF EXISTS ip`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DBPREFIXposts.ip to from varchar to varbinary
|
||||
dataType, err = common.ColumnType(db, tx, "ip", "DBPREFIXposts", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if common.IsStringType(dataType) {
|
||||
// rename `ip` to a temporary column to then be removed
|
||||
query = `ALTER TABLE DBPREFIXposts CHANGE ip ip_str varchar(45)`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXposts
|
||||
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// convert post IP VARCHAR(45) to VARBINARY(16)
|
||||
query = `UPDATE DBPREFIXposts SET ip = INET6_ATON(ip_str)`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXposts DROP COLUMN IF EXISTS ip_str`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DBPREFIXreports.ip to from varchar to varbinary
|
||||
dataType, err = common.ColumnType(db, tx, "ip", "DBPREFIXreports", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if common.IsStringType(dataType) {
|
||||
// rename `ip` to a temporary column to then be removed
|
||||
query = `ALTER TABLE DBPREFIXreports CHANGE ip ip_str varchar(45)`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXreports
|
||||
ADD COLUMN IF NOT EXISTS ip VARBINARY(16) NOT NULL`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// convert report IP VARCHAR(45) to VARBINARY(16)
|
||||
query = `UPDATE DBPREFIXreports SET ip = INET6_ATON(ip_str)`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXreports DROP COLUMN IF EXISTS ip_str`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
71
cmd/gochan-migration/internal/gcupdate/updatepostgres.go
Normal file
71
cmd/gochan-migration/internal/gcupdate/updatepostgres.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
package gcupdate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
)
|
||||
|
||||
func updatePostgresDB(db *gcsql.GCDB, tx *sql.Tx, dbName string, dbType string) error {
|
||||
query := `ALTER TABLE DBPREFIXwordfilters
|
||||
DROP CONSTRAINT IF EXISTS board_id_fk`
|
||||
_, err := db.ExecSQL(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query = `ALTER TABLE DBPREFIXwordfilters
|
||||
ADD COLUMN IF NOT EXISTS board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataType, err := common.ColumnType(db, tx, "ip", "DBPREFIXposts", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if common.IsStringType(dataType) {
|
||||
// change ip column to temporary ip_str
|
||||
query = `ALTER TABLE DBPREFIXposts RENAME COLUMN ip TO ip_str,`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add ip column with INET type, default '127.0.0.1' because it throws an error otherwise
|
||||
// because it is non-nil
|
||||
query = `ALTER TABLE DBPREFIXposts
|
||||
ADD COLUMN IF NOT EXISTS ip INET NOT NULL DEFAULT '127.0.0.1'`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `UPDATE TABLE DBPREFIXposts SET ip = ip_str`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `ALTER TABLE DBPREFIXposts DROP COLUMN ip_str`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dataType, err = common.ColumnType(db, tx, "ip", "DBPREFIXip_ban", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dataType != "" {
|
||||
query = `ALTER TABLE DBPREFIXip_ban
|
||||
ADD COLUMN IF NOT EXISTS range_start INET NOT NULL,
|
||||
ADD COLUMN IF NOT EXISTS range_end INET NOT NULL`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `UPDATE DBPREFIXip_ban SET range_start = ip::INET, SET range_end = ip::INET`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
26
cmd/gochan-migration/internal/gcupdate/updatesqlite3.go
Normal file
26
cmd/gochan-migration/internal/gcupdate/updatesqlite3.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package gcupdate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
)
|
||||
|
||||
func updateSqliteDB(db *gcsql.GCDB, tx *sql.Tx, dbName string, dbType string) error {
|
||||
_, err := db.ExecSQL(`PRAGMA foreign_keys = ON`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dataType, err := common.ColumnType(db, tx, "DBPREFIXwordfilters", "board_dirs", dbName, dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dataType == "" {
|
||||
query := `ALTER TABLE DBPREFIXwordfilters ADD COLUMN board_dirs varchar(255) DEFAULT '*'`
|
||||
if _, err = db.ExecTxSQL(tx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
59
devtools/get_previous_version.sh
Executable file
59
devtools/get_previous_version.sh
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Shell script that downloads a previous gochan release for testing gochan-migration -updatedb
|
||||
# This should only be used in a development environment
|
||||
|
||||
TESTING_VERSION="v3.7.0"
|
||||
RELEASE_DIR="gochan-${TESTING_VERSION}_linux"
|
||||
RELEASE_GZ="$RELEASE_DIR.tar.gz"
|
||||
RELEASE_URL="https://github.com/gochan-org/gochan/releases/download/$TESTING_VERSION/$RELEASE_GZ"
|
||||
|
||||
if [ "$USER" != "vagrant" ]; then
|
||||
echo "This must be run in the vagrant VM (expected \$USER to be vagrant, got $USER)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ~
|
||||
rm -f $RELEASE_GZ
|
||||
echo "Downloading $RELEASE_GZ"
|
||||
wget -q --show-progress $RELEASE_URL
|
||||
echo "Extracting $RELEASE_GZ"
|
||||
tar -xf gochan-${TESTING_VERSION}_linux.tar.gz
|
||||
cd $RELEASE_DIR
|
||||
|
||||
cp examples/configs/gochan.example.json gochan.json
|
||||
echo "Modifying $PWD/gochan.json for testing migration"
|
||||
sed -i gochan.json \
|
||||
-e 's/"Port": .*/"Port": 9000,/' \
|
||||
-e 's/"UseFastCGI": false/"UseFastCGI": true/' \
|
||||
-e "s/\"DBtype\": .*/\"DBtype\": \""$DBTYPE"\",/" \
|
||||
-e 's/"DBpassword": ""/"DBpassword": "gochan"/' \
|
||||
-e 's/"DBname": "gochan"/"DBname": "gochan_37"/' \
|
||||
-e 's/"SiteName": "Gochan"/"SiteName": "Gochan Migration Test"/' \
|
||||
-e 's/"SiteSlogan": ""/"SiteSlogan": "Gochan instance used for testing gochan-migrate -updatedb"/' \
|
||||
-e 's/"DebugMode": false/"DebugMode": true/' \
|
||||
-e 's/"Verbosity": 0/"Verbosity": 1/'
|
||||
|
||||
if [ "$DBTYPE" = "mysql" ]; then
|
||||
echo "Creating testing MySQL DB 'gochan_37' if it doesn't already exist"
|
||||
sudo mysql <<- EOF1
|
||||
CREATE DATABASE IF NOT EXISTS gochan_37;
|
||||
GRANT USAGE ON *.* TO gochan IDENTIFIED BY 'gochan'; \
|
||||
GRANT ALL PRIVILEGES ON gochan_37.* TO gochan; \
|
||||
SET PASSWORD FOR 'gochan'@'%' = PASSWORD('gochan');
|
||||
FLUSH PRIVILEGES;
|
||||
EOF1
|
||||
elif [ "$DBTYPE" = "postgresql" ]; then
|
||||
echo "Creating testing PostgreSQL DB 'gochan_37' if it doesn't already exist"
|
||||
sed -i /etc/gochan/gochan.json \
|
||||
-e 's/"DBhost": ".*"/"DBhost": "127.0.0.1"/'
|
||||
sudo -u postgres psql -f - <<- EOF1
|
||||
CREATE DATABASE gochan_37;
|
||||
GRANT ALL PRIVILEGES ON DATABASE gochan_37 TO gochan;
|
||||
EOF1
|
||||
else
|
||||
echo "Currently using unsupported \$DBTYPE: $DBTYPE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo ./gochan
|
|
@ -123,6 +123,21 @@ type IPBan struct {
|
|||
ipBanBase
|
||||
}
|
||||
|
||||
// IP was previously a field in the IPBan struct before range bans were
|
||||
// implemented. This is here as a fallback for templates
|
||||
//
|
||||
// Deprecated: Use the RangeStart and RangeEnd fields or gcutil.GetIPRangeSubnet
|
||||
func (ipb *IPBan) IP() string {
|
||||
if ipb.RangeStart == ipb.RangeEnd {
|
||||
return ipb.RangeStart
|
||||
}
|
||||
inet, err := gcutil.GetIPRangeSubnet(ipb.RangeStart, ipb.RangeEnd)
|
||||
if err != nil {
|
||||
return "?"
|
||||
}
|
||||
return inet.String()
|
||||
}
|
||||
|
||||
func (ipb *IPBan) IsBanned(ipStr string) (bool, error) {
|
||||
ipn, err := gcutil.GetIPRangeSubnet(ipb.RangeStart, ipb.RangeEnd)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<input type="hidden" name="do" value="add" />
|
||||
<h2>Add IP ban</h2>
|
||||
<table>
|
||||
<tr><th>Mask</th><td><input type="text" name="ip" value="{{banMask .ban}}" style="width: 100%;"/></td></tr>
|
||||
<tr><th>IP/Mask</th><td><input type="text" name="ip" value="{{banMask .ban}}" style="width: 100%;"/></td></tr>
|
||||
<tr><th>Duration</th><td><input type="text" name="duration" style="width: 100%;" {{if gt .ban.ID 0}}value="{{until .ban.ExpiresAt}}"{{end}}/></td></tr>
|
||||
<tr><th></th><td>e.g. '1y2mo3w4d5h6m7s',<br />'1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds'<br/>Optional if "Permanent" is checked, required otherwise</td></tr>
|
||||
<tr><th>Permanent</th><td><input type="checkbox" name="permanent" id="permanent" {{if .ban.Permanent}}checked{{end}}> (overrides the duration)</td></tr>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue