Security hardening, multi-site portability, and a documentation and API-surface sweep

This commit is contained in:
2026-08-14 16:28:34 -04:00
parent 72f8da0e58
commit 265ca2eb01
76 changed files with 3684 additions and 811 deletions

View File

@@ -5,6 +5,7 @@ from flask_jwt_extended import jwt_required
from shopdb.api import db, Asset, AssetType, Vendor, Communication, CommunicationType, AuditLog, success_response, error_response, paginated_response, ErrorCodes, get_pagination_params, paginate_query
from ..services.assetnumbers import generate_for_type
from ..models import NetworkDevice, NetworkDeviceType, Subnet, VLAN
from shopdb.api import require_permission, apply_import_timestamps
@@ -111,7 +112,8 @@ def create_network_device_type():
t = NetworkDeviceType(
networkdevicetype=data['networkdevicetype'],
description=data.get('description'),
icon=data.get('icon'), color=data.get('color')
icon=data.get('icon'), color=data.get('color'),
prefix=data.get('prefix')
)
db.session.add(t)
@@ -146,7 +148,8 @@ def update_network_device_type(type_id: int):
http_code=409
)
for key in ['networkdevicetype', 'description', 'icon', 'color', 'isactive']:
for key in ['networkdevicetype', 'description', 'icon', 'color', 'prefix',
'isactive']:
if key in data:
setattr(t, key, data[key])
@@ -359,8 +362,17 @@ def create_network_device():
if not data:
return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')
# Generate from the type prefix + name when left blank. Only when blank: a
# device carrying a real identifier of its own - vendor tag, controller
# name, serial - keeps it, which is the platform rule.
if not data.get('assetnumber'):
return error_response(ErrorCodes.VALIDATION_ERROR, 'assetnumber is required')
data['assetnumber'] = generate_for_type(
data.get('networkdevicetypeid'), data.get('name'))
if not data.get('assetnumber'):
return error_response(
ErrorCodes.VALIDATION_ERROR,
'assetnumber is required (or give a name, and a device type with a '
'prefix, to have one generated)')
# Check for duplicate assetnumber
if Asset.query.filter_by(assetnumber=data['assetnumber']).first():