Skip to content
2.12.0

Exchange Calendar ​

Карточка собрана автоматически из манифеста пакета. Так же пакет выглядит во вкладке «Обзор» в Студии.
Фоновый сервисexchange-calendarверсия 1.0.7

Фоновый сервис + виджет: недельный календарь Exchange/OWA через EWS (только чтение). Логин: шаблон {{user.login}}, пароль: личная настройка пользователя.

Фоновый сервис

Пакет запускается платформой как долгоживущий процесс. Отдельные навыки в каталоге чата он не регистрирует, зато отдаёт виджеты и HTTP-интерфейс.

Виджеты · 1

  • Календарь Exchange/

    Добавляется на доску виджетов и в панель виджетов EVA Desktop.

Настройки пакета · 8

Подключение

  • URL EWSews_urlобязательнообщее

    Точка подключения Exchange Web Services, напр. https://mail.example.com/EWS/Exchange.asmx

  • Тип аутентификацииauth_typeобщее

    ntlm: доменная авторизация (нужен «Домен»); basic: обычная Basic по HTTPS.

  • Домен (для NTLM)domainобщее

    Оставьте пустым, если NTLM не используется. Можно указывать как DOMAIN или DOMAIN\.

Учётные данные

  • Логин Exchangeexchange_loginобязательнообщее

    Шаблон логина. По умолчанию {{user.login}}: логин берётся у текущего пользователя. Можно вписать фиксированный сервисный логин.

  • Пароль Exchangeexchange_passwordобязательносекретна пользователя

    Личный пароль каждого пользователя (персональная настройка). В фоне не виден: попадает только в запросы этого пользователя.

Отображение

  • Часовой поясtimezoneобщее

    Пояс, в котором рассчитывается неделя Пн-Вс. IANA, напр. Europe/Moscow.

  • Максимум встреч за запросmax_itemsобщее

    Ограничение CalendarView (1-2000). По умолчанию 500.

  • Проверять TLS-сертификатverify_tlsобщее

    Отключите только для OWA с самоподписанным сертификатом.

Зависит от SDK

@eva/skill-sdk@eva/agent-sdk@eva/agent-chat-sdk@eva/widget-sdk@eva/context@eva/artifacts

README

# Exchange Calendar

Фоновый сервис + виджет: **персональный** недельный календарь Exchange/OWA через EWS. **Только чтение.**

## Как берутся учётные данные

Фоновый сервис: одиночный демон, у него нет пользовательского контекста. Поэтому в `main(ctx)`
доступны только global/daemon-safe настройки, а персональные значения приходят **в HTTP-обработчики
виджета**, после авторизации запроса:

| значение | ключ и scope | как читается |
|---|---|---|
| логин | `exchange_login`, `global` + `x-eva-template: true`, значение по умолчанию `{{user.login}}` | `req.ctx.settings.exchange_login` (шаблон раскрыт в логин текущего пользователя) |
| пароль | `exchange_password`, `x-eva-scope: user`, `format: password` | `req.ctx.settings.exchange_password` |
| подключение | `ews_url`, `auth_type`, `domain`, `timezone`, `verify_tls`, `max_items`: все `global` | корневой `ctx.settings` в `main(ctx)` |

В `main(ctx)` ключей `exchange_login` (как шаблон с `{{user.*}}`) и `exchange_password` **нет**: чтение такого ключа из корневого контекста намеренно бросает Error, поэтому `src/config.js`
читает их только из контекста запроса (`req.ctx` / 3-й аргумент handler / `getContext()`).

Пароль пользователя нигде не логируется и в ответах API не возвращается.
Он хранится только в реестре настроек платформы (личная настройка пользователя).

## HTTP API

Корень пакета: `/internal/bg-service/exchange-calendar/` (проксирует платформа, свои порты слушать не нужно).

| метод | путь | описание |
|---|---|---|
| GET | `/api/health` | конфиг без секретов, пользователь, полнота личных настроек |
| GET | `/api/health?deep=1` | то же + реальный запрос в EWS (`Folder.Bind`) |
| GET | `/api/me` | кто пользователь и хватает ли личных настроек (+`hint`) |
| GET | `/api/diagnose` | доступность EWS и его схемы авторизации: **без учётных данных** |
| GET | `/api/week?start=YYYY-MM-DD&tz=Europe/Moscow` | неделя Пн-Вс + встречи текущего пользователя |

Ответ `/api/week`:

```json
{
  "ok": true,
  "timezone": "Europe/Moscow",
  "user": { "id": "u_1", "login": "user@example.com", "name": "Пользователь" },
  "credentials": "personal",
  "week": { "start_date": "2026-10-12", "end_date": "2026-10-18", "today": "2026-10-16", "days": [] },
  "events": [{ "id": "…", "subject": "…", "start": "…", "end": "…", "all_day": false, "location": "…", "organizer": "…", "free_busy": "Busy" }],
  "count": 1,
  "fetched_at": "…",
  "notes": ["ntlm as DOMAIN\\us***"]
}
```

Ошибки:

- `503 not_configured`: не задан `ews_url`;
- `401 need_settings`: у пользователя не задан личный пароль (`missing_personal`) или не определён логин;
- `502` + `error.code` (`unauthorized` | `timeout` | `dns` | `tls` | `ews_error`).

Блок `week` возвращается и в ошибочных ответах, поэтому сетка остаётся на экране.

### Диагностика

`GET /api/diagnose` отправляет SOAP-запрос в EWS **без логина и пароля**: сервер обязан ответить
401 и заголовком `WWW-Authenticate`. Из него видно, что требует ваш OWA:

- `Negotiate`/`NTLM` → в настройках нужен `auth_type = ntlm` + «Домен»;
- `Basic` → `auth_type = basic` (только HTTPS);
- ошибка `dns`/`timeout`/`tls` → сервер не достижим из контейнера платформы (VPN, фаервол, DNS)
  или не проходит проверка сертификата.

Та же проверка доступна кнопкой **«Диагностика»** в шапке виджета.

## Виджет

`eva.widgets[].path = "/"`, поэтому фронт берёт base от `location.pathname`.
Сетка: Пн-Вс, часы 07:00-21:00, события позиционируются по минутам в целевом поясе,
красная линия: текущее время, автообновление раз в 5 минут, стрелки: навигация по неделям.

## Настройки

| ключ | scope | назначение |
|---|---|---|
| `ews_url` | global | точка EWS, напр. `https://mail.example.com/EWS/Exchange.asmx` |
| `auth_type` | global | `ntlm` (по умолчанию) или `basic` |
| `domain` | global | домен для NTLM (`DOMAIN` или `DOMAIN\`) |
| `exchange_login` | global, template | шаблон логина, по умолчанию `{{user.login}}` |
| `exchange_password` | **user**, secret | личный пароль Exchange: задаёт каждый пользователь у себя |
| `timezone` | global | пояс расчёта недели, по умолчанию `Europe/Moscow` |
| `verify_tls` | global | проверять TLS-сертификат |
| `max_items` | global | максимум встреч за запрос (1-2000) |

## Проверка

```bash
URL=http://platform:3000/internal/bg-service/exchange-calendar

curl -s "$URL/api/health" | jq
curl -s "$URL/api/diagnose" | jq '{hint, http}'      # какие схемы авторизации предлагает OWA
curl -s "$URL/api/me" | jq '{user, credentials, missing_personal}'
curl -s "$URL/api/week" | jq '.count, .events[0]'    # в контексте пользователя: логин из {{user.login}}
```

Из Studio-чата эндпоинты без пользовательского контекста покажут `credentials: "incomplete"`: это ожидаемо: личный пароль виден только в запросах самого пользователя.

## Технические детали

- **basic**: `service.Credentials = new WebCredentials(login, password)`; только по HTTPS.
- **ntlm**: `new XhrApi({ gzip: true }).useNtlmAuthentication('DOMAIN\\user', password)` +
  `ConfigurationApi.ConfigureXHR(xhr)`. `gzip: true` обязателен: иначе ломается разбор сжатых
  ответов (issue #334 у `ews-javascript-api`). NTLM-провайдер настраивается глобально, поэтому
  NTLM-запросы сериализуются (`withAuthLock`), а basic-запросы идут параллельно.
- Кэша недели нет: каждый `/api/week`: это `FindAppointments` (и `Folder.Bind` в deep-проверке).
  При частых обновлениях логично добавить кэш на 1-2 минуты с ключом «пользователь + неделя».
- Окно виджета 07:00-21:00 пока захардкожено.

Как подключить ​

Администратор загружает пакет в разделе Админ → Пакеты или публикует его из Студии. После публикации пакет появляется у пользователей: навыки в каталоге Навыки, а виджеты фоновых сервисов на доске виджетов. Настройки с меткой «общее» задаёт администратор, с меткой «на пользователя» каждый пользователь заполняет у себя.

Подробнее о жизненном цикле пакета: Студия: публикация и версии. Весь каталог: Пакеты EVA.

Документация экосистемы EVA 2.1