mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Emails on store level
This commit is contained in:
@@ -28,7 +28,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly EmailSenderFactory _EmailSenderFactory;
|
||||||
StoreRepository storeRepository;
|
StoreRepository storeRepository;
|
||||||
RoleManager<IdentityRole> _RoleManager;
|
RoleManager<IdentityRole> _RoleManager;
|
||||||
SettingsRepository _SettingsRepository;
|
SettingsRepository _SettingsRepository;
|
||||||
@@ -40,14 +40,14 @@ namespace BTCPayServer.Controllers
|
|||||||
RoleManager<IdentityRole> roleManager,
|
RoleManager<IdentityRole> roleManager,
|
||||||
StoreRepository storeRepository,
|
StoreRepository storeRepository,
|
||||||
SignInManager<ApplicationUser> signInManager,
|
SignInManager<ApplicationUser> signInManager,
|
||||||
IEmailSender emailSender,
|
EmailSenderFactory emailSenderFactory,
|
||||||
SettingsRepository settingsRepository,
|
SettingsRepository settingsRepository,
|
||||||
Configuration.BTCPayServerOptions options)
|
Configuration.BTCPayServerOptions options)
|
||||||
{
|
{
|
||||||
this.storeRepository = storeRepository;
|
this.storeRepository = storeRepository;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_emailSender = emailSender;
|
_EmailSenderFactory = emailSenderFactory;
|
||||||
_RoleManager = roleManager;
|
_RoleManager = roleManager;
|
||||||
_SettingsRepository = settingsRepository;
|
_SettingsRepository = settingsRepository;
|
||||||
_Options = options;
|
_Options = options;
|
||||||
@@ -286,7 +286,8 @@ namespace BTCPayServer.Controllers
|
|||||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
||||||
RegisteredUserId = user.Id;
|
RegisteredUserId = user.Id;
|
||||||
await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl);
|
|
||||||
|
_EmailSenderFactory.GetEmailSender().SendEmailConfirmation(model.Email, callbackUrl);
|
||||||
if (!policies.RequiresConfirmedEmail)
|
if (!policies.RequiresConfirmedEmail)
|
||||||
{
|
{
|
||||||
if(logon)
|
if(logon)
|
||||||
@@ -446,8 +447,9 @@ namespace BTCPayServer.Controllers
|
|||||||
// visit https://go.microsoft.com/fwlink/?LinkID=532713
|
// visit https://go.microsoft.com/fwlink/?LinkID=532713
|
||||||
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
|
||||||
var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme);
|
var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme);
|
||||||
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
|
_EmailSenderFactory.GetEmailSender().SendEmail(model.Email, "Reset Password",
|
||||||
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
|
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
|
||||||
|
|
||||||
return RedirectToAction(nameof(ForgotPasswordConfirmation));
|
return RedirectToAction(nameof(ForgotPasswordConfirmation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly EmailSenderFactory _EmailSenderFactory;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly UrlEncoder _urlEncoder;
|
private readonly UrlEncoder _urlEncoder;
|
||||||
TokenRepository _TokenRepository;
|
TokenRepository _TokenRepository;
|
||||||
@@ -44,7 +44,7 @@ namespace BTCPayServer.Controllers
|
|||||||
public ManageController(
|
public ManageController(
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
SignInManager<ApplicationUser> signInManager,
|
SignInManager<ApplicationUser> signInManager,
|
||||||
IEmailSender emailSender,
|
EmailSenderFactory emailSenderFactory,
|
||||||
ILogger<ManageController> logger,
|
ILogger<ManageController> logger,
|
||||||
UrlEncoder urlEncoder,
|
UrlEncoder urlEncoder,
|
||||||
TokenRepository tokenRepository,
|
TokenRepository tokenRepository,
|
||||||
@@ -54,7 +54,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_emailSender = emailSender;
|
_EmailSenderFactory = emailSenderFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_urlEncoder = urlEncoder;
|
_urlEncoder = urlEncoder;
|
||||||
_TokenRepository = tokenRepository;
|
_TokenRepository = tokenRepository;
|
||||||
@@ -156,8 +156,7 @@ namespace BTCPayServer.Controllers
|
|||||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
|
||||||
var email = user.Email;
|
var email = user.Email;
|
||||||
await _emailSender.SendEmailConfirmationAsync(email, callbackUrl);
|
_EmailSenderFactory.GetEmailSender().SendEmailConfirmation(email, callbackUrl);
|
||||||
|
|
||||||
StatusMessage = "Verification email sent. Please check your email.";
|
StatusMessage = "Verification email sent. Please check your email.";
|
||||||
return RedirectToAction(nameof(Index));
|
return RedirectToAction(nameof(Index));
|
||||||
}
|
}
|
||||||
|
|||||||
65
BTCPayServer/Controllers/StoresController.Email.cs
Normal file
65
BTCPayServer/Controllers/StoresController.Email.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Models.ServerViewModels;
|
||||||
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
|
using BTCPayServer.Payments.Changelly;
|
||||||
|
using BTCPayServer.Services.Mails;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Controllers
|
||||||
|
{
|
||||||
|
public partial class StoresController
|
||||||
|
{
|
||||||
|
|
||||||
|
[Route("{storeId}/emails")]
|
||||||
|
public IActionResult Emails()
|
||||||
|
{
|
||||||
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (store == null)
|
||||||
|
return NotFound();
|
||||||
|
var data = store.GetStoreBlob().EmailSettings ?? new EmailSettings();
|
||||||
|
return View(new EmailsViewModel() { Settings = data });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("{storeId}/emails")]
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> Emails(string storeId, EmailsViewModel model, string command)
|
||||||
|
{
|
||||||
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (store == null)
|
||||||
|
return NotFound();
|
||||||
|
if (command == "Test")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!model.Settings.IsComplete())
|
||||||
|
{
|
||||||
|
model.StatusMessage = "Error: Required fields missing";
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
var client = model.Settings.CreateSmtpClient();
|
||||||
|
await client.SendMailAsync(model.Settings.From, model.TestEmail, "BTCPay test", "BTCPay test");
|
||||||
|
model.StatusMessage = "Email sent to " + model.TestEmail + ", please, verify you received it";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
model.StatusMessage = "Error: " + ex.Message;
|
||||||
|
}
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
else // if(command == "Save")
|
||||||
|
{
|
||||||
|
|
||||||
|
var storeBlob = store.GetStoreBlob();
|
||||||
|
storeBlob.EmailSettings = model.Settings;
|
||||||
|
store.SetStoreBlob(storeBlob);
|
||||||
|
await _Repo.UpdateStore(store);
|
||||||
|
StatusMessage = "Email settings modified";
|
||||||
|
return RedirectToAction(nameof(UpdateStore), new {
|
||||||
|
storeId});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ using BTCPayServer.Payments.Changelly;
|
|||||||
using BTCPayServer.Payments.CoinSwitch;
|
using BTCPayServer.Payments.CoinSwitch;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Rating;
|
using BTCPayServer.Rating;
|
||||||
|
using BTCPayServer.Services.Mails;
|
||||||
|
|
||||||
namespace BTCPayServer.Data
|
namespace BTCPayServer.Data
|
||||||
{
|
{
|
||||||
@@ -403,6 +404,8 @@ namespace BTCPayServer.Data
|
|||||||
[Obsolete("Use SetWalletKeyPathRoot/GetWalletKeyPathRoot instead")]
|
[Obsolete("Use SetWalletKeyPathRoot/GetWalletKeyPathRoot instead")]
|
||||||
public Dictionary<string, string> WalletKeyPathRoots { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> WalletKeyPathRoots { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public EmailSettings EmailSettings { get; set; }
|
||||||
|
|
||||||
public IPaymentFilter GetExcludedPaymentMethods()
|
public IPaymentFilter GetExcludedPaymentMethods()
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ namespace BTCPayServer.Services
|
|||||||
{
|
{
|
||||||
public static class EmailSenderExtensions
|
public static class EmailSenderExtensions
|
||||||
{
|
{
|
||||||
public static Task SendEmailConfirmationAsync(this IEmailSender emailSender, string email, string link)
|
public static void SendEmailConfirmation(this IEmailSender emailSender, string email, string link)
|
||||||
{
|
{
|
||||||
return emailSender.SendEmailAsync(email, "Confirm your email",
|
emailSender.SendEmail(email, "Confirm your email",
|
||||||
$"Please confirm your account by clicking this link: <a href='{HtmlEncoder.Default.Encode(link)}'>link</a>");
|
$"Please confirm your account by clicking this link: <a href='{HtmlEncoder.Default.Encode(link)}'>link</a>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,20 +46,21 @@ namespace BTCPayServer.HostedServices
|
|||||||
EventAggregator _EventAggregator;
|
EventAggregator _EventAggregator;
|
||||||
InvoiceRepository _InvoiceRepository;
|
InvoiceRepository _InvoiceRepository;
|
||||||
BTCPayNetworkProvider _NetworkProvider;
|
BTCPayNetworkProvider _NetworkProvider;
|
||||||
IEmailSender _EmailSender;
|
private readonly EmailSenderFactory _EmailSenderFactory;
|
||||||
|
|
||||||
public InvoiceNotificationManager(
|
public InvoiceNotificationManager(
|
||||||
IBackgroundJobClient jobClient,
|
IBackgroundJobClient jobClient,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
InvoiceRepository invoiceRepository,
|
InvoiceRepository invoiceRepository,
|
||||||
BTCPayNetworkProvider networkProvider,
|
BTCPayNetworkProvider networkProvider,
|
||||||
IEmailSender emailSender)
|
ILogger<InvoiceNotificationManager> logger,
|
||||||
|
EmailSenderFactory emailSenderFactory)
|
||||||
{
|
{
|
||||||
_JobClient = jobClient;
|
_JobClient = jobClient;
|
||||||
_EventAggregator = eventAggregator;
|
_EventAggregator = eventAggregator;
|
||||||
_InvoiceRepository = invoiceRepository;
|
_InvoiceRepository = invoiceRepository;
|
||||||
_NetworkProvider = networkProvider;
|
_NetworkProvider = networkProvider;
|
||||||
_EmailSender = emailSender;
|
_EmailSenderFactory = emailSenderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Notify(InvoiceEntity invoice, int? eventCode = null, string name = null)
|
void Notify(InvoiceEntity invoice, int? eventCode = null, string name = null)
|
||||||
@@ -76,11 +77,14 @@ namespace BTCPayServer.HostedServices
|
|||||||
invoice.StoreId
|
invoice.StoreId
|
||||||
};
|
};
|
||||||
// TODO: Consider adding info on ItemDesc and payment info (amount)
|
// TODO: Consider adding info on ItemDesc and payment info (amount)
|
||||||
|
|
||||||
var emailBody = NBitcoin.JsonConverters.Serializer.ToString(ipn);
|
var emailBody = NBitcoin.JsonConverters.Serializer.ToString(ipn);
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
|
||||||
_EmailSender.SendEmailAsync(invoice.NotificationEmail, $"BtcPayServer Invoice Notification - ${invoice.StoreId}", emailBody);
|
_EmailSenderFactory.GetEmailSender(invoice.StoreId).SendEmail(
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
invoice.NotificationEmail,
|
||||||
|
$"BtcPayServer Invoice Notification - ${invoice.StoreId}",
|
||||||
|
emailBody);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(invoice.NotificationURL))
|
if (string.IsNullOrEmpty(invoice.NotificationURL))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace BTCPayServer.Hosting
|
|||||||
services.AddTransient<InvoiceController>();
|
services.AddTransient<InvoiceController>();
|
||||||
services.AddTransient<AppsPublicController>();
|
services.AddTransient<AppsPublicController>();
|
||||||
// Add application services.
|
// Add application services.
|
||||||
services.AddTransient<IEmailSender, EmailSender>();
|
services.AddSingleton<EmailSenderFactory>();
|
||||||
// bundling
|
// bundling
|
||||||
|
|
||||||
services.AddAuthorization(o => Policies.AddBTCPayPolicies(o));
|
services.AddAuthorization(o => Policies.AddBTCPayPolicies(o));
|
||||||
|
|||||||
@@ -1,47 +1,40 @@
|
|||||||
using BTCPayServer.Logging;
|
using BTCPayServer.Logging;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace BTCPayServer.Services.Mails
|
namespace BTCPayServer.Services.Mails
|
||||||
{
|
{
|
||||||
// This class is used by the application to send email for account confirmation and password reset.
|
public abstract class EmailSender : IEmailSender
|
||||||
// For more details see https://go.microsoft.com/fwlink/?LinkID=532713
|
|
||||||
public class EmailSender : IEmailSender
|
|
||||||
{
|
{
|
||||||
IBackgroundJobClient _JobClient;
|
IBackgroundJobClient _JobClient;
|
||||||
SettingsRepository _Repository;
|
|
||||||
public EmailSender(IBackgroundJobClient jobClient, SettingsRepository repository)
|
public EmailSender(IBackgroundJobClient jobClient)
|
||||||
{
|
{
|
||||||
if (jobClient == null)
|
_JobClient = jobClient ?? throw new ArgumentNullException(nameof(jobClient));
|
||||||
throw new ArgumentNullException(nameof(jobClient));
|
|
||||||
_JobClient = jobClient;
|
|
||||||
_Repository = repository;
|
|
||||||
}
|
|
||||||
public async Task SendEmailAsync(string email, string subject, string message)
|
|
||||||
{
|
|
||||||
var settings = await _Repository.GetSettingAsync<EmailSettings>() ?? new EmailSettings();
|
|
||||||
if (!settings.IsComplete())
|
|
||||||
{
|
|
||||||
Logs.Configuration.LogWarning("Should have sent email, but email settings are not configured");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_JobClient.Schedule(() => SendMailCore(email, subject, message), TimeSpan.Zero);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendMailCore(string email, string subject, string message)
|
public void SendEmail(string email, string subject, string message)
|
||||||
{
|
{
|
||||||
var settings = await _Repository.GetSettingAsync<EmailSettings>() ?? new EmailSettings();
|
_JobClient.Schedule(async () =>
|
||||||
if (!settings.IsComplete())
|
{
|
||||||
throw new InvalidOperationException("Email settings not configured");
|
var emailSettings = await GetEmailSettings();
|
||||||
var smtp = settings.CreateSmtpClient();
|
if (emailSettings?.IsComplete() != true)
|
||||||
MailMessage mail = new MailMessage(settings.From, email, subject, message);
|
{
|
||||||
mail.IsBodyHtml = true;
|
Logs.Configuration.LogWarning("Should have sent email, but email settings are not configured");
|
||||||
await smtp.SendMailAsync(mail);
|
return;
|
||||||
|
}
|
||||||
|
var smtp = emailSettings.CreateSmtpClient();
|
||||||
|
var mail = new MailMessage(emailSettings.From, email, subject, message)
|
||||||
|
{
|
||||||
|
IsBodyHtml = true
|
||||||
|
};
|
||||||
|
await smtp.SendMailAsync(mail);
|
||||||
|
|
||||||
|
}, TimeSpan.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Task<EmailSettings> GetEmailSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
BTCPayServer/Services/Mails/EmailSenderFactory.cs
Normal file
31
BTCPayServer/Services/Mails/EmailSenderFactory.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services.Mails
|
||||||
|
{
|
||||||
|
public class EmailSenderFactory
|
||||||
|
{
|
||||||
|
private readonly IBackgroundJobClient _JobClient;
|
||||||
|
private readonly SettingsRepository _Repository;
|
||||||
|
private readonly StoreRepository _StoreRepository;
|
||||||
|
|
||||||
|
public EmailSenderFactory(IBackgroundJobClient jobClient,
|
||||||
|
SettingsRepository repository,
|
||||||
|
StoreRepository storeRepository)
|
||||||
|
{
|
||||||
|
_JobClient = jobClient;
|
||||||
|
_Repository = repository;
|
||||||
|
_StoreRepository = storeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEmailSender GetEmailSender(string storeId = null)
|
||||||
|
{
|
||||||
|
var serverSender = new ServerEmailSender(_Repository, _JobClient);
|
||||||
|
if (string.IsNullOrEmpty(storeId))
|
||||||
|
return serverSender;
|
||||||
|
return new StoreEmailSender(_StoreRepository, serverSender, _JobClient, storeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,6 @@ namespace BTCPayServer.Services.Mails
|
|||||||
{
|
{
|
||||||
public interface IEmailSender
|
public interface IEmailSender
|
||||||
{
|
{
|
||||||
Task SendEmailAsync(string email, string subject, string message);
|
void SendEmail(string email, string subject, string message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
BTCPayServer/Services/Mails/ServerEmailSender.cs
Normal file
25
BTCPayServer/Services/Mails/ServerEmailSender.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services.Mails
|
||||||
|
{
|
||||||
|
class ServerEmailSender : EmailSender
|
||||||
|
{
|
||||||
|
public ServerEmailSender(SettingsRepository settingsRepository,
|
||||||
|
IBackgroundJobClient backgroundJobClient) : base(backgroundJobClient)
|
||||||
|
{
|
||||||
|
if (settingsRepository == null)
|
||||||
|
throw new ArgumentNullException(nameof(settingsRepository));
|
||||||
|
SettingsRepository = settingsRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsRepository SettingsRepository { get; }
|
||||||
|
|
||||||
|
public override Task<EmailSettings> GetEmailSettings()
|
||||||
|
{
|
||||||
|
return SettingsRepository.GetSettingAsync<EmailSettings>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
BTCPayServer/Services/Mails/StoreEmailSender.cs
Normal file
38
BTCPayServer/Services/Mails/StoreEmailSender.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services.Mails
|
||||||
|
{
|
||||||
|
class StoreEmailSender : EmailSender
|
||||||
|
{
|
||||||
|
public StoreEmailSender(StoreRepository storeRepository,
|
||||||
|
EmailSender fallback,
|
||||||
|
IBackgroundJobClient backgroundJobClient,
|
||||||
|
string storeId) : base(backgroundJobClient)
|
||||||
|
{
|
||||||
|
if (storeId == null)
|
||||||
|
throw new ArgumentNullException(nameof(storeId));
|
||||||
|
StoreRepository = storeRepository;
|
||||||
|
FallbackSender = fallback;
|
||||||
|
StoreId = storeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoreRepository StoreRepository { get; }
|
||||||
|
public EmailSender FallbackSender { get; }
|
||||||
|
public string StoreId { get; }
|
||||||
|
|
||||||
|
public override async Task<EmailSettings> GetEmailSettings()
|
||||||
|
{
|
||||||
|
var store = await StoreRepository.FindStore(StoreId);
|
||||||
|
var emailSettings = store.GetStoreBlob().EmailSettings;
|
||||||
|
if (emailSettings?.IsComplete() == true)
|
||||||
|
{
|
||||||
|
return emailSettings;
|
||||||
|
}
|
||||||
|
return await FallbackSender.GetEmailSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
BTCPayServer/Views/Stores/Emails.cshtml
Normal file
68
BTCPayServer/Views/Stores/Emails.cshtml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
@model BTCPayServer.Models.ServerViewModels.EmailsViewModel
|
||||||
|
@{
|
||||||
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
|
ViewData.SetActivePageAndTitle(StoreNavPages.Index, "Update Store Email Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
<partial name="_StatusMessage" for="StatusMessage" />
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.Server"></label>
|
||||||
|
<input asp-for="Settings.Server" class="form-control" />
|
||||||
|
<span asp-validation-for="Settings.Server" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.Port"></label>
|
||||||
|
<input asp-for="Settings.Port" class="form-control" />
|
||||||
|
<span asp-validation-for="Settings.Port" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.From"></label>
|
||||||
|
<input asp-for="Settings.From" class="form-control" />
|
||||||
|
<span asp-validation-for="Settings.From" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.Login"></label>
|
||||||
|
<input asp-for="Settings.Login" class="form-control" />
|
||||||
|
<span asp-validation-for="Settings.Login" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.Password"></label>
|
||||||
|
<input asp-for="Settings.Password" type="password" class="form-control" />
|
||||||
|
<span asp-validation-for="Settings.Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Settings.EnableSSL"></label>
|
||||||
|
<input asp-for="Settings.EnableSSL" type="checkbox" class="form-check-inline" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="TestEmail"></label>
|
||||||
|
<input asp-for="TestEmail" class="form-control" />
|
||||||
|
<span asp-validation-for="TestEmail" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
|
||||||
|
<button type="submit" class="btn btn-primary" name="command" value="Test">Test</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@await Html.PartialAsync("_ValidationScriptsPartial")
|
||||||
|
}
|
||||||
@@ -214,7 +214,29 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-group">
|
||||||
|
<h5>Services</h5>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<table class="table table-sm table-responsive-md">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Service</th>
|
||||||
|
<th style="text-align:right">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Email
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right"><a asp-action="Emails" >Modify</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@if(Model.CanDelete)
|
@if(Model.CanDelete)
|
||||||
{
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
Reference in New Issue
Block a user