260 lines
10 KiB
Python
260 lines
10 KiB
Python
from quart import Blueprint, jsonify, request, abort
|
|
from internal.db_wrappers import System, SystemDbController
|
|
from werkzeug.exceptions import HTTPException
|
|
|
|
systems_bp = Blueprint('systems', __name__)
|
|
db_h = SystemDbController()
|
|
|
|
|
|
@systems_bp.route("/", methods=['POST'])
|
|
async def create_system_route():
|
|
"""API endpoint to create a new system."""
|
|
print("\n--- Handling POST /systems ---")
|
|
try:
|
|
# In Quart, you need to explicitly get the JSON request body
|
|
request_data = await request.get_json()
|
|
|
|
if not request_data:
|
|
abort(400, "Request body must be JSON") # Bad Request
|
|
|
|
if '_id' in request_data:
|
|
id_search_result = await db_h.find_system({"_id": request_data["_id"]})
|
|
if id_search_result:
|
|
# If _id is provided and exists, return conflict
|
|
abort(409, f"System with ID '{request_data['_id']}' already exists")
|
|
|
|
# Check if name exists (optional, depending on requirements)
|
|
if 'name' in request_data:
|
|
name_search_result = await db_h.find_system({"name": request_data["name"]})
|
|
if name_search_result:
|
|
abort(409, f"System with name '{request_data['name']}' already exists")
|
|
|
|
# Check if frequency_khz exists (optional, depending on requirements)
|
|
if 'frequency_khz' in request_data:
|
|
freq_search_result = await db_h.find_system({"frequency_khz": request_data["frequency_khz"]})
|
|
if freq_search_result:
|
|
abort(409, f"System with frequency '{request_data['frequency_khz']}' already exists")
|
|
|
|
created_system = await db_h.create_system(request_data)
|
|
|
|
if created_system:
|
|
print("Created new system:", created_system)
|
|
return jsonify(created_system), 201
|
|
else:
|
|
abort(500, "Failed to create system in the database.")
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error creating system: {e}")
|
|
# Catch any other unexpected errors
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/', methods=['GET'])
|
|
async def list_systems_route():
|
|
"""API endpoint to get a list of all systems."""
|
|
print("\n--- Handling GET /systems ---")
|
|
try:
|
|
all_systems = await db_h.find_all_systems()
|
|
|
|
return jsonify([system.to_dict() for system in all_systems]), 200 # 200 OK status code
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error listing systems: {e}")
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/<string:system_id>', methods=['GET'])
|
|
async def get_system_route(system_id: str):
|
|
"""API endpoint to get details for a specific system by ID."""
|
|
print(f"\n--- Handling GET /systems/{system_id} ---")
|
|
try:
|
|
# Fix the query dictionary syntax
|
|
system = await db_h.find_system({'_id': system_id})
|
|
|
|
if system:
|
|
# system is a System object, jsonify will convert it
|
|
return jsonify(system.to_dict()), 200 # 200 OK
|
|
else:
|
|
# If system is None, it means the document was not found
|
|
abort(404, f"System with ID '{system_id}' not found") # 404 Not Found
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error getting system details for ID {system_id}: {e}")
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/client/<string:client_id>', methods=['GET'])
|
|
async def get_system_by_client_route(client_id: str):
|
|
"""API endpoint to get details for a specific system by ID."""
|
|
print(f"\n--- Handling GET /systems/client/{client_id} ---")
|
|
try:
|
|
# Fix the query dictionary syntax
|
|
systems = await db_h.find_systems({'avail_on_nodes': client_id})
|
|
|
|
if systems:
|
|
# system is a System object, jsonify will convert it
|
|
return jsonify([system.to_dict() for system in systems]), 200 # 200 OK
|
|
else:
|
|
# If system is None, it means the document was not found
|
|
abort(404, f"Client with ID '{client_id}' not found") # 404 Not Found
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error getting system details for client ID {client_id}: {e}")
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/<string:system_id>', methods=['PUT'])
|
|
async def update_system_route(system_id: str, updated_system_data):
|
|
try:
|
|
update_system = await db_h.update_system({"_id", system_id}, updated_system_data)
|
|
|
|
if update_system:
|
|
print("Updated system:", update_system)
|
|
return jsonify(update_system), 201
|
|
else:
|
|
abort(500, "Failed to update system in the database.")
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error updating system: {e}")
|
|
# Catch any other unexpected errors
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/<string:system_id>', methods=['DELETE'])
|
|
async def delete_system_route(system_id: str):
|
|
try:
|
|
deleted_system = await db_h.delete_system({"_id", system_id})
|
|
|
|
if deleted_system:
|
|
print("Deleted system:", deleted_system)
|
|
return jsonify(deleted_system), 201
|
|
else:
|
|
abort(500, "Failed to delete system in the database.")
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error deleting system: {e}")
|
|
# Catch any other unexpected errors
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/<string:system_id>/assign', methods=['POST'])
|
|
async def assign_client_to_system_route(system_id: str):
|
|
"""
|
|
API endpoint to assign a client ID to a system's available_on_nodes list.
|
|
Uses MongoDB $addToSet to add the client ID if not already present.
|
|
Expects JSON body: {"client_id": "..."}
|
|
"""
|
|
print(f"\n--- Handling POST /systems/{system_id}/assign ---")
|
|
try:
|
|
request_data = await request.get_json()
|
|
|
|
if not request_data or 'client_id' not in request_data:
|
|
abort(400, "Request body must contain 'client_id'")
|
|
|
|
client_id = request_data['client_id']
|
|
|
|
if not isinstance(client_id, str) or not client_id:
|
|
abort(400, "'client_id' must be a non-empty string")
|
|
|
|
# First, check if the system exists
|
|
existing_system = await db_h.find_system({"_id": system_id})
|
|
if existing_system is None:
|
|
abort(404, f"System with ID '{system_id}' not found")
|
|
|
|
# Use $addToSet to add the client_id to the avail_on_nodes array
|
|
# $addToSet only adds the element if it's not already in the array
|
|
update_query = {"_id": system_id}
|
|
update_data = {"$addToSet": {"avail_on_nodes": client_id}}
|
|
|
|
update_result = await db_h.update_system(update_query, update_data)
|
|
|
|
if update_result > 0:
|
|
print(f"Client '{client_id}' assigned to system '{system_id}'.")
|
|
status = "client_assigned"
|
|
else:
|
|
print(f"Client '{client_id}' was already assigned to system '{system_id}'.")
|
|
status = "already_assigned"
|
|
|
|
updated_system = await db_h.find_system({"_id": system_id})
|
|
if updated_system:
|
|
return jsonify({
|
|
"status": status,
|
|
"system": updated_system.to_dict() # Return dict representation
|
|
}), 200 # 200 OK
|
|
else:
|
|
# Should not happen if update_result.matched_count was 1, but handle defensively
|
|
print(f"Update matched but couldn't fetch updated system {system_id}.")
|
|
abort(500, "Failed to fetch system state after assignment attempt.")
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error during system assignment: {e}")
|
|
abort(500, f"Internal server error: {e}")
|
|
|
|
|
|
@systems_bp.route('/<string:system_id>/dismiss', methods=['POST'])
|
|
async def dismiss_client_from_system_route(system_id: str):
|
|
"""
|
|
API endpoint to dismiss (remove) a client ID from a system's available_on_nodes list.
|
|
Uses MongoDB $pull to remove the client ID if present.
|
|
Expects JSON body: {"client_id": "..."}
|
|
"""
|
|
print(f"\n--- Handling POST /systems/{system_id}/deassign ---")
|
|
try:
|
|
request_data = await request.get_json()
|
|
|
|
if not request_data or 'client_id' not in request_data:
|
|
abort(400, "Request body must contain 'client_id'")
|
|
|
|
client_id = request_data['client_id']
|
|
|
|
if not isinstance(client_id, str) or not client_id:
|
|
abort(400, "'client_id' must be a non-empty string")
|
|
|
|
# First, check if the system exists
|
|
existing_system = await db_h.find_system({"_id": system_id})
|
|
if existing_system is None:
|
|
abort(404, f"System with ID '{system_id}' not found")
|
|
|
|
# Use $pull to remove the client_id from the avail_on_nodes array
|
|
# $pull removes all occurrences of the value
|
|
update_query = {"_id": system_id}
|
|
update_data = {"$pull": {"avail_on_nodes": client_id}}
|
|
|
|
update_result = await db_h.update_system(update_query, update_data)
|
|
|
|
if update_result > 0:
|
|
print(f"Client '{client_id}' dismissed from system '{system_id}'.")
|
|
status = "client_deassigned"
|
|
else:
|
|
print(f"Client '{client_id}' was not found in avail_on_nodes for system '{system_id}'.")
|
|
status = "not_assigned"
|
|
# Note: update_result.matched_count will be 1 even if modified_count is 0
|
|
|
|
# Optionally fetch the updated document to return its current state
|
|
updated_system = await db_h.find_system({"_id": system_id})
|
|
if updated_system:
|
|
return jsonify({
|
|
"status": status,
|
|
"system": updated_system.to_dict() # Return dict representation
|
|
}), 200 # 200 OK
|
|
else:
|
|
# Should not happen if update_result.matched_count was 1, but handle defensively
|
|
print(f"Update matched but couldn't fetch updated system {system_id}.")
|
|
abort(500, "Failed to fetch system state after de-assignment attempt.")
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
print(f"Error during system de-assignment: {e}")
|
|
abort(500, f"Internal server error: {e}")
|