2018-11-08 10:21:06 +00:00
|
|
|
package companydb
|
2018-11-07 10:10:51 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2018-11-07 19:13:26 +00:00
|
|
|
"errors"
|
2018-11-07 10:10:51 +00:00
|
|
|
"fmt"
|
2018-11-13 18:02:47 +00:00
|
|
|
"io/ioutil"
|
2018-11-08 10:21:06 +00:00
|
|
|
tokenTools "multitenantStack/services/tokenTools"
|
2018-11-07 10:10:51 +00:00
|
|
|
"os"
|
|
|
|
|
2018-11-13 18:02:47 +00:00
|
|
|
"github.com/BurntSushi/toml"
|
2018-11-07 19:13:26 +00:00
|
|
|
jwt "github.com/dgrijalva/jwt-go"
|
2018-11-07 10:10:51 +00:00
|
|
|
)
|
|
|
|
|
2018-11-13 18:02:47 +00:00
|
|
|
type DBConfig struct {
|
|
|
|
User string
|
|
|
|
Password string
|
|
|
|
Host string
|
|
|
|
Port int
|
|
|
|
Db string
|
|
|
|
Ssl string
|
|
|
|
}
|
|
|
|
|
|
|
|
var Conf DBConfig
|
2018-11-07 10:10:51 +00:00
|
|
|
var dbs map[string]*sql.DB
|
|
|
|
|
2018-11-08 10:21:06 +00:00
|
|
|
// InitCompanyDBService Init companydb service and open system db connection
|
|
|
|
func InitCompanyDBService() {
|
2018-11-13 18:02:47 +00:00
|
|
|
|
|
|
|
tomlData, _ := ioutil.ReadFile("conf/dbConfig.toml")
|
|
|
|
if _, err := toml.Decode(string(tomlData), &Conf); err != nil {
|
|
|
|
// handle error
|
|
|
|
panic(err.Error())
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2018-11-08 10:21:06 +00:00
|
|
|
dbs = make(map[string]*sql.DB)
|
2018-11-07 10:10:51 +00:00
|
|
|
|
2018-11-13 18:02:47 +00:00
|
|
|
conStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", Conf.Host, Conf.Port, Conf.User, Conf.Password, Conf.Db, Conf.Ssl)
|
|
|
|
|
|
|
|
systemDB, err := sql.Open("postgres", conStr)
|
2018-11-07 10:10:51 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Fatal: could not connect to db, exiting... Error:", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
dbs["system"] = systemDB
|
|
|
|
}
|
|
|
|
|
2018-11-08 07:36:08 +00:00
|
|
|
// GetSystemDatabase returns system db
|
|
|
|
func GetSystemDatabase() *sql.DB {
|
|
|
|
return dbs["system"]
|
|
|
|
}
|
|
|
|
|
2018-11-08 10:42:31 +00:00
|
|
|
// GetDatabaseWithName Get orm and user information
|
2018-11-08 07:36:08 +00:00
|
|
|
func GetDatabaseWithName(companyName string) (*sql.DB, error) {
|
|
|
|
if dbs[companyName] != nil {
|
|
|
|
fmt.Println("DB Already open")
|
|
|
|
return dbs[companyName], nil
|
|
|
|
}
|
|
|
|
|
2018-11-13 18:02:47 +00:00
|
|
|
conStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", Conf.Host, Conf.Port, Conf.User, Conf.Password, companyName, Conf.Ssl)
|
2018-11-08 07:36:08 +00:00
|
|
|
db, err := sql.Open("postgres", conStr)
|
2018-11-08 10:21:06 +00:00
|
|
|
dbs[companyName] = db
|
2018-11-08 07:36:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db, nil
|
|
|
|
}
|
|
|
|
|
2018-11-07 10:10:51 +00:00
|
|
|
// GetDatabase Get orm and user information
|
2018-11-07 19:13:26 +00:00
|
|
|
func GetDatabase(tokenString string) (jwt.MapClaims, *sql.DB, error) {
|
2018-11-07 10:10:51 +00:00
|
|
|
// validate token
|
2018-11-08 10:21:06 +00:00
|
|
|
valid, token := tokenTools.Validate(tokenString)
|
2018-11-07 19:13:26 +00:00
|
|
|
if !valid {
|
|
|
|
return nil, nil, errors.New("Token is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
tokenMap := token.Claims.(jwt.MapClaims)
|
|
|
|
companyName := tokenMap["companyName"].(string)
|
|
|
|
|
|
|
|
if dbs[companyName] != nil {
|
|
|
|
fmt.Println("DB Already open")
|
|
|
|
return tokenMap, dbs[companyName], nil
|
|
|
|
}
|
|
|
|
|
2018-11-13 20:39:04 +00:00
|
|
|
db, err := GetDatabaseWithName(companyName)
|
2018-11-07 19:13:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2018-11-07 10:10:51 +00:00
|
|
|
// return db with orm or error
|
2018-11-07 19:13:26 +00:00
|
|
|
return tokenMap, db, nil
|
2018-11-07 10:10:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 20:39:04 +00:00
|
|
|
// HasDatabase Check if DB exists
|
|
|
|
func HasDatabase(dbname string) bool {
|
|
|
|
systemDB := GetSystemDatabase()
|
|
|
|
result, err := systemDB.Query("SELECT datname FROM pg_database WHERE datistemplate = false;")
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for result.Next() {
|
|
|
|
var aDbName string
|
|
|
|
result.Scan(&aDbName)
|
|
|
|
if aDbName == dbname {
|
|
|
|
return true
|
2018-11-07 10:10:51 +00:00
|
|
|
}
|
2018-11-13 20:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateDatabase Create a database by copying the template
|
|
|
|
func CreateDatabase(companyName string) (*sql.DB, error) {
|
|
|
|
if HasDatabase(companyName) {
|
|
|
|
return nil, errors.New("DB already exists")
|
|
|
|
}
|
|
|
|
|
|
|
|
systemDB := GetSystemDatabase()
|
|
|
|
// Takes about 1.2 seconds and we trust companyName to be sanitized in register
|
|
|
|
queryString := fmt.Sprintf("CREATE DATABASE %s TEMPLATE company_template;", companyName)
|
|
|
|
_, err := systemDB.Exec(queryString)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
db, err := GetDatabaseWithName(companyName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db, nil
|
2018-11-07 10:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteDatabase Delete an entire database, this is very very dangerous :-)
|
2018-11-13 20:39:04 +00:00
|
|
|
func DeleteDatabase(companyName string) error {
|
|
|
|
if !HasDatabase(companyName) {
|
|
|
|
return errors.New("DB does not exist")
|
|
|
|
}
|
|
|
|
systemDB := GetSystemDatabase()
|
|
|
|
|
|
|
|
db, err := GetDatabaseWithName(companyName)
|
|
|
|
db.Close()
|
|
|
|
delete(dbs, companyName)
|
|
|
|
fmt.Println("Closed %s", companyName)
|
|
|
|
|
|
|
|
queryString := fmt.Sprintf("DROP DATABASE %s;", companyName)
|
|
|
|
_, err = systemDB.Exec(queryString)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
2018-11-07 10:10:51 +00:00
|
|
|
}
|