import express from 'express'; import { getCompanies } from './companies'; import { config } from './config'; import { getAppOnlyToken } from './graphAuth'; import { submitFeedback } from './sharepoint'; const app = express(); app.use(express.json()); app.get('/healthz', (_req, res) => { res.status(200).send('ok'); }); // Временный диагностический эндпоинт: подтверждает, что связка // "сертификат -> подписанный JWT -> access-токен" реально работает, // до того как появится сама логика сохранения формы в Graph/SharePoint. app.get('/diag/token', async (_req, res) => { try { await getAppOnlyToken(); res.status(200).json({ ok: true }); } catch (error) { res.status(502).json({ ok: false, error: (error as Error).message }); } }); // Справочник компаний для выпадающего списка формы. Ходит в api.tnsu.kz за // нас, чтобы токен не утекал в браузер, и отдаёт список как есть. app.get('/companies', async (_req, res) => { try { res.status(200).json(await getCompanies()); } catch (error) { const message = (error as Error).message; console.error('Не удалось получить справочник компаний:', message); res.status(502).json({ ok: false, error: message }); } }); app.post('/feedback', async (req, res) => { try { await submitFeedback(req.body); res.status(201).json({ ok: true }); } catch (error) { const message = (error as Error).message; // Логируем целиком в stdout прод-контейнера — если отвалится авторизация // (протухший/незарегистрированный сертификат, неверный scope), это должно // быть видно сразу в логах, а не тонуть в одной строке ответа клиенту. console.error('Не удалось отправить обращение в SharePoint:', message); res.status(502).json({ ok: false, error: message }); } }); app.listen(config.port, () => { console.log(`hr-appeals-auth listening on :${config.port}`); });