diff --git a/backend/Makefile b/backend/Makefile index da0e254..9cfa335 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -118,7 +118,3 @@ uml: plantuml.jar install-just: @echo "Installing just" @curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin - -.PHONY: types -types: - tygo generate \ No newline at end of file diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index c13308b..a0cf5b9 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -21,7 +21,7 @@ type Database interface { AddProject(name string, description string, username string) error Migrate(dirname string) error GetProjectId(projectname string) (int, error) - AddTimeReport(projectName string, userName string, activityType string, start time.Time, end time.Time) 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 GetAllUsersProject(projectname string) ([]UserProjectMember, error) @@ -52,8 +52,8 @@ const projectInsert = "INSERT INTO projects (name, description, owner_user_id) S const promoteToAdmin = "INSERT INTO site_admin (admin_id) SELECT id FROM users WHERE username = ?" 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, activity_type, start, end) - VALUES ((SELECT id FROM ProjectLookup), (SELECT id FROM UserLookup),?, ?, ?);` + 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 = ?" @@ -89,34 +89,29 @@ func DbConnect(dbpath string) Database { return &Db{db} } -// GetProjectsForUser retrieves all projects associated with a specific user. func (d *Db) GetProjectsForUser(username string) ([]types.Project, error) { var projects []types.Project err := d.Select(&projects, getProjectsForUser, username) return projects, err } -// GetAllProjects retrieves all projects from the database. func (d *Db) GetAllProjects() ([]types.Project, error) { var projects []types.Project err := d.Select(&projects, "SELECT * FROM projects") return projects, err } -// GetProject retrieves a specific project by its ID. func (d *Db) GetProject(projectId int) (types.Project, error) { var project types.Project err := d.Select(&project, "SELECT * FROM projects WHERE id = ?") return project, err } -// AddTimeReport adds a time report for a specific project and user. -func (d *Db) AddTimeReport(projectName string, userName string, activityType string, start time.Time, end time.Time) error { // WIP - _, err := d.Exec(addTimeReport, userName, projectName, activityType, start, end) +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 } -// AddUserToProject adds a user to a project with a specified role. func (d *Db) AddUserToProject(username string, projectname string, role string) error { // WIP var userid int userid, err := d.GetUserId(username) @@ -134,28 +129,23 @@ func (d *Db) AddUserToProject(username string, projectname string, role string) return err3 } -// ChangeUserRole changes the role of a user within a project. func (d *Db) ChangeUserRole(username string, projectname string, role string) error { - // Get the user ID var userid int userid, err := d.GetUserId(username) if err != nil { panic(err) } - // Get the project ID var projectid int projectid, err2 := d.GetProjectId(projectname) if err2 != nil { panic(err2) } - // Execute the SQL query to change the user's role _, err3 := d.Exec(changeUserRole, role, userid, projectid) return err3 } -// GetUserRole retrieves the role of a user within a project. 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) diff --git a/backend/internal/database/db_test.go b/backend/internal/database/db_test.go index 9118e2f..117c08a 100644 --- a/backend/internal/database/db_test.go +++ b/backend/internal/database/db_test.go @@ -112,7 +112,7 @@ func TestAddTimeReport(t *testing.T) { var now = time.Now() var then = now.Add(time.Hour) - err = db.AddTimeReport("testproject", "testuser", "activity", now, then) + err = db.AddTimeReport("testproject", "testuser", now, then) if err != nil { t.Error("AddTimeReport failed:", err) } @@ -137,7 +137,7 @@ func TestAddUserToProject(t *testing.T) { var now = time.Now() var then = now.Add(time.Hour) - err = db.AddTimeReport("testproject", "testuser", "activity", now, then) + err = db.AddTimeReport("testproject", "testuser", now, then) if err != nil { t.Error("AddTimeReport failed:", err) } diff --git a/backend/internal/database/migrations/0030_time_reports.sql b/backend/internal/database/migrations/0030_time_reports.sql index 7c169c2..76812a1 100644 --- a/backend/internal/database/migrations/0030_time_reports.sql +++ b/backend/internal/database/migrations/0030_time_reports.sql @@ -2,12 +2,10 @@ CREATE TABLE IF NOT EXISTS time_reports ( id INTEGER PRIMARY KEY, project_id INTEGER NOT NULL, user_id INTEGER NOT NULL, - activity_type TEXT 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 - FOREIGN KEY (activity_type) REFERENCES activity_types (name) ON DELETE CASCADE ); CREATE TRIGGER IF NOT EXISTS time_reports_start_before_end diff --git a/backend/internal/database/migrations/0070_salts.sql b/backend/internal/database/migrations/0070_salts.sql index de9757d..b84dfac 100644 --- a/backend/internal/database/migrations/0070_salts.sql +++ b/backend/internal/database/migrations/0070_salts.sql @@ -1,7 +1,7 @@ -- It is unclear weather this table will be used -- Create the table to store hash salts -CREATE TABLE IF NOT EXISTS salts ( +CREATE TABLE salts ( id INTEGER PRIMARY KEY, salt TEXT NOT NULL ); diff --git a/backend/internal/database/migrations/0080_activity_types.sql b/backend/internal/database/migrations/0080_activity_types.sql deleted file mode 100644 index d984d58..0000000 --- a/backend/internal/database/migrations/0080_activity_types.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE IF NOT EXISTS activity_types ( - name TEXT PRIMARY KEY -); - -INSERT OR IGNORE INTO activity_types (name) VALUES ('Development'); -INSERT OR IGNORE INTO activity_types (name) VALUES ('Meeting'); -INSERT OR IGNORE INTO activity_types (name) VALUES ('Administration'); -INSERT OR IGNORE INTO activity_types (name) VALUES ('Own Work'); -INSERT OR IGNORE INTO activity_types (name) VALUES ('Studies'); -INSErt OR IGNORE INTO activity_types (name) VALUES ('Testing'); \ No newline at end of file diff --git a/backend/tygo.yaml b/backend/tygo.yaml deleted file mode 100644 index 54c1e8f..0000000 --- a/backend/tygo.yaml +++ /dev/null @@ -1,9 +0,0 @@ -packages: - - path: "ttime/internal/types" - output_path: "../frontend/src/Types/goTypes.ts" - type_mappings: - time.Time: "string /* RFC3339 */" - null.String: "null | string" - null.Bool: "null | boolean" - uuid.UUID: "string /* uuid */" - uuid.NullUUID: "null | string /* uuid */" diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index 1051c03..447a464 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -9,7 +9,7 @@ module.exports = { 'plugin:react-hooks/recommended', 'plugin:prettier/recommended', ], - ignorePatterns: ['dist', '.eslintrc.cjs', 'tailwind.config.js', 'postcss.config.js', 'jest.config.cjs', 'goTypes.ts'], + ignorePatterns: ['dist', '.eslintrc.cjs', 'tailwind.config.js', 'postcss.config.js', 'jest.config.cjs'], parser: '@typescript-eslint/parser', plugins: ['react-refresh', 'prettier'], rules: { diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 248ad37..f33c87c 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -1,120 +1,57 @@ import { NewProject, Project } from "../Types/Project"; import { NewUser, User } from "../Types/Users"; -// This type of pattern should be hard to misuse -interface APIResponse { - success: boolean; - message?: string; - data?: T; -} - -// Note that all protected routes also require a token // Defines all the methods that an instance of the API must implement interface API { /** Register a new user */ - registerUser(user: NewUser): Promise>; + registerUser(user: NewUser): Promise; /** Remove a user */ - removeUser(username: string, token: string): Promise>; + removeUser(username: string): Promise; /** Create a project */ - createProject( - project: NewProject, - token: string, - ): Promise>; + createProject(project: NewProject): Promise; /** Renew the token */ - renewToken(token: string): Promise>; + renewToken(token: string): Promise; } // Export an instance of the API export const api: API = { - async registerUser(user: NewUser): Promise> { - try { - const response = await fetch("/api/register", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(user), - }); - - if (!response.ok) { - return { success: false, message: "Failed to register user" }; - } else { - const data = (await response.json()) as User; - return { success: true, data }; - } - } catch (e) { - return { success: false, message: "Failed to register user" }; - } + async registerUser(user: NewUser): Promise { + return fetch("/api/register", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(user), + }).then((res) => res.json() as Promise); }, - async removeUser( - username: string, - token: string, - ): Promise> { - try { - const response = await fetch("/api/userdelete", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(username), - }); - - if (!response.ok) { - return { success: false, message: "Failed to remove user" }; - } else { - const data = (await response.json()) as User; - return { success: true, data }; - } - } catch (e) { - return { success: false, message: "Failed to remove user" }; - } + async removeUser(username: string): Promise { + return fetch("/api/userdelete", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(username), + }).then((res) => res.json() as Promise); }, - async createProject( - project: NewProject, - token: string, - ): Promise> { - try { - const response = await fetch("/api/project", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(project), - }); - - if (!response.ok) { - return { success: false, message: "Failed to create project" }; - } else { - const data = (await response.json()) as Project; - return { success: true, data }; - } - } catch (e) { - return { success: false, message: "Failed to create project" }; - } + async createProject(project: NewProject): Promise { + return fetch("/api/project", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(project), + }).then((res) => res.json() as Promise); }, - async renewToken(token: string): Promise> { - try { - const response = await fetch("/api/loginrenew", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - }); - - if (!response.ok) { - return { success: false, message: "Failed to renew token" }; - } else { - const data = (await response.json()) as string; - return { success: true, data }; - } - } catch (e) { - return { success: false, message: "Failed to renew token" }; - } + async renewToken(token: string): Promise { + return fetch("/api/loginrenew", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + token, + }, + }).then((res) => res.json() as Promise); }, }; diff --git a/frontend/src/Components/Button.tsx b/frontend/src/Components/Button.tsx index 38a1853..cf6a887 100644 --- a/frontend/src/Components/Button.tsx +++ b/frontend/src/Components/Button.tsx @@ -1,17 +1,14 @@ function Button({ text, onClick, - type, }: { text: string; onClick: () => void; - type: "submit" | "button" | "reset"; }): JSX.Element { return ( diff --git a/frontend/src/Components/Register.tsx b/frontend/src/Components/Register.tsx index e4a3ba0..d0e3da6 100644 --- a/frontend/src/Components/Register.tsx +++ b/frontend/src/Components/Register.tsx @@ -1,8 +1,6 @@ import { useState } from "react"; import { NewUser } from "../Types/Users"; import { api } from "../API/API"; -import Logo from "../assets/Logo.svg"; -import Button from "./Button"; export default function Register(): JSX.Element { const [username, setUsername] = useState(""); @@ -14,32 +12,25 @@ export default function Register(): JSX.Element { }; return ( -
-
+
+
{ e.preventDefault(); void handleRegister(); }} > - TTIME Logo -

- Register New User -

+

Register new user

-

diff --git a/frontend/src/Pages/AdminPages/AdminAddProject.tsx b/frontend/src/Pages/AdminPages/AdminAddProject.tsx index 2922400..9fd8bed 100644 --- a/frontend/src/Pages/AdminPages/AdminAddProject.tsx +++ b/frontend/src/Pages/AdminPages/AdminAddProject.tsx @@ -11,14 +11,12 @@ function AdminAddProject(): JSX.Element { onClick={(): void => { return; }} - type="button" />
diff --git a/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx b/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx index bd800a7..6d87b90 100644 --- a/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx +++ b/frontend/src/Pages/ProjectManagerPages/PMChangeRole.tsx @@ -11,14 +11,12 @@ function ChangeRole(): JSX.Element { onClick={(): void => { return; }} - type="button" />