Add USB, Notifications, Network plugins and reusable EmployeeSearch component
New Plugins: - USB plugin: Device checkout/checkin with employee lookup, checkout history - Notifications plugin: Announcements with types, scheduling, shopfloor display - Network plugin: Network device management with subnets and VLANs - Equipment and Computers plugins: Asset type separation Frontend: - EmployeeSearch component: Reusable employee lookup with autocomplete - USB views: List, detail, checkout/checkin modals - Notifications views: List, form with recognition mode - Network views: Device list, detail, form - Calendar view with FullCalendar integration - Shopfloor and TV dashboard views - Reports index page - Map editor for asset positioning - Light/dark mode fixes for map tooltips Backend: - Employee search API with external lookup service - Collector API for PowerShell data collection - Reports API endpoints - Slides API for TV dashboard - Fixed AppVersion model (removed BaseModel inheritance) - Added checkout_name column to usbcheckouts table Styling: - Unified detail page styles - Improved pagination (page numbers instead of prev/next) - Dark/light mode theme improvements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,18 @@
|
||||
"""Machines API endpoints."""
|
||||
"""
|
||||
Machines API endpoints.
|
||||
|
||||
from flask import Blueprint, request
|
||||
DEPRECATED: This API is deprecated and will be removed in a future version.
|
||||
Please migrate to the new asset-based APIs:
|
||||
- /api/assets - Unified asset queries
|
||||
- /api/equipment - Equipment CRUD
|
||||
- /api/computers - Computers CRUD
|
||||
- /api/network - Network devices CRUD
|
||||
- /api/printers - Printers CRUD
|
||||
"""
|
||||
|
||||
import logging
|
||||
from functools import wraps
|
||||
from flask import Blueprint, request, g
|
||||
from flask_jwt_extended import jwt_required, current_user
|
||||
|
||||
from shopdb.extensions import db
|
||||
@@ -14,11 +26,40 @@ from shopdb.utils.responses import (
|
||||
)
|
||||
from shopdb.utils.pagination import get_pagination_params, paginate_query
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
machines_bp = Blueprint('machines', __name__)
|
||||
|
||||
|
||||
def add_deprecation_headers(f):
|
||||
"""Decorator to add deprecation headers to responses."""
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
response = f(*args, **kwargs)
|
||||
|
||||
# Add deprecation headers
|
||||
if hasattr(response, 'headers'):
|
||||
response.headers['X-Deprecated'] = 'true'
|
||||
response.headers['X-Deprecated-Message'] = (
|
||||
'This endpoint is deprecated. '
|
||||
'Please migrate to /api/assets, /api/equipment, /api/computers, /api/network, or /api/printers.'
|
||||
)
|
||||
response.headers['Sunset'] = '2026-12-31' # Target sunset date
|
||||
|
||||
# Log deprecation warning (once per request)
|
||||
if not getattr(g, '_deprecation_logged', False):
|
||||
logger.warning(
|
||||
f"Deprecated /api/machines endpoint called: {request.method} {request.path}"
|
||||
)
|
||||
g._deprecation_logged = True
|
||||
|
||||
return response
|
||||
return decorated_function
|
||||
|
||||
|
||||
@machines_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@add_deprecation_headers
|
||||
def list_machines():
|
||||
"""
|
||||
List all machines with filtering and pagination.
|
||||
@@ -149,6 +190,7 @@ def list_machines():
|
||||
|
||||
@machines_bp.route('/<int:machine_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@add_deprecation_headers
|
||||
def get_machine(machine_id: int):
|
||||
"""Get a single machine by ID."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -180,6 +222,7 @@ def get_machine(machine_id: int):
|
||||
|
||||
@machines_bp.route('', methods=['POST'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def create_machine():
|
||||
"""Create a new machine."""
|
||||
data = request.get_json()
|
||||
@@ -227,6 +270,7 @@ def create_machine():
|
||||
|
||||
@machines_bp.route('/<int:machine_id>', methods=['PUT'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def update_machine(machine_id: int):
|
||||
"""Update an existing machine."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -274,6 +318,7 @@ def update_machine(machine_id: int):
|
||||
|
||||
@machines_bp.route('/<int:machine_id>', methods=['DELETE'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def delete_machine(machine_id: int):
|
||||
"""Soft delete a machine."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -293,6 +338,7 @@ def delete_machine(machine_id: int):
|
||||
|
||||
@machines_bp.route('/<int:machine_id>/communications', methods=['GET'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def get_machine_communications(machine_id: int):
|
||||
"""Get all communications for a machine."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -310,6 +356,7 @@ def get_machine_communications(machine_id: int):
|
||||
|
||||
@machines_bp.route('/<int:machine_id>/communication', methods=['PUT'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def update_machine_communication(machine_id: int):
|
||||
"""Update machine communication (IP address)."""
|
||||
from shopdb.core.models.communication import Communication, CommunicationType
|
||||
@@ -364,6 +411,7 @@ def update_machine_communication(machine_id: int):
|
||||
|
||||
@machines_bp.route('/<int:machine_id>/relationships', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@add_deprecation_headers
|
||||
def get_machine_relationships(machine_id: int):
|
||||
"""Get all relationships for a machine (both parent and child)."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -429,6 +477,7 @@ def get_machine_relationships(machine_id: int):
|
||||
|
||||
@machines_bp.route('/<int:machine_id>/relationships', methods=['POST'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def create_machine_relationship(machine_id: int):
|
||||
"""Create a relationship for a machine."""
|
||||
machine = Machine.query.get(machine_id)
|
||||
@@ -504,6 +553,7 @@ def create_machine_relationship(machine_id: int):
|
||||
|
||||
@machines_bp.route('/relationships/<int:relationship_id>', methods=['DELETE'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def delete_machine_relationship(relationship_id: int):
|
||||
"""Delete a machine relationship."""
|
||||
relationship = MachineRelationship.query.get(relationship_id)
|
||||
@@ -523,6 +573,7 @@ def delete_machine_relationship(relationship_id: int):
|
||||
|
||||
@machines_bp.route('/relationshiptypes', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@add_deprecation_headers
|
||||
def list_relationship_types():
|
||||
"""List all relationship types."""
|
||||
types = RelationshipType.query.order_by(RelationshipType.relationshiptype).all()
|
||||
@@ -535,6 +586,7 @@ def list_relationship_types():
|
||||
|
||||
@machines_bp.route('/relationshiptypes', methods=['POST'])
|
||||
@jwt_required()
|
||||
@add_deprecation_headers
|
||||
def create_relationship_type():
|
||||
"""Create a new relationship type."""
|
||||
data = request.get_json()
|
||||
|
||||
Reference in New Issue
Block a user