Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions dtbase/backend/api/user/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,51 @@ def delete_user() -> Tuple[Response, int]:
@jwt_required()
def change_password() -> Tuple[Response, int]:
"""
Change a users password
Change a user's password.

POST request should have json data (mimetype "application/json") containing
POST request should have JSON data (mimetype "application/json") containing
{
"email": <type_email:str>,
"password": <type_password:str>,
"current_password": <type_current_password:str>,
"new_password": <type_new_password:str>,
"confirm_new_password": <type_confirm_new_password:str>,
}
where `password` is the new password.
where `new_password` is the new password and `confirm_new_password`
must match `new_password`.

Returns 400 if user doesn't exist, otherwise 200.
Returns 400 if user doesn't exist, if current password is incorrect,
or if passwords do not match. Otherwise, returns 200.
"""
payload = request.get_json()
required_keys = ["email", "password"]
required_keys = [
"email",
"current_password",
"new_password",
"confirm_new_password",
]
error_response = check_keys(payload, required_keys, "/change-password")
if error_response:
return error_response

email = payload.get("email")
password = payload.get("password")
current_password = payload.get("current_password")
new_password = payload.get("new_password")
confirm_new_password = payload.get("confirm_new_password")

if new_password != confirm_new_password:
return (
jsonify({"message": "New password and confirm new password do not match"}),
400,
)

try:
users.change_password(email, password, session=db.session)
# Assuming `verify_password` checks the current password is correct
if not users.verify_password(email, current_password, session=db.session):
return jsonify({"message": "Current password is incorrect"}), 400

users.change_password(email, new_password, session=db.session)
except NoResultFound:
return jsonify({"message": "User doesn't exist"}), 400

db.session.commit()
return jsonify({"message": "Password changed"}), 200
return jsonify({"message": "Password changed successfully"}), 200
47 changes: 47 additions & 0 deletions dtbase/webapp/app/base/templates/security/password_reset.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{% extends "base_site.html" %}

{% block title %} Password Reset {% endblock title %}

{% block stylesheets %}
{{ super() }}
<link href="{{ url_for('static', filename='css/login.css') }}" rel="stylesheet">
{% endblock stylesheets %}

{% block body_class %}password-reset{% endblock body_class %}

{% block body %}
<div>
<div class="login_wrapper">
<div class="form login_form">
<section class="login_content">
<form method="post">
{{ form.hidden_tag() }}
<h1>Password Reset</h1>
{% for field in form if field.widget.input_type != 'hidden' %}
<div style="position: relative">
{{ field(class="form-control required", size=20, placeholder=field.label.text) }}
{% if field.name == "new_password" %}
<i class="fa fa-eye password-toggle" id="show-new-password"></i>
{% elif field.name == "confirm_new_password" %}
<i class="fa fa-eye password-toggle" id="show-confirm-new-password"></i>
{% endif %}
</div>
{% endfor %}
<div>
<button type="submit" class="btn btn-default submit">Reset Password</button>
</div>
</form>
</section>
</div>
</div>
</div>

{% block javascripts %}
{{ super() }}
<script src="{{ url_for('static', filename='javascript/utility.js') }}"></script>
<script>
document.getElementById("show-new-password").addEventListener("click", window.passwordToggle);
document.getElementById("show-confirm-new-password").addEventListener("click", window.passwordToggle);
</script>
{% endblock javascripts %}
{% endblock body %}
56 changes: 56 additions & 0 deletions scripts/setup_dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/zsh

ENV_NAME="dt_env"
# Function to check and activate Conda environment
check_activate_conda() {
if conda env list | grep "${ENV_NAME}" > /dev/null 2>&1; then
source ~/miniconda3/etc/profile.d/conda.sh
echo "Activating Conda environment: ${ENV_NAME}"
conda activate "${ENV_NAME}"
return 0
else
return 1
fi
}

# Function to check for Poetry environment
check_activate_poetry() {
if poetry env list | grep "${ENV_NAME}" > /dev/null 2>&1; then
echo "Activating Poetry environment: ${ENV_NAME}"
poetry shell
return 0
else
return 1
fi
}

# Function to check and activate PyEnv environment
check_activate_pyenv() {
if pyenv versions | grep "${ENV_NAME}" > /dev/null 2>&1; then
echo "Activating PyEnv environment: ${ENV_NAME}"
pyenv activate "${ENV_NAME}"
return 0
else
return 1
fi
}

# Check for environment management systems in the order of preference
if ! { conda --version &>/dev/null && check_activate_conda; } &&
! { type poetry &>/dev/null && check_activate_poetry; } &&
! { type pyenv &>/dev/null && check_activate_pyenv; } &&
[[ -z "$VIRTUAL_ENV" ]]; then
echo "No suitable Python environment management system is installed or the ${ENV_NAME} environment does not exist."
fi


# Make sure everything is installed
pip install '.[dev]'

# Start the backend API
(cd dtbase/backend && DT_CONFIG_MODE=Debug ./run_localdb.sh) &

# Start the frontend
(cd dtbase/webapp && npm install && FLASK_DEBUG=true DT_CONFIG_MODE=Auto-login ./run.sh) &

echo "DTBase setup complete. Backend running on http://localhost:5000, frontend on http://localhost:8000."