Move ingestion + Telegram/Bale/Divar config to DB-backed admin settings
- AppSetting gains source config: AutoIngestEnabled, IngestIntervalMinutes, Telegram/Bale/Divar enabled+channels/token/queries - IListingSource.FetchAsync(AppSetting) — sources read config from DB, not IOptions/appsettings; sample source dev-only - IngestionWorker reads AutoIngest+interval from DB each cycle (toggle at runtime, no redeploy) - /Admin/Settings gets a 'منابع جمعآوری' section; removed Ingestion env/appsettings + compose env vars - ENV_FILE shrinks to HOST_PORT + POSTGRES_* + ADMIN_PHONE (AI + sources are all in-admin); migration Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,46 +1,34 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using JobsMedical.Web.Models;
|
||||
|
||||
namespace JobsMedical.Web.Services.Scraping;
|
||||
|
||||
public class BaleOptions
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string? BotToken { get; set; }
|
||||
public string BaseUrl { get; set; } = "https://tapi.bale.ai"; // Bale Bot API host
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bale (Iranian messenger) source via its Telegram-compatible Bot API getUpdates. The bot must
|
||||
/// be a member/admin of the channels it should read. Pulls text from messages and channel posts.
|
||||
/// Bale (Iranian messenger) source via its Telegram-compatible Bot API getUpdates. Enabled +
|
||||
/// bot token come from admin settings (DB). The bot must be a member of the channels it reads.
|
||||
/// </summary>
|
||||
public class BaleListingSource : IListingSource
|
||||
{
|
||||
private readonly BaleOptions _opts;
|
||||
private const string BaseUrl = "https://tapi.bale.ai";
|
||||
private readonly IHttpClientFactory _http;
|
||||
private readonly ILogger<BaleListingSource> _log;
|
||||
|
||||
public BaleListingSource(IOptions<BaleOptions> opts, IHttpClientFactory http,
|
||||
ILogger<BaleListingSource> log)
|
||||
public BaleListingSource(IHttpClientFactory http, ILogger<BaleListingSource> log)
|
||||
{
|
||||
_opts = opts.Value;
|
||||
_http = http;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public string Name => "بله";
|
||||
public bool Enabled => _opts.Enabled && !string.IsNullOrWhiteSpace(_opts.BotToken);
|
||||
|
||||
public async Task<IReadOnlyList<ScrapedItem>> FetchAsync(CancellationToken ct = default)
|
||||
public async Task<IReadOnlyList<ScrapedItem>> FetchAsync(AppSetting s, CancellationToken ct = default)
|
||||
{
|
||||
if (!Enabled) { _log.LogInformation("Bale source disabled/unconfigured."); return Array.Empty<ScrapedItem>(); }
|
||||
if (!s.BaleEnabled || string.IsNullOrWhiteSpace(s.BaleBotToken)) return Array.Empty<ScrapedItem>();
|
||||
|
||||
try
|
||||
{
|
||||
var client = _http.CreateClient("scrape");
|
||||
var url = $"{_opts.BaseUrl.TrimEnd('/')}/bot{_opts.BotToken}/getUpdates";
|
||||
var body = await client.GetStringAsync(url, ct);
|
||||
|
||||
var body = await client.GetStringAsync($"{BaseUrl}/bot{s.BaleBotToken}/getUpdates", ct);
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
if (!doc.RootElement.TryGetProperty("result", out var result) || result.ValueKind != JsonValueKind.Array)
|
||||
return Array.Empty<ScrapedItem>();
|
||||
@@ -54,11 +42,7 @@ public class BaleListingSource : IListingSource
|
||||
}
|
||||
return items;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.LogWarning(ex, "Bale fetch failed.");
|
||||
return Array.Empty<ScrapedItem>();
|
||||
}
|
||||
catch (Exception ex) { _log.LogWarning(ex, "Bale fetch failed."); return Array.Empty<ScrapedItem>(); }
|
||||
}
|
||||
|
||||
private static string? TextOf(JsonElement update, string key)
|
||||
|
||||
Reference in New Issue
Block a user