YetAnotherToDoList/database/main.go

118 lines
4.5 KiB
Go

/*
YetAnotherToDoList
Copyright © 2023 gilex-dev gilex-dev@proton.me
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package database
import (
"database/sql"
"fmt"
"log"
"time"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
)
type CustomDB struct {
connection *sql.DB
logger *log.Logger
schema uint
secret []byte
}
var initTimeStamp int
func InitSQLite3(path string, schema uint, logger *log.Logger, secret []byte, initialAdminName string, initialAdminPassword string) *CustomDB {
initTimeStamp = int(time.Now().Unix())
db := CustomDB{logger: logger, schema: schema, secret: secret}
var err error
db.connection, err = sql.Open("sqlite3", "file:"+path+"?_foreign_keys=1")
if err != nil {
db.logger.Fatalln("Unable to open:", err)
}
if err = db.connection.Ping(); err != nil {
db.logger.Fatalln("Unable to connect:", err)
}
var user_version uint
err = db.connection.QueryRow("PRAGMA user_version").Scan(&user_version)
if err != nil {
db.logger.Fatalln("Failed to get database schema version")
}
switch {
case user_version == 0:
db.logger.Println("Initializing empty database")
if err = db.createSQLite3Tables(); err != nil {
db.logger.Fatalln("Error in creating table: ", err)
}
err = db.CreateInitialAdmin(initialAdminName, initialAdminPassword)
if err != nil {
db.logger.Fatal("failed to create initial admin. Try to fix and delete old database file: ", err)
}
case user_version > db.schema:
db.logger.Fatalln("Incompatible database schema version. Try updating this software.")
case user_version < db.schema:
db.logger.Fatalln("Upgrading database schema currently not supported")
}
return &db
}
func (db CustomDB) createSQLite3Tables() error {
tables := []struct {
name string
sql string
}{
{"User", "userId INTEGER PRIMARY KEY NOT NULL, userName VARCHAR NOT NULL UNIQUE CHECK(length(userName)!=0), passwordHash VARCHAR NOT NULL CHECK(length(passwordHash)!=0), fullName VARCHAR CHECK(length(fullName)!=0)"},
{"Todo", "todoId INTEGER PRIMARY KEY NOT NULL, text VARCHAR NOT NULL CHECK(length(text)!=0), IS_done BOOL NOT NULL DEFAULT false, FK_User_userId INTEGER NOT NULL, FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
{"R_User_Role", "relationId INTEGER PRIMARY KEY NOT NULL, FK_Role_roleId INTEGER NOT NULL, FK_User_userId INTEGER NOT NULL, IS_roleManager BOOL NOT NULL, UNIQUE(FK_Role_roleId, FK_User_userId), FOREIGN KEY(FK_Role_roleId) REFERENCES Role(roleId) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
{"Role", "roleId INTEGER PRIMARY KEY NOT NULL, roleName VARCHAR NOT NULL UNIQUE CHECK(length(roleName)!=0), IS_admin BOOL NOT NULL, IS_userCreator BOOL NOT NULL"},
{"RefreshToken", "tokenId INTEGER PRIMARY KEY NOT NULL, FK_User_userId INTEGER NOT NULL, selector VARCHAR NOT NULL CHECK(length(selector)!=0) UNIQUE, tokenHash VARCHAR NOT NULL CHECK(length(tokenHash)!=0), expiryDate INTEGER NOT NULL, tokenName VARCHAR CHECK(length(tokenName)!=0), FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
}
for _, table := range tables {
_, err := db.connection.Exec("CREATE TABLE IF NOT EXISTS " + table.name + " (" + table.sql + ")")
if err != nil {
return err
} else {
db.logger.Println("Successfully created", table.name)
}
}
_, err := db.connection.Exec("PRAGMA user_version = " + fmt.Sprintf("%d", db.schema))
if err != nil {
db.logger.Fatalln("Failed to set user_version:", err)
}
return nil
}
func (db CustomDB) CreateInitialAdmin(initialAdminName string, initialAdminPassword string) error {
role, err := db.CreateRole(&model.NewRole{RoleName: "admin", IsAdmin: true, IsUserCreator: true})
if err != nil {
return err
}
user, err := db.CreateUser(model.NewUser{UserName: initialAdminName, Password: initialAdminPassword})
if err != nil {
return err
}
_, err = db.AddUserRole(user.ID, role.ID, true)
if err != nil {
return err
}
return nil
}