diff --git a/.gitea/workflows/deploy-socialize.yml b/.gitea/workflows/deploy-socialize.yml index 8afb6a3..303fbfb 100644 --- a/.gitea/workflows/deploy-socialize.yml +++ b/.gitea/workflows/deploy-socialize.yml @@ -47,9 +47,15 @@ jobs: DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_SSH_PRIVATE_KEY_B64: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY_B64 }} POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} + RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL: ${{ secrets.RESEND_FROM_EMAIL }} + JWT_SIGNING_KEY: ${{ secrets.JWT_SIGNING_KEY }} SOCIALIZE_IMAGE_TAG: ${{ gitea.sha }} run: | : "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD secret is required}" + : "${RESEND_API_KEY:?RESEND_API_KEY secret is required}" + : "${RESEND_FROM_EMAIL:?RESEND_FROM_EMAIL secret is required}" + : "${JWT_SIGNING_KEY:?JWT_SIGNING_KEY secret is required}" : "${SOCIALIZE_IMAGE_TAG:?SOCIALIZE_IMAGE_TAG is required}" mkdir -p ~/.ssh @@ -69,6 +75,14 @@ jobs: write_env_value POSTGRES_PASSWORD "$POSTGRES_PASSWORD" write_env_value POSTGRES_DB socialize write_env_value ASPNETCORE_ENVIRONMENT Production + write_env_value WEBSITE_FRONTEND_BASE_URL https://socialize.mapachotes.com + write_env_value RESEND_API_KEY "$RESEND_API_KEY" + write_env_value RESEND_FROM_EMAIL "$RESEND_FROM_EMAIL" + write_env_value JWT_ISSUER https://socialize.mapachotes.com + write_env_value JWT_AUDIENCE socialize-preprod + write_env_value JWT_SIGNING_KEY "$JWT_SIGNING_KEY" + write_env_value JWT_LIFETIME 00:05:00 + write_env_value JWT_REFRESH_TOKEN_LIFETIME 0.00:30:00 write_env_value SOCIALIZE_IMAGE_TAG "$SOCIALIZE_IMAGE_TAG" } > "$deploy_env" diff --git a/README.md b/README.md index baff943..f0949ad 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,8 @@ http://localhost:8080 http://:8080 ``` -For preprod deployment, configure the `POSTGRES_PASSWORD` Gitea secret. +For preprod deployment, configure the `POSTGRES_PASSWORD`, `RESEND_API_KEY`, +`RESEND_FROM_EMAIL`, and `JWT_SIGNING_KEY` Gitea secrets. The deploy workflow writes the remote `.env` file before running the server deploy script. ## Solution diff --git a/backend/src/Socialize.Api/Infrastructure/DependencyInjection.cs b/backend/src/Socialize.Api/Infrastructure/DependencyInjection.cs index 586d3ef..c0fc5c6 100644 --- a/backend/src/Socialize.Api/Infrastructure/DependencyInjection.cs +++ b/backend/src/Socialize.Api/Infrastructure/DependencyInjection.cs @@ -26,8 +26,14 @@ public static class DependencyInjection builder.Services.Configure( builder.Configuration.GetSection(EmailerOptions.ConfigurationSection)); - builder.Services.AddTransient(); - //builder.Services.AddTransient(); + if (builder.Environment.IsDevelopment()) + { + builder.Services.AddTransient(); + } + else + { + builder.Services.AddTransient(); + } builder.Services.AddHttpClient(); diff --git a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/LoggerEmailSender.cs b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/LoggerEmailSender.cs index cca2efc..8f52f15 100644 --- a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/LoggerEmailSender.cs +++ b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/LoggerEmailSender.cs @@ -5,18 +5,15 @@ namespace Socialize.Api.Infrastructure.Emailer.Services; public class LoggerEmailSender(ILogger logger) : IEmailSender { - public async Task SendEmailAsync(string email, string subject, string message) + public Task SendEmailAsync(string email, string subject, string message) { - try - { - logger.LogInformation("Sending email to {Email} with subject: {Subject}", email, subject); - await Task.Delay(1000); - logger.LogInformation("Email sent successfully to {Email}", email); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to send email to {Email}", email); - throw; - } + logger.LogInformation( + "Development email to {Email} with subject {Subject}:{NewLine}{Message}", + email, + subject, + Environment.NewLine, + message); + + return Task.CompletedTask; } } diff --git a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs index 3935c42..ce5ee12 100644 --- a/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs +++ b/backend/src/Socialize.Api/Infrastructure/Emailer/Services/ResendEmailSender.cs @@ -20,6 +20,16 @@ public class ResendEmailSender : IEmailSender _httpClient = httpClientFactory.CreateClient(); _options = options.Value; + if (string.IsNullOrWhiteSpace(_options.ApiKey)) + { + throw new InvalidOperationException("Emailer:ApiKey is required when using Resend email delivery."); + } + + if (string.IsNullOrWhiteSpace(_options.FromEmail)) + { + throw new InvalidOperationException("Emailer:FromEmail is required when using Resend email delivery."); + } + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _options.ApiKey); diff --git a/docker-compose.yml b/docker-compose.yml index 7373eed..a3019e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,14 @@ services: ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT:-Development} ASPNETCORE_URLS: http://0.0.0.0:8080 ConnectionStrings__PostgresConnection: Host=postgres;Port=5432;Database=${POSTGRES_DB:-socialize};Username=${POSTGRES_USER:-sa};Password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + Website__FrontendBaseUrl: ${WEBSITE_FRONTEND_BASE_URL:-http://localhost:8080} + Emailer__ApiKey: ${RESEND_API_KEY:-} + Emailer__FromEmail: ${RESEND_FROM_EMAIL:-} + Authentication__Jwt__Issuer: ${JWT_ISSUER:-http://localhost:8080} + Authentication__Jwt__Audience: ${JWT_AUDIENCE:-socialize-local} + Authentication__Jwt__Key: ${JWT_SIGNING_KEY:-socialize-dev-local-signing-key-please-change} + Authentication__Jwt__Lifetime: ${JWT_LIFETIME:-00:05:00} + Authentication__Jwt__RefreshTokenLifetime: ${JWT_REFRESH_TOKEN_LIFETIME:-0.00:30:00} depends_on: postgres: condition: service_healthy