feat: TTLock — scan TTHotel sources for API config (CE_ConfigServer)

- Agent: ttlock:find_api_config command scans TTHotel app JS files
  for CE_ConfigServer calls, oauth2 endpoints, API server URLs
- Backend: POST /ttlock/find-api-config route
- UI: Search button on each workstation row to trigger scan

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 11:10:40 +03:00
parent 92821a8436
commit ee7e515f61
3 changed files with 62 additions and 1 deletions

View File

@@ -131,6 +131,35 @@ const ttlockRoutes: FastifyPluginAsync = async (fastify) => {
},
)
// ── POST /api/hotels/:slug/ttlock/find-api-config ───────────────────────────
// Ищет в исходниках TTHotel вызовы CE_ConfigServer и API-сервер
fastify.post<SlugParam & { Body: { workstation_id: string } }>(
'/api/hotels/:slug/ttlock/find-api-config',
{ onRequest: [fastify.authenticate] },
async (req, reply) => {
const { slug } = req.params
if (!canManage(req.user.hotelSlug, req.user.role, slug))
return reply.code(403).send({ error: 'Forbidden' })
const hotelId = await getHotelId(slug)
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
const { workstation_id } = req.body
if (!workstation_id) return reply.code(400).send({ error: 'workstation_id required' })
try {
const result = await sendCommandAndWait(workstation_id, {
type: 'ttlock:find_api_config',
}, 20_000) as { ok?: boolean; appDir?: string; results?: { path: string; matches: string[] }[]; error?: string }
if (!result.ok) return reply.code(502).send({ error: result.error ?? 'Ничего не найдено', appDir: result.appDir })
return { ok: true, appDir: result.appDir, results: result.results }
} catch (err) {
const msg = err instanceof Error ? err.message : 'Агент не ответил'
return reply.code(502).send({ error: msg })
}
},
)
// ── POST /api/hotels/:slug/ttlock/test-api ──────────────────────────────────
// Проверяет подключение к TTLock Cloud API (OAuth + список замков)
fastify.post<SlugParam & { Body: { workstation_id: string } }>(