Merge imbs

This commit is contained in:
Imbus 2024-03-14 14:37:50 +01:00
commit be04ba148d
10 changed files with 204 additions and 64 deletions

View file

@ -1,9 +1,7 @@
package database
import (
"database/sql"
"embed"
"fmt"
"os"
"path/filepath"
"time"
@ -16,19 +14,15 @@ import (
type Database interface {
// Insert a new user into the database, password should be hashed before calling
AddUser(username string, password string) error
RemoveUser(username string) error
PromoteToAdmin(username string) error
GetUserId(username string) (int, error)
AddProject(name string, description string, username string) error
Migrate(dirname string) error
// AddTimeReport(projectname string, start time.Time, end time.Time) error
// AddUserToProject(username string, projectname string) error
// ChangeUserRole(username string, projectname string, role string) error
// AddTimeReport(projectname string, start time.Time, end time.Time) error
// AddUserToProject(username string, projectname string) error
ChangeUserRole(username string, projectname string, role string) error
GetProjectId(projectname string) (int, error)
AddTimeReport(projectName string, userName string, start time.Time, end time.Time) error
AddUserToProject(username string, projectname string, role string) error
ChangeUserRole(username string, projectname string, role string) error
}
// This struct is a wrapper type that holds the database connection
@ -40,11 +34,16 @@ type Db struct {
//go:embed migrations
var scripts embed.FS
// TODO: Possibly break these out into separate files bundled with the embed package?
const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)"
const projectInsert = "INSERT INTO projects (name, description, owner_user_id) SELECT ?, ?, id FROM users WHERE username = ?"
const promoteToAdmin = "INSERT INTO site_admin (admin_id) SELECT id FROM users WHERE username = ?"
const addTimeReport = "INSERT INTO activity (report_id, activity_nbr, start_time, end_time, break, comment) VALUES (?, ?, ?, ?, ?, ?)" // WIP
const addUserToProject = "INSERT INTO project_member (project_id, user_id, role) VALUES (?, ?, ?)" // WIP
const addTimeReport = `WITH UserLookup AS (SELECT id FROM users WHERE username = ?),
ProjectLookup AS (SELECT id FROM projects WHERE name = ?)
INSERT INTO time_reports (project_id, user_id, start, end)
VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup), ?, ?);`
const addUserToProject = "INSERT INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)" // WIP
const changeUserRole = "UPDATE user_roles SET p_role = ? WHERE user_id = ? AND project_id = ?"
// DbConnect connects to the database
func DbConnect(dbpath string) Database {
@ -63,24 +62,8 @@ func DbConnect(dbpath string) Database {
return &Db{db}
}
func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
userID, err := d.GetUserId(username)
if err != nil {
return err
}
projectID, err := d.GetProjectId(projectname)
if err != nil {
return err
}
// Update user role in the project using the correct table name
_, err = d.Exec("INSERT OR REPLACE INTO user_roles (user_id, project_id, p_role) VALUES (?, ?, ?)", userID, projectID, role)
return err
}
func (d *Db) AddTimeReport(projectname string, start time.Time, end time.Time, breakTime uint32) error { // WIP
_, err := d.Exec(addTimeReport, projectname, 0, start, end, breakTime, false)
func (d *Db) AddTimeReport(projectName string, userName string, start time.Time, end time.Time) error { // WIP
_, err := d.Exec(addTimeReport, userName, projectName, start, end)
return err
}
@ -97,13 +80,26 @@ func (d *Db) AddUserToProject(username string, projectname string, role string)
panic(err2)
}
_, err3 := d.Exec(addUserToProject, projectid, userid, role)
_, err3 := d.Exec(addUserToProject, userid, projectid, role)
return err3
}
// func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
func (d *Db) ChangeUserRole(username string, projectname string, role string) error {
var userid int
userid, err := d.GetUserId(username)
if err != nil {
panic(err)
}
// }
var projectid int
projectid, err2 := d.GetProjectId(projectname)
if err2 != nil {
panic(err2)
}
_, err3 := d.Exec(changeUserRole, role, userid, projectid)
return err3
}
// AddUser adds a user to the database
func (d *Db) AddUser(username string, password string) error {
@ -131,13 +127,7 @@ func (d *Db) GetUserId(username string) (int, error) {
func (d *Db) GetProjectId(projectname string) (int, error) {
var id int
err := d.Get(&id, "SELECT id FROM projects WHERE name = ?", projectname)
if err != nil {
if err == sql.ErrNoRows {
return 0, fmt.Errorf("project '%s' not found", projectname)
}
return 0, err
}
return id, nil
return id, err
}
// Creates a new project in the database, associated with a user

View file

@ -2,6 +2,7 @@ package database
import (
"testing"
"time"
)
// Tests are not guaranteed to be sequential
@ -92,40 +93,84 @@ func TestPromoteToAdmin(t *testing.T) {
}
}
func TestDbChangeUserRole(t *testing.T) {
// Set up the initial state
func TestAddTimeReport(t *testing.T) {
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
}
// Add a user
err = db.AddUser("test", "password")
err = db.AddUser("testuser", "password")
if err != nil {
t.Error("AddUser failed:", err)
}
// Add a project
err = db.AddProject("test_project", "project description", "test")
err = db.AddProject("testproject", "description", "testuser")
if err != nil {
t.Error("AddProject failed:", err)
}
// Change user role
err = db.ChangeUserRole("test", "test_project", "project_manager")
var now = time.Now()
var then = now.Add(time.Hour)
err = db.AddTimeReport("testproject", "testuser", now, then)
if err != nil {
t.Error("AddTimeReport failed:", err)
}
}
func TestAddUserToProject(t *testing.T) {
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
}
err = db.AddUser("testuser", "password")
if err != nil {
t.Error("AddUser failed:", err)
}
err = db.AddProject("testproject", "description", "testuser")
if err != nil {
t.Error("AddProject failed:", err)
}
var now = time.Now()
var then = now.Add(time.Hour)
err = db.AddTimeReport("testproject", "testuser", now, then)
if err != nil {
t.Error("AddTimeReport failed:", err)
}
err = db.AddUserToProject("testuser", "testproject", "user")
if err != nil {
t.Error("AddUserToProject failed:", err)
}
}
func TestChangeUserRole(t *testing.T) {
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
}
err = db.AddUser("testuser", "password")
if err != nil {
t.Error("AddUser failed:", err)
}
err = db.AddProject("testproject", "description", "testuser")
if err != nil {
t.Error("AddProject failed:", err)
}
err = db.AddUserToProject("testuser", "testproject", "user")
if err != nil {
t.Error("AddUserToProject failed:", err)
}
err = db.ChangeUserRole("testuser", "testproject", "admin")
if err != nil {
t.Error("ChangeUserRole failed:", err)
}
}
// func TestAddTimeReport(t *testing.T) {
// }
// func TestAddUserToProject(t *testing.T) {
// }
// func TestChangeUserRole(t *testing.T) {
// }

View file

@ -1,11 +1,9 @@
CREATE TABLE IF NOT EXISTS projects (
id INTEGER PRIMARY KEY,
projectId TEXT DEFAULT (HEX(RANDOMBLOB(4))) NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL UNIQUE,
description TEXT NOT NULL,
owner_user_id INTEGER NOT NULL,
FOREIGN KEY (owner_user_id) REFERENCES users (id)
);
CREATE INDEX IF NOT EXISTS projects_projectId_index ON projects (projectId);
CREATE INDEX IF NOT EXISTS projects_user_id_index ON projects (owner_user_id);

View file

@ -1,10 +1,11 @@
CREATE TABLE IF NOT EXISTS time_reports (
id INTEGER PRIMARY KEY,
reportId TEXT DEFAULT (HEX(RANDOMBLOB(6))) NOT NULL UNIQUE,
project_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
start DATETIME NOT NULL,
end DATETIME NOT NULL,
FOREIGN KEY (project_id) REFERENCES projects (id) ON DELETE CASCADE
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
);
CREATE TRIGGER IF NOT EXISTS time_reports_start_before_end