|
5 | 5 | from flask_login import current_user |
6 | 6 |
|
7 | 7 | from pydatalab.config import CONFIG |
| 8 | +from pydatalab.models.people import Person |
8 | 9 | from pydatalab.mongo import flask_mongo |
9 | 10 | from pydatalab.permissions import admin_only, get_default_permissions |
10 | 11 |
|
| 12 | + |
| 13 | +def check_manager_cycle(user_id_str, new_manager_id_str): |
| 14 | + visited = set() |
| 15 | + current_id = new_manager_id_str |
| 16 | + |
| 17 | + while current_id is not None: |
| 18 | + if current_id == user_id_str: |
| 19 | + return True |
| 20 | + if current_id in visited: |
| 21 | + break |
| 22 | + visited.add(current_id) |
| 23 | + |
| 24 | + try: |
| 25 | + manager = flask_mongo.db.users.find_one({"_id": ObjectId(current_id)}) |
| 26 | + if manager and "managers" in manager and manager["managers"]: |
| 27 | + if isinstance(manager["managers"], list) and len(manager["managers"]) > 0: |
| 28 | + current_id = manager["managers"][0] |
| 29 | + else: |
| 30 | + break |
| 31 | + else: |
| 32 | + break |
| 33 | + except Exception: |
| 34 | + break |
| 35 | + |
| 36 | + return False |
| 37 | + |
| 38 | + |
11 | 39 | ADMIN = Blueprint("admins", __name__) |
12 | 40 |
|
13 | 41 |
|
@@ -37,13 +65,21 @@ def get_users(): |
37 | 65 | "then": "user", |
38 | 66 | "else": {"$arrayElemAt": ["$role.role", 0]}, |
39 | 67 | } |
40 | | - } |
| 68 | + }, |
41 | 69 | } |
42 | 70 | }, |
43 | 71 | ] |
44 | 72 | ) |
45 | 73 |
|
46 | | - return jsonify({"status": "success", "data": list(users)}) |
| 74 | + users_list = list(users) |
| 75 | + |
| 76 | + for user in users_list: |
| 77 | + if "managers" not in user: |
| 78 | + user["managers"] = [] |
| 79 | + elif not isinstance(user["managers"], list): |
| 80 | + user["managers"] = [] |
| 81 | + |
| 82 | + return jsonify({"status": "success", "data": [Person(**d).dict() for d in users_list]}) |
47 | 83 |
|
48 | 84 |
|
49 | 85 | @ADMIN.route("/roles/<user_id>", methods=["PATCH"]) |
@@ -97,6 +133,59 @@ def save_role(user_id): |
97 | 133 | return (jsonify({"status": "success"}), 200) |
98 | 134 |
|
99 | 135 |
|
| 136 | +@ADMIN.route("/users/<user_id>/managers", methods=["PATCH"]) |
| 137 | +def update_user_managers(user_id): |
| 138 | + """Update the managers for a specific user using ObjectIds""" |
| 139 | + |
| 140 | + request_json = request.get_json() |
| 141 | + |
| 142 | + if request_json is None or "managers" not in request_json: |
| 143 | + return jsonify({"status": "error", "message": "Managers list not provided"}), 400 |
| 144 | + |
| 145 | + managers = request_json["managers"] |
| 146 | + |
| 147 | + if not isinstance(managers, list): |
| 148 | + return jsonify({"status": "error", "message": "Managers must be a list"}), 400 |
| 149 | + |
| 150 | + existing_user = flask_mongo.db.users.find_one({"_id": ObjectId(user_id)}) |
| 151 | + if not existing_user: |
| 152 | + return jsonify({"status": "error", "message": "User not found"}), 404 |
| 153 | + |
| 154 | + manager_object_ids = [] |
| 155 | + for manager_id in managers: |
| 156 | + if manager_id: |
| 157 | + try: |
| 158 | + manager_oid = ObjectId(manager_id) |
| 159 | + except Exception: |
| 160 | + return jsonify( |
| 161 | + {"status": "error", "message": f"Invalid manager ID format: {manager_id}"} |
| 162 | + ), 400 |
| 163 | + |
| 164 | + if not flask_mongo.db.users.find_one({"_id": manager_oid}): |
| 165 | + return jsonify( |
| 166 | + {"status": "error", "message": f"Manager with ID {manager_id} not found"} |
| 167 | + ), 404 |
| 168 | + |
| 169 | + if check_manager_cycle(user_id, manager_id): |
| 170 | + return jsonify( |
| 171 | + { |
| 172 | + "status": "error", |
| 173 | + "message": "Cannot assign manager: would create a circular management hierarchy", |
| 174 | + } |
| 175 | + ), 400 |
| 176 | + |
| 177 | + manager_object_ids.append(str(manager_oid)) |
| 178 | + |
| 179 | + update_result = flask_mongo.db.users.update_one( |
| 180 | + {"_id": ObjectId(user_id)}, {"$set": {"managers": manager_object_ids}} |
| 181 | + ) |
| 182 | + |
| 183 | + if update_result.matched_count != 1: |
| 184 | + return jsonify({"status": "error", "message": "Unable to update user managers"}), 400 |
| 185 | + |
| 186 | + return jsonify({"status": "success"}), 200 |
| 187 | + |
| 188 | + |
100 | 189 | @ADMIN.route("/items/<refcode>/invalidate-access-token", methods=["POST"]) |
101 | 190 | def invalidate_access_token(refcode: str): |
102 | 191 | if len(refcode.split(":")) != 2: |
|
0 commit comments