mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Added EmailSenderEx. Improve error handling and reporting of email failures.
This commit is contained in:
parent
5b852ae474
commit
ac52bd5559
@ -24,7 +24,7 @@ namespace Remotely.Server.API
|
||||
[ApiController]
|
||||
public class OrganizationManagementController : ControllerBase
|
||||
{
|
||||
public OrganizationManagementController(DataService dataService, UserManager<RemotelyUser> userManager, IEmailSender emailSender)
|
||||
public OrganizationManagementController(DataService dataService, UserManager<RemotelyUser> userManager, IEmailSenderEx emailSender)
|
||||
{
|
||||
this.DataService = dataService;
|
||||
this.UserManager = userManager;
|
||||
@ -32,7 +32,7 @@ namespace Remotely.Server.API
|
||||
}
|
||||
|
||||
private DataService DataService { get; }
|
||||
private IEmailSender EmailSender { get; }
|
||||
private IEmailSenderEx EmailSender { get; }
|
||||
private UserManager<RemotelyUser> UserManager { get; }
|
||||
|
||||
|
||||
@ -268,14 +268,20 @@ namespace Remotely.Server.API
|
||||
var newInvite = DataService.AddInvite(orgID, invite);
|
||||
|
||||
var inviteURL = $"{Request.Scheme}://{Request.Host}/Invite?id={newInvite.ID}";
|
||||
await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
||||
var emailResult = await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
||||
$@"<img src='https://remotely.one/media/Remotely_Logo.png'/>
|
||||
<br><br>
|
||||
Hello!
|
||||
<br><br>
|
||||
You've been invited to join an organization in Remotely.
|
||||
<br><br>
|
||||
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.");
|
||||
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.",
|
||||
orgID);
|
||||
|
||||
if (!emailResult)
|
||||
{
|
||||
return Problem("There was an error sending the invitation email.");
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -19,11 +19,11 @@ namespace Remotely.Server.Areas.Identity.Pages.Account
|
||||
public class ForgotPasswordModel : PageModel
|
||||
{
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly IEmailSenderEx _emailSender;
|
||||
|
||||
private DataService DataService { get; }
|
||||
|
||||
public ForgotPasswordModel(UserManager<RemotelyUser> userManager, IEmailSender emailSender, DataService dataService)
|
||||
public ForgotPasswordModel(UserManager<RemotelyUser> userManager, IEmailSenderEx emailSender, DataService dataService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_emailSender = emailSender;
|
||||
@ -63,11 +63,18 @@ namespace Remotely.Server.Areas.Identity.Pages.Account
|
||||
|
||||
DataService.WriteEvent($"Sending password reset for user {user.UserName}. Reset URL: {callbackUrl}", user.OrganizationID);
|
||||
|
||||
await _emailSender.SendEmailAsync(
|
||||
var emailResult = await _emailSender.SendEmailAsync(
|
||||
Input.Email,
|
||||
"Reset Password",
|
||||
$"<img src='https://remotely.one/media/Remotely_Logo.png'/><br><br>Please reset your Remotely password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
|
||||
if (!emailResult)
|
||||
{
|
||||
ModelState.AddModelError("EmailError", "Error sending email.");
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
||||
return RedirectToPage("./ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
|
||||
@ -7,11 +7,11 @@ using System.Threading.Tasks;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Server.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using System.Text;
|
||||
using Remotely.Server.Services;
|
||||
|
||||
namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
{
|
||||
@ -19,12 +19,12 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
{
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly SignInManager<RemotelyUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly IEmailSenderEx _emailSender;
|
||||
|
||||
public IndexModel(
|
||||
UserManager<RemotelyUser> userManager,
|
||||
SignInManager<RemotelyUser> signInManager,
|
||||
IEmailSender emailSender)
|
||||
IEmailSenderEx emailSender)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
@ -131,7 +131,6 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
}
|
||||
|
||||
|
||||
var userId = await _userManager.GetUserIdAsync(user);
|
||||
var email = await _userManager.GetEmailAsync(user);
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||
@ -140,12 +139,20 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
pageHandler: null,
|
||||
values: new { area = "Identity", userId = user.Id, code = code },
|
||||
protocol: Request.Scheme);
|
||||
await _emailSender.SendEmailAsync(
|
||||
var emailResult = await _emailSender.SendEmailAsync(
|
||||
email,
|
||||
"Confirm your email",
|
||||
$"<img src='https://remotely.one/media/Remotely_Logo.png'/><br><br>Please confirm your Remotely account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
$"<img src='https://remotely.one/media/Remotely_Logo.png'/><br><br>Please confirm your Remotely account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.",
|
||||
user.OrganizationID);
|
||||
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
if (!emailResult)
|
||||
{
|
||||
StatusMessage = "Error sending verification email.";
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusMessage = "Verification email sent. Please check your email.";
|
||||
}
|
||||
return RedirectToPage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
{
|
||||
public class OrganizationModel : PageModel
|
||||
{
|
||||
public OrganizationModel(DataService dataService, UserManager<RemotelyUser> userManager, IEmailSender emailSender)
|
||||
public OrganizationModel(DataService dataService, UserManager<RemotelyUser> userManager, IEmailSenderEx emailSender)
|
||||
{
|
||||
DataService = dataService;
|
||||
UserManager = userManager;
|
||||
@ -45,7 +45,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
|
||||
private DataService DataService { get; }
|
||||
|
||||
private IEmailSender EmailSender { get; }
|
||||
private IEmailSenderEx EmailSender { get; }
|
||||
|
||||
private UserManager<RemotelyUser> UserManager { get; }
|
||||
|
||||
@ -127,16 +127,23 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
|
||||
var newInvite = DataService.AddInvite(currentUser.OrganizationID, invite);
|
||||
|
||||
var inviteURL = $"{Request.Scheme}://{Request.Host}/Invite?id={newInvite.ID}";
|
||||
await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
||||
$@"<img src='https://remotely.one/media/Remotely_Logo.png'/>
|
||||
var emailResult = await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely",
|
||||
$@"<img src='https://remotely.one/media/Remotely_Logo.png'/>
|
||||
<br><br>
|
||||
Hello!
|
||||
<br><br>
|
||||
You've been invited to join an organization in Remotely.
|
||||
<br><br>
|
||||
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.");
|
||||
|
||||
StatusMessage = "Invitation sent.";
|
||||
You can join the organization by <a href='{HtmlEncoder.Default.Encode(inviteURL)}'>clicking here</a>.",
|
||||
currentUser.OrganizationID);
|
||||
if (emailResult)
|
||||
{
|
||||
StatusMessage = "Invitation sent.";
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusMessage = "Error sending invititation email.";
|
||||
}
|
||||
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="form-group">
|
||||
<label asp-for="AppSettingsInput.KnownProxies" class="control-label"></label>
|
||||
<br />
|
||||
<select id="knownProxiesSelect"
|
||||
<select id="knownProxiesSelect"
|
||||
asp-for="AppSettingsInput.KnownProxies"
|
||||
asp-items="Model.AppSettingsInput.KnownProxies?.Select(x=>new SelectListItem(x,x))"
|
||||
class="form-control"></select>
|
||||
@ -170,9 +170,9 @@
|
||||
<div class="form-group">
|
||||
<label asp-for="AppSettingsInput.TrustedCorsOrigins" class="control-label"></label>
|
||||
<br />
|
||||
<select id="trustedCorsSelect"
|
||||
asp-for="AppSettingsInput.TrustedCorsOrigins"
|
||||
asp-items="Model.AppSettingsInput.TrustedCorsOrigins?.Select(x=>new SelectListItem(x,x))"
|
||||
<select id="trustedCorsSelect"
|
||||
asp-for="AppSettingsInput.TrustedCorsOrigins"
|
||||
asp-items="Model.AppSettingsInput.TrustedCorsOrigins?.Select(x=>new SelectListItem(x,x))"
|
||||
class="form-control"></select>
|
||||
|
||||
<div class="text-right mb-2 mt-1">
|
||||
@ -233,8 +233,8 @@
|
||||
<div class="form-group">
|
||||
<label asp-for="ServerAdmins" class="control-label"></label>
|
||||
<br />
|
||||
<select id="serverAdminsSelect"
|
||||
asp-for="ServerAdmins"
|
||||
<select id="serverAdminsSelect"
|
||||
asp-for="ServerAdmins"
|
||||
asp-items="Model.ServerAdmins?.Select(x=>new SelectListItem(x,x))"
|
||||
class="form-control"></select>
|
||||
<div class="text-right mb-2 mt-1">
|
||||
|
||||
@ -25,7 +25,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account
|
||||
private readonly SignInManager<RemotelyUser> _signInManager;
|
||||
private readonly UserManager<RemotelyUser> _userManager;
|
||||
private readonly ILogger<RegisterModel> _logger;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly IEmailSenderEx _emailSender;
|
||||
private readonly DataService _dataService;
|
||||
private readonly ApplicationConfig _appConfig;
|
||||
|
||||
@ -33,7 +33,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account
|
||||
UserManager<RemotelyUser> userManager,
|
||||
SignInManager<RemotelyUser> signInManager,
|
||||
ILogger<RegisterModel> logger,
|
||||
IEmailSender emailSender,
|
||||
IEmailSenderEx emailSender,
|
||||
DataService dataService,
|
||||
ApplicationConfig appConfig)
|
||||
{
|
||||
|
||||
@ -288,7 +288,7 @@ namespace Remotely.Server.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteEvent(ex);
|
||||
WriteEvent(ex, organizationID);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -851,45 +851,62 @@ namespace Remotely.Server.Services
|
||||
}
|
||||
public void WriteEvent(EventLog eventLog)
|
||||
{
|
||||
RemotelyContext.EventLogs.Add(eventLog);
|
||||
RemotelyContext.SaveChanges();
|
||||
try
|
||||
{
|
||||
RemotelyContext.EventLogs.Add(eventLog);
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void WriteEvent(Exception ex)
|
||||
public void WriteEvent(Exception ex, string organizationID = null)
|
||||
{
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
try
|
||||
{
|
||||
EventType = EventType.Error,
|
||||
Message = ex.Message,
|
||||
Source = ex.Source,
|
||||
StackTrace = ex.StackTrace,
|
||||
TimeStamp = DateTimeOffset.Now
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
{
|
||||
EventType = EventType.Error,
|
||||
Message = ex.Message,
|
||||
Source = ex.Source,
|
||||
StackTrace = ex.StackTrace,
|
||||
TimeStamp = DateTimeOffset.Now,
|
||||
OrganizationID = organizationID
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void WriteEvent(string message, string organizationId)
|
||||
public void WriteEvent(string message, string organizationID)
|
||||
{
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
try
|
||||
{
|
||||
EventType = EventType.Info,
|
||||
Message = message,
|
||||
TimeStamp = DateTimeOffset.Now,
|
||||
OrganizationID = organizationId
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
{
|
||||
EventType = EventType.Info,
|
||||
Message = message,
|
||||
TimeStamp = DateTimeOffset.Now,
|
||||
OrganizationID = organizationID
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void WriteEvent(string message, EventType eventType, string organizationId)
|
||||
public void WriteEvent(string message, EventType eventType, string organizationID)
|
||||
{
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
try
|
||||
{
|
||||
EventType = eventType,
|
||||
Message = message,
|
||||
TimeStamp = DateTimeOffset.Now,
|
||||
OrganizationID = organizationId
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
RemotelyContext.EventLogs.Add(new EventLog()
|
||||
{
|
||||
EventType = eventType,
|
||||
Message = message,
|
||||
TimeStamp = DateTimeOffset.Now,
|
||||
OrganizationID = organizationID
|
||||
});
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ namespace Remotely.Server.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DataService.WriteEvent(ex);
|
||||
DataService.WriteEvent(ex, Device?.OrganizationID);
|
||||
}
|
||||
|
||||
Context.Abort();
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Remotely.Server.Data;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -8,12 +7,19 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
|
||||
namespace Remotely.Server.Services
|
||||
{
|
||||
public class EmailSender : IEmailSender
|
||||
public interface IEmailSenderEx
|
||||
{
|
||||
public EmailSender(ApplicationConfig appConfig, DataService dataService)
|
||||
Task<bool> SendEmailAsync(string email, string replyTo, string subject, string htmlMessage, string organizationID = null);
|
||||
Task<bool> SendEmailAsync(string email, string subject, string htmlMessage, string organizationID = null);
|
||||
}
|
||||
|
||||
public class EmailSenderEx : IEmailSenderEx
|
||||
{
|
||||
public EmailSenderEx(ApplicationConfig appConfig, DataService dataService)
|
||||
{
|
||||
AppConfig = appConfig;
|
||||
DataService = dataService;
|
||||
@ -22,7 +28,7 @@ namespace Remotely.Server.Services
|
||||
private ApplicationConfig AppConfig { get; }
|
||||
private DataService DataService { get; }
|
||||
|
||||
public Task SendEmailAsync(string email, string replyTo, string subject, string htmlMessage)
|
||||
public Task<bool> SendEmailAsync(string email, string replyTo, string subject, string htmlMessage, string organizationID = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -42,17 +48,33 @@ namespace Remotely.Server.Services
|
||||
mailMessage.Body = htmlMessage;
|
||||
mailMessage.ReplyToList.Add(new MailAddress(replyTo));
|
||||
mailClient.Send(mailMessage);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DataService.WriteEvent(ex);
|
||||
DataService.WriteEvent(ex, organizationID);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<bool> SendEmailAsync(string email, string subject, string htmlMessage, string organizationID = null)
|
||||
{
|
||||
return SendEmailAsync(email, AppConfig.SmtpEmail, subject, htmlMessage, organizationID);
|
||||
}
|
||||
}
|
||||
public class EmailSender : IEmailSender
|
||||
{
|
||||
public EmailSender(IEmailSenderEx emailSenderEx)
|
||||
{
|
||||
EmailSenderEx = emailSenderEx;
|
||||
}
|
||||
|
||||
private IEmailSenderEx EmailSenderEx { get; }
|
||||
|
||||
public Task SendEmailAsync(string email, string subject, string htmlMessage)
|
||||
{
|
||||
return SendEmailAsync(email, AppConfig.SmtpEmail, subject, htmlMessage);
|
||||
return EmailSenderEx.SendEmailAsync(email, subject, htmlMessage, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -166,7 +166,8 @@ namespace Remotely.Server
|
||||
});
|
||||
|
||||
services.AddLogging();
|
||||
services.AddScoped<IEmailSender, EmailSender>();;
|
||||
services.AddScoped<IEmailSenderEx, EmailSenderEx>();
|
||||
services.AddScoped<IEmailSender, EmailSender>();
|
||||
services.AddScoped<DataService>();
|
||||
services.AddScoped<RemoteControlSessionRecorder>();
|
||||
services.AddSingleton<ApplicationConfig>();
|
||||
|
||||
@ -57,7 +57,7 @@ namespace Remotely.Tests
|
||||
|
||||
services.AddTransient<DataService>();
|
||||
services.AddTransient<ApplicationConfig>();
|
||||
services.AddTransient<IEmailSender, EmailSender>();
|
||||
services.AddTransient<IEmailSenderEx, EmailSenderEx>();
|
||||
IoCActivator.ServiceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ namespace Remotely.Tests
|
||||
{
|
||||
var dataService = IoCActivator.ServiceProvider.GetRequiredService<DataService>();
|
||||
var userManager = IoCActivator.ServiceProvider.GetRequiredService<UserManager<RemotelyUser>>();
|
||||
var emailSender = IoCActivator.ServiceProvider.GetRequiredService<IEmailSender>();
|
||||
var emailSender = IoCActivator.ServiceProvider.GetRequiredService<IEmailSenderEx>();
|
||||
var organizationModel = new OrganizationModel(dataService, userManager, emailSender);
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user