feat: implement Blazor web interface for GM session management
Deploy Telegram Bot / deploy (push) Has been cancelled

- Created GmRelay.Web project (Blazor Server)
- Created GmRelay.Shared library for domain models and rendering
- Refactored GmRelay.Bot to use the Shared library
- Integrated Telegram Login widget with server-side HMAC verification
- Added Dashboard, Group Details, and Edit Session pages
- Enabled bot notifications and in-place message updates from web actions
- Updated .NET Aspire orchestration and Docker Compose configuration
This commit is contained in:
2026-04-17 11:06:59 +03:00
parent c27456e726
commit 988133e389
93 changed files with 61016 additions and 34 deletions
+92
View File
@@ -0,0 +1,92 @@
using GmRelay.Web.Components;
using GmRelay.Web.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;
using Telegram.Bot;
using Npgsql;
var builder = WebApplication.CreateBuilder(args);
// Add Aspire service defaults
builder.AddServiceDefaults();
// Add Npgsql
builder.AddNpgsqlDataSource("gmrelay-db");
// Add Services
builder.Services.AddSingleton<TelegramAuthService>();
builder.Services.AddSingleton<SessionService>();
// Add Bot Client
builder.Services.AddSingleton<ITelegramBotClient>(sp =>
{
var config = sp.GetRequiredService<IConfiguration>();
var token = config["Telegram__BotToken"] ?? config["Telegram:BotToken"]
?? throw new InvalidOperationException("Telegram__BotToken is required.");
return new TelegramBotClient(token);
});
// Add Authentication
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/login";
options.AccessDeniedPath = "/access-denied";
});
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Endpoint to handle Telegram Login callback
app.MapGet("/auth/telegram", async (HttpContext context, TelegramAuthService authService) =>
{
if (authService.Verify(context.Request.Query, out var telegramId, out var name))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, telegramId.ToString()),
new Claim(ClaimTypes.Name, name),
new Claim("TelegramId", telegramId.ToString())
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties { IsPersistent = true };
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
return Results.Redirect("/");
}
return Results.Redirect("/login?error=auth_failed");
});
app.MapPost("/auth/logout", async (HttpContext context) =>
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.Redirect("/");
});
app.Run();