read permissions on every GET
This commit is contained in:
@@ -17,7 +17,7 @@ computers_bp = Blueprint('computers', __name__)
|
||||
# =============================================================================
|
||||
|
||||
@computers_bp.route('/types', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def list_computer_types():
|
||||
"""List all computer types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -39,7 +39,7 @@ def list_computer_types():
|
||||
|
||||
|
||||
@computers_bp.route('/types/<int:type_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def get_computer_type(type_id: int):
|
||||
"""Get a single computer type."""
|
||||
t = db.session.get(ComputerType, type_id)
|
||||
@@ -145,7 +145,7 @@ def delete_computer_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@computers_bp.route('/protocols', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def list_protocols():
|
||||
"""List access protocols. ?active=false includes disabled ones."""
|
||||
query = AccessProtocol.query
|
||||
@@ -293,7 +293,7 @@ def _sync_access_methods(comp, data):
|
||||
# =============================================================================
|
||||
|
||||
@computers_bp.route('/display-kiosks', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def list_display_kiosks():
|
||||
"""Reporting display kiosks, for the Dashboard Defaults picker.
|
||||
|
||||
@@ -329,7 +329,7 @@ def list_display_kiosks():
|
||||
|
||||
|
||||
@computers_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def list_computers():
|
||||
"""
|
||||
List all computers with filtering and pagination.
|
||||
@@ -437,7 +437,7 @@ def list_computers():
|
||||
|
||||
|
||||
@computers_bp.route('/<int:computer_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def get_computer(computer_id: int):
|
||||
"""Get a single computer with full details."""
|
||||
comp = db.session.get(Computer, computer_id)
|
||||
@@ -461,7 +461,7 @@ def get_computer(computer_id: int):
|
||||
|
||||
|
||||
@computers_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def get_computer_by_asset(asset_id: int):
|
||||
"""Get computer data by asset ID."""
|
||||
comp = Computer.query.filter_by(assetid=asset_id).first()
|
||||
@@ -480,7 +480,7 @@ def get_computer_by_asset(asset_id: int):
|
||||
|
||||
|
||||
@computers_bp.route('/by-hostname/<hostname>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def get_computer_by_hostname(hostname: str):
|
||||
"""Get computer by hostname."""
|
||||
comp = Computer.query.filter_by(hostname=hostname).first()
|
||||
@@ -753,7 +753,7 @@ def delete_computer(computer_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@computers_bp.route('/<int:computer_id>/apps', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def get_installed_apps(computer_id: int):
|
||||
"""Get all installed applications for a computer."""
|
||||
comp = db.session.get(Computer, computer_id)
|
||||
@@ -897,7 +897,7 @@ def report_status(computer_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@computers_bp.route('/dashboard/summary', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('computers.view')
|
||||
def dashboard_summary():
|
||||
"""Get computer dashboard summary data."""
|
||||
# Total active computers
|
||||
|
||||
@@ -29,6 +29,7 @@ from shopdb.api import Setting
|
||||
from shopdb.api import send_upload
|
||||
|
||||
from ..models import DirectoryEmployee
|
||||
from shopdb.api import require_permission
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -198,6 +199,7 @@ def _with_photo_url(employee):
|
||||
|
||||
|
||||
@employees_bp.route('/resolve/<sso>', methods=['GET'])
|
||||
@require_permission('employees.view')
|
||||
@jwt_required()
|
||||
def resolve_employee(sso):
|
||||
"""Resolve one SSO to a name and photo, and say HOW.
|
||||
@@ -275,6 +277,7 @@ def resolve_employee(sso):
|
||||
|
||||
|
||||
@employees_bp.route('/search', methods=['GET'])
|
||||
@require_permission('employees.view')
|
||||
def search_employees():
|
||||
"""
|
||||
Search employees by name.
|
||||
@@ -327,6 +330,7 @@ def search_employees():
|
||||
|
||||
|
||||
@employees_bp.route('/lookup/<sso>', methods=['GET'])
|
||||
@require_permission('employees.view')
|
||||
def lookup_employee(sso):
|
||||
"""Look up a single employee by SSO."""
|
||||
if not sso.isdigit():
|
||||
@@ -370,6 +374,7 @@ def lookup_employee(sso):
|
||||
|
||||
|
||||
@employees_bp.route('/lookup', methods=['GET'])
|
||||
@require_permission('employees.view')
|
||||
def lookup_employees():
|
||||
"""
|
||||
Look up multiple employees by SSO list.
|
||||
@@ -429,7 +434,7 @@ def lookup_employees():
|
||||
# =============================================================================
|
||||
|
||||
@employees_bp.route('/directory', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('employees.view')
|
||||
def list_directory():
|
||||
"""Full self-hosted directory (for the management page)."""
|
||||
guard = _require_selfhosted()
|
||||
|
||||
@@ -51,6 +51,18 @@ class EmployeesPlugin(BasePlugin):
|
||||
api_prefix=self._manifest.get('api_prefix', '/api/employees'),
|
||||
)
|
||||
|
||||
def get_permissions(self) -> List:
|
||||
"""Reading the staff directory.
|
||||
|
||||
The directory is names, SSOs, photographs and who reports to whom. It
|
||||
was reachable with no account at all, which is how a permissions
|
||||
question ends up answered by nobody. One read permission: the write
|
||||
side of this plugin is an import, run from the CLI.
|
||||
"""
|
||||
return [
|
||||
('employees.view', 'View the employee directory', 'employees'),
|
||||
]
|
||||
|
||||
def get_blueprint(self) -> Optional[Blueprint]:
|
||||
"""Return Flask Blueprint with API routes."""
|
||||
return employees_bp
|
||||
|
||||
@@ -77,7 +77,7 @@ def _search_clause(search):
|
||||
|
||||
|
||||
@knowledgebase_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('kb.view')
|
||||
def list_articles():
|
||||
"""List all knowledge base articles."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -142,7 +142,7 @@ def list_articles():
|
||||
|
||||
|
||||
@knowledgebase_bp.route('/stats', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('kb.view')
|
||||
def get_stats():
|
||||
"""Get knowledge base statistics."""
|
||||
# Counted over the same set the list shows. A total that includes articles
|
||||
@@ -158,7 +158,7 @@ def get_stats():
|
||||
|
||||
|
||||
@knowledgebase_bp.route('/<int:link_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('kb.view')
|
||||
def get_article(link_id: int):
|
||||
"""Get a single knowledge base article."""
|
||||
article = db.session.get(KnowledgeBase, link_id)
|
||||
|
||||
@@ -17,7 +17,7 @@ machines_bp = Blueprint('machines', __name__)
|
||||
# =============================================================================
|
||||
|
||||
@machines_bp.route('/types', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def list_machine_types():
|
||||
"""List all machine types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -39,7 +39,7 @@ def list_machine_types():
|
||||
|
||||
|
||||
@machines_bp.route('/types/<int:type_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def get_machine_type(type_id: int):
|
||||
"""Get a single machine type."""
|
||||
t = db.session.get(MachineType, type_id)
|
||||
@@ -144,7 +144,7 @@ def delete_machine_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@machines_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def list_machines():
|
||||
"""
|
||||
List all machines with filtering and pagination.
|
||||
@@ -281,7 +281,7 @@ def _dualpath_partner_for(assetid):
|
||||
|
||||
|
||||
@machines_bp.route('/<int:machine_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def get_machine(machine_id: int):
|
||||
"""Get a single machine item with full details."""
|
||||
mach = db.session.get(Machine, machine_id)
|
||||
@@ -301,7 +301,7 @@ def get_machine(machine_id: int):
|
||||
|
||||
|
||||
@machines_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def get_machine_by_asset(asset_id: int):
|
||||
"""Get machine data by asset ID."""
|
||||
mach = Machine.query.filter_by(assetid=asset_id).first()
|
||||
@@ -525,7 +525,7 @@ def delete_machine(machine_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@machines_bp.route('/dashboard/summary', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('machines.view')
|
||||
def dashboard_summary():
|
||||
"""Get machine dashboard summary data."""
|
||||
# Dualpath single-machine collapse: hide the secondary bay from counts so a
|
||||
|
||||
@@ -49,7 +49,7 @@ def _merged(tool, today=None):
|
||||
# =============================================================================
|
||||
|
||||
@measuringtools_bp.route('/types', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def list_types():
|
||||
"""List measuring-tool types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -64,7 +64,7 @@ def list_types():
|
||||
|
||||
|
||||
@measuringtools_bp.route('/types/<int:type_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def get_type(type_id: int):
|
||||
"""Get one measuring-tool type."""
|
||||
tool_type = db.session.get(MeasuringToolType, type_id)
|
||||
@@ -150,7 +150,7 @@ def delete_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@measuringtools_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def list_tools():
|
||||
"""List measuring tools with filters + pagination.
|
||||
|
||||
@@ -208,7 +208,7 @@ def list_tools():
|
||||
|
||||
|
||||
@measuringtools_bp.route('/<int:tool_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def get_tool(tool_id: int):
|
||||
"""Get one measuring tool (asset core merged with the extension)."""
|
||||
tool = db.session.get(MeasuringTool, tool_id)
|
||||
@@ -219,7 +219,7 @@ def get_tool(tool_id: int):
|
||||
|
||||
|
||||
@measuringtools_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def get_tool_by_asset(asset_id: int):
|
||||
"""Get a measuring tool by its core asset id."""
|
||||
tool = MeasuringTool.query.filter_by(assetid=asset_id).first()
|
||||
@@ -371,7 +371,7 @@ def delete_tool(tool_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@measuringtools_bp.route('/map-overlay', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def map_overlay():
|
||||
"""Calibration-status overlay for active measuring tools.
|
||||
|
||||
@@ -402,7 +402,7 @@ def map_overlay():
|
||||
# =============================================================================
|
||||
|
||||
@measuringtools_bp.route('/report/calibration', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('measuringtools.view')
|
||||
def calibration_report():
|
||||
"""Counts + lists bucketed by derived calibration status."""
|
||||
today = date.today()
|
||||
|
||||
@@ -47,7 +47,7 @@ def _upsert_primary_ip(asset, ip):
|
||||
# =============================================================================
|
||||
|
||||
@network_bp.route('/types', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def list_network_device_types():
|
||||
"""List all network device types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -69,7 +69,7 @@ def list_network_device_types():
|
||||
|
||||
|
||||
@network_bp.route('/types/<int:type_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_network_device_type(type_id: int):
|
||||
"""Get a single network device type."""
|
||||
t = db.session.get(NetworkDeviceType, type_id)
|
||||
@@ -176,7 +176,7 @@ def delete_network_device_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@network_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def list_network_devices():
|
||||
"""
|
||||
List all network devices with filtering and pagination.
|
||||
@@ -284,7 +284,7 @@ def list_network_devices():
|
||||
|
||||
|
||||
@network_bp.route('/<int:device_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_network_device(device_id: int):
|
||||
"""Get a single network device with full details."""
|
||||
netdev = db.session.get(NetworkDevice, device_id)
|
||||
@@ -304,7 +304,7 @@ def get_network_device(device_id: int):
|
||||
|
||||
|
||||
@network_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_network_device_by_asset(asset_id: int):
|
||||
"""Get network device data by asset ID."""
|
||||
netdev = NetworkDevice.query.filter_by(assetid=asset_id).first()
|
||||
@@ -324,7 +324,7 @@ def get_network_device_by_asset(asset_id: int):
|
||||
|
||||
|
||||
@network_bp.route('/by-hostname/<hostname>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_network_device_by_hostname(hostname: str):
|
||||
"""Get network device by hostname."""
|
||||
netdev = NetworkDevice.query.filter_by(hostname=hostname).first()
|
||||
@@ -583,7 +583,7 @@ def delete_network_device(device_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@network_bp.route('/dashboard/summary', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def dashboard_summary():
|
||||
"""Get network device dashboard summary data."""
|
||||
# Total active network devices
|
||||
@@ -631,7 +631,7 @@ def dashboard_summary():
|
||||
# =============================================================================
|
||||
|
||||
@network_bp.route('/vlans', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def list_vlans():
|
||||
"""List all VLANs with filtering and pagination."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -664,7 +664,7 @@ def list_vlans():
|
||||
|
||||
|
||||
@network_bp.route('/vlans/<int:vlan_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_vlan(vlan_id: int):
|
||||
"""Get a single VLAN with its subnets."""
|
||||
vlan = db.session.get(VLAN, vlan_id)
|
||||
@@ -806,7 +806,7 @@ def delete_vlan(vlan_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@network_bp.route('/subnets', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def list_subnets():
|
||||
"""List all subnets with filtering and pagination."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -847,7 +847,7 @@ def list_subnets():
|
||||
|
||||
|
||||
@network_bp.route('/subnets/<int:subnet_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('network.view')
|
||||
def get_subnet(subnet_id: int):
|
||||
"""Get a single subnet plus the network devices whose primary IP falls in
|
||||
its CIDR range."""
|
||||
|
||||
@@ -239,6 +239,7 @@ def _employee_picture(sso):
|
||||
# =============================================================================
|
||||
|
||||
@notifications_bp.route('/types', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def list_notification_types():
|
||||
"""List all notification types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -333,6 +334,7 @@ def update_notification_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@notifications_bp.route('', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def list_notifications():
|
||||
"""
|
||||
List all notifications with filtering and pagination.
|
||||
@@ -388,6 +390,7 @@ def list_notifications():
|
||||
|
||||
|
||||
@notifications_bp.route('/<int:notification_id>', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def get_notification(notification_id: int):
|
||||
"""Get a single notification."""
|
||||
n = db.session.get(Notification, notification_id)
|
||||
@@ -551,6 +554,7 @@ def delete_notification(notification_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@notifications_bp.route('/active', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def get_active_notifications():
|
||||
"""
|
||||
Get currently active notifications for display.
|
||||
@@ -581,6 +585,7 @@ def get_active_notifications():
|
||||
|
||||
|
||||
@notifications_bp.route('/calendar', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def get_calendar_events():
|
||||
"""
|
||||
Get notifications in FullCalendar event format.
|
||||
@@ -619,6 +624,7 @@ def get_calendar_events():
|
||||
|
||||
|
||||
@notifications_bp.route('/dashboard/summary', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
def dashboard_summary():
|
||||
"""Get notifications dashboard summary."""
|
||||
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
@@ -869,6 +875,7 @@ def get_shopfloor_notifications():
|
||||
|
||||
|
||||
@notifications_bp.route('/dashboard/active', methods=['GET'])
|
||||
@require_permission('notifications.view')
|
||||
@jwt_required()
|
||||
def dashboard_active():
|
||||
"""Notifications currently showing on the floor.
|
||||
|
||||
@@ -542,7 +542,7 @@ def _csv_response(rows, columns, filename):
|
||||
|
||||
|
||||
@printedparts_bp.route('/reports/stock', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printedparts.view')
|
||||
def report_stock():
|
||||
"""Stock levels with low-stock flags and the cache-vs-ledger reconcile.
|
||||
|
||||
@@ -576,7 +576,7 @@ def report_stock():
|
||||
|
||||
|
||||
@printedparts_bp.route('/reports/consumption', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printedparts.view')
|
||||
def report_consumption():
|
||||
"""Takes per item, optionally bounded by ?days=<n> (default 30)."""
|
||||
days = request.args.get('days', 30, type=int)
|
||||
@@ -604,7 +604,7 @@ def report_consumption():
|
||||
|
||||
|
||||
@printedparts_bp.route('/reports/by-person', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printedparts.view')
|
||||
def report_by_person():
|
||||
"""Takes grouped by employee, optionally bounded by ?days=<n> (default 30)."""
|
||||
days = request.args.get('days', 30, type=int)
|
||||
@@ -722,7 +722,7 @@ def upload_item_file(item_id: int):
|
||||
|
||||
|
||||
@printedparts_bp.route('/files/<int:file_id>/download', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printedparts.view')
|
||||
def download_item_file(file_id: int):
|
||||
"""Download a revision under its original filename."""
|
||||
record = db.session.get(PrintedItemFile, file_id)
|
||||
|
||||
@@ -30,7 +30,7 @@ printers_asset_bp = Blueprint('printers_asset', __name__)
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('/types', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def list_printer_types():
|
||||
"""List all printer types."""
|
||||
page, per_page = get_pagination_params(request)
|
||||
@@ -52,7 +52,7 @@ def list_printer_types():
|
||||
|
||||
|
||||
@printers_asset_bp.route('/types/<int:type_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def get_printer_type(type_id: int):
|
||||
"""Get a single printer type."""
|
||||
t = db.session.get(PrinterType, type_id)
|
||||
@@ -147,7 +147,7 @@ def delete_printer_type(type_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('/drivers', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def list_drivers():
|
||||
"""List printer drivers. ?active=false includes inactive ones."""
|
||||
query = PrinterDriver.query
|
||||
@@ -207,7 +207,7 @@ def delete_driver(driver_id):
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def list_printers():
|
||||
"""
|
||||
List all printers with filtering and pagination.
|
||||
@@ -964,7 +964,7 @@ def printers_for_host(hostname: str):
|
||||
|
||||
|
||||
@printers_asset_bp.route('/assignments/for-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def get_asset_printer_assignment(asset_id: int):
|
||||
"""What THIS asset is assigned, without inheritance.
|
||||
|
||||
@@ -1778,7 +1778,7 @@ def seed_assignment_from_observed(asset_id: int):
|
||||
|
||||
|
||||
@printers_asset_bp.route('/<int:printer_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def get_printer(printer_id: int):
|
||||
"""Get a single printer with full details."""
|
||||
printer = db.session.get(Printer, printer_id)
|
||||
@@ -1811,7 +1811,7 @@ def get_printer(printer_id: int):
|
||||
|
||||
|
||||
@printers_asset_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def get_printer_by_asset(asset_id: int):
|
||||
"""Get printer data by asset ID."""
|
||||
printer = Printer.query.filter_by(assetid=asset_id).first()
|
||||
@@ -2043,7 +2043,7 @@ def delete_printer(printer_id: int):
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('/<int:printer_id>/supplies', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def get_printer_supplies(printer_id: int):
|
||||
"""Get supply levels from Zabbix (real-time lookup)."""
|
||||
printer = db.session.get(Printer, printer_id)
|
||||
@@ -2238,7 +2238,7 @@ def _get_low_supplies_data():
|
||||
|
||||
|
||||
@printers_asset_bp.route('/lowsupplies', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def low_supplies():
|
||||
"""Get printers with low or critical supply levels."""
|
||||
data = _get_low_supplies_data()
|
||||
@@ -2246,7 +2246,7 @@ def low_supplies():
|
||||
|
||||
|
||||
@printers_asset_bp.route('/lookup', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def printer_lookup():
|
||||
"""Find a printer by IP or FQDN. Parity with the classic printerlookup.asp.
|
||||
|
||||
@@ -2306,7 +2306,7 @@ def refresh_supplies_cache():
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('/dashboard/summary', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def dashboard_summary():
|
||||
"""Get printer dashboard summary data."""
|
||||
# Total active printers
|
||||
@@ -2380,7 +2380,7 @@ def _validate_supply_payload(data):
|
||||
|
||||
|
||||
@printers_asset_bp.route('/supplies/meta', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def supplies_meta():
|
||||
"""Allowed values for supply type, color, and capacity tier (for the UI)."""
|
||||
return success_response({
|
||||
@@ -2391,7 +2391,7 @@ def supplies_meta():
|
||||
|
||||
|
||||
@printers_asset_bp.route('/models', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def list_supply_models():
|
||||
"""List models with a supply count, for the supply-management picker.
|
||||
|
||||
@@ -2450,7 +2450,7 @@ def list_supply_models():
|
||||
|
||||
|
||||
@printers_asset_bp.route('/models/<int:modelnumberid>/supplies', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def list_model_supplies(modelnumberid: int):
|
||||
"""List all supplies mapped to a model."""
|
||||
model = db.session.get(Model, modelnumberid)
|
||||
@@ -2667,7 +2667,7 @@ def dashboard_supplies():
|
||||
# =============================================================================
|
||||
|
||||
@printers_asset_bp.route('/supplies/forecast', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('printers.view')
|
||||
def supplies_forecast():
|
||||
"""Days-to-empty and replacement counts per printer.
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ def _log_to_dict(cur, row):
|
||||
# =============================================================================
|
||||
|
||||
@usb_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('usb.view')
|
||||
def list_usb_devices():
|
||||
"""List USB devices with checkout status.
|
||||
|
||||
@@ -306,7 +306,7 @@ def list_usb_devices():
|
||||
|
||||
|
||||
@usb_bp.route('/<device_id>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('usb.view')
|
||||
def get_usb_device(device_id):
|
||||
"""Get a single device plus its last 20 check-in/out log rows."""
|
||||
if _usb_selfhosted():
|
||||
@@ -595,7 +595,7 @@ def checkin_device(device_id):
|
||||
# =============================================================================
|
||||
|
||||
@usb_bp.route('/<device_id>/history', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('usb.view')
|
||||
def get_device_history(device_id):
|
||||
"""Paginated check-in/out log for one device."""
|
||||
if _usb_selfhosted():
|
||||
@@ -625,7 +625,7 @@ def get_device_history(device_id):
|
||||
|
||||
|
||||
@usb_bp.route('/checkouts', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('usb.view')
|
||||
def list_all_checkouts():
|
||||
"""List check-out log rows.
|
||||
|
||||
@@ -676,7 +676,7 @@ def list_all_checkouts():
|
||||
|
||||
|
||||
@usb_bp.route('/checkouts/active', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('usb.view')
|
||||
def list_active_checkouts():
|
||||
"""List the latest check-out log row for every currently checked-out device.
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ def _apply_links(warranty, assetids):
|
||||
# =============================================================================
|
||||
|
||||
@warranty_bp.route('', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('warranty.view')
|
||||
def list_warranties():
|
||||
"""List warranties. Filters: ?status=, ?assetid=, ?active=false."""
|
||||
query = Warranty.query
|
||||
@@ -174,7 +174,7 @@ def list_warranties():
|
||||
|
||||
|
||||
@warranty_bp.route('/asset/<int:assetid>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('warranty.view')
|
||||
def warranties_for_asset(assetid):
|
||||
"""Warranties covering one asset (for the asset-detail panel)."""
|
||||
links = WarrantyAsset.query.filter_by(assetid=assetid).all()
|
||||
@@ -188,7 +188,7 @@ def warranties_for_asset(assetid):
|
||||
|
||||
|
||||
@warranty_bp.route('/<int:warrantyid>', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('warranty.view')
|
||||
def get_warranty(warrantyid):
|
||||
warranty = db.session.get(Warranty, warrantyid)
|
||||
if not warranty:
|
||||
@@ -395,7 +395,7 @@ def sync_dell():
|
||||
# =============================================================================
|
||||
|
||||
@warranty_bp.route('/report', methods=['GET'])
|
||||
@jwt_required(optional=True)
|
||||
@require_permission('warranty.view')
|
||||
def warranty_report():
|
||||
"""Counts + lists bucketed by derived status."""
|
||||
today = date.today()
|
||||
|
||||
Reference in New Issue
Block a user