diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 322c812..8026f58 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -19,174 +19,19 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/login": { - "post": { - "description": "logs the user in and returns a jwt token", - "consumes": [ - "application/json" - ], - "produces": [ - "text/plain" - ], - "tags": [ - "User" - ], - "summary": "login", - "parameters": [ - { - "description": "login info", - "name": "NewUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.NewUser" - } - } - ], - "responses": { - "200": { - "description": "Successfully signed token for user", - "schema": { - "type": "Token" - } - }, - "400": { - "description": "Bad request", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "type": "string" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "type": "string" - } - } - } - } - }, - "/loginerenew": { - "post": { - "security": [ - { - "bererToken": [] - } - ], - "description": "renews the users token", - "consumes": [ - "application/json" - ], - "produces": [ - "text/plain" - ], - "tags": [ - "User" - ], - "summary": "LoginRenews", - "responses": { - "200": { - "description": "Successfully signed token for user", - "schema": { - "type": "Token" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "type": "string" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "type": "string" - } - } - } - } - }, - "/promoteToAdmin": { - "post": { - "description": "promote chosen user to admin", - "consumes": [ - "application/json" - ], - "produces": [ - "text/plain" - ], - "tags": [ - "User" - ], - "summary": "PromoteToAdmin", - "parameters": [ - { - "description": "user info", - "name": "NewUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.NewUser" - } - } - ], - "responses": { - "200": { - "description": "Successfully prometed user", - "schema": { - "type": "json" - } - }, - "400": { - "description": "bad request", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "type": "string" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "type": "string" - } - } - } - } - }, - "/register": { + "/api/register": { "post": { "description": "Register a new user", "consumes": [ "application/json" ], "produces": [ - "text/plain" + "application/json" ], "tags": [ "User" ], - "summary": "Register", - "parameters": [ - { - "description": "User to register", - "name": "NewUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.NewUser" - } - } - ], + "summary": "Register a new user", "responses": { "200": { "description": "User added", @@ -208,102 +53,6 @@ const docTemplate = `{ } } } - }, - "/userdelete/{username}": { - "delete": { - "description": "UserDelete deletes a user from the database", - "consumes": [ - "application/json" - ], - "produces": [ - "text/plain" - ], - "tags": [ - "User" - ], - "summary": "UserDelete", - "responses": { - "200": { - "description": "User deleted", - "schema": { - "type": "string" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "type": "string" - } - }, - "403": { - "description": "You can only delete yourself", - "schema": { - "type": "string" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "type": "string" - } - } - } - } - }, - "/users/all": { - "get": { - "description": "lists all users", - "consumes": [ - "application/json" - ], - "produces": [ - "text/plain" - ], - "tags": [ - "User" - ], - "summary": "ListsAllUsers", - "responses": { - "200": { - "description": "Successfully signed token for user", - "schema": { - "type": "json" - } - }, - "401": { - "description": "Unauthorized", - "schema": { - "type": "string" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "type": "string" - } - } - } - } - } - }, - "definitions": { - "types.NewUser": { - "type": "object", - "properties": { - "password": { - "type": "string" - }, - "username": { - "type": "string" - } - } - } - }, - "securityDefinitions": { - "bererToken": { - "type": "apiKey", - "name": "Authorization", - "in": "header" } }, "externalDocs": { diff --git a/backend/internal/database/db.go b/backend/internal/database/db.go index bc6e1e8..25dd04b 100644 --- a/backend/internal/database/db.go +++ b/backend/internal/database/db.go @@ -201,25 +201,7 @@ func (d *Db) GetProjectId(projectname string) (int, error) { // Creates a new project in the database, associated with a user func (d *Db) AddProject(name string, description string, username string) error { - tx := d.MustBegin() - _, err := tx.Exec(projectInsert, name, description, username) - if err != nil { - if err := tx.Rollback(); err != nil { - return err - } - return err - } - _, err = tx.Exec(changeUserRole, "project_manager", username, name) - if err != nil { - if err := tx.Rollback(); err != nil { - return err - } - return err - } - if err := tx.Commit(); err != nil { - return err - } - + _, err := d.Exec(projectInsert, name, description, username) return err } diff --git a/backend/internal/handlers/handlers_user_related.go b/backend/internal/handlers/handlers_user_related.go index 96fddb7..8f4108c 100644 --- a/backend/internal/handlers/handlers_user_related.go +++ b/backend/internal/handlers/handlers_user_related.go @@ -12,16 +12,15 @@ import ( // Register is a simple handler that registers a new user // -// @Summary Register +// @Summary Register a new user // @Description Register a new user // @Tags User // @Accept json -// @Produce plain -// @Param NewUser body types.NewUser true "User to register" -// @Success 200 {string} string "User added" -// @Failure 400 {string} string "Bad request" -// @Failure 500 {string} string "Internal server error" -// @Router /register [post] +// @Produce json +// @Success 200 {string} string "User added" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" +// @Router /api/register [post] func (gs *GState) Register(c *fiber.Ctx) error { u := new(types.NewUser) if err := c.BodyParser(u); err != nil { @@ -41,17 +40,6 @@ func (gs *GState) Register(c *fiber.Ctx) error { // This path should obviously be protected in the future // UserDelete deletes a user from the database -// -// @Summary UserDelete -// @Description UserDelete deletes a user from the database -// @Tags User -// @Accept json -// @Produce plain -// @Success 200 {string} string "User deleted" -// @Failure 403 {string} string "You can only delete yourself" -// @Failure 500 {string} string "Internal server error" -// @Failure 401 {string} string "Unauthorized" -// @Router /userdelete/{username} [delete] func (gs *GState) UserDelete(c *fiber.Ctx) error { // Read from path parameters username := c.Params("username") @@ -74,21 +62,8 @@ func (gs *GState) UserDelete(c *fiber.Ctx) error { } // Login is a simple login handler that returns a JWT token -// -// @Summary login -// @Description logs the user in and returns a jwt token -// @Tags User -// @Accept json -// @Param NewUser body types.NewUser true "login info" -// @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 400 {string} string "Bad request" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" -// @Router /login [post] func (gs *GState) Login(c *fiber.Ctx) error { // The body type is identical to a NewUser - u := new(types.NewUser) if err := c.BodyParser(u); err != nil { log.Warn("Error parsing body") @@ -119,22 +94,11 @@ func (gs *GState) Login(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusInternalServerError) } - println("Successfully signed token for user:", u.Username) - return c.JSON(types.Token{Token: t}) + log.Info("Successfully signed token for user:", u.Username) + return c.JSON(fiber.Map{"token": t}) } // LoginRenew is a simple handler that renews the token -// -// @Summary LoginRenews -// @Description renews the users token -// @Security bererToken -// @Tags User -// @Accept json -// @Produce plain -// @Success 200 Token types.Token "Successfully signed token for user" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" -// @Router /loginerenew [post] func (gs *GState) LoginRenew(c *fiber.Ctx) error { user := c.Locals("user").(*jwt.Token) @@ -155,20 +119,10 @@ func (gs *GState) LoginRenew(c *fiber.Ctx) error { } log.Info("Successfully renewed token for user:", user.Claims.(jwt.MapClaims)["name"]) - return c.JSON(types.Token{Token: t}) + return c.JSON(fiber.Map{"token": t}) } // ListAllUsers is a handler that returns a list of all users in the application database -// -// @Summary ListsAllUsers -// @Description lists all users -// @Tags User -// @Accept json -// @Produce plain -// @Success 200 {json} json "Successfully signed token for user" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" -// @Router /users/all [get] func (gs *GState) ListAllUsers(c *fiber.Ctx) error { // Get all users from the database users, err := gs.Db.GetAllUsersApplication() @@ -182,17 +136,6 @@ func (gs *GState) ListAllUsers(c *fiber.Ctx) error { return c.JSON(users) } -// @Summary PromoteToAdmin -// @Description promote chosen user to admin -// @Tags User -// @Accept json -// @Produce plain -// @Param NewUser body types.NewUser true "user info" -// @Success 200 {json} json "Successfully prometed user" -// @Failure 400 {string} string "bad request" -// @Failure 401 {string} string "Unauthorized" -// @Failure 500 {string} string "Internal server error" -// @Router /promoteToAdmin [post] func (gs *GState) PromoteToAdmin(c *fiber.Ctx) error { // Extract the username from the request body var newUser types.NewUser diff --git a/backend/internal/types/users.go b/backend/internal/types/users.go index d3f2170..e9dff67 100644 --- a/backend/internal/types/users.go +++ b/backend/internal/types/users.go @@ -27,8 +27,3 @@ type PublicUser struct { UserId string `json:"userId"` Username string `json:"username"` } - -// wrapper type for token -type Token struct { - Token string `json:"token"` -} diff --git a/backend/main.go b/backend/main.go index e578c52..9abe995 100644 --- a/backend/main.go +++ b/backend/main.go @@ -23,10 +23,6 @@ import ( // @license.name AGPL // @license.url https://www.gnu.org/licenses/agpl-3.0.html -//@securityDefinitions.apikey bererToken -//@in header -//@name Authorization - // @host localhost:8080 // @BasePath /api @@ -83,7 +79,7 @@ func main() { })) // Protected routes (require a valid JWT bearer token authentication header) - server.Post("/api/submitWeeklyReport", gs.SubmitWeeklyReport) + server.Post("/api/submitReport", gs.SubmitWeeklyReport) 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 @@ -93,7 +89,7 @@ func main() { server.Post("/api/signReport", gs.SignReport) server.Put("/api/addUserToProject", gs.AddUserToProjectHandler) server.Post("/api/promoteToAdmin", gs.PromoteToAdmin) - server.Get("/api/users/all", gs.ListAllUsers) + // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { diff --git a/frontend/src/Components/AllTimeReportsInProject.tsx b/frontend/src/Components/AllTimeReportsInProject.tsx deleted file mode 100644 index 067712e..0000000 --- a/frontend/src/Components/AllTimeReportsInProject.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { NewWeeklyReport } from "../Types/goTypes"; -import { Link, useParams } from "react-router-dom"; - -function AllTimeReportsInProject(): JSX.Element { - const { projectName } = useParams(); - const [weeklyReports, setWeeklyReports] = useState([]); - - /* const getWeeklyReports = async (): Promise => { - const token = localStorage.getItem("accessToken") ?? ""; - const response = await api.getWeeklyReports(token); - console.log(response); - if (response.success) { - setWeeklyReports(response.data ?? []); - } else { - console.error(response.message); - } -}; */ - - const getWeeklyReports = async (): Promise => { - const report: NewWeeklyReport[] = [ - { - projectName: projectName ?? "", - week: 10, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 1, - }, - { - projectName: projectName ?? "", - week: 11, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 100, - studyTime: 1, - testingTime: 1, - }, - { - projectName: projectName ?? "", - week: 12, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 1000, - }, - { - projectName: projectName ?? "", - week: 20, - developmentTime: 1, - meetingTime: 1, - adminTime: 1, - ownWorkTime: 1, - studyTime: 1, - testingTime: 10000, - }, - // Add more reports as needed - ]; - setWeeklyReports(report); - await Promise.resolve(); - }; - - // Call getProjects when the component mounts - useEffect(() => { - void getWeeklyReports(); - }, []); - - return ( - <> -
- {weeklyReports.map((newWeeklyReport, index) => ( - -
-

- {"Week: "} - {newWeeklyReport.week} -

-

- {"Total Time: "} - {newWeeklyReport.developmentTime + - newWeeklyReport.meetingTime + - newWeeklyReport.adminTime + - newWeeklyReport.ownWorkTime + - newWeeklyReport.studyTime + - newWeeklyReport.testingTime}{" "} - min -

-

- {"Signed: "} - YES -

-
- - ))} -
- - ); -} - -export default AllTimeReportsInProject; diff --git a/frontend/src/Components/EditWeeklyReport.tsx b/frontend/src/Components/EditWeeklyReport.tsx index 3017204..b0e8771 100644 --- a/frontend/src/Components/EditWeeklyReport.tsx +++ b/frontend/src/Components/EditWeeklyReport.tsx @@ -1,10 +1,11 @@ import { useState, useEffect } from "react"; import { NewWeeklyReport } from "../Types/goTypes"; import { api } from "../API/API"; -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import Button from "./Button"; export default function GetWeeklyReport(): JSX.Element { + const [projectName, setProjectName] = useState(""); const [week, setWeek] = useState(0); const [developmentTime, setDevelopmentTime] = useState(0); const [meetingTime, setMeetingTime] = useState(0); @@ -15,48 +16,46 @@ export default function GetWeeklyReport(): JSX.Element { const token = localStorage.getItem("accessToken") ?? ""; const username = localStorage.getItem("username") ?? ""; - const { projectName } = useParams(); - const { fetchedWeek } = useParams(); - - const fetchWeeklyReport = async (): Promise => { - const response = await api.getWeeklyReport( - username, - projectName ?? "", - fetchedWeek?.toString() ?? "0", - token, - ); - - if (response.success) { - const report: NewWeeklyReport = response.data ?? { - projectName: "", - week: 0, - developmentTime: 0, - meetingTime: 0, - adminTime: 0, - ownWorkTime: 0, - studyTime: 0, - testingTime: 0, - }; - - setWeek(report.week); - setDevelopmentTime(report.developmentTime); - setMeetingTime(report.meetingTime); - setAdminTime(report.adminTime); - setOwnWorkTime(report.ownWorkTime); - setStudyTime(report.studyTime); - setTestingTime(report.testingTime); - } else { - console.error("Failed to fetch weekly report:", response.message); - } - }; useEffect(() => { + const fetchWeeklyReport = async (): Promise => { + const response = await api.getWeeklyReport( + username, + projectName, + week.toString(), + token, + ); + + if (response.success) { + const report: NewWeeklyReport = response.data ?? { + projectName: "", + week: 0, + developmentTime: 0, + meetingTime: 0, + adminTime: 0, + ownWorkTime: 0, + studyTime: 0, + testingTime: 0, + }; + setProjectName(report.projectName); + setWeek(report.week); + setDevelopmentTime(report.developmentTime); + setMeetingTime(report.meetingTime); + setAdminTime(report.adminTime); + setOwnWorkTime(report.ownWorkTime); + setStudyTime(report.studyTime); + setTestingTime(report.testingTime); + } else { + console.error("Failed to fetch weekly report:", response.message); + } + }; + void fetchWeeklyReport(); - }); + }, [projectName, token, username, week]); const handleNewWeeklyReport = async (): Promise => { const newWeeklyReport: NewWeeklyReport = { - projectName: projectName ?? "", + projectName, week, developmentTime, meetingTime, @@ -83,7 +82,7 @@ export default function GetWeeklyReport(): JSX.Element { } e.preventDefault(); void handleNewWeeklyReport(); - navigate(-1); + navigate("/project"); }} >
@@ -234,7 +233,7 @@ export default function GetWeeklyReport(): JSX.Element {