Feedback page

This commit is contained in:
2026-05-27 18:30:05 +03:00
parent fe34408b13
commit ea4747ec16
11 changed files with 321 additions and 45 deletions

View File

@@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MailKit" Version="4.16.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.0" />

View File

@@ -0,0 +1,71 @@
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Options;
using MimeKit;
public record FeedbackRequest(string? Message);
public class EmailOptions
{
public string SmtpHost { get; set; } = string.Empty;
public int SmtpPort { get; set; } = 587;
public string FromAddress { get; set; } = string.Empty;
public string ToAddress { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
public static class FeedbackEndpoints
{
public static void MapFeedbackEndpoints(WebApplication app)
{
app.MapPost("/feedback", async (
FeedbackRequest request,
IOptions<EmailOptions> emailOptions,
ILogger<Program> logger) =>
{
if (string.IsNullOrWhiteSpace(request.Message))
{
return Results.BadRequest(new { Message = "Feedback message is required." });
}
var message = request.Message.Trim();
if (message.Length > 5000)
{
return Results.BadRequest(new { Message = "Feedback message is too long." });
}
var options = emailOptions.Value;
var email = new MimeMessage();
email.From.Add(MailboxAddress.Parse(options.FromAddress));
email.To.Add(MailboxAddress.Parse(options.ToAddress));
email.Subject = "Klapi New feedback";
email.Body = new TextPart("plain") { Text = message };
try
{
using var smtp = new SmtpClient();
await smtp.ConnectAsync(options.SmtpHost, options.SmtpPort, SecureSocketOptions.StartTls);
if (!string.IsNullOrWhiteSpace(options.Username))
{
await smtp.AuthenticateAsync(options.Username, options.Password);
}
await smtp.SendAsync(email);
await smtp.DisconnectAsync(true);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to send feedback email.");
return Results.Problem("Failed to send feedback. Please try again later.");
}
return Results.Ok(new { Message = "Feedback sent." });
})
.RequireCors("FrontendWriteCors")
.WithName("SubmitFeedback");
}
}

View File

@@ -46,6 +46,29 @@ public class Program
builder.Services.Configure<AuthOptions>(builder.Configuration.GetSection("Auth"));
var emailOptions = builder.Configuration.GetSection("Email").Get<EmailOptions>()
?? throw new InvalidOperationException("Email configuration was not found.");
if (builder.Environment.IsProduction())
{
emailOptions.Username =
Environment.GetEnvironmentVariable("KLAPI_SMTP_USERNAME")
?? throw new InvalidOperationException("SMTP username must be set in production using KLAPI_SMTP_USERNAME environment variable.");
emailOptions.Password =
Environment.GetEnvironmentVariable("KLAPI_SMTP_PASSWORD")
?? throw new InvalidOperationException("SMTP password must be set in production using KLAPI_SMTP_PASSWORD environment variable.");
}
builder.Services.Configure<EmailOptions>(o =>
{
o.SmtpHost = emailOptions.SmtpHost;
o.SmtpPort = emailOptions.SmtpPort;
o.FromAddress = emailOptions.FromAddress;
o.ToAddress = emailOptions.ToAddress;
o.Username = emailOptions.Username;
o.Password = emailOptions.Password;
});
builder.Services.AddScoped(_ => new SqliteConnection(resolvedConnectionString));
builder.Services.AddScoped<LokService>();
builder.Services.AddScoped<UserService>();
@@ -285,6 +308,7 @@ public class Program
AuthEndpoints.MapAuthEndpoints(app);
LokEndpoints.MapLokEndpoints(app);
UserEndpoints.MapUserEndpoints(app);
FeedbackEndpoints.MapFeedbackEndpoints(app);
app.Run();
}

View File

@@ -23,5 +23,13 @@
"Password": "changeme",
"DisplayName": "Administrator"
}
},
"Email": {
"SmtpHost": "mail.tietokonepaja.fi",
"SmtpPort": 587,
"FromAddress": "feedback@tietokonepaja.fi",
"ToAddress": "veikko@lintujarvi.fi",
"Username": "",
"Password": ""
}
}
}

View File

@@ -12,12 +12,22 @@
"Issuer": "klapi-api",
"Audience": "klapi-ui",
"SigningKey": "change-this-to-a-long-random-32-char-minimum-key",
"AllowedOrigins": ["https://klapi.tietokonepaja.fi"],
"AllowedOrigins": [
"https://klapi.tietokonepaja.fi"
],
"Admin": {
"Username": "admin",
"Password": "<set in env var KLAPI_ADMIN_PASSWORD>",
"DisplayName": "Administrator"
}
},
"Email": {
"SmtpHost": "mail.tietokonepaja.fi",
"SmtpPort": 587,
"FromAddress": "feedback@tietokonepaja.fi",
"ToAddress": "veikko@lintujarvi.fi",
"Username": "<set in env var KLAPI_SMTP_USERNAME>",
"Password": "<set in env var KLAPI_SMTP_PASSWORD>"
},
"AllowedHosts": "*"
}
}