Add batch management APIs, API security, rate limiting, and optimizations

- Batch device CRUD: POST /api/devices/batch (create 500), PUT /api/devices/batch (update 500),
  POST /api/devices/batch-delete (delete 100) with WHERE IN bulk queries
- Batch command: POST /api/commands/batch with model_validator mutual exclusion
- API key auth (X-API-Key header, secrets.compare_digest timing-safe)
- Rate limiting via SlowAPIMiddleware (60/min default, 30/min writes)
- Real client IP extraction (X-Forwarded-For / CF-Connecting-IP)
- Global exception handler (no stack trace leaks, passes HTTPException through)
- CORS with auto-disable credentials on wildcard origins
- Schema validation: IMEI pattern, lat/lon ranges, Literal enums, MAC/UUID patterns
- Heartbeats router, per-ID endpoints for locations/attendance/bluetooth
- Input dedup in batch create, result ordering preserved
- Baidu reverse geocoding, Gaode map tiles with WGS84→GCJ02 conversion
- Device detail panel with feature toggles and command controls
- Side panel for location/beacon pages with auto-select active device

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
2026-03-20 09:18:43 +00:00
parent 1bdbe4fa19
commit 7d6040af41
23 changed files with 1564 additions and 294 deletions

View File

@@ -136,6 +136,57 @@ PROTOCOLS_REQUIRING_RESPONSE: FrozenSet[int] = frozenset({
# Note: PROTO_BT_LOCATION (0xB3) does NOT require a response per protocol spec
})
# ---------------------------------------------------------------------------
# Device Defaults
# ---------------------------------------------------------------------------
DEFAULT_DEVICE_TYPE: str = "P240"
# ---------------------------------------------------------------------------
# Language Codes (used in 0x80 / 0x82 packets)
# ---------------------------------------------------------------------------
LANG_CHINESE: int = 0x0001
LANG_ENGLISH: int = 0x0002
DEFAULT_LANGUAGE: int = LANG_CHINESE
DEFAULT_LANGUAGE_BYTES: bytes = b"\x00\x01"
# Server flag placeholder (4 bytes, used in command/message packets)
SERVER_FLAG_BYTES: bytes = b"\x00\x00\x00\x00"
# ---------------------------------------------------------------------------
# Attendance Status (from terminal_info byte, bits[5:2])
# ---------------------------------------------------------------------------
ATTENDANCE_STATUS_SHIFT: int = 2
ATTENDANCE_STATUS_MASK: int = 0x0F
ATTENDANCE_TYPES: Dict[int, str] = {
0b0001: "clock_in",
0b0010: "clock_out",
}
# ---------------------------------------------------------------------------
# GPS Course/Status Bit Fields
# ---------------------------------------------------------------------------
COURSE_BIT_REALTIME: int = 0x2000 # bit 13
COURSE_BIT_POSITIONED: int = 0x1000 # bit 12
COURSE_BIT_EAST: int = 0x0800 # bit 11
COURSE_BIT_NORTH: int = 0x0400 # bit 10
COURSE_MASK: int = 0x03FF # bits 9-0
# MCC high-bit flag: if set, MNC is 2 bytes instead of 1
MCC_MNC2_FLAG: int = 0x8000
# ---------------------------------------------------------------------------
# Voltage Levels (0x00-0x06)
# ---------------------------------------------------------------------------
VOLTAGE_LEVELS: Dict[int, str] = {
0x00: "shutdown",
0x01: "very_low",
0x02: "low",
0x03: "medium",
0x04: "good",
0x05: "high",
0x06: "full",
}
# ---------------------------------------------------------------------------
# Protocol Number -> Human-Readable Name
# ---------------------------------------------------------------------------