Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SentinelKnowledgebase.Api.Extensions;
using SentinelKnowledgebase.Application.DTOs.Integrations;
using SentinelKnowledgebase.Application.Services.Interfaces;

namespace SentinelKnowledgebase.Api.Controllers;

[ApiController]
[Authorize]
[Route("api/v1/integrations/telegram")]
public class TelegramIntegrationsController : ControllerBase
{
private readonly ITelegramIntegrationService _telegramIntegrationService;

public TelegramIntegrationsController(ITelegramIntegrationService telegramIntegrationService)
{
_telegramIntegrationService = telegramIntegrationService;
}

[HttpGet("status")]
[ProducesResponseType(typeof(TelegramLinkStatusDto), StatusCodes.Status200OK)]
public async Task<ActionResult<TelegramLinkStatusDto>> GetStatus()
{
if (!User.TryGetUserId(out var userId))
{
return Unauthorized();
}

return Ok(await _telegramIntegrationService.GetStatusAsync(userId));
}

[HttpPost("link-code")]
[ProducesResponseType(typeof(TelegramLinkCodeResponseDto), StatusCodes.Status200OK)]
public async Task<ActionResult<TelegramLinkCodeResponseDto>> IssueLinkCode()
{
if (!User.TryGetUserId(out var userId))
{
return Unauthorized();
}

return Ok(await _telegramIntegrationService.IssueLinkCodeAsync(userId));
}

[HttpDelete("link")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> Unlink()
{
if (!User.TryGetUserId(out var userId))
{
return Unauthorized();
}

await _telegramIntegrationService.UnlinkAsync(userId);
return NoContent();
}
}
2 changes: 2 additions & 0 deletions backend/src/SentinelKnowledgebase.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using SentinelKnowledgebase.Api.HealthChecks;
using SentinelKnowledgebase.Application;
using SentinelKnowledgebase.Application.Services;
using SentinelKnowledgebase.Application.Services.Telegram;
using SentinelKnowledgebase.Infrastructure.Authentication;
using SentinelKnowledgebase.Infrastructure.Data;
using SentinelKnowledgebase.Infrastructure;
Expand Down Expand Up @@ -83,6 +84,7 @@

builder.Services.AddApplication();
builder.Services.AddInfrastructure(builder.Configuration);
builder.Services.Configure<TelegramIntegrationOptions>(builder.Configuration.GetSection(TelegramIntegrationOptions.SectionName));
var hangfireRetryAttempts = builder.Configuration.GetValue<int?>("Hangfire:RetryAttempts") ?? 10;
var hangfireRetryDelays = builder.Configuration.GetSection("Hangfire:RetryDelaysInSeconds").Get<int[]>();
var retryFilter = new AutomaticRetryAttribute
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,13 @@
"BootstrapAdminDisplayName": "Sentinel Admin"
},
"VectorSize": 1536
,
"Telegram": {
"BotToken": "",
"PollTimeoutSeconds": 20,
"PollLimit": 25,
"PollCadenceSeconds": 3,
"LinkCodeTtlMinutes": 10,
"MaxRawContentLength": 8000
}
}
9 changes: 9 additions & 0 deletions backend/src/SentinelKnowledgebase.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,13 @@
"BootstrapAdminDisplayName": "Sentinel Admin"
},
"VectorSize": 1536
,
"Telegram": {
"BotToken": "",
"PollTimeoutSeconds": 20,
"PollLimit": 25,
"PollCadenceSeconds": 3,
"LinkCodeTtlMinutes": 10,
"MaxRawContentLength": 8000
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace SentinelKnowledgebase.Application.DTOs.Integrations;

public sealed class TelegramLinkCodeResponseDto
{
public string Code { get; set; } = string.Empty;
public DateTimeOffset ExpiresAt { get; set; }
}

public sealed class TelegramLinkStatusDto
{
public bool IsLinked { get; set; }
public long? TelegramChatId { get; set; }
public string? ChatDisplayName { get; set; }
public string? SenderDisplayName { get; set; }
public DateTimeOffset? LinkedAt { get; set; }
public TelegramLinkCodeResponseDto? PendingCode { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using SentinelKnowledgebase.Application.DTOs.Search;
using SentinelKnowledgebase.Application.Services;
using SentinelKnowledgebase.Application.Services.Interfaces;
using SentinelKnowledgebase.Application.Services.Telegram;
using SentinelKnowledgebase.Application.Validators;

namespace SentinelKnowledgebase.Application;
Expand All @@ -23,6 +24,7 @@ public static IServiceCollection AddApplication(this IServiceCollection services
services.AddSingleton<IMonitoringService, MonitoringService>();
services.AddScoped<IContentProcessor, ContentProcessor>();
services.AddHttpClient<IAssistantChatService, AssistantChatService>();
services.AddScoped<ITelegramIntegrationService, TelegramIntegrationService>();

services.AddValidatorsFromAssemblyContaining<CaptureRequestValidator>();
services.AddValidatorsFromAssemblyContaining<SemanticSearchRequestValidator>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using SentinelKnowledgebase.Application.DTOs.Integrations;

namespace SentinelKnowledgebase.Application.Services.Interfaces;

public interface ITelegramIntegrationService
{
Task<TelegramLinkStatusDto> GetStatusAsync(Guid ownerUserId);
Task<TelegramLinkCodeResponseDto> IssueLinkCodeAsync(Guid ownerUserId);
Task UnlinkAsync(Guid ownerUserId);
Task PollAndIngestAsync(CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SentinelKnowledgebase.Application.Services.Telegram;

public class TelegramIntegrationOptions
{
public const string SectionName = "Telegram";

public string BotToken { get; set; } = string.Empty;
public int PollTimeoutSeconds { get; set; } = 20;
public int PollLimit { get; set; } = 25;
public int PollCadenceSeconds { get; set; } = 3;
public int LinkCodeTtlMinutes { get; set; } = 10;
public int MaxRawContentLength { get; set; } = 8000;
}
Loading