diff --git a/go.mod b/go.mod index 09943f7..fb562ff 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module tms go 1.22.0 -require github.com/mattn/go-sqlite3 v1.14.24 // indirect +require ( + github.com/mattn/go-sqlite3 v1.14.24 // indirect + golang.org/x/crypto v0.33.0 +) diff --git a/go.sum b/go.sum index 9dcdc9b..c2beb89 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= diff --git a/main.go b/main.go index 338ea75..c7f938f 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,8 @@ import ( "net/http" "time" + "golang.org/x/crypto/bcrypt" + _ "github.com/mattn/go-sqlite3" ) @@ -300,16 +302,87 @@ func addTrainerHandler(w http.ResponseWriter, r *http.Request) { } +func hashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(bytes), err +} + +func setupAdminHandler(w http.ResponseWriter, r *http.Request) { + // Check if an admin exists + var count int + err := db.QueryRow("SELECT COUNT(*) FROM admins").Scan(&count) + if err != nil { + http.Error(w, "Database error", http.StatusInternalServerError) + return + } + + // If an admin exists, redirect to login + if count > 0 { + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + + // If it's a POST request, create the admin + if r.Method == http.MethodPost { + name := r.FormValue("name") + email := r.FormValue("email") + password := r.FormValue("password") + + if email == "" || password == "" || name == "" { + http.Error(w, "Name, email and password are required", http.StatusBadRequest) + return + } + + // Hash the password + hashedPassword, err := hashPassword(password) + if err != nil { + http.Error(w, "Error hashing password", http.StatusInternalServerError) + return + } + + // Insert the admin into the database + _, err = db.Exec("INSERT INTO admins (name, email, password) VALUES (?, ?, ?)", name, email, hashedPassword) + if err != nil { + http.Error(w, "Error saving admin", http.StatusInternalServerError) + return + } + + // Redirect to login after setup + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + + // Show the admin setup page + err = tmpl.ExecuteTemplate(w, "setup_admin.html", nil) + if err != nil { + http.Error(w, "Template rendering error", http.StatusInternalServerError) + } +} + +func redirectIfNoAdmin(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var count int + err := db.QueryRow("SELECT COUNT(*) FROM admins").Scan(&count) + if err != nil || count == 0 { + http.Redirect(w, r, "/setup-admin", http.StatusSeeOther) + return + } + next.ServeHTTP(w, r) + }) +} + func main() { initDB() initTemplates() - http.HandleFunc("/", homeHandler) - http.HandleFunc("/trainings", trainingListHandler) - http.HandleFunc("/trainers", trainerListHandler) - http.HandleFunc("/trainers/add", addTrainerHandler) - http.HandleFunc("/training-areas", trainingAreaListHandler) - http.HandleFunc("/training-areas/add", addTrainingAreaHandler) - http.HandleFunc("/training-areas/assign-trainer", assignTrainerToAreaHandler) + http.Handle("/", redirectIfNoAdmin(http.HandlerFunc(homeHandler))) + http.Handle("/trainings", redirectIfNoAdmin(http.HandlerFunc(trainingListHandler))) + http.Handle("/trainers", redirectIfNoAdmin(http.HandlerFunc(trainerListHandler))) + http.Handle("/trainers/add", redirectIfNoAdmin(http.HandlerFunc(addTrainerHandler))) + http.Handle("/training-areas", redirectIfNoAdmin(http.HandlerFunc(trainingAreaListHandler))) + http.Handle("/training-areas/add", redirectIfNoAdmin(http.HandlerFunc(addTrainingAreaHandler))) + http.Handle("/training-areas/assign-trainer", redirectIfNoAdmin(http.HandlerFunc(assignTrainerToAreaHandler))) + + http.HandleFunc("/setup-admin", setupAdminHandler) fmt.Println("Server running on http://localhost:8080") http.ListenAndServe(":8080", nil) diff --git a/schema.sql b/schema.sql index e567faf..eab07a8 100644 --- a/schema.sql +++ b/schema.sql @@ -42,3 +42,10 @@ CREATE TABLE IF NOT EXISTS training_training_areas ( FOREIGN KEY (training_id) REFERENCES trainings(id), FOREIGN KEY (training_area_id) REFERENCES training_areas(id) ); + +CREATE TABLE IF NOT EXISTS admins ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + email TEXT UNIQUE NOT NULL, + password TEXT NOT NULL +); \ No newline at end of file diff --git a/templates/setup_admin.html b/templates/setup_admin.html new file mode 100644 index 0000000..af6ea2a --- /dev/null +++ b/templates/setup_admin.html @@ -0,0 +1,20 @@ + + +{{template "head.html" .}} + + +{{template "header.html" .}} +

Setup Admin Account

+
+ +
+ +
+ + +
+ + +
+ +