Merge remote-tracking branch 'origin/AlexTester' into BumBranch

This commit is contained in:
al8763be 2024-03-28 16:44:29 +01:00
commit 5d714bbacf
8 changed files with 219 additions and 68 deletions

View file

@ -42,6 +42,7 @@ type Database interface {
IsProjectManager(username string, projectname string) (bool, error) IsProjectManager(username string, projectname string) (bool, error)
GetProjectTimes(projectName string) (map[string]int, error) GetProjectTimes(projectName string) (map[string]int, error)
UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error UpdateWeeklyReport(projectName string, userName string, week int, developmentTime int, meetingTime int, adminTime int, ownWorkTime int, studyTime int, testingTime int) error
RemoveProject(projectname string) error
} }
// This struct is a wrapper type that holds the database connection // This struct is a wrapper type that holds the database connection
@ -595,3 +596,8 @@ func (d *Db) GetProjectTimes(projectName string) (map[string]int, error) {
return totalTime, nil return totalTime, nil
} }
func (d *Db) RemoveProject(projectname string) error {
_, err := d.Exec("DELETE FROM projects WHERE name = ?", projectname)
return err
}

View file

@ -935,3 +935,33 @@ func TestUpdateWeeklyReport(t *testing.T) {
t.Error("UpdateWeeklyReport failed: report not updated correctly") t.Error("UpdateWeeklyReport failed: report not updated correctly")
} }
} }
func TestRemoveProject(t *testing.T) {
db, err := setupAdvancedState()
if err != nil {
t.Error("setupState failed:", err)
}
// Promote user to Admin
err = db.PromoteToAdmin("demouser")
if err != nil {
t.Error("PromoteToAdmin failed:", err)
}
// Remove project
err = db.RemoveProject("projecttest")
if err != nil {
t.Error("RemoveProject failed:", err)
}
// Check if the project was removed
projects, err := db.GetAllProjects()
if err != nil {
t.Error("GetAllProjects failed:", err)
}
if len(projects) != 0 {
t.Error("RemoveProject failed: expected 0, got", len(projects))
}
}

View file

@ -30,6 +30,7 @@ type GlobalState interface {
GetAllUsersProject(c *fiber.Ctx) error // WIP GetAllUsersProject(c *fiber.Ctx) error // WIP
GetUnsignedReports(c *fiber.Ctx) error // GetUnsignedReports(c *fiber.Ctx) error //
UpdateWeeklyReport(c *fiber.Ctx) error UpdateWeeklyReport(c *fiber.Ctx) error
RemoveProject(c *fiber.Ctx) error
} }
// "Constructor" // "Constructor"

View file

@ -219,7 +219,7 @@ func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error {
username := claims["name"].(string) username := claims["name"].(string)
// Extract necessary parameters from the request query string // Extract necessary parameters from the request query string
projectName := c.Params("projectName") projectName := c.Query("projectName")
log.Info("Checking if user ", username, " is a project manager for project ", projectName) log.Info("Checking if user ", username, " is a project manager for project ", projectName)
@ -231,59 +231,85 @@ func (gs *GState) IsProjectManagerHandler(c *fiber.Ctx) error {
} }
// Return the result as JSON // Return the result as JSON
return c.JSON(fiber.Map{"isProjectManager": isManager}) return c.JSON(map[string]bool{"isProjectManager": isManager})
} }
func (gs *GState) GetProjectTimesHandler(c *fiber.Ctx) error { func (gs *GState) GetProjectTimesHandler(c *fiber.Ctx) error {
// Get the username from the token // Get the username from the token
user := c.Locals("user").(*jwt.Token) user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims) claims := user.Claims.(jwt.MapClaims)
username := claims["name"].(string) username := claims["name"].(string)
// Get project // Get project
projectName := c.Params("projectName") projectName := c.Params("projectName")
if projectName == "" { if projectName == "" {
log.Info("No project name provided") log.Info("No project name provided")
return c.Status(400).SendString("No project name provided") return c.Status(400).SendString("No project name provided")
} }
// Get all users in the project and roles // Get all users in the project and roles
userProjects, err := gs.Db.GetAllUsersProject(projectName) userProjects, err := gs.Db.GetAllUsersProject(projectName)
if err != nil { if err != nil {
log.Info("Error getting users in project:", err) log.Info("Error getting users in project:", err)
return c.Status(500).SendString(err.Error()) return c.Status(500).SendString(err.Error())
} }
// If the user is member // If the user is member
isMember := false isMember := false
for _, userProject := range userProjects { for _, userProject := range userProjects {
if userProject.Username == username { if userProject.Username == username {
isMember = true isMember = true
break break
} }
} }
// If the user is admin // If the user is admin
if !isMember { if !isMember {
isAdmin, err := gs.Db.IsSiteAdmin(username) isAdmin, err := gs.Db.IsSiteAdmin(username)
if err != nil { if err != nil {
log.Info("Error checking admin status:", err) log.Info("Error checking admin status:", err)
return c.Status(500).SendString(err.Error()) return c.Status(500).SendString(err.Error())
} }
if !isAdmin { if !isAdmin {
log.Info("User is neither a project member nor a site admin:", username) log.Info("User is neither a project member nor a site admin:", username)
return c.Status(403).SendString("User is neither a project member nor a site admin") return c.Status(403).SendString("User is neither a project member nor a site admin")
} }
} }
// Get project times // Get project times
projectTimes, err := gs.Db.GetProjectTimes(projectName) projectTimes, err := gs.Db.GetProjectTimes(projectName)
if err != nil { if err != nil {
log.Info("Error getting project times:", err) log.Info("Error getting project times:", err)
return c.Status(500).SendString(err.Error()) return c.Status(500).SendString(err.Error())
} }
// Return project times as JSON // Return project times as JSON
log.Info("Returning project times for project:", projectName) log.Info("Returning project times for project:", projectName)
return c.JSON(projectTimes) return c.JSON(projectTimes)
} }
func (gs *GState) RemoveProject(c *fiber.Ctx) error {
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
username := claims["name"].(string)
// Check if the user is a site admin
isAdmin, err := gs.Db.IsSiteAdmin(username)
if err != nil {
log.Info("Error checking admin status:", err)
return c.Status(500).SendString(err.Error())
}
if !isAdmin {
log.Info("User is not a site admin:", username)
return c.Status(403).SendString("User is not a site admin")
}
projectName := c.Params("projectName")
if err := gs.Db.RemoveProject(projectName); err != nil {
return c.Status(500).SendString((err.Error()))
}
return c.Status(200).SendString("Project deleted")
}

View file

@ -109,6 +109,7 @@ func main() {
server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange) server.Post("/api/ProjectRoleChange", gs.ProjectRoleChange)
server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject) server.Get("/api/getUsersProject/:projectName", gs.ListAllUsersProject)
server.Put("/api/updateWeeklyReport", gs.UpdateWeeklyReport) server.Put("/api/updateWeeklyReport", gs.UpdateWeeklyReport)
server.Delete("/api/removeProject/:projectName", gs.RemoveProject)
// Announce the port we are listening on and start the server // Announce the port we are listening on and start the server
err = server.Listen(fmt.Sprintf(":%d", conf.Port)) err = server.Listen(fmt.Sprintf(":%d", conf.Port))

View file

@ -47,7 +47,6 @@ interface API {
* @returns {Promise<APIResponse<boolean>>} A promise containing the API response indicating if the user is a project manager. * @returns {Promise<APIResponse<boolean>>} A promise containing the API response indicating if the user is a project manager.
*/ */
checkIfProjectManager( checkIfProjectManager(
username: string,
projectName: string, projectName: string,
token: string, token: string,
): Promise<APIResponse<boolean>>; ): Promise<APIResponse<boolean>>;
@ -133,6 +132,11 @@ interface API {
projectName: string, projectName: string,
token: string, token: string,
): Promise<APIResponse<UserProjectMember[]>>; ): Promise<APIResponse<UserProjectMember[]>>;
removeProject(
projectName: string,
token: string,
): Promise<APIResponse<string>>;
} }
/** An instance of the API */ /** An instance of the API */
@ -190,19 +194,20 @@ export const api: API = {
}, },
async checkIfProjectManager( async checkIfProjectManager(
username: string,
projectName: string, projectName: string,
token: string, token: string,
): Promise<APIResponse<boolean>> { ): Promise<APIResponse<boolean>> {
try { try {
const response = await fetch("/api/checkIfProjectManager", { const response = await fetch(
method: "GET", `/api/checkIfProjectManager?projectName=${projectName}`,
headers: { {
"Content-Type": "application/json", method: "GET",
Authorization: "Bearer " + token, headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
}, },
body: JSON.stringify({ username, projectName }), );
});
if (!response.ok) { if (!response.ok) {
return { return {
@ -214,7 +219,7 @@ export const api: API = {
return { success: true, data }; return { success: true, data };
} }
} catch (e) { } catch (e) {
return { success: false, message: "fuck" }; return { success: false, message: "Failed to check if project manager" };
} }
}, },
@ -484,4 +489,34 @@ export const api: API = {
}); });
} }
}, },
async removeProject(
projectName: string,
token: string,
): Promise<APIResponse<string>> {
try {
const response = await fetch(`/api/projectdelete/${projectName}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
});
if (!response.ok) {
return Promise.resolve({
success: false,
message: "Failed to remove project",
});
} else {
const data = await response.text();
return Promise.resolve({ success: true, message: data });
}
} catch (e) {
return Promise.resolve({
success: false,
message: "Failed to remove project",
});
}
},
}; };

View file

@ -1,17 +1,26 @@
import { useParams } from "react-router-dom";
import { api } from "../../API/API";
import BackButton from "../../Components/BackButton"; import BackButton from "../../Components/BackButton";
import BasicWindow from "../../Components/BasicWindow"; import BasicWindow from "../../Components/BasicWindow";
import Button from "../../Components/Button"; import Button from "../../Components/Button";
async function handleDeleteProject(
projectName: string,
token: string,
): Promise<void> {
await api.removeProject(projectName, token);
}
function AdminProjectPage(): JSX.Element { function AdminProjectPage(): JSX.Element {
const content = <></>; const content = <></>;
const { projectName } = useParams();
const token = localStorage.getItem("accessToken");
const buttons = ( const buttons = (
<> <>
<Button <Button
text="Delete" text="Delete"
onClick={(): void => { onClick={() => handleDeleteProject(projectName, token)}
return;
}}
type="button" type="button"
/> />
<BackButton /> <BackButton />
@ -20,4 +29,5 @@ function AdminProjectPage(): JSX.Element {
return <BasicWindow content={content} buttons={buttons} />; return <BasicWindow content={content} buttons={buttons} />;
} }
export default AdminProjectPage; export default AdminProjectPage;

View file

@ -44,6 +44,7 @@ getUsersProjectPath = base_url + "/api/getUsersProject"
getUnsignedReportsPath = base_url + "/api/getUnsignedReports" getUnsignedReportsPath = base_url + "/api/getUnsignedReports"
getChangeUserNamePath = base_url + "/api/changeUserName" getChangeUserNamePath = base_url + "/api/changeUserName"
getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport" getUpdateWeeklyReportPath = base_url + "/api/updateWeeklyReport"
removeProjectPath = base_url + "/api/removeProject"
#ta bort auth i handlern för att få testet att gå igenom #ta bort auth i handlern för att få testet att gå igenom
def test_ProjectRoleChange(): def test_ProjectRoleChange():
@ -465,7 +466,47 @@ def test_update_weekly_report():
assert response.status_code == 200, "Update weekly report failed" assert response.status_code == 200, "Update weekly report failed"
gprint("test_update_weekly_report successful") gprint("test_update_weekly_report successful")
def test_remove_project():
admin_username = randomString()
admin_password = "admin_password2"
dprint(
"Registering with username: ", admin_username, " and password: ", admin_password
)
response = requests.post(
registerPath, json={"username": admin_username, "password": admin_password}
)
dprint(response.text)
# Log in as the admin
admin_token = login(admin_username, admin_password).json()["token"]
response = requests.post(
promoteToAdminPath,
json={"username": admin_username},
headers={"Authorization": "Bearer " + admin_token},
)
# Create a new project
new_project = randomString()
response = requests.post(
addProjectPath,
json={"name": new_project, "description": "This is a project"},
headers={"Authorization": "Bearer " + admin_token},
)
assert response.status_code == 200, "Add project failed"
# Remove the project
response = requests.delete(
removeProjectPath + "/" + new_project,
headers={"Authorization": "Bearer " + admin_token},
)
assert response.status_code == 200, "Remove project failed"
gprint("test_remove_project successful")
if __name__ == "__main__": if __name__ == "__main__":
test_remove_project()
test_get_user_projects() test_get_user_projects()
test_create_user() test_create_user()
test_login() test_login()
@ -482,4 +523,5 @@ if __name__ == "__main__":
test_get_unsigned_reports() test_get_unsigned_reports()
test_list_all_users_project() test_list_all_users_project()
test_change_user_name() test_change_user_name()
test_update_weekly_report() test_update_weekly_report()