Feedback page
This commit is contained in:
@@ -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" />
|
||||
|
||||
71
api/App/Endpoints/FeedbackEndpoints.cs
Normal file
71
api/App/Endpoints/FeedbackEndpoints.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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": "*"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user