ChangeUserPassword Handler + API

This commit is contained in:
al8763be 2024-04-17 22:04:23 +02:00
parent 47d4bda99b
commit 0176f78067
8 changed files with 163 additions and 7 deletions

View file

@ -48,6 +48,7 @@ type Database interface {
UnsignWeeklyReport(reportId int, projectManagerId int) error UnsignWeeklyReport(reportId int, projectManagerId int) error
DeleteReport(reportID int) error DeleteReport(reportID int) error
ChangeProjectName(projectName string, newProjectName string) error ChangeProjectName(projectName string, newProjectName string) error
ChangeUserPassword(username string, password string) error
} }
// This struct is a wrapper type that holds the database connection // This struct is a wrapper type that holds the database connection
@ -677,3 +678,8 @@ func (d *Db) ChangeProjectName(projectName string, newProjectName string) error
_, err := d.Exec("UPDATE projects SET name = ? WHERE name = ?", newProjectName, projectName) _, err := d.Exec("UPDATE projects SET name = ? WHERE name = ?", newProjectName, projectName)
return err return err
} }
func (d *Db) ChangeUserPassword(username string, password string) error {
_, err := d.Exec("UPDATE users SET password = ? WHERE username = ?", password, username)
return err
}

View file

@ -1120,3 +1120,25 @@ func TestChangeProjectName(t *testing.T) {
t.Error("ChangeProjectName failed: expected newprojectname, got", projects[0].Name) t.Error("ChangeProjectName failed: expected newprojectname, got", projects[0].Name)
} }
} }
func TestChangeUserPassword(t *testing.T) {
db, err := setupState()
if err != nil {
t.Error("setupState failed:", err)
}
// Add a user
_ = db.AddUser("testuser", "password")
// Change user password
err = db.ChangeUserPassword("testuser", "newpassword")
if err != nil {
t.Error("ChangeUserPassword failed:", err)
}
// Check if the password was changed
if !db.CheckUser("testuser", "newpassword") {
t.Error("ChangeUserPassword failed: password not changed")
}
}

View file

@ -20,16 +20,17 @@ func ChangeProjectName(c *fiber.Ctx) error {
projectName := c.Params("projectName") projectName := c.Params("projectName")
newProjectName := c.Query("newProjectName") newProjectName := c.Query("newProjectName")
// Check if user is project manager // Check if user is site admin
ismanager, err := db.GetDb(c).IsProjectManager(username, projectName) issiteadmin, err := db.GetDb(c).IsSiteAdmin(username)
if err != nil { if err != nil {
log.Warn("Error checking if projectmanager:", err) log.Warn("Error checking if siteadmin:", err)
return c.Status(500).SendString(err.Error()) return c.Status(500).SendString(err.Error())
} else if !ismanager { } else if !issiteadmin {
log.Warn("User is not projectmanager") log.Warn("User is not siteadmin")
return c.Status(401).SendString("User is not projectmanager") return c.Status(401).SendString("User is not siteadmin")
} }
// Perform the project name change // Perform the project name change
err = db.GetDb(c).ChangeProjectName(projectName, newProjectName) err = db.GetDb(c).ChangeProjectName(projectName, newProjectName)
if err != nil { if err != nil {

View file

@ -0,0 +1,42 @@
package users
import (
db "ttime/internal/database"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/log"
"github.com/golang-jwt/jwt/v5"
)
// ChangeUserPassword is a handler that changes the password of a user
func ChangeUserPassword(c *fiber.Ctx) error {
//Check token and get username of current user
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
admin := claims["name"].(string)
// Extract the necessary parameters from the request
username := c.Params("username")
newPassword := c.Query("newPassword")
// Check if user is site admin
issiteadmin, err := db.GetDb(c).IsSiteAdmin(admin)
if err != nil {
log.Warn("Error checking if siteadmin:", err)
return c.Status(500).SendString(err.Error())
} else if !issiteadmin {
log.Warn("User is not siteadmin")
return c.Status(401).SendString("User is not siteadmin")
}
// Perform the password change
err = db.GetDb(c).ChangeUserPassword(username, newPassword)
if err != nil {
log.Warn("Error changing password:", err)
return c.Status(500).SendString(err.Error())
}
// Return a success message
return c.Status(200).SendString("Password changed successfully")
}

View file

@ -110,6 +110,7 @@ func main() {
api.Post("/promoteToAdmin", users.PromoteToAdmin) api.Post("/promoteToAdmin", users.PromoteToAdmin)
api.Put("/changeUserName", users.ChangeUserName) api.Put("/changeUserName", users.ChangeUserName)
api.Delete("/userdelete/:username", users.UserDelete) // Perhaps just use POST to avoid headaches api.Delete("/userdelete/:username", users.UserDelete) // Perhaps just use POST to avoid headaches
api.Put("/changeUserPassword/:username", users.ChangeUserPassword)
// All project related routes // All project related routes
// projectGroup := api.Group("/project") // Not currently in use // projectGroup := api.Group("/project") // Not currently in use

View file

@ -283,6 +283,18 @@ interface API {
newProjectName: string, newProjectName: string,
token: string, token: string,
): Promise<APIResponse<string>>; ): Promise<APIResponse<string>>;
/**
* Changes the password of a user
* @param {string} username The username of the user
* @param {string} newPassword The new password
* @param {string} token The authentication token
*/
changeUserPassword(
username: string,
newPassword: string,
token: string,
): Promise<APIResponse<string>>;
} }
/** An instance of the API */ /** An instance of the API */
@ -1041,4 +1053,31 @@ export const api: API = {
return { success: false, message: "Failed to change project name" }; return { success: false, message: "Failed to change project name" };
} }
}, },
async changeUserPassword(
username: string,
newPassword: string,
token: string,
): Promise<APIResponse<string>> {
try {
const response = await fetch(
`/api/changePassword/${username}?newPassword=${newPassword}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
},
);
if (!response.ok) {
return { success: false, message: "Failed to change password" };
} else {
return { success: true, message: "Password changed" };
}
} catch (e) {
return { success: false, message: "Failed to change password" };
}
},
}; };

View file

@ -38,8 +38,9 @@ unsignReportPath = base_url + "/api/unsignReport"
deleteReportPath = base_url + "/api/deleteReport" deleteReportPath = base_url + "/api/deleteReport"
getStatisticsPath = base_url + "/api/getStatistics" getStatisticsPath = base_url + "/api/getStatistics"
changeProjectNamePath = base_url + "/api/changeProjectName" changeProjectNamePath = base_url + "/api/changeProjectName"
changeUserPasswordPath = base_url + "/api/changeUserPassword"
debug_output = True debug_output = False
def gprint(*args, **kwargs): def gprint(*args, **kwargs):
@ -180,3 +181,11 @@ def changeProjectName(token: string, projectName: string, newProjectName: string
params={"newProjectName": newProjectName} params={"newProjectName": newProjectName}
) )
return response return response
def changeUserPassword(token: string, username: string, newPassword: string):
response = requests.put(
changeUserPasswordPath + "/" + username,
headers = {"Authorization": "Bearer " + token},
params={"newPassword": newPassword}
)
return response

View file

@ -675,6 +675,14 @@ def test_project_name_change():
token = register_and_login(admin_username, admin_password) token = register_and_login(admin_username, admin_password)
# Promote to admin
response = requests.post(
promoteToAdminPath,
json={"username": admin_username},
headers={"Authorization": "Bearer " + token},
)
response = create_project(token, project_name) response = create_project(token, project_name)
assert response.status_code == 200, "Create project failed" assert response.status_code == 200, "Create project failed"
@ -703,8 +711,36 @@ def test_project_name_change():
assert response.status_code == 200, "Project name change failed" assert response.status_code == 200, "Project name change failed"
gprint("test_projectNameChange successful") gprint("test_projectNameChange successful")
def test_change_user_password():
# Create admin
admin_username = randomString()
admin_password = randomString()
user = randomString()
password = randomString()
token = register_and_login(admin_username, admin_password)
# Promote to admin
response = requests.post(
promoteToAdminPath,
json={"username": admin_username},
headers={"Authorization": "Bearer " + token},
)
_ = register_and_login(user, password)
response = changeUserPassword(token, user, "new_password")
assert response.status_code == 200, "Change user password failed"
response = login(user, "new_password")
assert response.status_code == 200, "Login failed with new password"
gprint("test_change_user_password successful")
if __name__ == "__main__": if __name__ == "__main__":
test_change_user_password()
test_project_name_change(); test_project_name_change();
test_delete_report() test_delete_report()
test_unsign_report() test_unsign_report()