ChangeUserPassword Handler + API
This commit is contained in:
parent
47d4bda99b
commit
0176f78067
8 changed files with 163 additions and 7 deletions
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
42
backend/internal/handlers/users/ChangeUserPassword.go
Normal file
42
backend/internal/handlers/users/ChangeUserPassword.go
Normal 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")
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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" };
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue