b4a10510e1
Список юрлиц группы меняется без нашего участия, а две копии в репозитории (COMPANY_OPTIONS во фронте и COMPANY_NAMES на сервере) неизбежно разошлись бы с источником и между собой. Теперь единственный источник — /Dictionary/Companies: - GET /companies проксирует справочник, чтобы токен не утекал в браузер; - имя компании для колонки Company резолвится по нему же, на сервере; - в кэше 10 минут — новое юрлицо подхватится без перезапуска сервиса. Пока список грузится, в select показывается «Загружаем…»; если не загрузился — ошибка в слоте обязательного поля, а не пустой список. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
55 lines
2.3 KiB
TypeScript
55 lines
2.3 KiB
TypeScript
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}`);
|
|
});
|