diff --git a/Server/API/OrganizationManagementController.cs b/Server/API/OrganizationManagementController.cs index fae69529..515e2f0c 100644 --- a/Server/API/OrganizationManagementController.cs +++ b/Server/API/OrganizationManagementController.cs @@ -24,7 +24,7 @@ namespace Remotely.Server.API [ApiController] public class OrganizationManagementController : ControllerBase { - public OrganizationManagementController(DataService dataService, UserManager userManager, IEmailSender emailSender) + public OrganizationManagementController(DataService dataService, UserManager 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 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", $@"

Hello!

You've been invited to join an organization in Remotely.

- You can join the organization by clicking here."); + You can join the organization by clicking here.", + orgID); + + if (!emailResult) + { + return Problem("There was an error sending the invitation email."); + } return Ok(); } diff --git a/Server/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs b/Server/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs index 6f9ec063..cf66254e 100644 --- a/Server/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/ForgotPassword.cshtml.cs @@ -19,11 +19,11 @@ namespace Remotely.Server.Areas.Identity.Pages.Account public class ForgotPasswordModel : PageModel { private readonly UserManager _userManager; - private readonly IEmailSender _emailSender; + private readonly IEmailSenderEx _emailSender; private DataService DataService { get; } - public ForgotPasswordModel(UserManager userManager, IEmailSender emailSender, DataService dataService) + public ForgotPasswordModel(UserManager 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", $"

Please reset your Remotely password by clicking here."); + if (!emailResult) + { + ModelState.AddModelError("EmailError", "Error sending email."); + return Page(); + } + + return RedirectToPage("./ForgotPasswordConfirmation"); } diff --git a/Server/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs b/Server/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs index 0d9d9423..fa910340 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/Manage/Index.cshtml.cs @@ -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 _userManager; private readonly SignInManager _signInManager; - private readonly IEmailSender _emailSender; + private readonly IEmailSenderEx _emailSender; public IndexModel( UserManager userManager, SignInManager 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", - $"

Please confirm your Remotely account by clicking here."); + $"

Please confirm your Remotely account by clicking here.", + 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(); } } diff --git a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs index 4a0d76c9..de135f6b 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs @@ -18,7 +18,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage { public class OrganizationModel : PageModel { - public OrganizationModel(DataService dataService, UserManager userManager, IEmailSender emailSender) + public OrganizationModel(DataService dataService, UserManager 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 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", - $@" + var emailResult = await EmailSender.SendEmailAsync(invite.InvitedUser, "Invitation to Organization in Remotely", + $@"

Hello!

You've been invited to join an organization in Remotely.

- You can join the organization by clicking here."); - - StatusMessage = "Invitation sent."; + You can join the organization by clicking here.", + currentUser.OrganizationID); + if (emailResult) + { + StatusMessage = "Invitation sent."; + } + else + { + StatusMessage = "Error sending invititation email."; + } return RedirectToPage(); } diff --git a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml index 5cf00258..97367aa4 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml +++ b/Server/Areas/Identity/Pages/Account/Manage/ServerConfig.cshtml @@ -56,7 +56,7 @@

- @@ -170,9 +170,9 @@

-
@@ -233,8 +233,8 @@

-
diff --git a/Server/Areas/Identity/Pages/Account/Register.cshtml.cs b/Server/Areas/Identity/Pages/Account/Register.cshtml.cs index 746d7ac6..659f5ce3 100644 --- a/Server/Areas/Identity/Pages/Account/Register.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/Register.cshtml.cs @@ -25,7 +25,7 @@ namespace Remotely.Server.Areas.Identity.Pages.Account private readonly SignInManager _signInManager; private readonly UserManager _userManager; private readonly ILogger _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 userManager, SignInManager signInManager, ILogger logger, - IEmailSender emailSender, + IEmailSenderEx emailSender, DataService dataService, ApplicationConfig appConfig) { diff --git a/Server/Services/DataService.cs b/Server/Services/DataService.cs index c17c29eb..0b046728 100644 --- a/Server/Services/DataService.cs +++ b/Server/Services/DataService.cs @@ -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 { } } } } diff --git a/Server/Services/DeviceSocketHub.cs b/Server/Services/DeviceSocketHub.cs index d5bc15b5..67d9d9a0 100644 --- a/Server/Services/DeviceSocketHub.cs +++ b/Server/Services/DeviceSocketHub.cs @@ -109,7 +109,7 @@ namespace Remotely.Server.Services } catch (Exception ex) { - DataService.WriteEvent(ex); + DataService.WriteEvent(ex, Device?.OrganizationID); } Context.Abort(); diff --git a/Server/Services/EmailSender.cs b/Server/Services/EmailSender.cs index db912ad1..7eacd98a 100644 --- a/Server/Services/EmailSender.cs +++ b/Server/Services/EmailSender.cs @@ -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 SendEmailAsync(string email, string replyTo, string subject, string htmlMessage, string organizationID = null); + Task 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 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 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); } } + } diff --git a/Server/Startup.cs b/Server/Startup.cs index 39268b0f..41869fa9 100644 --- a/Server/Startup.cs +++ b/Server/Startup.cs @@ -166,7 +166,8 @@ namespace Remotely.Server }); services.AddLogging(); - services.AddScoped();; + services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); diff --git a/Tests/IoCActivator.cs b/Tests/IoCActivator.cs index 93e0ed7b..586b8c75 100644 --- a/Tests/IoCActivator.cs +++ b/Tests/IoCActivator.cs @@ -57,7 +57,7 @@ namespace Remotely.Tests services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); IoCActivator.ServiceProvider = services.BuildServiceProvider(); } diff --git a/Tests/TestData.cs b/Tests/TestData.cs index 224e03cd..999d717b 100644 --- a/Tests/TestData.cs +++ b/Tests/TestData.cs @@ -78,7 +78,7 @@ namespace Remotely.Tests { var dataService = IoCActivator.ServiceProvider.GetRequiredService(); var userManager = IoCActivator.ServiceProvider.GetRequiredService>(); - var emailSender = IoCActivator.ServiceProvider.GetRequiredService(); + var emailSender = IoCActivator.ServiceProvider.GetRequiredService(); var organizationModel = new OrganizationModel(dataService, userManager, emailSender);