417 lines
18 KiB
C#
417 lines
18 KiB
C#
using Google.Apis.Auth.OAuth2;
|
|
using Google.Apis.Auth.OAuth2.Flows;
|
|
using Google.Apis.Auth.OAuth2.Responses;
|
|
using Google.Apis.Auth.OAuth2.Web;
|
|
using Google.Apis.Util.Store;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Nop.Core;
|
|
using Nop.Core.Domain.Customers;
|
|
using Nop.Core.Domain.Messages;
|
|
using Nop.Core.Infrastructure;
|
|
using Nop.Services.Common;
|
|
using Nop.Services.Configuration;
|
|
using Nop.Services.Localization;
|
|
using Nop.Services.Logging;
|
|
using Nop.Services.Messages;
|
|
using Nop.Services.Security;
|
|
using Nop.Web.Areas.Admin.Factories;
|
|
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
|
|
using Nop.Web.Areas.Admin.Models.Messages;
|
|
using Nop.Web.Framework.Controllers;
|
|
using Nop.Web.Framework.Mvc.Filters;
|
|
|
|
namespace Nop.Web.Areas.Admin.Controllers;
|
|
|
|
public partial class EmailAccountController : BaseAdminController
|
|
{
|
|
#region Fields
|
|
|
|
private const char SEPARATOR = '-';
|
|
|
|
protected readonly EmailAccountSettings _emailAccountSettings;
|
|
protected readonly ICustomerActivityService _customerActivityService;
|
|
protected readonly IEmailAccountModelFactory _emailAccountModelFactory;
|
|
protected readonly IEmailAccountService _emailAccountService;
|
|
protected readonly IEmailSender _emailSender;
|
|
protected readonly IGenericAttributeService _genericAttributeService;
|
|
protected readonly ILocalizationService _localizationService;
|
|
protected readonly INopFileProvider _fileProvider;
|
|
protected readonly INotificationService _notificationService;
|
|
protected readonly IPermissionService _permissionService;
|
|
protected readonly ISettingService _settingService;
|
|
protected readonly IStoreContext _storeContext;
|
|
protected readonly IWebHelper _webHelper;
|
|
protected readonly IWorkContext _workContext;
|
|
|
|
#endregion
|
|
|
|
#region Ctor
|
|
|
|
public EmailAccountController(EmailAccountSettings emailAccountSettings,
|
|
ICustomerActivityService customerActivityService,
|
|
IEmailAccountModelFactory emailAccountModelFactory,
|
|
IEmailAccountService emailAccountService,
|
|
IEmailSender emailSender,
|
|
IGenericAttributeService genericAttributeService,
|
|
ILocalizationService localizationService,
|
|
INopFileProvider fileProvider,
|
|
INotificationService notificationService,
|
|
IPermissionService permissionService,
|
|
ISettingService settingService,
|
|
IStoreContext storeContext,
|
|
IWebHelper webHelper,
|
|
IWorkContext workContext)
|
|
{
|
|
_emailAccountSettings = emailAccountSettings;
|
|
_customerActivityService = customerActivityService;
|
|
_emailAccountModelFactory = emailAccountModelFactory;
|
|
_emailAccountService = emailAccountService;
|
|
_emailSender = emailSender;
|
|
_genericAttributeService = genericAttributeService;
|
|
_localizationService = localizationService;
|
|
_fileProvider = fileProvider;
|
|
_notificationService = notificationService;
|
|
_permissionService = permissionService;
|
|
_settingService = settingService;
|
|
_storeContext = storeContext;
|
|
_webHelper = webHelper;
|
|
_workContext = workContext;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utilities
|
|
|
|
protected virtual async Task<string> PrepareOAuthUrlAsync(EmailAccount emailAccount)
|
|
{
|
|
if (string.IsNullOrEmpty(emailAccount.ClientSecret) || string.IsNullOrEmpty(emailAccount.ClientId))
|
|
{
|
|
ModelState.AddModelError(nameof(EmailAccountModel.ClientSecret), await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Fields.ClientSecret.Required"));
|
|
return string.Empty;
|
|
}
|
|
|
|
var tokenFilePath = _fileProvider.MapPath(NopMessageDefaults.GmailAuthStorePath);
|
|
var credentialRoot = _fileProvider.Combine(tokenFilePath, emailAccount.Email);
|
|
|
|
var codeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
|
|
{
|
|
ClientSecrets = new ClientSecrets
|
|
{
|
|
ClientId = emailAccount.ClientId,
|
|
ClientSecret = emailAccount.ClientSecret
|
|
},
|
|
Scopes = NopMessageDefaults.GmailScopes,
|
|
DataStore = new FileDataStore(credentialRoot, true),
|
|
UserDefinedQueryParams = new Dictionary<string, string> { ["emailAccountId"] = emailAccount.Id.ToString() }
|
|
});
|
|
|
|
var redirectUri = Url.Action(nameof(AuthReturn), null, null, _webHelper.GetCurrentRequestProtocol());
|
|
var authCode = new AuthorizationCodeWebApp(codeFlow, redirectUri, $"{emailAccount.Id}{SEPARATOR}");
|
|
var authResult = await authCode.AuthorizeAsync(emailAccount.Email, CancellationToken.None);
|
|
|
|
return authResult.RedirectUri?.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> List(bool showtour = false)
|
|
{
|
|
//prepare model
|
|
var model = await _emailAccountModelFactory.PrepareEmailAccountSearchModelAsync(new EmailAccountSearchModel());
|
|
|
|
//show configuration tour
|
|
if (showtour)
|
|
{
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
var hideCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.HideConfigurationStepsAttribute);
|
|
var closeCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.CloseConfigurationStepsAttribute);
|
|
|
|
if (!hideCard && !closeCard)
|
|
ViewBag.ShowTour = true;
|
|
}
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> List(EmailAccountSearchModel searchModel)
|
|
{
|
|
//prepare model
|
|
var model = await _emailAccountModelFactory.PrepareEmailAccountListModelAsync(searchModel);
|
|
|
|
return Json(model);
|
|
}
|
|
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> MarkAsDefaultEmail(int id)
|
|
{
|
|
var defaultEmailAccount = await _emailAccountService.GetEmailAccountByIdAsync(id);
|
|
if (defaultEmailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
_emailAccountSettings.DefaultEmailAccountId = defaultEmailAccount.Id;
|
|
await _settingService.SaveSettingAsync(_emailAccountSettings);
|
|
|
|
return RedirectToAction("List");
|
|
}
|
|
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> Create()
|
|
{
|
|
//prepare model
|
|
var model = await _emailAccountModelFactory.PrepareEmailAccountModelAsync(new EmailAccountModel(), null);
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> Create(EmailAccountModel model, bool continueEditing)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var emailAccount = model.ToEntity<EmailAccount>();
|
|
|
|
//set password manually
|
|
emailAccount.Password = model.Password;
|
|
await _emailAccountService.InsertEmailAccountAsync(emailAccount);
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("AddNewEmailAccount",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.AddNewEmailAccount"), emailAccount.Id), emailAccount);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Added"));
|
|
|
|
return continueEditing ? RedirectToAction("Edit", new { id = emailAccount.Id }) : RedirectToAction("List");
|
|
}
|
|
|
|
//prepare model
|
|
model = await _emailAccountModelFactory.PrepareEmailAccountModelAsync(model, null, true);
|
|
|
|
//if we got this far, something failed, redisplay form
|
|
return View(model);
|
|
}
|
|
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> Edit(int id, bool showtour = false)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
//prepare model
|
|
var model = await _emailAccountModelFactory.PrepareEmailAccountModelAsync(null, emailAccount);
|
|
|
|
if (emailAccount.EmailAuthenticationMethod == EmailAuthenticationMethod.GmailOAuth2)
|
|
model.AuthUrl = await PrepareOAuthUrlAsync(emailAccount);
|
|
|
|
//show configuration tour
|
|
if (showtour)
|
|
{
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
var hideCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.HideConfigurationStepsAttribute);
|
|
var closeCard = await _genericAttributeService.GetAttributeAsync<bool>(customer, NopCustomerDefaults.CloseConfigurationStepsAttribute);
|
|
|
|
if (!hideCard && !closeCard)
|
|
ViewBag.ShowTour = true;
|
|
}
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
|
|
[FormValueRequired("save", "save-continue")]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> Edit(EmailAccountModel model, bool continueEditing)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(model.Id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
emailAccount = model.ToEntity(emailAccount);
|
|
await _emailAccountService.UpdateEmailAccountAsync(emailAccount);
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("EditEmailAccount",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditEmailAccount"), emailAccount.Id), emailAccount);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Updated"));
|
|
|
|
return continueEditing ? RedirectToAction("Edit", new { id = emailAccount.Id }) : RedirectToAction("List");
|
|
}
|
|
|
|
//prepare model
|
|
model = await _emailAccountModelFactory.PrepareEmailAccountModelAsync(model, emailAccount, true);
|
|
|
|
if (emailAccount.EmailAuthenticationMethod == EmailAuthenticationMethod.GmailOAuth2)
|
|
model.AuthUrl = await PrepareOAuthUrlAsync(emailAccount);
|
|
|
|
//if we got this far, something failed, redisplay form
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost, ActionName("Edit")]
|
|
[FormValueRequired("changesecret")]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> ChangeSecret(EmailAccountModel model)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(model.Id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
//do not validate model
|
|
emailAccount.ClientSecret = model.ClientSecret;
|
|
await _emailAccountService.UpdateEmailAccountAsync(emailAccount);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Fields.ClientSecret.ClientSecretChanged"));
|
|
|
|
return RedirectToAction("Edit", new { id = emailAccount.Id });
|
|
}
|
|
|
|
[HttpPost, ActionName("Edit")]
|
|
[FormValueRequired("changepassword")]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> ChangePassword(EmailAccountModel model)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(model.Id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
//do not validate model
|
|
emailAccount.Password = model.Password;
|
|
await _emailAccountService.UpdateEmailAccountAsync(emailAccount);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Fields.Password.PasswordChanged"));
|
|
|
|
return RedirectToAction("Edit", new { id = emailAccount.Id });
|
|
}
|
|
|
|
[HttpPost, ActionName("Edit")]
|
|
[FormValueRequired("sendtestemail")]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> SendTestEmail(EmailAccountModel model)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(model.Id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
if (!CommonHelper.IsValidEmail(model.SendTestEmailTo))
|
|
{
|
|
_notificationService.ErrorNotification(await _localizationService.GetResourceAsync("Admin.Common.WrongEmail"));
|
|
return View(await _emailAccountModelFactory.PrepareEmailAccountModelAsync(model, emailAccount, true));
|
|
}
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(model.SendTestEmailTo))
|
|
throw new NopException("Enter test email address");
|
|
var store = await _storeContext.GetCurrentStoreAsync();
|
|
var subject = store.Name + ". Testing email functionality.";
|
|
var body = "Email works fine.";
|
|
await _emailSender.SendEmailAsync(emailAccount, subject, body, emailAccount.Email, emailAccount.DisplayName, model.SendTestEmailTo, null);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.SendTestEmail.Success"));
|
|
|
|
return RedirectToAction("Edit", new { id = emailAccount.Id });
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
_notificationService.ErrorNotification(exc.Message);
|
|
}
|
|
|
|
//prepare model
|
|
model = await _emailAccountModelFactory.PrepareEmailAccountModelAsync(model, emailAccount, true);
|
|
|
|
//if we got this far, something failed, redisplay form
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
[CheckPermission(StandardPermission.Configuration.MANAGE_EMAIL_ACCOUNTS)]
|
|
public virtual async Task<IActionResult> Delete(int id)
|
|
{
|
|
//try to get an email account with the specified id
|
|
var emailAccount = await _emailAccountService.GetEmailAccountByIdAsync(id);
|
|
if (emailAccount == null)
|
|
return RedirectToAction("List");
|
|
|
|
try
|
|
{
|
|
await _emailAccountService.DeleteEmailAccountAsync(emailAccount);
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("DeleteEmailAccount",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteEmailAccount"), emailAccount.Id), emailAccount);
|
|
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.Configuration.EmailAccounts.Deleted"));
|
|
|
|
return RedirectToAction("List");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
await _notificationService.ErrorNotificationAsync(exc);
|
|
return RedirectToAction("Edit", new { id = emailAccount.Id });
|
|
}
|
|
}
|
|
|
|
public async Task<IActionResult> AuthReturn(AuthorizationCodeResponseUrl authorizationCode)
|
|
{
|
|
if (string.IsNullOrEmpty(authorizationCode.State))
|
|
return RedirectToAction(nameof(List));
|
|
|
|
var strAccountId = authorizationCode.State.Split(SEPARATOR).FirstOrDefault();
|
|
|
|
if (!int.TryParse(strAccountId, out var accountId) ||
|
|
await _emailAccountService.GetEmailAccountByIdAsync(accountId) is not EmailAccount emailAccount)
|
|
{
|
|
_notificationService.ErrorNotification("Email account could not be loaded");
|
|
return RedirectToAction(nameof(List));
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(authorizationCode.Error))
|
|
{
|
|
_notificationService.ErrorNotification(authorizationCode.Error);
|
|
return RedirectToAction(nameof(Edit), new { id = emailAccount.Id });
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(authorizationCode?.Code))
|
|
return RedirectToAction(nameof(Edit), new { id = emailAccount.Id });
|
|
|
|
var tokenFilePath = _fileProvider.MapPath(NopMessageDefaults.GmailAuthStorePath);
|
|
var credentialRoot = _fileProvider.Combine(tokenFilePath, emailAccount.Email);
|
|
|
|
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
|
|
{
|
|
ClientSecrets = new ClientSecrets
|
|
{
|
|
ClientId = emailAccount.ClientId,
|
|
ClientSecret = emailAccount.ClientSecret
|
|
},
|
|
Scopes = NopMessageDefaults.GmailScopes,
|
|
DataStore = new FileDataStore(credentialRoot, true)
|
|
});
|
|
|
|
var redirectUri = Url.Action(nameof(AuthReturn), null, null, _webHelper.GetCurrentRequestProtocol());
|
|
var tokenResponse = await flow.ExchangeCodeForTokenAsync(emailAccount.Email, authorizationCode.Code, redirectUri, CancellationToken.None);
|
|
|
|
if (tokenResponse is null || tokenResponse.IsStale)
|
|
return RedirectToAction(nameof(Edit), new { id = emailAccount.Id });
|
|
|
|
_notificationService.SuccessNotification("The token was successfully retrieved from the server");
|
|
|
|
return RedirectToAction(nameof(Edit), new { id = emailAccount.Id });
|
|
}
|
|
|
|
#endregion
|
|
} |