diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/change-user-password.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/change-user-password.js new file mode 100644 index 000000000..a0a8dc5ba --- /dev/null +++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/change-user-password.js @@ -0,0 +1,69 @@ +/*\ +title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/change-password.js +type: application/javascript +module-type: mws-route + +POST /change-user-password + +\*/ +(function () { + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; +var authenticator = require("$:/plugins/tiddlywiki/multiwikiserver/auth/authentication.js").Authenticator; + +exports.method = "POST"; + +exports.path = /^\/change-user-password\/?$/; + +exports.bodyFormat = "www-form-urlencoded"; + +exports.csrfDisable = true; + +exports.handler = function (request, response, state) { + if(!state.authenticatedUser) { + response.writeHead(401, "Unauthorized", { "Content-Type": "text/plain" }); + response.end("Unauthorized"); + return; + } + var auth = authenticator($tw); + + var userId = state.authenticatedUser.user_id; + var currentPassword = state.data.currentPassword; + var newPassword = state.data.newPassword; + var confirmPassword = state.data.confirmPassword; + + if(newPassword !== confirmPassword) { + response.setHeader("Set-Cookie", "flashMessage=New passwords do not match; Path=/; HttpOnly; Max-Age=5"); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + response.end(); + return; + } + + var userData = state.server.sqlTiddlerDatabase.getUser(userId); + + if(!userData) { + response.setHeader("Set-Cookie", "flashMessage=User not found; Path=/; HttpOnly; Max-Age=5"); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + response.end(); + return; + } + + var isCurrentPasswordValid = auth.verifyPassword(currentPassword, userData.password); + if(!isCurrentPasswordValid) { + response.setHeader("Set-Cookie", "flashMessage=Current password is incorrect; Path=/; HttpOnly; Max-Age=5"); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + response.end(); + return; + } + + var newHash = auth.hashPassword(newPassword); + var result = state.server.sqlTiddlerDatabase.updateUserPassword(userId, newHash); + + response.setHeader("Set-Cookie", `flashMessage=${result.message}; Path=/; HttpOnly; Max-Age=5`); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + response.end(); +}; + +}()); \ No newline at end of file diff --git a/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/update-user-profile.js b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/update-user-profile.js new file mode 100644 index 000000000..a8880f9fe --- /dev/null +++ b/plugins/tiddlywiki/multiwikiserver/modules/routes/handlers/update-user-profile.js @@ -0,0 +1,46 @@ +/*\ +title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/update-profile.js +type: application/javascript +module-type: mws-route + +POST /update-user-profile + +\*/ +(function () { + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.method = "POST"; + +exports.path = /^\/update-user-profile\/?$/; + +exports.bodyFormat = "www-form-urlencoded"; + +exports.csrfDisable = true; + +exports.handler = function (request,response,state) { + if(!state.authenticatedUser) { + response.writeHead(401, "Unauthorized", { "Content-Type": "text/plain" }); + response.end("Unauthorized"); + return; + } + + var userId = state.authenticatedUser.user_id; + var username = state.data.username; + var email = state.data.email; + + var result = state.server.sqlTiddlerDatabase.updateUser(userId, username, email); + + if(result.success) { + response.setHeader("Set-Cookie", "flashMessage="+result.mesasge+"; Path=/; HttpOnly; Max-Age=5"); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + } else { + response.setHeader("Set-Cookie", "flashMessage="+result.mesasge+"; Path=/; HttpOnly; Max-Age=5"); + response.writeHead(302, { "Location": "/admin/users/" + userId }); + } + response.end(); +}; + +}()); \ No newline at end of file diff --git a/plugins/tiddlywiki/multiwikiserver/modules/store/sql-tiddler-database.js b/plugins/tiddlywiki/multiwikiserver/modules/store/sql-tiddler-database.js index 20d238c20..4a13f836e 100644 --- a/plugins/tiddlywiki/multiwikiserver/modules/store/sql-tiddler-database.js +++ b/plugins/tiddlywiki/multiwikiserver/modules/store/sql-tiddler-database.js @@ -781,16 +781,66 @@ SqlTiddlerDatabase.prototype.getUserByUsername = function(username) { }); }; -SqlTiddlerDatabase.prototype.updateUser = function(userId, username, email) { - this.engine.runStatement(` - UPDATE users - SET username = $username, email = $email - WHERE user_id = $userId - `, { +SqlTiddlerDatabase.prototype.updateUser = function (userId, username, email) { + const existingUser = this.engine.runStatement(` + SELECT user_id FROM users + WHERE email = $email AND user_id != $userId +`, { + $email: email, + $userId: userId + }); + + if (existingUser.length > 0) { + return { + success: false, + message: "Email address already in use by another user." + }; + } + + try { + this.engine.runStatement(` + UPDATE users + SET username = $username, email = $email + WHERE user_id = $userId + `, { $userId: userId, $username: username, $email: email - }); + }); + + return { + success: true, + message: "User profile updated successfully." + }; + } catch (error) { + return { + success: false, + message: "Failed to update user profile: " + error.message + }; + } +}; + +SqlTiddlerDatabase.prototype.updateUserPassword = function (userId, newHash) { + try { + this.engine.runStatement(` + UPDATE users + SET password = $newHash + WHERE user_id = $userId + `, { + $userId: userId, + $newHash: newHash, + }); + + return { + success: true, + message: "Password updated successfully." + }; + } catch (error) { + return { + success: false, + message: "Failed to update password: " + error.message + }; + } }; SqlTiddlerDatabase.prototype.deleteUser = function(userId) { diff --git a/plugins/tiddlywiki/multiwikiserver/templates/manage-user.tid b/plugins/tiddlywiki/multiwikiserver/templates/manage-user.tid index 434ebd66a..9d190f822 100644 --- a/plugins/tiddlywiki/multiwikiserver/templates/manage-user.tid +++ b/plugins/tiddlywiki/multiwikiserver/templates/manage-user.tid @@ -42,36 +42,48 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/manage-user -
+ + <$let flash-message={{{ [[$:/state/mws/flash-message]get[text]] }}}> + <$reveal type="nomatch" state="$:/state/mws/flash-message" text=""> + + <$action-setfield $tiddler="$:/state/mws/flash-message" text=""/> + $reveal> + $let>