Ensure only admins can delete users/exercises and users can only edit there own name
This commit is contained in:
14
app.py
14
app.py
@@ -5,7 +5,7 @@ from flask_login import LoginManager, login_required, current_user
|
|||||||
import jinja_partials
|
import jinja_partials
|
||||||
from jinja2_fragments import render_block
|
from jinja2_fragments import render_block
|
||||||
from decorators import (validate_person, validate_topset, validate_workout,
|
from decorators import (validate_person, validate_topset, validate_workout,
|
||||||
require_ownership, get_auth_message, get_person_id_from_context)
|
require_ownership, get_auth_message, get_person_id_from_context, admin_required)
|
||||||
from routes.auth import auth, get_person_by_id
|
from routes.auth import auth, get_person_by_id
|
||||||
from routes.changelog import changelog_bp
|
from routes.changelog import changelog_bp
|
||||||
from routes.calendar import calendar_bp # Import the new calendar blueprint
|
from routes.calendar import calendar_bp # Import the new calendar blueprint
|
||||||
@@ -165,8 +165,8 @@ def create_person():
|
|||||||
|
|
||||||
@ app.route("/person/<int:person_id>/delete", methods=['DELETE'])
|
@ app.route("/person/<int:person_id>/delete", methods=['DELETE'])
|
||||||
@login_required
|
@login_required
|
||||||
|
@admin_required
|
||||||
@validate_person
|
@validate_person
|
||||||
@require_ownership
|
|
||||||
def delete_person(person_id):
|
def delete_person(person_id):
|
||||||
db.delete_person(person_id)
|
db.delete_person(person_id)
|
||||||
return "", 200, {"HX-Trigger": "updatedPeople"}
|
return "", 200, {"HX-Trigger": "updatedPeople"}
|
||||||
@@ -198,6 +198,7 @@ def get_person_name(person_id):
|
|||||||
|
|
||||||
|
|
||||||
@ app.route("/exercise", methods=['POST'])
|
@ app.route("/exercise", methods=['POST'])
|
||||||
|
@login_required
|
||||||
def create_exercise():
|
def create_exercise():
|
||||||
name = request.form.get("name")
|
name = request.form.get("name")
|
||||||
attribute_ids = request.form.getlist('attribute_ids')
|
attribute_ids = request.form.getlist('attribute_ids')
|
||||||
@@ -218,6 +219,7 @@ def get_exercise(exercise_id):
|
|||||||
|
|
||||||
|
|
||||||
@ app.route("/exercise/<int:exercise_id>/edit_form", methods=['GET'])
|
@ app.route("/exercise/<int:exercise_id>/edit_form", methods=['GET'])
|
||||||
|
@login_required
|
||||||
def get_exercise_edit_form(exercise_id):
|
def get_exercise_edit_form(exercise_id):
|
||||||
exercise = db.get_exercise(exercise_id)
|
exercise = db.get_exercise(exercise_id)
|
||||||
all_attributes = db.exercises.get_attributes_by_category()
|
all_attributes = db.exercises.get_attributes_by_category()
|
||||||
@@ -243,6 +245,7 @@ def get_exercise_edit_form(exercise_id):
|
|||||||
|
|
||||||
|
|
||||||
@ app.route("/exercise/<int:exercise_id>/update", methods=['PUT'])
|
@ app.route("/exercise/<int:exercise_id>/update", methods=['PUT'])
|
||||||
|
@login_required
|
||||||
def update_exercise(exercise_id):
|
def update_exercise(exercise_id):
|
||||||
new_name = request.form.get('name')
|
new_name = request.form.get('name')
|
||||||
attribute_ids = request.form.getlist('attribute_ids')
|
attribute_ids = request.form.getlist('attribute_ids')
|
||||||
@@ -262,9 +265,6 @@ def delete_exercise(exercise_id):
|
|||||||
@ app.route("/settings")
|
@ app.route("/settings")
|
||||||
@ login_required
|
@ login_required
|
||||||
def settings():
|
def settings():
|
||||||
# check if user is admin
|
|
||||||
if current_user.id != 1007:
|
|
||||||
return redirect(url_for('dashboard'))
|
|
||||||
people = db.get_people()
|
people = db.get_people()
|
||||||
exercises = db.get_all_exercises()
|
exercises = db.get_all_exercises()
|
||||||
all_attributes = db.exercises.get_attributes_by_category()
|
all_attributes = db.exercises.get_attributes_by_category()
|
||||||
@@ -329,6 +329,7 @@ def get_exercises():
|
|||||||
return render_template('partials/exercise/exercise_dropdown.html', exercises=exercises, person_id=person_id)
|
return render_template('partials/exercise/exercise_dropdown.html', exercises=exercises, person_id=person_id)
|
||||||
|
|
||||||
@app.route("/exercise/<int:exercise_id>/edit_name", methods=['GET', 'POST'])
|
@app.route("/exercise/<int:exercise_id>/edit_name", methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
def edit_exercise_name(exercise_id):
|
def edit_exercise_name(exercise_id):
|
||||||
exercise = db.exercises.get_exercise(exercise_id)
|
exercise = db.exercises.get_exercise(exercise_id)
|
||||||
person_id = request.args.get('person_id', type=int)
|
person_id = request.args.get('person_id', type=int)
|
||||||
@@ -340,6 +341,7 @@ def edit_exercise_name(exercise_id):
|
|||||||
return render_template('partials/exercise/exercise_list_item.html', exercise=updated_exercise, person_id=person_id)
|
return render_template('partials/exercise/exercise_list_item.html', exercise=updated_exercise, person_id=person_id)
|
||||||
|
|
||||||
@app.route("/exercises/add", methods=['POST'])
|
@app.route("/exercises/add", methods=['POST'])
|
||||||
|
@login_required
|
||||||
def add_exercise():
|
def add_exercise():
|
||||||
exercise_name = request.form['query']
|
exercise_name = request.form['query']
|
||||||
new_exercise = db.exercises.add_exercise(exercise_name)
|
new_exercise = db.exercises.add_exercise(exercise_name)
|
||||||
@@ -347,6 +349,8 @@ def add_exercise():
|
|||||||
return render_template('partials/exercise/exercise_list_item.html', exercise=new_exercise, person_id=person_id)
|
return render_template('partials/exercise/exercise_list_item.html', exercise=new_exercise, person_id=person_id)
|
||||||
|
|
||||||
@ app.route("/exercise/<int:exercise_id>/delete", methods=['DELETE'])
|
@ app.route("/exercise/<int:exercise_id>/delete", methods=['DELETE'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
def delete_exercise(exercise_id):
|
def delete_exercise(exercise_id):
|
||||||
db.exercises.delete_exercise(exercise_id)
|
db.exercises.delete_exercise(exercise_id)
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -97,11 +97,30 @@ ACTION_MAP = {
|
|||||||
'tags.delete_tag': 'delete this tag',
|
'tags.delete_tag': 'delete this tag',
|
||||||
'tags.add_tag_to_workout': 'add a tag to this workout',
|
'tags.add_tag_to_workout': 'add a tag to this workout',
|
||||||
'tags.create_new_tag_for_workout': 'create a new tag for this workout',
|
'tags.create_new_tag_for_workout': 'create a new tag for this workout',
|
||||||
'programs.create_program': 'create a workout program',
|
'workout.create_program': 'create a workout program',
|
||||||
'programs.delete_program': 'delete this workout program',
|
'programs.delete_program': 'delete this workout program',
|
||||||
|
'delete_exercise': 'delete an exercise',
|
||||||
|
'delete_person': 'delete a user',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def admin_required(func):
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if not current_user.is_authenticated or not getattr(current_user, 'is_admin', False):
|
||||||
|
from flask import flash
|
||||||
|
msg = "You must be an admin to perform this action."
|
||||||
|
if request.endpoint in ACTION_MAP:
|
||||||
|
msg = f"You must be an admin to {ACTION_MAP[request.endpoint]}."
|
||||||
|
|
||||||
|
flash(msg, "warning")
|
||||||
|
if request.headers.get('HX-Request'):
|
||||||
|
return '', 200, {'HX-Redirect': url_for('dashboard')}
|
||||||
|
return render_template('error.html', error='403', message=msg, url='/')
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def get_auth_message(endpoint, person_id=None, is_authenticated=False):
|
def get_auth_message(endpoint, person_id=None, is_authenticated=False):
|
||||||
"""Generates a friendly authorization message."""
|
"""Generates a friendly authorization message."""
|
||||||
action = ACTION_MAP.get(endpoint)
|
action = ACTION_MAP.get(endpoint)
|
||||||
@@ -128,8 +147,9 @@ def require_ownership(func):
|
|||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
person_id = get_person_id_from_context()
|
person_id = get_person_id_from_context()
|
||||||
|
|
||||||
# Authorization check: must be logged in and the owner
|
# Authorization check: must be logged in and (the owner or an admin)
|
||||||
if not current_user.is_authenticated or person_id is None or int(current_user.get_id()) != person_id:
|
is_admin = getattr(current_user, 'is_admin', False)
|
||||||
|
if not current_user.is_authenticated or (person_id is not None and int(current_user.get_id()) != person_id and not is_admin):
|
||||||
from flask import flash
|
from flask import flash
|
||||||
msg = get_auth_message(request.endpoint, person_id, is_authenticated=current_user.is_authenticated)
|
msg = get_auth_message(request.endpoint, person_id, is_authenticated=current_user.is_authenticated)
|
||||||
flash(msg, "info")
|
flash(msg, "info")
|
||||||
|
|||||||
Reference in New Issue
Block a user