feat(api,core,domain): HelpDocument - ответ заглушка, если нет еще такой документации

This commit is contained in:
Mikhail Trubnikov
2026-10-12 15:13:14 +10:00
parent 4e81ee72f4
commit 09d8244b03
4 changed files with 27 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
using PARR.Core.Services.HelpDocument.Interfaces;
using PARR.Domain.Common.Roles;
using PARR.Domain.Exceptions;
using PARR.Domain.Settings;
using System.Text.Json.Nodes;
@@ -75,13 +76,13 @@ namespace PARR.API.Controllers.V1
if (!Request.Headers.TryGetValue("X-Gitlab-Token", out var receivedToken))
{
_logger.LogWarning("Запрос вебхука отклонен. Отсутствует заголовок X-Gitlab-Token.");
return Unauthorized("Отсутствует авторизационный токен вебхука.");
throw new UnauthorizedException("Отсутствует авторизационный токен вебхука.");
}
if (receivedToken.ToString() != _helpDocumentSettings.WebhookToken)
{
_logger.LogWarning("Запрос вебхука отклонен. Передан невалидный Secret Token.");
return Unauthorized("Неверный токен вебхука.");
throw new UnauthorizedException("Неверный токен вебхука.");
}
#endregion
@@ -164,7 +165,7 @@ namespace PARR.API.Controllers.V1
_logger.LogError(ex, "Ошибка при обработке Webhook от GitLab");
// Возвращаем 200 или 500 в зависимости от политики.
// Обычно возвращают BadRequest/InternalServerError, чтобы в GitLab в истории вебхуков была видна ошибка отладки.
return StatusCode(500, "Внутренняя ошибка обработки вебхука");
throw new ExternalServiceException("Внутренняя ошибка обработки вебхука");
}
}

View File

@@ -127,6 +127,7 @@
"DefaultBranch": "main"
},
"CacheTTL": "23:59:00",
"ShortTTL": "00:10:00",
"WebhookToken": "ParrSecret2026"
}
}

View File

@@ -57,7 +57,23 @@ namespace PARR.Core.Services.HelpDocument.Implementations
if (remoteDocument == null)
{
_logger.LogWarning("Документ не найден ни в Redis, ни в GitLab. HelpId: {HelpId}", helpId);
return null;
// Создаем понятный для пользователя текст-заглушку если нет документации
remoteDocument = new HelpDocumentResult
{
HelpId = helpId,
Title = "Раздел в разработке",
Content = "### 📚 Отсутствует документация по данному разделу.\n\n" +
"Если у вас возникли срочные вопросы, свяжитесь с теми, кто знает на них ответы :)."
};
// Кэшируем заглушку на короткий срок (например, на 5-10 минут), а не на 24 часа.
// Это нужно, чтобы как только аналитик создаст файл и прилетит хук, кэш обновился,
// но при этом частые клики пользователей по сломанному вопросику не спамили GitLab запросами 404.
await _redisCacheService.SetCachedDataAsync(cacheKey, remoteDocument, _helpDocumentSettings.ShortTTL, useCompression: true);
return remoteDocument;
}
// 3. Сохраняем полученный документ в Redis для последующих запросов

View File

@@ -12,6 +12,11 @@
/// </summary>
public TimeSpan CacheTTL { get; init; } = TimeSpan.FromHours(1);
/// <summary>
/// Коротки TTL для страниц где не найдена документация. По умолчанию 10 минут.
/// </summary>
public TimeSpan ShortTTL { get; init; } = TimeSpan.FromMinutes(10);
public string WebhookToken { get; set; } = string.Empty;
}