diff --git a/backend/routes/login.py b/backend/routes/login.py index 10bf84a..847150d 100644 --- a/backend/routes/login.py +++ b/backend/routes/login.py @@ -8,7 +8,7 @@ ) from werkzeug.urls import url_parse -from backend import app, jwt, redis_client +from backend import app, db, jwt, redis_client from backend.models import User from . import auth @@ -110,3 +110,42 @@ def logout(): jti = get_raw_jwt()["jti"] redis_client.set(jti, "true", app.config["JWT_ACCESS_TOKEN_EXPIRES"] * 1.2) return jsonify(message="User logged out", type="LOGGED_OUT"), 200 + + +@auth.route("/reset", methods=["PATCH"]) +@jwt_required +def reset_password(): + identity = get_jwt_identity() + request_user = User.query.filter_by(username=identity["username"]).first() + + if not request.is_json: + return jsonify(message="Missing JSON in request"), 400 + + old_password = request.json.get("oldpassword", None) + new_password = request.json.get("newpassword", None) + + if request_user is None or not request_user.check_password(old_password): + return ( + jsonify( + message="Incorrect password!", type="INCORRECT_CREDENTIALS" + ), + 401, + ) + + if new_password is None or new_password is "": + return ( + jsonify( + message="New password field is blank!" + ), + 400, + ) + + try: + request_user.set_password(new_password) + db.session.commit() + except Exception as e: + app.logger.error("Error resetting the user password") + app.logger.error(e) + return jsonify(message="Error resetting the user password!"), 500 + + return jsonify(user_id=request_user.id, message="User password has been reset!"), 200 diff --git a/frontend/src/containers/forms/resetPasswordForm.js b/frontend/src/containers/forms/resetPasswordForm.js new file mode 100644 index 0000000..1b425dd --- /dev/null +++ b/frontend/src/containers/forms/resetPasswordForm.js @@ -0,0 +1,126 @@ +import React from "react"; +import axios from "axios"; +import { withRouter } from "react-router"; +import { withStore } from "@spyna/react-store"; + +import Alert from "../../components/alert"; +import { Button } from "../../components/button"; + +import { setAuthorizationToken } from "../../utils"; + +class ResetPassword extends React.Component { + constructor(props) { + super(props); + + this.initialState = { + newpassword: "", + oldpassword: "", + isResetIn: false, + errorMessage: "", + successMessage: "", + }; + + this.state = Object.assign({}, this.initialState); + } + + resetState() { + this.setState(this.initialState); + } + + handlePasswordChange(e) { + console.log(); + const passType = e.target.id; + if (passType == "old-password") { + this.setState({ oldpassword: e.target.value }); + } else { + this.setState({ newpassword: e.target.value }); + } + } + + handleResetPass(e) { + const { oldpassword, newpassword } = this.state; + + axios({ + method: "patch", + url: "auth/reset", + data: { + oldpassword, + newpassword, + }, + }) + .then((response) => { + this.setState({ + errorMessage: null, + successMessage: "Password Succesfully reset!", + }); + }) + .catch((error) => { + this.setState({ + isResetIn: false, + successMessage: "", + errorMessage: error.response.data.message, + }); + }); + } + + handleAlertDismiss(e) { + e.preventDefault(); + this.setState({ + successMessage: "", + errorMessage: "", + }); + } + + render() { + const { isResetIn, successMessage, errorMessage } = this.state; + return ( +
+ {errorMessage ? ( + this.handleAlertDismiss(e)} + /> + ) : null} + {successMessage ? ( + this.handleAlertDismiss(e)} + /> + ) : null} +
+ this.handlePasswordChange(e)} + /> +
+
+ this.handlePasswordChange(e)} + /> +
+
+
+ + ); + } +} +export default withStore(withRouter(ResetPassword)); diff --git a/frontend/src/containers/modal.js b/frontend/src/containers/modal.js index bab258f..478ea35 100644 --- a/frontend/src/containers/modal.js +++ b/frontend/src/containers/modal.js @@ -9,6 +9,7 @@ import EditLabelForm from "./forms/editLabelForm"; import ManageUsersProjectForm from "./forms/manageUsersProjectForm"; import CreateLabelValueForm from "./forms/createLabelValuelForm"; import EditLabelValueForm from "./forms/editLabelValueForm"; +import ResetPassword from "./forms/resetPasswordForm"; const FormModal = (props) => { return ( @@ -27,6 +28,7 @@ const FormModal = (props) => { {props.formType === "NEW_USER" ? : null} + {props.formType === "RESET_USER" ? : null} {props.formType === "NEW_PROJECT" ? : null} {props.formType === "EDIT_USER" ? ( diff --git a/frontend/src/containers/navbar.js b/frontend/src/containers/navbar.js index 10786ea..cdba250 100644 --- a/frontend/src/containers/navbar.js +++ b/frontend/src/containers/navbar.js @@ -6,7 +6,14 @@ import { withStore } from "@spyna/react-store"; import { setAuthorizationToken } from "../utils"; +import FormModal from "./modal"; + class NavBar extends React.Component { + constructor(props) { + super(props); + this.state = { modalShow: false }; + } + handleLogout(e) { const { history } = this.props; @@ -30,6 +37,14 @@ class NavBar extends React.Component { }); } + setModalShow(modalShow) { + this.setState({ modalShow }); + } + + handleResetPassword(e) { + this.setModalShow(true); + } + render() { const isUserLoggedIn = this.props.store.get("isUserLoggedIn"); const isAdmin = this.props.store.get("isAdmin"); @@ -66,6 +81,23 @@ class NavBar extends React.Component { Logout +
  • + +
  • + {this.state.modalShow ? ( + this.setModalShow(false)} + /> + ) : null}