diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index e7f9251..5221e4d 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -5,7 +5,6 @@ import ( "os" "path/filepath" "time" - "ttime/internal/types" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" @@ -24,11 +23,6 @@ type Database interface { 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 - GetAllUsersProject(projectname string) ([]UserProjectMember, error) - GetAllUsersApplication() ([]string, error) - GetProjectsForUser(username string) ([]types.Project, error) - GetAllProjects() ([]types.Project, error) - GetUserRole(username string, projectname string) (string, error) } // This struct is a wrapper type that holds the database connection @@ -37,11 +31,6 @@ type Db struct { *sqlx.DB } -type UserProjectMember struct { - Username string `db:"username"` - UserRole string `db:"p_role"` -} - //go:embed migrations var scripts embed.FS @@ -56,21 +45,6 @@ const addTimeReport = `WITH UserLookup AS (SELECT id FROM users WHERE username = 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 = ?" -const getProjectsForUser = ` -SELECT - projects.id, - projects.name, - projects.description, - projects.owner_user_id -FROM - projects -JOIN - user_roles ON projects.id = user_roles.project_id -JOIN - users ON user_roles.user_id = users.id -WHERE - users.username = ?;` - // DbConnect connects to the database func DbConnect(dbpath string) Database { // Open the database @@ -88,18 +62,6 @@ func DbConnect(dbpath string) Database { return &Db{db} } -func (d *Db) GetProjectsForUser(username string) ([]types.Project, error) { - var projects []types.Project - err := d.Select(&projects, getProjectsForUser, username) - return projects, err -} - -func (d *Db) GetAllProjects() ([]types.Project, error) { - var projects []types.Project - err := d.Select(&projects, "SELECT * FROM projects") - return projects, err -} - 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 @@ -139,12 +101,6 @@ func (d *Db) ChangeUserRole(username string, projectname string, role string) er return err3 } -func (d *Db) GetUserRole(username string, projectname string) (string, error) { - var role string - err := d.Get(&role, "SELECT p_role FROM user_roles WHERE user_id = (SELECT id FROM users WHERE username = ?) AND project_id = (SELECT id FROM projects WHERE name = ?)", username, projectname) - return role, err -} - // AddUser adds a user to the database func (d *Db) AddUser(username string, password string) error { _, err := d.Exec(userInsert, username, password) @@ -180,69 +136,6 @@ func (d *Db) AddProject(name string, description string, username string) error return err } -func (d *Db) GetAllUsersProject(projectname string) ([]UserProjectMember, error) { - // Define the SQL query to fetch users and their roles for a given project - query := ` - SELECT u.username, ur.p_role - FROM users u - INNER JOIN user_roles ur ON u.id = ur.user_id - INNER JOIN projects p ON ur.project_id = p.id - WHERE p.name = ? - ` - - // Execute the query - rows, err := d.Queryx(query, projectname) - if err != nil { - return nil, err - } - defer rows.Close() - - // Iterate over the rows and populate the result slice - var users []UserProjectMember - for rows.Next() { - var user UserProjectMember - if err := rows.StructScan(&user); err != nil { - return nil, err - } - users = append(users, user) - } - if err := rows.Err(); err != nil { - return nil, err - } - - return users, nil -} - -// GetAllUsersApplication retrieves all usernames from the database -func (d *Db) GetAllUsersApplication() ([]string, error) { - // Define the SQL query to fetch all usernames - query := ` - SELECT username FROM users - ` - - // Execute the query - rows, err := d.Queryx(query) - if err != nil { - return nil, err - } - defer rows.Close() - - // Iterate over the rows and populate the result slice - var usernames []string - for rows.Next() { - var username string - if err := rows.Scan(&username); err != nil { - return nil, err - } - usernames = append(usernames, username) - } - if err := rows.Err(); err != nil { - return nil, err - } - - return usernames, nil -} - // Reads a directory of migration files and applies them to the database. // This will eventually be used on an embedded directory func (d *Db) Migrate(dirname string) error { diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index 7650739..b5fe49f 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -169,177 +169,8 @@ func TestChangeUserRole(t *testing.T) { t.Error("AddUserToProject failed:", err) } - role, err := db.GetUserRole("testuser", "testproject") - if err != nil { - t.Error("GetUserRole failed:", err) - } - if role != "user" { - t.Error("GetUserRole failed: expected user, got", role) - } - err = db.ChangeUserRole("testuser", "testproject", "admin") if err != nil { t.Error("ChangeUserRole failed:", err) } - - role, err = db.GetUserRole("testuser", "testproject") - if err != nil { - t.Error("GetUserRole failed:", err) - } - if role != "admin" { - t.Error("GetUserRole failed: expected admin, got", role) - } - -} - -func TestGetAllUsersProject(t *testing.T) { - db, err := setupState() - if err != nil { - t.Error("setupState failed:", err) - } - - err = db.AddUser("testuser1", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - err = db.AddUser("testuser2", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - err = db.AddProject("testproject", "description", "testuser1") - if err != nil { - t.Error("AddProject failed:", err) - } - - err = db.AddUserToProject("testuser1", "testproject", "project_manager") - if err != nil { - t.Error("AddUserToProject failed:", err) - } - - err = db.AddUserToProject("testuser2", "testproject", "user") - if err != nil { - t.Error("AddUserToProject failed:", err) - } - - users, err := db.GetAllUsersProject("testproject") - if err != nil { - t.Error("GetAllUsersProject failed:", err) - } - - // Check if both users are returned with their roles - if len(users) != 2 { - t.Errorf("Expected 2 users, got %d", len(users)) - } - - // Check if testuser1 has project manager role - foundProjectManager := false - for _, user := range users { - if user.Username == "testuser1" && user.UserRole == "project_manager" { - foundProjectManager = true - break - } - } - if !foundProjectManager { - t.Error("Project Manager user not found") - } - - // Check if testuser2 has user role - foundUser := false - for _, user := range users { - if user.Username == "testuser2" && user.UserRole == "user" { - foundUser = true - break - } - } - if !foundUser { - t.Error("User user not found") - } -} - -func TestGetAllUsersApplication(t *testing.T) { - db, err := setupState() - if err != nil { - t.Error("setupState failed:", err) - } - - err = db.AddUser("testuser1", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - err = db.AddUser("testuser2", "password") - if err != nil { - t.Error("AddUser failed:", err) - } - - users, err := db.GetAllUsersApplication() - if err != nil { - t.Error("GetAllUsersApplication failed:", err) - } - - // Check if both users are returned - if len(users) != 2 { - t.Errorf("Expected 2 users, got %d", len(users)) - } - - // Check if the test users are included in the list - foundTestUser1 := false - foundTestUser2 := false - for _, user := range users { - if user == "testuser1" { - foundTestUser1 = true - } - if user == "testuser2" { - foundTestUser2 = true - } - } - - if !foundTestUser1 { - t.Error("testuser1 not found") - } - if !foundTestUser2 { - t.Error("testuser2 not found") - } -} - -func TestGetProjectsForUser(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) - } - - projects1, err := db.GetAllProjects() - if err != nil { - t.Error("GetAllProjects failed:", err) - } - - if len(projects1) != 1 { - t.Error("GetAllProjects failed: expected 1, got", len(projects1)) - } - - projects, err := db.GetProjectsForUser("testuser") - if err != nil { - t.Error("GetProjectsForUser failed:", err) - } - - if len(projects) != 1 { - t.Error("GetProjectsForUser failed: expected 1, got", len(projects)) - } } diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 0f3fcc0..9c42133 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -11,12 +11,12 @@ import ( // The actual interface that we will use type GlobalState interface { - Register(c *fiber.Ctx) error // To register a new user - UserDelete(c *fiber.Ctx) error // To delete a user - Login(c *fiber.Ctx) error // To get the token - LoginRenew(c *fiber.Ctx) error // To renew the token - CreateProject(c *fiber.Ctx) error // To create a new project - GetUserProjects(c *fiber.Ctx) error // To get all projects + Register(c *fiber.Ctx) error // To register a new user + UserDelete(c *fiber.Ctx) error // To delete a user + Login(c *fiber.Ctx) error // To get the token + LoginRenew(c *fiber.Ctx) error // To renew the token + CreateProject(c *fiber.Ctx) error // To create a new project + // GetProjects(c *fiber.Ctx) error // To get all projects // GetProject(c *fiber.Ctx) error // To get a specific project // UpdateProject(c *fiber.Ctx) error // To update a project // DeleteProject(c *fiber.Ctx) error // To delete a project @@ -163,20 +163,3 @@ func (gs *GState) CreateProject(c *fiber.Ctx) error { return c.Status(200).SendString("Project added") } - -// GetUserProjects returns all projects that the user is a member of -func (gs *GState) GetUserProjects(c *fiber.Ctx) error { - // First we get the username from the token - user := c.Locals("user").(*jwt.Token) - claims := user.Claims.(jwt.MapClaims) - username := claims["name"].(string) - - // Then dip into the database to get the projects - projects, err := gs.Db.GetProjectsForUser(username) - if err != nil { - return c.Status(500).SendString(err.Error()) - } - - // Return a json serialized list of projects - return c.JSON(projects) -} diff --git a/backend/internal/types/project.go b/backend/internal/types/project.go index 8fcfaf5..cabf6c6 100644 --- a/backend/internal/types/project.go +++ b/backend/internal/types/project.go @@ -1,11 +1,16 @@ package types +import ( + "time" +) + // Project is a struct that holds the information about a project type Project struct { - ID int `json:"id" db:"id"` - Name string `json:"name" db:"name"` - Description string `json:"description" db:"description"` - Owner string `json:"owner" db:"owner_user_id"` + ID int `json:"id" db:"id"` + Name string `json:"name" db:"name"` + Description string `json:"description" db:"description"` + Owner string `json:"owner" db:"owner"` + Created time.Time `json:"created" db:"created"` } // As it arrives from the client diff --git a/backend/main.go b/backend/main.go index f7b0f7f..bba3fa6 100644 --- a/backend/main.go +++ b/backend/main.go @@ -69,7 +69,6 @@ func main() { SigningKey: jwtware.SigningKey{Key: []byte("secret")}, })) - server.Get("/api/getUserProjects", gs.GetUserProjects) server.Post("/api/loginrenew", gs.LoginRenew) server.Delete("/api/userdelete", gs.UserDelete) // Perhaps just use POST to avoid headaches server.Post("/api/project", gs.CreateProject) diff --git a/frontend/src/Components/Header.tsx b/frontend/src/Components/Header.tsx index ba0a939..5c642b8 100644 --- a/frontend/src/Components/Header.tsx +++ b/frontend/src/Components/Header.tsx @@ -15,7 +15,7 @@ function Header({ username }: { username: string }): JSX.Element { > TTIME Logo diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index d0e3da6..8181774 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { NewUser } from "../Types/Users"; +import { NewUser, User } from "../Types/Users"; import { api } from "../API/API"; export default function Register(): JSX.Element { @@ -8,7 +8,7 @@ export default function Register(): JSX.Element { const handleRegister = async (): Promise => { const newUser: NewUser = { userName: username, password }; - await api.registerUser(newUser); // TODO: Handle errors + const user = await api.registerUser(newUser); }; return ( diff --git a/frontend/src/Components/TimeReport.tsx b/frontend/src/Components/TimeReport.tsx deleted file mode 100644 index c4ddc38..0000000 --- a/frontend/src/Components/TimeReport.tsx +++ /dev/null @@ -1,59 +0,0 @@ -function NewTimeReport(): JSX.Element { - const activities = [ - "Development", - "Meeting", - "Administration", - "Own Work", - "Studies", - "Testing", - ]; - - return ( - <> -
- { - event.preventDefault(); - }} - onPaste={(event) => { - event.preventDefault(); - }} - /> - - - - - - - - - {activities.map((activity, index) => ( - - - - - ))} - -
Activity - Total Time (min) -
{activity} - { - const keyValue = event.key; - if (!/\d/.test(keyValue) && keyValue !== "Backspace") - event.preventDefault(); - }} - /> -
-
- - ); -} - -export default NewTimeReport; diff --git a/frontend/src/Pages/AdminPages/AdminAddProject.tsx b/frontend/src/Pages/AdminPages/AdminAddProject.tsx deleted file mode 100644 index 9fd8bed..0000000 --- a/frontend/src/Pages/AdminPages/AdminAddProject.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import BasicWindow from "../../Components/BasicWindow"; -import Button from "../../Components/Button"; - -function AdminAddProject(): JSX.Element { - const content = <>; - - const buttons = ( - <> -