package fic import ( "database/sql" "log" "os" "time" _ "github.com/go-sql-driver/mysql" ) // db stores the connection to the database var db *sql.DB // DSNGenerator returns DSN filed with values from environment func DSNGenerator() string { db_user := "fic" db_password := "fic" db_host := "" db_db := "fic" if v, exists := os.LookupEnv("MYSQL_HOST"); exists { db_host = v } if v, exists := os.LookupEnv("MYSQL_PASSWORD"); exists { db_password = v } else if v, exists := os.LookupEnv("MYSQL_ROOT_PASSWORD"); exists { db_user = "root" db_password = v } if v, exists := os.LookupEnv("MYSQL_USER"); exists { db_user = v } if v, exists := os.LookupEnv("MYSQL_DATABASE"); exists { db_db = v } return db_user + ":" + db_password + "@" + db_host + "/" + db_db } // DBInit establishes the connection to the database func DBInit(dsn string) (err error) { if db, err = sql.Open("mysql", dsn + "?parseTime=true&foreign_key_checks=1"); err != nil { return } _, err = db.Exec(`SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO';`) for i := 0; err != nil && i < 15; i += 1 { if _, err = db.Exec(`SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO';`); err != nil && i <= 5 { log.Println("An error occurs when trying to connect to DB, will retry in 2 seconds: ", err) time.Sleep(2 * time.Second) } } return } // DBCreate creates all necessary tables used by the package func DBCreate() error { if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS events( id_event INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, txt VARCHAR(255) NOT NULL, kind ENUM('alert-primary', 'alert-secondary', 'alert-success', 'alert-danger', 'alert-warning', 'alert-info', 'alert-light', 'alert-dark') NOT NULL, time TIMESTAMP NOT NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS themes( id_theme INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL UNIQUE, url_id VARCHAR(255) NOT NULL UNIQUE, intro TEXT NOT NULL, authors TEXT NOT NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS teams( id_team INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, color INTEGER NOT NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS certificates( id_cert BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, creation TIMESTAMP NOT NULL, password VARCHAR(255) NOT NULL, revoked TIMESTAMP NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS team_members( id_member INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_team INTEGER, firstname VARCHAR(255) NOT NULL, lastname VARCHAR(255) NOT NULL, nickname VARCHAR(255) NOT NULL, company VARCHAR(255) NOT NULL, FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercices( id_exercice INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_theme INTEGER NOT NULL, title VARCHAR(255) NOT NULL, url_id VARCHAR(255) NOT NULL, path VARCHAR(255) NOT NULL, statement TEXT NOT NULL, overview TEXT NOT NULL, depend INTEGER, gain INTEGER NOT NULL, coefficient_cur FLOAT NOT NULL DEFAULT 1.0, video_uri VARCHAR(255) NOT NULL, FOREIGN KEY(id_theme) REFERENCES themes(id_theme), FOREIGN KEY(depend) REFERENCES exercices(id_exercice) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_files( id_file INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, origin VARCHAR(255) NOT NULL, path VARCHAR(255) NOT NULL UNIQUE, id_exercice INTEGER NOT NULL, name VARCHAR(255) NOT NULL, cksum BINARY(64) NOT NULL, size INTEGER NOT NULL, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_hints( id_hint INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_exercice INTEGER NOT NULL, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, cost INTEGER NOT NULL, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_keys( id_key INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_exercice INTEGER NOT NULL, type VARCHAR(255) NOT NULL, cksum BINARY(64) NOT NULL, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_mcq( id_mcq INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_exercice INTEGER NOT NULL, title VARCHAR(255) NOT NULL, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS mcq_entries( id_mcq_entry INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_mcq INTEGER NOT NULL, label VARCHAR(255) NOT NULL, response BOOLEAN NOT NULL, FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS mcq_found( id_mcq INTEGER NOT NULL, id_team INTEGER NOT NULL, time TIMESTAMP NOT NULL, CONSTRAINT uq_found UNIQUE (id_mcq,id_team), FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS key_found( id_key INTEGER NOT NULL, id_team INTEGER NOT NULL, time TIMESTAMP NOT NULL, CONSTRAINT uc_found UNIQUE (id_key,id_team), FOREIGN KEY(id_key) REFERENCES exercice_keys(id_key), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_solved( id_exercice INTEGER NOT NULL, id_team INTEGER NOT NULL, time TIMESTAMP NOT NULL, coefficient FLOAT NOT NULL DEFAULT 1.0, CONSTRAINT uc_solved UNIQUE (id_exercice,id_team), FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS exercice_tries( id_exercice INTEGER NOT NULL, id_team INTEGER NOT NULL, time TIMESTAMP NOT NULL, nbdiff INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS team_hints( id_team INTEGER, id_hint INTEGER, time TIMESTAMP NOT NULL, CONSTRAINT uc_displayed UNIQUE (id_team,id_hint), FOREIGN KEY(id_hint) REFERENCES exercice_hints(id_hint), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS claim_assignees( id_assignee INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL UNIQUE ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS claims( id_claim INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, subject VARCHAR(255) NOT NULL, id_team INTEGER, id_assignee INTEGER, creation TIMESTAMP NOT NULL, state ENUM('new', 'need-info', 'confirmed', 'in-progress', 'need-review', 'closed', 'invalid') NOT NULL, priority ENUM('low', 'medium', 'high', 'critical') NOT NULL, FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee), FOREIGN KEY(id_team) REFERENCES teams(id_team) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } if _, err := db.Exec(` CREATE TABLE IF NOT EXISTS claim_descriptions( id_description INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_claim INTEGER NOT NULL, id_assignee INTEGER NOT NULL, date TIMESTAMP NOT NULL, content TEXT NOT NULL, FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee), FOREIGN KEY(id_claim) REFERENCES claims(id_claim) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } return nil } // DBClose closes the connection to the database func DBClose() error { return db.Close() } func DBPrepare(query string) (*sql.Stmt, error) { return db.Prepare(query) } func DBQuery(query string, args ...interface{}) (*sql.Rows, error) { return db.Query(query, args...) } func DBExec(query string, args ...interface{}) (sql.Result, error) { return db.Exec(query, args...) } func DBQueryRow(query string, args ...interface{}) *sql.Row { return db.QueryRow(query, args...) }