Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/LinkTracker.Bot/Clients/IScrapperClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public interface IScrapperClient

[Get("/links")]
Task<ListLinksResponse> GetLinks([Header("Tg-Chat-Id")] long chatId, [Query] string? tag = null);

[Delete("/links")]
Task<LinkResponse> RemoveLink([Header("Tg-Chat-Id")] long chatId, [Body] RemoveLinkRequest request);
}
6 changes: 3 additions & 3 deletions src/LinkTracker.Bot/Commands/CommandDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class CommandDispatcher(
public async Task HandleMessageAsync(ITelegramBotClient bot, Message msg, CancellationToken ct)
{
if (msg.Text is not { } messageText) return;

var chatId = msg.Chat.Id;
var session = stateService.GetSession(chatId);

Expand All @@ -36,7 +36,7 @@ public async Task HandleMessageAsync(ITelegramBotClient bot, Message msg, Cancel
}
return;
}

if (session.State != UserState.Idle && commandName != "/track")
{
stateService.ResetSession(chatId);
Expand Down Expand Up @@ -80,7 +80,7 @@ private async Task HandleDialogueStep(ITelegramBotClient bot, Message msg, UserS
else if (session.State == UserState.TrackAwaitingTags)
{
var tags = text?.ToLower() == "/skip" ? Array.Empty<string>() : text?.Split(',').Select(t => t.Trim()).ToArray();
try
try
{
await scrapperClient.AddLink(chatId, new AddLinkRequest(session.TempUrl!, tags));
await bot.SendMessage(chatId, "Success! Link added.", cancellationToken: ct);
Expand Down
2 changes: 1 addition & 1 deletion src/LinkTracker.Bot/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public async Task ExecuteAsync(ITelegramBotClient botClient, Message message, Ca
"/help - Show this message\n" +
"/list - Show your tracked links\n" +
" └Tip: Use '/list <tag>' to filter by category";

await botClient.SendMessage(message.Chat.Id, text, cancellationToken: ct);
}
}
14 changes: 7 additions & 7 deletions src/LinkTracker.Bot/Commands/ListCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,30 @@ public async Task ExecuteAsync(ITelegramBotClient bot, Message msg, Cancellation
await bot.SendMessage(chatId, "No data received from service.", cancellationToken: ct);
return;
}

var linkList = response.Links.ToList();

if (linkList.Count == 0)
{
var emptyMsg = tagFilter == null
? "You are not tracking any links yet. Use /track to add one!"
var emptyMsg = tagFilter == null
? "You are not tracking any links yet. Use /track to add one!"
: $"No links found with tag: *{tagFilter}*";

await bot.SendMessage(chatId, emptyMsg, parseMode: ParseMode.Markdown, cancellationToken: ct);
return;
}

var header = tagFilter == null
? "📋 *Your tracked links:*"
var header = tagFilter == null
? "📋 *Your tracked links:*"
: $"📋 *Links with tag '{tagFilter}':*";

var messageLines = linkList.Select((l, i) =>
{
var safeUrl = l.Url.Replace("_", "\\_");
var tags = l.Tags ?? Array.Empty<string>();
var safeTags = tags.Select(t => t.Replace("_", "\\_"));
var tagsPart = tags.Length > 0
? $" _{string.Join(", ", safeTags)}_"
var tagsPart = tags.Length > 0
? $" _{string.Join(", ", safeTags)}_"
: "";
return $"{i + 1}. {safeUrl}{tagsPart}";
});
Expand Down
2 changes: 1 addition & 1 deletion src/LinkTracker.Bot/Commands/StartCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class StartCommand(IScrapperClient scrapper) : IBotCommand
{
public string Name => "/start";
public string Description => "Start the bot and register";

public async Task ExecuteAsync(ITelegramBotClient bot, Message msg, CancellationToken ct)
{
await scrapper.RegisterChat(msg.Chat.Id);
Expand Down
2 changes: 1 addition & 1 deletion src/LinkTracker.Bot/Controllers/UpdatesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace LinkTracker.Bot.Controllers;
[ApiController]
[Route("updates")]
public class UpdatesController(
ITelegramBotClient botClient,
ITelegramBotClient botClient,
ILogger<UpdatesController> logger) : ControllerBase
{
[HttpPost]
Expand Down
6 changes: 3 additions & 3 deletions src/LinkTracker.Bot/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@

builder.Services.Configure<BotOptions>(builder.Configuration.GetSection(BotOptions.SectionName));

builder.Services.AddSingleton<ITelegramBotClient>(sp =>
builder.Services.AddSingleton<ITelegramBotClient>(sp =>
{
var options = sp.GetRequiredService<IOptions<BotOptions>>().Value;
return new TelegramBotClient(options.BotToken);
});

builder.Services.AddRefitClient<IScrapperClient>()
.ConfigureHttpClient((sp, client) =>
.ConfigureHttpClient((sp, client) =>
{
var options = sp.GetRequiredService<IOptions<BotOptions>>().Value;
client.BaseAddress = new Uri(options.ScrapperUrl);
Expand All @@ -40,6 +40,6 @@

var app = builder.Build();

app.MapControllers();
app.MapControllers();

app.Run();
8 changes: 4 additions & 4 deletions src/LinkTracker.Bot/Services/BotHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var botCommands = _commands.Select(c => new BotCommand
{
Command = c.Name.TrimStart('/'),
Command = c.Name.TrimStart('/'),
Description = c.Description
}).ToList();

try
try
{
await _botClient.SetMyCommands(botCommands, cancellationToken: stoppingToken);
_logger.LogInformation("Bot commands registered successfully in Telegram menu.");
Expand All @@ -47,7 +47,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
AllowedUpdates = Array.Empty<UpdateType>(),
};

await _botClient.ReceiveAsync(
updateHandler: HandleUpdateAsync,
HandleErrorAsync,
Expand All @@ -61,7 +61,7 @@ private async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update
return;

_logger.LogInformation("Received message from {ChatId}: {Text}", message.Chat.Id, message.Text);

await _dispatcher.HandleMessageAsync(botClient, message, cancellationToken);
}

Expand Down
8 changes: 4 additions & 4 deletions src/LinkTracker.Scrapper/Clients/GitHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ public class GitHubClient(HttpClient httpClient, ILogger<GitHubClient> logger)
try
{
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LinkTrackerBot/1.0");

var response = await httpClient.GetAsync($"https://api.github.com/repos/{owner}/{repo}");

if (!response.IsSuccessStatusCode)
{
logger.LogWarning("GitHub API made error {Code} to {Owner}/{Repo}", response.StatusCode, owner, repo);
return null;
}

var json = await response.Content.ReadFromJsonAsync<JsonElement>();

if (json.TryGetProperty("pushed_at", out var dateProp))
{
return dateProp.GetDateTimeOffset();
Expand All @@ -29,7 +29,7 @@ public class GitHubClient(HttpClient httpClient, ILogger<GitHubClient> logger)
{
logger.LogError(ex, "Error GitHub API");
}

return null;
}
}
4 changes: 2 additions & 2 deletions src/LinkTracker.Scrapper/Clients/StackOverflowClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class StackOverflowClient(HttpClient httpClient, ILogger<StackOverflowCli
try
{
var url = $"https://api.stackexchange.com/2.3/questions/{questionId}?site=stackoverflow";

var response = await httpClient.GetAsync(url);

if (!response.IsSuccessStatusCode)
Expand All @@ -19,7 +19,7 @@ public class StackOverflowClient(HttpClient httpClient, ILogger<StackOverflowCli
}

var json = await response.Content.ReadFromJsonAsync<JsonElement>();

if (json.TryGetProperty("items", out var items) && items.GetArrayLength() > 0)
{
var firstItem = items[0];
Expand Down
8 changes: 4 additions & 4 deletions src/LinkTracker.Scrapper/Controllers/LinksController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public IActionResult Get([FromHeader(Name = "Tg-Chat-Id")] long chatId, [FromQue
{
return NotFound("Chat is not registered");
}

var links = repo.GetLinks(chatId).ToList();

if (!string.IsNullOrEmpty(tag))
Expand All @@ -26,8 +26,8 @@ public IActionResult Get([FromHeader(Name = "Tg-Chat-Id")] long chatId, [FromQue
}

var responseLinks = links.Select(l => new LinkResponse(
l.Id,
l.Url,
l.Id,
l.Url,
l.Tags ?? Array.Empty<string>()
)).ToArray();

Expand Down Expand Up @@ -63,7 +63,7 @@ public IActionResult Remove([FromHeader(Name = "Tg-Chat-Id")] long chatId, [From
{
return NotFound("Link is not registered");
}

return Ok(req);
}
}
18 changes: 9 additions & 9 deletions src/LinkTracker.Scrapper/Database/LinkTrackerDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ namespace LinkTracker.Scrapper.Database;
public class LinkTrackerDbContext(DbContextOptions<LinkTrackerDbContext> options) : DbContext(options)
{
public DbSet<ChatEntity> Chats => Set<ChatEntity>();

public DbSet<LinkEntity> Links => Set<LinkEntity>();

public DbSet<ChatLinkEntity> ChatLinks => Set<ChatLinkEntity>();

public DbSet<TagEntity> Tags => Set<TagEntity>();

public DbSet<ChatLinkTagEntity> ChatLinkTags => Set<ChatLinkTagEntity>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
Expand Down Expand Up @@ -40,19 +40,19 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

entity.Property(link => link.Id)
.HasColumnName("id");

entity.Property(link => link.Url)
.HasColumnName("url")
.IsRequired();

entity.Property(link => link.LastCheckedAt)
.HasColumnName("last_checked_at")
.HasDefaultValueSql("NOW()");

entity.Property(link => link.CreatedAt)
.HasColumnName("created_at")
.HasDefaultValueSql("NOW()");

entity.HasIndex(link => link.Url)
.IsUnique();
});
Expand Down Expand Up @@ -133,7 +133,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
chatLinkTag.LinkId
})
.OnDelete(DeleteBehavior.Cascade);

entity.HasOne(chatLinkTag => chatLinkTag.Tag)
.WithMany(tag => tag.ChatLinkTags)
.HasForeignKey(chatLinkTag => chatLinkTag.TagId)
Expand Down
4 changes: 2 additions & 2 deletions src/LinkTracker.Scrapper/Database/MigrationRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static void Run(IServiceProvider services)
{
throw new InvalidOperationException("Database connection string is not configured.");
}

var migrationsPath = Path.Combine(AppContext.BaseDirectory, "migrations");

if (!Directory.Exists(migrationsPath))
Expand All @@ -36,7 +36,7 @@ public static void Run(IServiceProvider services)
.WithScriptsFromFileSystem(migrationsPath)
.LogToConsole()
.Build();

var result = upgrader.PerformUpgrade();

if (!result.Successful)
Expand Down
4 changes: 4 additions & 0 deletions src/LinkTracker.Scrapper/LinkTracker.Scrapper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<Folder Include="Repositories\Orm\" />
</ItemGroup>
</Project>
13 changes: 8 additions & 5 deletions src/LinkTracker.Scrapper/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@
builder.Services.AddHttpClient<GitHubClient>();
builder.Services.AddHttpClient<StackOverflowClient>();

builder.Services.AddHttpClient("BotClient", client => {
builder.Services.AddHttpClient("BotClient", client =>
{
var botUrl = builder.Configuration["BotUrl"] ?? "http://localhost:5100";
client.BaseAddress = new Uri(botUrl);
});

builder.Services.AddQuartz(q => {
builder.Services.AddQuartz(q =>
{
var jobKey = new JobKey("LinkUpdaterJob");

q.AddJob<LinkUpdaterJob>(opts => opts.WithIdentity(jobKey));

q.AddTrigger(opts => opts
.ForJob(jobKey)
.WithIdentity("LinkUpdaterJob-trigger")
Expand All @@ -43,7 +45,8 @@

MigrationRunner.Run(app.Services);

if (app.Environment.IsDevelopment()) {
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
Expand Down
Loading
Loading