Add IEmailService interface + StubEmailService
- IEmailService in Domain/Interfaces for membership notifications - StubEmailService in Infrastructure/Services logs instead of sending - TODO comments for future SMTP implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
264119695f
commit
a1bad43d88
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Koogle.Domain.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Service interface for email notifications.
|
||||
/// </summary>
|
||||
public interface IEmailService
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends notification to club admins about a new membership request.
|
||||
/// </summary>
|
||||
/// <param name="clubId">The club receiving the membership request.</param>
|
||||
/// <param name="userDisplayName">Display name of the requesting user.</param>
|
||||
/// <param name="userEmail">Email of the requesting user.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task SendMembershipRequestNotificationAsync(
|
||||
Guid clubId,
|
||||
string userDisplayName,
|
||||
string userEmail,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends notification to user that their membership was approved.
|
||||
/// </summary>
|
||||
/// <param name="userEmail">Email of the approved user.</param>
|
||||
/// <param name="clubName">Name of the club.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task SendMembershipApprovedAsync(
|
||||
string userEmail,
|
||||
string clubName,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends notification to user that their membership was rejected.
|
||||
/// </summary>
|
||||
/// <param name="userEmail">Email of the rejected user.</param>
|
||||
/// <param name="clubName">Name of the club.</param>
|
||||
/// <param name="reason">Optional rejection reason.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task SendMembershipRejectedAsync(
|
||||
string userEmail,
|
||||
string clubName,
|
||||
string? reason,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using Koogle.Infrastructure.Data;
|
|||
using Koogle.Infrastructure.Identity;
|
||||
using Koogle.Infrastructure.Repositories;
|
||||
using Koogle.Infrastructure.Security;
|
||||
using Koogle.Infrastructure.Services;
|
||||
using KoogleApp.Data;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
|
@ -84,6 +85,9 @@ public static class DependencyInjection
|
|||
services.AddScoped<IDayRepository, DayRepository>();
|
||||
services.AddScoped<IPersonExpenseRepository, PersonExpenseRepository>();
|
||||
|
||||
// Services
|
||||
services.AddScoped<IEmailService, StubEmailService>();
|
||||
|
||||
services.AddCascadingAuthenticationState();
|
||||
|
||||
return services;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
using Koogle.Domain.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Koogle.Infrastructure.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Stub email service that logs instead of sending emails.
|
||||
/// TODO: Replace with actual SMTP implementation.
|
||||
/// </summary>
|
||||
public class StubEmailService : IEmailService
|
||||
{
|
||||
private readonly ILogger<StubEmailService> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new StubEmailService instance.
|
||||
/// </summary>
|
||||
public StubEmailService(ILogger<StubEmailService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SendMembershipRequestNotificationAsync(
|
||||
Guid clubId,
|
||||
string userDisplayName,
|
||||
string userEmail,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"[EMAIL STUB] Membership request notification - ClubId: {ClubId}, User: {UserDisplayName} ({UserEmail})",
|
||||
clubId, userDisplayName, userEmail);
|
||||
|
||||
// TODO: Implement actual email sending via SMTP
|
||||
// - Get club admin emails from database
|
||||
// - Build notification template
|
||||
// - Send via configured SMTP provider
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SendMembershipApprovedAsync(
|
||||
string userEmail,
|
||||
string clubName,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"[EMAIL STUB] Membership approved - To: {UserEmail}, Club: {ClubName}",
|
||||
userEmail, clubName);
|
||||
|
||||
// TODO: Implement actual email sending via SMTP
|
||||
// - Build approval notification template
|
||||
// - Include link to dashboard
|
||||
// - Send via configured SMTP provider
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SendMembershipRejectedAsync(
|
||||
string userEmail,
|
||||
string clubName,
|
||||
string? reason,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"[EMAIL STUB] Membership rejected - To: {UserEmail}, Club: {ClubName}, Reason: {Reason}",
|
||||
userEmail, clubName, reason ?? "(no reason provided)");
|
||||
|
||||
// TODO: Implement actual email sending via SMTP
|
||||
// - Build rejection notification template
|
||||
// - Include reason if provided
|
||||
// - Send via configured SMTP provider
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue