2023-10-10 22:26:07 +02:00
/ *
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"
2023-11-05 17:42:14 +01:00
"time"
2023-10-10 22:26:07 +02:00
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
)
type CustomDB struct {
connection * sql . DB
logger * log . Logger
schema uint
2023-11-05 17:42:14 +01:00
secret [ ] byte
2023-10-10 22:26:07 +02:00
}
2023-11-05 17:42:14 +01:00
var initTimeStamp int
2023-10-10 22:26:07 +02:00
2023-11-05 17:42:14 +01:00
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 }
2023-10-10 22:26:07 +02:00
var err error
2023-10-27 13:08:39 +02:00
db . connection , err = sql . Open ( "sqlite3" , "file:" + path + "?_foreign_keys=1" )
2023-10-10 22:26:07 +02:00
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 )
}
2023-11-05 17:42:14 +01:00
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 )
}
2023-10-10 22:26:07 +02:00
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
} {
2023-11-05 17:42:14 +01:00
{ "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)" } ,
2023-11-17 19:09:01 +01:00
{ "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" } ,
2023-11-18 15:51:10 +01:00
{ "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" } ,
2023-11-05 17:42:14 +01:00
{ "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" } ,
2023-10-10 22:26:07 +02:00
}
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 )
}
}
2023-10-27 13:08:39 +02:00
_ , err := db . connection . Exec ( "PRAGMA user_version = " + fmt . Sprintf ( "%d" , db . schema ) )
2023-10-10 22:26:07 +02:00
if err != nil {
db . logger . Fatalln ( "Failed to set user_version:" , err )
}
return nil
}
2023-11-05 17:42:14 +01:00
func ( db CustomDB ) CreateInitialAdmin ( initialAdminName string , initialAdminPassword string ) error {
role , err := db . CreateRole ( & model . NewRole { RoleName : "admin" , IsAdmin : true , IsUserCreator : true } )
2023-10-10 22:26:07 +02:00
if err != nil {
2023-11-05 17:42:14 +01:00
return err
2023-10-10 22:26:07 +02:00
}
2023-11-05 17:42:14 +01:00
user , err := db . CreateUser ( model . NewUser { UserName : initialAdminName , Password : initialAdminPassword } )
2023-10-10 22:26:07 +02:00
if err != nil {
2023-11-05 17:42:14 +01:00
return err
2023-10-10 22:26:07 +02:00
}
2023-11-18 15:51:10 +01:00
_ , err = db . AddUserRole ( user . ID , role . ID , true )
2023-10-10 22:26:07 +02:00
if err != nil {
2023-11-05 17:42:14 +01:00
return err
2023-10-10 22:26:07 +02:00
}
2023-11-05 17:42:14 +01:00
return nil
2023-10-10 22:26:07 +02:00
}