130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from sqlalchemy import text
|
|
|
|
from services.database_service_base import DatabaseServiceBase
|
|
from utils.logger import session_logger
|
|
|
|
|
|
class DeviceIdentityInitializationError(ValueError):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DeviceIdentityInitializationResult:
|
|
imei: str
|
|
device_id: str
|
|
serial_number: str
|
|
activated: bool
|
|
|
|
|
|
class DeviceIdentityInitializer(DatabaseServiceBase):
|
|
def __init__(self):
|
|
super().__init__(service_name="device_identity_initializer")
|
|
|
|
async def initialize_by_imei(self, imei: str) -> DeviceIdentityInitializationResult:
|
|
normalized_imei = str(imei or "").strip()
|
|
if not normalized_imei:
|
|
raise DeviceIdentityInitializationError("imei is required")
|
|
|
|
db_session = await self.get_session()
|
|
try:
|
|
mapping_result = await db_session.execute(
|
|
text(
|
|
"""
|
|
SELECT imei, device_id, serial_number, status
|
|
FROM device_imei_mapping
|
|
WHERE imei = :imei
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"imei": normalized_imei},
|
|
)
|
|
mapping = mapping_result.mappings().first()
|
|
if mapping is None:
|
|
raise DeviceIdentityInitializationError("imei mapping not found")
|
|
|
|
device_id = str(mapping["device_id"]).strip()
|
|
serial_number = str(mapping["serial_number"]).strip()
|
|
if not device_id or not serial_number:
|
|
raise DeviceIdentityInitializationError("imei mapping is incomplete")
|
|
|
|
device_auth_result = await db_session.execute(
|
|
text(
|
|
"""
|
|
SELECT device_id, serial_number
|
|
FROM device_auth
|
|
WHERE device_id = :device_id
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"device_id": device_id},
|
|
)
|
|
device_auth = device_auth_result.mappings().first()
|
|
if device_auth is None:
|
|
await db_session.execute(
|
|
text(
|
|
"""
|
|
INSERT INTO device_auth (device_id, serial_number, is_active)
|
|
VALUES (:device_id, :serial_number, 1)
|
|
"""
|
|
),
|
|
{"device_id": device_id, "serial_number": serial_number},
|
|
)
|
|
elif str(device_auth["serial_number"]) != serial_number:
|
|
raise DeviceIdentityInitializationError("device_auth serial_number conflict")
|
|
else:
|
|
await db_session.execute(
|
|
text(
|
|
"""
|
|
UPDATE device_auth
|
|
SET is_active = 1
|
|
WHERE device_id = :device_id
|
|
"""
|
|
),
|
|
{"device_id": device_id},
|
|
)
|
|
|
|
await db_session.execute(
|
|
text(
|
|
"""
|
|
UPDATE device_imei_mapping
|
|
SET status = 'activated',
|
|
activated_at = COALESCE(activated_at, CURRENT_TIMESTAMP)
|
|
WHERE imei = :imei
|
|
"""
|
|
),
|
|
{"imei": normalized_imei},
|
|
)
|
|
await db_session.commit()
|
|
|
|
session_logger.info(
|
|
device_id,
|
|
"device_identity_initializer",
|
|
f"IMEI identity initialized: imei={normalized_imei}",
|
|
)
|
|
return DeviceIdentityInitializationResult(
|
|
imei=normalized_imei,
|
|
device_id=device_id,
|
|
serial_number=serial_number,
|
|
activated=str(mapping["status"]) == "activated",
|
|
)
|
|
except DeviceIdentityInitializationError:
|
|
await db_session.rollback()
|
|
raise
|
|
except Exception as exc:
|
|
await db_session.rollback()
|
|
session_logger.error(
|
|
normalized_imei,
|
|
"device_identity_initializer",
|
|
f"initialize identity failed: {exc}",
|
|
)
|
|
raise
|
|
finally:
|
|
await db_session.close()
|
|
|
|
|
|
device_identity_initializer = DeviceIdentityInitializer()
|