dhruv575 commited on
Commit
7d66e3d
·
1 Parent(s): ecbc4c7

Fixing department routes

Browse files
controllers/department_controller.py CHANGED
@@ -259,7 +259,7 @@ def add_member(department_id):
259
  logger.error(f"Error adding member: {str(e)}")
260
  return jsonify({'message': f'Error adding member: {str(e)}'}), 500
261
 
262
- def get_department_members(department_id):
263
  """Get all members of a department"""
264
  department = Department.find_by_id(department_id)
265
  if not department:
 
259
  logger.error(f"Error adding member: {str(e)}")
260
  return jsonify({'message': f'Error adding member: {str(e)}'}), 500
261
 
262
+ def get_department_members(department_id, current_user=None):
263
  """Get all members of a department"""
264
  department = Department.find_by_id(department_id)
265
  if not department:
fix/auth_utils_fix.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import jwt
3
+ from datetime import datetime, timedelta
4
+ from functools import wraps
5
+ from flask import request, jsonify
6
+ from models.user import User
7
+
8
+ # Secret key for JWT
9
+ SECRET_KEY = os.environ.get('JWT_SECRET')
10
+
11
+ def generate_token(user_id, permissions, expiration_hours=24*30): # 30-day token by default
12
+ """Generate JWT token for authentication"""
13
+ payload = {
14
+ 'user_id': str(user_id),
15
+ 'permissions': permissions,
16
+ 'exp': datetime.utcnow() + timedelta(hours=expiration_hours)
17
+ }
18
+ return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
19
+
20
+ def decode_token(token):
21
+ """Decode JWT token and return payload"""
22
+ try:
23
+ return jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
24
+ except:
25
+ return None
26
+
27
+ def token_required(f):
28
+ """
29
+ Fixed decorator for routes that require a valid token.
30
+ This version passes current_user as a kwarg instead of an arg,
31
+ avoiding parameter conflicts with URL path parameters.
32
+ """
33
+ @wraps(f)
34
+ def decorated(*args, **kwargs):
35
+ token = None
36
+ auth_header = request.headers.get('Authorization')
37
+
38
+ if auth_header:
39
+ if auth_header.startswith('Bearer '):
40
+ token = auth_header.split(" ")[1]
41
+
42
+ if not token:
43
+ return jsonify({'message': 'Token is missing'}), 401
44
+
45
+ data = decode_token(token)
46
+ if not data:
47
+ return jsonify({'message': 'Token is invalid or expired'}), 401
48
+
49
+ current_user = User.find_by_id(data['user_id'])
50
+ if not current_user:
51
+ return jsonify({'message': 'User not found'}), 401
52
+
53
+ # Pass current_user as a keyword argument instead of positional argument
54
+ kwargs['current_user'] = current_user
55
+ return f(*args, **kwargs)
56
+
57
+ return decorated
58
+
59
+ def admin_required(f):
60
+ """
61
+ Fixed decorator for routes that require admin permissions.
62
+ This version passes current_user as a kwarg instead of an arg,
63
+ avoiding parameter conflicts with URL path parameters.
64
+ """
65
+ @wraps(f)
66
+ def decorated(*args, **kwargs):
67
+ token = None
68
+ auth_header = request.headers.get('Authorization')
69
+
70
+ if auth_header:
71
+ if auth_header.startswith('Bearer '):
72
+ token = auth_header.split(" ")[1]
73
+
74
+ if not token:
75
+ return jsonify({'message': 'Token is missing'}), 401
76
+
77
+ data = decode_token(token)
78
+ if not data:
79
+ return jsonify({'message': 'Token is invalid or expired'}), 401
80
+
81
+ if data['permissions'] != 'Admin':
82
+ return jsonify({'message': 'Admin permissions required'}), 403
83
+
84
+ current_user = User.find_by_id(data['user_id'])
85
+ if not current_user:
86
+ return jsonify({'message': 'User not found'}), 401
87
+
88
+ # Pass current_user as a keyword argument instead of positional argument
89
+ kwargs['current_user'] = current_user
90
+ return f(*args, **kwargs)
91
+
92
+ return decorated
fix/department_routes_fix.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from controllers.department_controller import (
3
+ create_department, get_department, update_department,
4
+ delete_department, get_all_departments, add_members_csv,
5
+ add_member, get_department_members, remove_member, update_member_permissions
6
+ )
7
+ from utils.auth import token_required, admin_required
8
+
9
+ # Create blueprint
10
+ department_bp = Blueprint('departments', __name__)
11
+
12
+ # Public route for creating a new department with first admin
13
+ department_bp.route('', methods=['POST'])(create_department)
14
+
15
+ # Routes that require authentication
16
+ department_bp.route('/', methods=['GET'])(token_required(get_all_departments))
17
+ department_bp.route('/<department_id>', methods=['GET'])(token_required(get_department))
18
+
19
+ # Routes that require admin permissions
20
+ department_bp.route('/<department_id>', methods=['PUT'])(admin_required(update_department))
21
+ department_bp.route('/<department_id>', methods=['DELETE'])(admin_required(delete_department))
22
+
23
+ # Member management routes (admin only)
24
+ # FIX: Wrap the function to avoid parameter conflict with department_id
25
+ @department_bp.route('/<department_id>/members', methods=['GET'])
26
+ @token_required
27
+ def get_members_route(current_user, department_id):
28
+ """Route wrapper to avoid parameter conflict"""
29
+ return get_department_members(department_id)
30
+
31
+ department_bp.route('/<department_id>/members', methods=['POST'])(admin_required(add_member))
32
+ department_bp.route('/<department_id>/members/csv', methods=['POST'])(admin_required(add_members_csv))
33
+ department_bp.route('/<department_id>/members/<user_id>', methods=['DELETE'])(admin_required(remove_member))
34
+ department_bp.route('/<department_id>/members/<user_id>/permissions', methods=['PUT'])(admin_required(update_member_permissions))
routes/department_routes.py CHANGED
@@ -21,6 +21,8 @@ department_bp.route('/<department_id>', methods=['PUT'])(admin_required(update_d
21
  department_bp.route('/<department_id>', methods=['DELETE'])(admin_required(delete_department))
22
 
23
  # Member management routes (admin only)
 
 
24
  department_bp.route('/<department_id>/members', methods=['GET'])(token_required(get_department_members))
25
  department_bp.route('/<department_id>/members', methods=['POST'])(admin_required(add_member))
26
  department_bp.route('/<department_id>/members/csv', methods=['POST'])(admin_required(add_members_csv))
 
21
  department_bp.route('/<department_id>', methods=['DELETE'])(admin_required(delete_department))
22
 
23
  # Member management routes (admin only)
24
+ # This now works because we've fixed the token_required decorator to pass current_user as a kwarg
25
+ # instead of as a positional argument, avoiding the parameter conflict with department_id
26
  department_bp.route('/<department_id>/members', methods=['GET'])(token_required(get_department_members))
27
  department_bp.route('/<department_id>/members', methods=['POST'])(admin_required(add_member))
28
  department_bp.route('/<department_id>/members/csv', methods=['POST'])(admin_required(add_members_csv))
utils/auth.py CHANGED
@@ -48,7 +48,8 @@ def token_required(f):
48
  if not current_user:
49
  return jsonify({'message': 'User not found'}), 401
50
 
51
- return f(current_user, *args, **kwargs)
 
52
 
53
  return decorated
54
 
@@ -77,6 +78,7 @@ def admin_required(f):
77
  if not current_user:
78
  return jsonify({'message': 'User not found'}), 401
79
 
80
- return f(current_user, *args, **kwargs)
 
81
 
82
  return decorated
 
48
  if not current_user:
49
  return jsonify({'message': 'User not found'}), 401
50
 
51
+ kwargs['current_user'] = current_user
52
+ return f(*args, **kwargs)
53
 
54
  return decorated
55
 
 
78
  if not current_user:
79
  return jsonify({'message': 'User not found'}), 401
80
 
81
+ kwargs['current_user'] = current_user
82
+ return f(*args, **kwargs)
83
 
84
  return decorated