diff --git a/services/app-api/handlers/users/post/updateUser.js b/services/app-api/handlers/users/post/updateUser.js index 04c3baa4..5ffad37a 100644 --- a/services/app-api/handlers/users/post/updateUser.js +++ b/services/app-api/handlers/users/post/updateUser.js @@ -19,6 +19,8 @@ export const main = handler(async (event, context) => { await authorizeAdmin(event); } + assertPayloadIsValid(data); + const params = { TableName: process.env.AUTH_USER_TABLE_NAME ?? process.env.AuthUserTableName, @@ -26,13 +28,11 @@ export const main = handler(async (event, context) => { userId: currentUser["Items"][0].userId, }, UpdateExpression: - "SET username = :username, #r = :role, states = :states, lastLogin = :lastLogin, usernameSub = :usernameSub", + "SET #r = :role, states = :states, lastLogin = :lastLogin", ExpressionAttributeValues: { - ":username": data.username, ":role": data.role, ":states": data.states ?? "", ":lastLogin": new Date().toISOString(), - ":usernameSub": data.usernameSub ?? null, }, ExpressionAttributeNames: { "#r": "role", @@ -51,3 +51,30 @@ function modifyingAnythingButAnEmptyStateList(incomingUser, existingUser) { if (existingUser.states.length > 0) return true; return false; } + +function assertPayloadIsValid (data) { + if (!data) { + throw new Error("User update payload is missing"); + } + + if (typeof data.role !== "string" || !data.role) { + throw new Error("Invalid user role - must be a nonempty string"); + } + if (!["admin", "business", "state"].includes(data.role)) { + throw new Error("Invalid user role - must be an existing role"); + } + + if (data.states && data.states !== "null") { + if (!Array.isArray(data.states)) { + throw new Error("Invalid user states - must be an array"); + } + for (let state of data.states) { + if (typeof state !== "string") { + throw new Error("Invalid user states - must be strings"); + } + if (!/^[A-Z]{2}$/.test(state)) { + throw new Error("Invalid user states - must be 2-letter abbreviations"); + } + } + } +} diff --git a/services/ui-src/src/components/EditUser/EditUser.jsx b/services/ui-src/src/components/EditUser/EditUser.jsx index 80cf744c..a4e58f16 100644 --- a/services/ui-src/src/components/EditUser/EditUser.jsx +++ b/services/ui-src/src/components/EditUser/EditUser.jsx @@ -176,6 +176,7 @@ const EditUser = ({ stateList }) => { value={user.username} type="text" onChange={e => updateLocalUser(e, "username")} + disabled={true} name="username" className="form-input" /> diff --git a/services/ui-src/src/components/EditUser/EditUser.test.jsx b/services/ui-src/src/components/EditUser/EditUser.test.jsx index 1d8dfbdc..2a774de1 100644 --- a/services/ui-src/src/components/EditUser/EditUser.test.jsx +++ b/services/ui-src/src/components/EditUser/EditUser.test.jsx @@ -144,16 +144,17 @@ describe("Test EditUser.js", () => { renderComponent(mockUser); await waitFor(() => expect(getUserById).toHaveBeenCalled()); - const table = screen.getByTestId("table"); - const usernameInput = table.querySelector(".userName input"); - userEvent.type(usernameInput, "TY"); + const roleDropdown = screen.getByPlaceholderText("Select a Role"); + userEvent.click(roleDropdown); + const adminOption = screen.getByText("Admin User"); + userEvent.click(adminOption); const saveButton = screen.getByText("Update User", { selector: "button" }); userEvent.click(saveButton); expect(updateUser).toHaveBeenCalledWith( expect.objectContaining({ - username: "QWERTY" + role: "admin", }) ); });