diff --git a/Justfile b/Justfile index 0d99e3a..432fbd1 100644 --- a/Justfile +++ b/Justfile @@ -11,7 +11,7 @@ start-release: build-container-release remove-podman-containers # Removes and stops any containers related to the project [private] remove-podman-containers: - podman container rm -f ttime + podman container rm -fi ttime # Saves the release container to a tarball, pigz is just gzip but multithreaded save-release: build-container-release @@ -23,14 +23,14 @@ load-release file: # Tests every part of the project testall: - cd backend && make test - cd backend && make lint cd frontend && npm test cd frontend && npm run lint + cd backend && make test + cd backend && make lint # Cleans up everything related to the project clean: remove-podman-containers - podman image rm -f ttime-server + podman image rm -fi ttime-server rm -rf frontend/dist rm -rf frontend/node_modules rm -f ttime-server.tar.gz @@ -41,3 +41,6 @@ clean: remove-podman-containers [confirm] podman-clean: podman system reset --force + +install-linter: + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.56.2 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..668ccf1 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +# Builds a release container +build-container-release: + podman build -t ttime-server -f container/Containerfile . + +# Builds a release container and runs it +start-release: build-container-release remove-podman-containers + podman run -d -e DATABASE_URL=sqlite:release.db -p 8080:8080 --name ttime ttime-server + @echo "Started production ttime-server on http://localhost:8080" + +# Removes and stops any containers related to the project +remove-podman-containers: + podman container rm -fi ttime + +# Tests every part of the project +testall: + cd frontend && npm test + cd frontend && npm run lint + cd backend && make test + cd backend && make lint + +# Cleans up everything related to the project +clean: remove-podman-containers + podman image rm -fi ttime-server + rm -rf frontend/dist + rm -rf frontend/node_modules + rm -f ttime-server.tar.gz + cd backend && make clean + @echo "Cleaned up!" + +# Cleans up everything related to podman, not just the project. Make sure you understand what this means. +podman-clean: + podman system reset --force + +# Installs the linter, which is not included in the ubuntu repo +install-linter: + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.56.2 + +# This installs just, a make alternative, which is slightly more ergonomic to use +install-just: + @echo "Installing just" + @curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin \ No newline at end of file diff --git a/README.md b/README.md index fc55126..d75861a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ My recommendation would be to make WSL your primary development environment if y You should consult the [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/install), but for any recent version of windows, installation essentially boils down to running the following command in **PowerShell as an administrator**: ```powershell -wsl --install +wsl --install -d Ubuntu-22.04 # To get a somewhat recent version of Go ``` If you get any errors related to virtualization, you will need to enable virtualization in the BIOS. This is a common issue, and you can find a guide for your specific motherboard online. This is a one-time operation and will not affect your windows installation. This setting is usually called "VT-x" or "AMD-V" and is usually found in the CPU settings. If you can't find it, shoot me a message and I'll find it for you. diff --git a/backend/Makefile b/backend/Makefile index 23eefa0..dcc79b4 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -69,3 +69,7 @@ lint: # Default target default: build + +install-just: + @echo "Installing just" + @curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin diff --git a/backend/go.mod b/backend/go.mod index ab9be66..94d5519 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -10,8 +10,8 @@ require ( require ( github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect - github.com/gofiber/contrib/jwt v1.0.8 // indirect - github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/gofiber/contrib/jwt v1.0.8 + github.com/golang-jwt/jwt/v5 v5.2.1 ) // These are all for fiber diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index 6e86641..84937f1 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -14,9 +14,13 @@ import ( type Database interface { 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 } // This struct is a wrapper type that holds the database connection @@ -30,6 +34,11 @@ var scripts embed.FS const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)" const projectInsert = "INSERT INTO projects (name, description, user_id) SELECT ?, ?, id FROM users WHERE username = ?" +const promoteToAdmin = "INSERT INTO site_admin (admin_id) SELECT id FROM users WHERE username = ?" + +// const addTimeReport = "" +// const addUserToProject = "" +// const changeUserRole = "" // DbConnect connects to the database func DbConnect(dbpath string) Database { @@ -48,6 +57,18 @@ func DbConnect(dbpath string) Database { return &Db{db} } +// func (d *Db) AddTimeReport(projectname string, start time.Time, end time.Time) error { + +// } + +// func (d *Db) AddUserToProject(username string, projectname string) error { + +// } + +// func (d *Db) ChangeUserRole(username string, projectname string, role string) error { + +// } + // AddUser adds a user to the database func (d *Db) AddUser(username string, password string) error { _, err := d.Exec(userInsert, username, password) @@ -60,6 +81,11 @@ func (d *Db) RemoveUser(username string) error { return err } +func (d *Db) PromoteToAdmin(username string) error { + _, err := d.Exec(promoteToAdmin, username) + return err +} + func (d *Db) GetUserId(username string) (int, error) { var id int err := d.Get(&id, "SELECT id FROM users WHERE username = ?", username) diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index 6830668..96eb9b7 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -74,3 +74,32 @@ func TestDbRemoveUser(t *testing.T) { t.Error("RemoveUser failed:", err) } } + +func TestPromoteToAdmin(t *testing.T) { + db, err := setupState() + if err != nil { + t.Error("setupState failed:", err) + } + + err = db.AddUser("test", "password") + if err != nil { + t.Error("AddUser failed:", err) + } + + err = db.PromoteToAdmin("test") + if err != nil { + t.Error("PromoteToAdmin failed:", err) + } +} + +// func TestAddTimeReport(t *testing.T) { + +// } + +// func TestAddUserToProject(t *testing.T) { + +// } + +// func TestChangeUserRole(t *testing.T) { + +// } diff --git a/backend/internal/database/migrations/0060_site_admin.sql b/backend/internal/database/migrations/0060_site_admin.sql new file mode 100644 index 0000000..14de60d --- /dev/null +++ b/backend/internal/database/migrations/0060_site_admin.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS site_admin ( + admin_id INTEGER PRIMARY KEY, + FOREIGN KEY (admin_id) REFERENCES users (id) ON DELETE CASCADE +) \ No newline at end of file diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 5dc8895..ffe2072 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -115,6 +115,7 @@ func (gs *GState) Login(c *fiber.Ctx) error { // LoginRenew is a simple handler that renews the token func (gs *GState) LoginRenew(c *fiber.Ctx) error { + // For testing: curl localhost:3000/restricted -H "Authorization: Bearer " user := c.Locals("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) claims["exp"] = time.Now().Add(time.Hour * 72).Unix()