0d1e4e5993
Add the ExtraTmpls developer setting to config.json Call ForumStore.BypassGet in ForumStore.Reload instead of duplicating it. Fix a potential deadlock in ForumStore.Create. Attempt to fix a weird installation bug. Add a few more forum store test cases. You will need to run the updater / patcher for this commit.
235 lines
4.9 KiB
Go
235 lines
4.9 KiB
Go
/*
|
|
*
|
|
* Gosora MySQL Interface
|
|
* Copyright Azareal 2017 - 2020
|
|
*
|
|
*/
|
|
package install
|
|
|
|
import (
|
|
"bytes"
|
|
"database/sql"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/Azareal/Gosora/query_gen"
|
|
_ "github.com/go-sql-driver/mysql"
|
|
)
|
|
|
|
//var dbCollation string = "utf8mb4_general_ci"
|
|
|
|
func init() {
|
|
adapters["mysql"] = &MysqlInstaller{dbHost: ""}
|
|
}
|
|
|
|
type MysqlInstaller struct {
|
|
db *sql.DB
|
|
dbHost string
|
|
dbUsername string
|
|
dbPassword string
|
|
dbName string
|
|
dbPort string
|
|
}
|
|
|
|
func (ins *MysqlInstaller) SetConfig(dbHost string, dbUsername string, dbPassword string, dbName string, dbPort string) {
|
|
ins.dbHost = dbHost
|
|
ins.dbUsername = dbUsername
|
|
ins.dbPassword = dbPassword
|
|
ins.dbName = dbName
|
|
ins.dbPort = dbPort
|
|
}
|
|
|
|
func (ins *MysqlInstaller) Name() string {
|
|
return "mysql"
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DefaultPort() string {
|
|
return "3306"
|
|
}
|
|
|
|
func (ins *MysqlInstaller) dbExists(dbName string) (bool, error) {
|
|
var waste string
|
|
err := ins.db.QueryRow("SHOW DATABASES LIKE '" + dbName + "'").Scan(&waste)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return false, err
|
|
} else if err == sql.ErrNoRows {
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (ins *MysqlInstaller) InitDatabase() (err error) {
|
|
_dbPassword := ins.dbPassword
|
|
if _dbPassword != "" {
|
|
_dbPassword = ":" + _dbPassword
|
|
}
|
|
db, err := sql.Open("mysql", ins.dbUsername+_dbPassword+"@tcp("+ins.dbHost+":"+ins.dbPort+")/")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Make sure that the connection is alive..
|
|
err = db.Ping()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("Successfully connected to the database")
|
|
|
|
ins.db = db
|
|
ok, err := ins.dbExists(ins.dbName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !ok {
|
|
fmt.Println("Unable to find the database. Attempting to create it")
|
|
_, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + ins.dbName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("The database was successfully created")
|
|
}
|
|
|
|
/*fmt.Println("Switching to database ", ins.dbName)
|
|
_, err = db.Exec("USE " + ins.dbName)
|
|
if err != nil {
|
|
return err
|
|
}*/
|
|
db.Close()
|
|
|
|
db, err = sql.Open("mysql", ins.dbUsername+_dbPassword+"@tcp("+ins.dbHost+":"+ins.dbPort+")/"+ins.dbName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Make sure that the connection is alive..
|
|
err = db.Ping()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("Successfully connected to the database")
|
|
|
|
// Ready the query builder
|
|
ins.db = db
|
|
qgen.Builder.SetConn(db)
|
|
return qgen.Builder.SetAdapter("mysql")
|
|
}
|
|
|
|
func (ins *MysqlInstaller) createTable(f os.FileInfo) error {
|
|
table := strings.TrimPrefix(f.Name(), "query_")
|
|
ext := filepath.Ext(table)
|
|
if ext != ".sql" {
|
|
return nil
|
|
}
|
|
table = strings.TrimSuffix(table, ext)
|
|
|
|
// ? - This is mainly here for tests, although it might allow the installer to overwrite a production database, so we might want to proceed with caution
|
|
q := "DROP TABLE IF EXISTS `" + table + "`;"
|
|
_, err := ins.db.Exec(q)
|
|
if err != nil {
|
|
fmt.Println("Failed query:", q)
|
|
fmt.Println("e:", err)
|
|
return err
|
|
}
|
|
|
|
data, err := ioutil.ReadFile("./schema/mysql/" + f.Name())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data = bytes.TrimSpace(data)
|
|
|
|
q = string(data)
|
|
_, err = ins.db.Exec(q)
|
|
if err != nil {
|
|
fmt.Println("Failed query:", q)
|
|
fmt.Println("e:", err)
|
|
return err
|
|
}
|
|
fmt.Printf("Created table '%s'\n", table)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ins *MysqlInstaller) TableDefs() (err error) {
|
|
fmt.Println("Creating the tables")
|
|
files, err := ioutil.ReadDir("./schema/mysql/")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = ins.db.Exec("SET FOREIGN_KEY_CHECKS = 0;")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, f := range files {
|
|
if !strings.HasPrefix(f.Name(), "query_") {
|
|
continue
|
|
}
|
|
err := ins.createTable(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
_, err = ins.db.Exec("SET FOREIGN_KEY_CHECKS = 1;")
|
|
return err
|
|
}
|
|
|
|
// ? - Moved this here since it was breaking the installer, we need to add this at some point
|
|
/* TODO: Implement the html-attribute setting type before deploying this */
|
|
/*INSERT INTO settings(`name`,`content`,`type`) VALUES ('meta_desc','','html-attribute');*/
|
|
|
|
func (ins *MysqlInstaller) InitialData() error {
|
|
fmt.Println("Seeding the tables")
|
|
data, err := ioutil.ReadFile("./schema/mysql/inserts.sql")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data = bytes.TrimSpace(data)
|
|
|
|
statements := bytes.Split(data, []byte(";"))
|
|
for key, sBytes := range statements {
|
|
statement := string(sBytes)
|
|
if statement == "" {
|
|
continue
|
|
}
|
|
statement += ";"
|
|
|
|
fmt.Println("Executing query #" + strconv.Itoa(key) + " " + statement)
|
|
_, err = ins.db.Exec(statement)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ins *MysqlInstaller) CreateAdmin() error {
|
|
return createAdmin()
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DBHost() string {
|
|
return ins.dbHost
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DBUsername() string {
|
|
return ins.dbUsername
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DBPassword() string {
|
|
return ins.dbPassword
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DBName() string {
|
|
return ins.dbName
|
|
}
|
|
|
|
func (ins *MysqlInstaller) DBPort() string {
|
|
return ins.dbPort
|
|
}
|