diff --git a/backend/internal/database/sample_data/0010_sample_data.sql b/backend/internal/database/sample_data/0010_sample_data.sql index ab74f1a..092fbb0 100644 --- a/backend/internal/database/sample_data/0010_sample_data.sql +++ b/backend/internal/database/sample_data/0010_sample_data.sql @@ -7,8 +7,6 @@ VALUES ("user", "123"); INSERT OR IGNORE INTO users(username, password) VALUES ("user2", "123"); -INSERT OR IGNORE INTO site_admin VALUES (1); - INSERT OR IGNORE INTO projects(name,description,owner_user_id) VALUES ("projecttest","test project", 1); diff --git a/backend/internal/handlers/handlers_project_related.go b/backend/internal/handlers/handlers_project_related.go index e9ef966..603f4cd 100644 --- a/backend/internal/handlers/handlers_project_related.go +++ b/backend/internal/handlers/handlers_project_related.go @@ -44,11 +44,10 @@ func (gs *GState) DeleteProject(c *fiber.Ctx) error { // GetUserProjects returns all projects that the user is a member of func (gs *GState) GetUserProjects(c *fiber.Ctx) error { - username := c.Params("username") - if username == "" { - log.Info("No username provided") - return c.Status(400).SendString("No username provided") - } + // 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) diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index bc4ae2d..39788ae 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -59,9 +59,9 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read username from Locals auth_username := c.Locals("user").(*jwt.Token).Claims.(jwt.MapClaims)["name"].(string) - if username == auth_username { - log.Info("User tried to delete itself") - return c.Status(403).SendString("You can't delete yourself") + if username != auth_username { + log.Info("User tried to delete another user") + return c.Status(403).SendString("You can only delete yourself") } if err := gs.Db.RemoveUser(username); err != nil { diff --git a/backend/main.go b/backend/main.go index 7d98918..ff6b94e 100644 --- a/backend/main.go +++ b/backend/main.go @@ -84,7 +84,7 @@ func main() { // Protected routes (require a valid JWT bearer token authentication header) server.Post("/api/submitWeeklyReport", gs.SubmitWeeklyReport) - server.Get("/api/getUserProjects/:username", gs.GetUserProjects) + server.Get("/api/getUserProjects", gs.GetUserProjects) server.Post("/api/loginrenew", gs.LoginRenew) server.Delete("/api/userdelete/:username", gs.UserDelete) // Perhaps just use POST to avoid headaches server.Delete("api/project/:projectID", gs.DeleteProject) // WIP diff --git a/frontend/src/API/API.ts b/frontend/src/API/API.ts index 39b5d0a..5c49a8d 100644 --- a/frontend/src/API/API.ts +++ b/frontend/src/API/API.ts @@ -6,8 +6,6 @@ import { NewProject, UserProjectMember, WeeklyReport, - StrNameChange, - NewProjMember, } from "../Types/goTypes"; /** @@ -114,14 +112,10 @@ interface API { ): Promise>; /** Gets all the projects of a user - * @param {string} username - The authentication token. * @param {string} token - The authentication token. * @returns {Promise>} A promise containing the API response with the user's projects. */ - getUserProjects( - username: string, - token: string, - ): Promise>; + getUserProjects(token: string): Promise>; /** Gets a project by its id. * @param {number} id The id of the project to retrieve. @@ -139,20 +133,6 @@ interface API { projectName: string, token: string, ): Promise>; - /** - * Changes the username of a user in the database. - * @param {StrNameChange} data The object containing the previous and new username. - * @param {string} token The authentication token. - * @returns {Promise>} A promise resolving to an API response. - */ - changeUserName( - data: StrNameChange, - token: string, - ): Promise>; - addUserToProject( - user: NewProjMember, - token: string, - ): Promise>; } /** An instance of the API */ @@ -190,17 +170,19 @@ export const api: API = { ): Promise> { try { const response = await fetch(`/api/userdelete/${username}`, { - method: "DELETE", + method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer " + token, }, body: JSON.stringify(username), }); + if (!response.ok) { - return { success: false, message: "Could not remove user" }; + return { success: false, message: "Failed to remove user" }; } else { - return { success: true }; + const data = (await response.json()) as User; + return { success: true, data }; } } catch (e) { return { success: false, message: "Failed to remove user" }; @@ -261,30 +243,6 @@ export const api: API = { } }, - async addUserToProject( - user: NewProjMember, - token: string, - ): Promise> { - try { - const response = await fetch("/api/addUserToProject", { - method: "PUT", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(user), - }); - - if (!response.ok) { - return { success: false, message: "Failed to add member" }; - } else { - return { success: true, message: "Added member" }; - } - } catch (e) { - return { success: false, message: "Failed to add member" }; - } - }, - async renewToken(token: string): Promise> { try { const response = await fetch("/api/loginrenew", { @@ -306,12 +264,9 @@ export const api: API = { } }, - async getUserProjects( - username: string, - token: string, - ): Promise> { + async getUserProjects(token: string): Promise> { try { - const response = await fetch(`/api/getUserProjects/${username}`, { + const response = await fetch("/api/getUserProjects", { method: "GET", headers: { "Content-Type": "application/json", @@ -529,28 +484,4 @@ export const api: API = { }); } }, - - async changeUserName( - data: StrNameChange, - token: string, - ): Promise> { - try { - const response = await fetch("/api/changeUserName", { - method: "PUT", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer " + token, - }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - return { success: false, message: "Failed to change username" }; - } else { - return { success: true }; - } - } catch (e) { - return { success: false, message: "Failed to change username" }; - } - }, }; diff --git a/frontend/src/Components/AddMember.tsx b/frontend/src/Components/AddMember.tsx deleted file mode 100644 index d29be68..0000000 --- a/frontend/src/Components/AddMember.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { APIResponse, api } from "../API/API"; -import { NewProjMember } from "../Types/goTypes"; - -/** - * Tries to add a member to a project - * @param {Object} props - A NewProjMember - * @returns {boolean} True if added, false if not - */ -function AddMember(props: { memberToAdd: NewProjMember }): boolean { - let added = false; - if ( - props.memberToAdd.username === "" || - props.memberToAdd.role === "" || - props.memberToAdd.projectname === "" - ) { - alert("All fields must be filled before adding"); - return added; - } - api - .addUserToProject( - props.memberToAdd, - localStorage.getItem("accessToken") ?? "", - ) - .then((response: APIResponse) => { - if (response.success) { - alert("Member added"); - added = true; - } else { - alert("Member not added"); - console.error(response.message); - } - }) - .catch((error) => { - console.error("An error occurred during member add:", error); - }); - return added; -} - -export default AddMember; diff --git a/frontend/src/Components/AddUserToProject.tsx b/frontend/src/Components/AddUserToProject.tsx deleted file mode 100644 index 9f4439b..0000000 --- a/frontend/src/Components/AddUserToProject.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useState } from "react"; -import { NewProjMember } from "../Types/goTypes"; -import Button from "./Button"; -import GetAllUsers from "./GetAllUsers"; -import AddMember from "./AddMember"; -import BackButton from "./BackButton"; - -/** - * Provides UI for adding a member to a project. - * @returns {JSX.Element} - Returns the component UI for adding a member - */ -function AddUserToProject(): JSX.Element { - const [name, setName] = useState(""); - const [users, setUsers] = useState([]); - const [role, setRole] = useState(""); - GetAllUsers({ setUsersProp: setUsers }); - - const handleClick = (): boolean => { - const newMember: NewProjMember = { - username: name, - projectname: localStorage.getItem("projectName") ?? "", - role: role, - }; - return AddMember({ memberToAdd: newMember }); - }; - - return ( -
-

- User chosen: [{name}] -

-

- Role chosen: [{role}] -

-

- Project chosen: [{localStorage.getItem("projectName") ?? ""}] -

-

Choose role:

-
-
    -
  • { - setRole("member"); - }} - > - {"Member"} -
  • -
  • { - setRole("project_manager"); - }} - > - {"Project manager"} -
  • -
-
-

Choose user:

-
-
    -
    - {users.map((user) => ( -
  • { - setName(user); - }} - > - {user} -
  • - ))} -
-
-
-
-

-
- ); -} - -export default AddUserToProject; diff --git a/frontend/src/Components/ChangeUsername.tsx b/frontend/src/Components/ChangeUsername.tsx index e297a04..3c35e94 100644 --- a/frontend/src/Components/ChangeUsername.tsx +++ b/frontend/src/Components/ChangeUsername.tsx @@ -1,48 +1,23 @@ import React, { useState } from "react"; import InputField from "./InputField"; -import { api } from "../API/API"; function ChangeUsername(): JSX.Element { const [newUsername, setNewUsername] = useState(""); - const [errorMessage, setErrorMessage] = useState(""); const handleChange = (e: React.ChangeEvent): void => { setNewUsername(e.target.value); }; - const handleSubmit = async (): Promise => { - try { - // Call the API function to change the username - const token = localStorage.getItem("accessToken"); - if (!token) { - throw new Error("Access token not found"); - } - - const response = await api.changeUserName( - { prevName: "currentName", newName: newUsername }, - token, - ); - - if (response.success) { - // Optionally, add a success message or redirect the user - console.log("Username changed successfully"); - } else { - // Handle the error message - console.error("Failed to change username:", response.message); - setErrorMessage(response.message ?? "Failed to change username"); - } - } catch (error) { - console.error("Error changing username:", error); - // Optionally, handle the error - setErrorMessage("Failed to change username"); - } - }; - - const handleButtonClick = (): void => { - handleSubmit().catch((error) => { - console.error("Error in handleSubmit:", error); - }); - }; + // const handleSubmit = async (): Promise => { + // try { + // // Call the API function to update the username + // await api.updateUsername(newUsername); + // // Optionally, add a success message or redirect the user + // } catch (error) { + // console.error("Error updating username:", error); + // // Optionally, handle the error + // } + // }; return (
@@ -52,8 +27,6 @@ function ChangeUsername(): JSX.Element { value={newUsername} onChange={handleChange} /> - {errorMessage &&
{errorMessage}
} -
); } diff --git a/frontend/src/Components/DeleteUser.tsx b/frontend/src/Components/DeleteUser.tsx index d1dbc7f..db49724 100644 --- a/frontend/src/Components/DeleteUser.tsx +++ b/frontend/src/Components/DeleteUser.tsx @@ -11,6 +11,7 @@ import { api, APIResponse } from "../API/API"; */ function DeleteUser(props: { usernameToDelete: string }): boolean { + //console.log(props.usernameToDelete); FOR DEBUG let removed = false; api .removeUser( @@ -19,16 +20,12 @@ function DeleteUser(props: { usernameToDelete: string }): boolean { ) .then((response: APIResponse) => { if (response.success) { - alert("User has been deleted!"); - location.reload(); removed = true; } else { - alert("User has not been deleted"); console.error(response.message); } }) .catch((error) => { - alert("User has not been deleted"); console.error("An error occurred during creation:", error); }); return removed; diff --git a/frontend/src/Components/DisplayUserProjects.tsx b/frontend/src/Components/DisplayUserProjects.tsx index 0cd5a8e..f4fd782 100644 --- a/frontend/src/Components/DisplayUserProjects.tsx +++ b/frontend/src/Components/DisplayUserProjects.tsx @@ -1,7 +1,7 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Project } from "../Types/goTypes"; import { Link } from "react-router-dom"; -import GetProjects from "./GetProjects"; +import { api } from "../API/API"; /** * Renders a component that displays the projects a user is a part of and links to the projects start-page. @@ -10,10 +10,21 @@ import GetProjects from "./GetProjects"; function DisplayUserProject(): JSX.Element { const [projects, setProjects] = useState([]); - GetProjects({ - setProjectsProp: setProjects, - username: localStorage.getItem("username") ?? "", - }); + const getProjects = async (): Promise => { + const token = localStorage.getItem("accessToken") ?? ""; + const response = await api.getUserProjects(token); + console.log(response); + if (response.success) { + setProjects(response.data ?? []); + } else { + console.error(response.message); + } + }; + + // Call getProjects when the component mounts + useEffect(() => { + void getProjects(); + }, []); return ( <> diff --git a/frontend/src/Components/GetProjects.tsx b/frontend/src/Components/GetProjects.tsx index 764b082..d6ab1f7 100644 --- a/frontend/src/Components/GetProjects.tsx +++ b/frontend/src/Components/GetProjects.tsx @@ -12,7 +12,6 @@ import { api } from "../API/API"; */ function GetProjects(props: { setProjectsProp: Dispatch>; - username: string; }): void { const setProjects: Dispatch> = props.setProjectsProp; @@ -20,7 +19,7 @@ function GetProjects(props: { const fetchUsers = async (): Promise => { try { const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getUserProjects(props.username, token); + const response = await api.getUserProjects(token); if (response.success) { setProjects(response.data ?? []); } else { @@ -32,7 +31,7 @@ function GetProjects(props: { }; void fetchUsers(); - }, [props.username, setProjects]); + }, [setProjects]); } export default GetProjects; diff --git a/frontend/src/Components/ProjectInfoModal.tsx b/frontend/src/Components/ProjectInfoModal.tsx index 3075b19..b153e9c 100644 --- a/frontend/src/Components/ProjectInfoModal.tsx +++ b/frontend/src/Components/ProjectInfoModal.tsx @@ -2,7 +2,6 @@ import { useState } from "react"; import Button from "./Button"; import { UserProjectMember } from "../Types/goTypes"; import GetUsersInProject from "./GetUsersInProject"; -import { Link } from "react-router-dom"; function ProjectInfoModal(props: { isVisible: boolean; @@ -19,12 +18,9 @@ function ProjectInfoModal(props: { className="fixed inset-0 bg-black bg-opacity-30 backdrop-blur-sm flex justify-center items-center" > -
+
-

- {localStorage.getItem("projectName") ?? ""} -

-

Project members:

+

Project members:

    @@ -54,15 +50,6 @@ function ProjectInfoModal(props: { }} type="button" /> - -