private void NotifyOrgAdminAboutApprovedRequest(Organisation organisation, OrgUser orgUser) { if (organisation.RootUserId.HasValue) { var orgAdmin = UnitOfWork.OrgUsersRepository .AllAsNoTracking .Where(x => x.Id == organisation.RootUserId.Value) .SingleOrDefault(); var rootIndex = WebHelpers.GetRootIndexPath(); var url = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}#!/users/mobile/"; var emailBody = @"<p>A new user has joined your organisation: <strong>" + orgUser.UserName + @"</strong>.</p> <p>The user's personal case is now filed under your organisation and you have access to it.</p> <p>You can remove this user whenever you like, and put them back under OnRecord.</p> <p><br></p> <p>View the <a href='" + url + @"'>directory of mobile users</a> on the dashboard.</p>"; var orgAdminEmail = new Email { To = orgAdmin.Email, Subject = $"User joined organization - {orgUser.UserName}", Content = WebHelpers.GenerateEmailTemplate(emailBody, "A user has joined your organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(orgAdminEmail); } }
private void NotifyEmailRecipientsAboutNewRequest(string organisationName) { var recipients = UnitOfWork.EmailRecipientsRepository .AllAsNoTracking .Where(x => x.OrgConnectionRequests == true) .ToList(); var rootIndex = WebHelpers.GetRootIndexPath(); var url = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}#!/organisations/connection-requests/"; var emailContent = @"<p>User name: <b>" + CurrentOrgUser.UserName + @"</b></p> <p>Organisation: <b>" + organisationName + @"</b></p> <p><br></p> <p>View <a href='" + url + @"'>connection requests</a> on the dashboard.</p>"; foreach (var recipient in recipients) { var recipientEmail = new Email { To = recipient.OrgUser.Email, Subject = $"A user has request to join an organization", Content = WebHelpers.GenerateEmailTemplate(emailContent, "A user has requested to join an organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(recipientEmail); } }
public IHttpActionResult SendEmail(SendEmailDTO value) { if (string.IsNullOrEmpty(value.EmailAddress)) { return(BadRequest("email address is required")); } if (string.IsNullOrEmpty(value.Body)) { return(BadRequest("email body is required")); } var email = new Email { To = value.EmailAddress, Subject = string.Format("Message from OnRecord - {0}", CurrentUser.UserName), Content = WebHelpers.GenerateEmailTemplate(value.Body, "Message from OnRecord") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); try { UnitOfWork.Save(); return(Ok()); } catch (Exception ex) { return(InternalServerError(ex)); } }
private void NotifyOrgAdminAboutNewRequest(Organisation organisation) { if (organisation.RootUser != null) { var orgAdmin = UnitOfWork.OrgUsersRepository .AllAsNoTracking .Where(x => x.Id == organisation.RootUser.Id) .SingleOrDefault(); var rootIndex = WebHelpers.GetRootIndexPath(); var url = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}#!/organisations/connection-requests/"; var content = @"<p>User name: <b>" + CurrentOrgUser.UserName + @"</b></p> <p><br></p> <p>View <a href='" + url + @"'>connection requests</a> on the dashboard.</p>"; var orgAdminEmail = new Email { To = orgAdmin.Email, Subject = $"A user has requested to join your organization", Content = WebHelpers.GenerateEmailTemplate(content, "A user has request to join your organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(orgAdminEmail); } }
public async Task <IHttpActionResult> SendEmailConfirmation(SendEmailConfirmationModel model) { var user = await UserManager.FindByEmailAsync(model.Email); if (user == null) { return(NotFound()); } if (user.EmailConfirmed) { return(Ok()); } var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); var encodedCode = HttpUtility.UrlEncode(code); var rootIndex = WebHelpers.GetRootIndexPath(); var baseUrl = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}"; var callbackUrl = $"{baseUrl}#!/verify-email?userId={user.Id}&code={encodedCode}"; var content = @"<p>Your new account has been created. To complete your registration please confirm your email address by clicking the link below.</p> <p><a href='" + callbackUrl + @"'>Verify Email Address</a></p>"; var messageBody = WebHelpers.GenerateEmailTemplate(content, "Confirm your registration"); await UserManager.SendEmailAsync(user.Id, "Confirm your account", messageBody); return(Ok()); }
private void NotifyUserAboutLeavingTeam(OrganisationTeam team, string userEmail) { var content = @"<p>You have left <strong>" + team.Name + @"</strong> from <strong>" + team.Organisation.Name + @"</strong>.</p>"; var email = new Email { To = userEmail, Subject = $"Left organization team - {team.Name}", Content = WebHelpers.GenerateEmailTemplate(content, "You have left a team") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); }
private void NotifyUserAboutVoucherSubscription() { var message = @"<p>You have redeemed your voucher code and are now subscribed.</p> <p>This subscription has a fixed monthly quota. If you need more space to continue please purchase a paid plan or join an organization.</p>"; var email = new Email { To = CurrentOrgUser.Email, Subject = $"Voucher Redeemed", Content = WebHelpers.GenerateEmailTemplate(message, "Voucher Redeemed") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); }
private void NotifyUserAboutLeavingOrganisation(string organisationName, string userEmail) { var userEmailContent = @"<p>You have left the <strong>" + organisationName + @"</strong> organization.</p> <p>Your personal case has been moved back to OnRecord. And they don't have access to your files anymore, except for any assignments you might have created.</p>"; var email = new Email { To = userEmail, Subject = $"Left organization - {organisationName}", Content = WebHelpers.GenerateEmailTemplate(userEmailContent, "You have left an organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); }
private void NotifyUserAboutApprovedRequest(string organisationName, string userEmail) { var content = @"<p>You have joined the <strong>" + organisationName + @"</strong> organization.</p> <p>Your personal case and its threads are now filed under this organization.</p> <p>If you like to opt-out and disconnect from this organization, please contact your administrator.</p>"; var email = new Email { To = userEmail, Subject = $"Joined organization - {organisationName}", Content = WebHelpers.GenerateEmailTemplate(content, "You have joined an organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); }
private void NotifyOrgAdminAboutUserLeaving(Organisation organisation, string userName) { if (organisation.RootUser != null) { var adminEmailContent = @"<p>A user has left your organization: <strong>" + userName + @"</strong>.</p> <p>And their personal case has been moved back to OnRecord.</p>"; var adminEmail = new Email { To = organisation.RootUser.Email, Subject = $"User left organization - {userName}", Content = WebHelpers.GenerateEmailTemplate(adminEmailContent, "A user has left your organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(adminEmail); } }
private void NotifyUserAboutPurchase(SubscriptionPlan plan) { var content = @"<p>Subscription purchased: <strong>" + plan.Name + @"</strong></p> <p>Description: " + plan.Description + @"</p> <p>Price: " + plan.Price + @" GBP</p> <p>Length: " + plan.Length + @" month(s)</p> <p>Is Limited: " + plan.IsLimited + @"</p> <p>Monthly Quota: " + plan.MonthlyQuota.ToString() + @"</p> <p>PDF Export: " + plan.PdfExport + @"</p> <p>Zip Export: " + plan.ZipExport + @"</p>"; var email = new Email { To = CurrentOrgUser.Email, Subject = $"Subscription purchase - {plan.Name}", Content = WebHelpers.GenerateEmailTemplate(content, "Subscription Purchased") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); }
public async Task <IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model) { if (model == null || !ModelState.IsValid) { return(BadRequest(ModelState)); } var user = await UserManager.FindByNameAsync(model.Email); // if user isn't found or the email isn't confirmed, don't reveal anything just return Ok. if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id))) { return(Ok()); } // generate the reset token and send the email. string token = await UserManager.GeneratePasswordResetTokenAsync(user.Id); var encodedToken = HttpUtility.UrlEncode(token); var rootIndex = WebHelpers.GetRootIndexPath(); var baseUrl = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}"; var redirectLink = $"{baseUrl}#!/set-password?email={model.Email}&token={encodedToken}"; //var baseUrl = Request.RequestUri.GetLeftPart(UriPartial.Authority); //var redirectLink = baseUrl + "/wwwroot/dist/index.html#!/set-password?email=" + model.Email + "&token=" + encodedToken; //var content = @"<p>Click on <a href='" + redirectLink + @"'>this link</a> to set a new password.</p><br> // <p>If the link didn't work, copy/paste the token below and reset your password manually.</p> // <p style='color: gray; font-weight: italic'>" + encodedToken + @"</p>"; var content = @"<p>Click on <a href='" + redirectLink + @"'>this link</a> to set a new password.</p>"; var emailBody = WebHelpers.GenerateEmailTemplate(content, "Reset your password"); await UserManager.SendEmailAsync(user.Id, "Password reset request", emailBody); return(Ok()); }
public IHttpActionResult Post(FeedbackDTO model) { var feedback = Mapper.Map <Feedback>(model); feedback.AddedAt = DateTimeService.UtcNow; feedback.AddedById = CurrentOrgUser.Id; feedback.OrganisationId = CurrentOrganisation.Id; ModelState.Clear(); Validate(feedback); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } try { UnitOfWork.FeedbacksRepository.InsertOrUpdate(feedback); var onrecord = UnitOfWork.OrganisationRepository .AllAsNoTracking .Where(x => x.Name == "OnRecord") .SingleOrDefault(); if (onrecord.RootUserId.HasValue) { var onRecordAdmin = UnitOfWork.OrgUsersRepository.Find(onrecord.RootUserId.Value); var content = $"<p>{feedback.Comment}</p>"; var adminEmail = new Email { To = onrecord.RootUser.Email, Subject = $"New feedback arrived - {CurrentOrgUser.UserName}", Content = WebHelpers.GenerateEmailTemplate(content, "User Feedback") }; UnitOfWork.EmailsRepository.InsertOrUpdate(adminEmail); } // find feedback recipients var recipients = UnitOfWork.EmailRecipientsRepository.AllAsNoTracking .Where(x => x.Feedbacks == true) .ToList(); // queue emails for all recipients foreach (var recipient in recipients) { var recipientEmail = new Email { To = recipient.OrgUser.Email, Subject = $"New feedback arrived - {CurrentOrgUser.UserName}", Content = WebHelpers.GenerateEmailTemplate($"<p>{feedback.Comment}</p>", "User Feedback") }; UnitOfWork.EmailsRepository.InsertOrUpdate(recipientEmail); } UnitOfWork.Save(); return(Ok()); } catch (DbEntityValidationException dbEx) { foreach (var validationErrors in dbEx.EntityValidationErrors) { foreach (var validationError in validationErrors.ValidationErrors) { Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); } } throw dbEx; } }
public async Task <IHttpActionResult> Post([FromBody] OrgUserDTO value) { // not necessary to validate password, // because we generate a random password and // send it as part of the account confirmation email. //if (string.IsNullOrEmpty(value.Password)) // ModelState.AddModelError("Password", "Please provide password."); //if (value.Password != value.ConfirmPassword) // ModelState.AddModelError("ConfirmPassword", "'Password' and 'Confirm password' must be the same."); if (value.AccountType == AccountType.MobileAccount) { // the OrgUserType property is hidden in mobile-users' edit form. // so the Type is null at this point. fetch and populate. // TeamUser Type ID: 379c989a-9919-4338-a468-a7c20eb76e28 var teamUserType = UnitOfWork.OrgUserTypesRepository .AllAsNoTracking .Where(x => x.SystemName == "TeamUser") .SingleOrDefault(); value.Type = Mapper.Map <OrgUserTypeDTO>(teamUserType); } var orguser = Mapper.Map <OrgUser>(value); orguser.UserName = orguser.Email; if (CurrentUser is SuperUser || CurrentUser is PlatformUser) { orguser.OrganisationId = Guid.Parse(value.Organisation.Id); orguser.Organisation = null; } else if (CurrentUser is OrgUser) { orguser.OrganisationId = CurrentOrgUser.OrganisationId.Value; } // generate a random password var randomPassword = System.Web.Security.Membership.GeneratePassword(12, 1); var identityResult = ServiceContext.UserManager.CreateSync(orguser, randomPassword); if (!identityResult.Succeeded) { throw new Exception(identityResult.Errors.ToString(". ")); } // assign roles by type. orguser.Type = UnitOfWork.OrgUserTypesRepository.Find(orguser.TypeId); UnitOfWork.UserManager.AssignRolesByUserType(orguser); var organisation = UnitOfWork.OrganisationRepository.Find(orguser.OrganisationId.Value); if (value.Type.Name.ToLower() == "administrator") { var projects = UnitOfWork.ProjectsRepository .AllAsNoTracking .Where(p => p.OrganisationId == orguser.OrganisationId.Value) .Select(x => x.Id) .ToList(); foreach (var projectId in projects) { var orgUserAssignment = new Assignment { ProjectId = projectId, OrgUserId = orguser.Id, CanView = true, CanAdd = true, CanEdit = true, CanDelete = true, CanExportPdf = true, CanExportZip = true }; UnitOfWork.AssignmentsRepository.InsertOrUpdate(orgUserAssignment); } UnitOfWork.Save(); } // create a project for this user var project = new Project() { Name = $"{orguser.FirstName} {orguser.Surname}", StartDate = DateTimeService.UtcNow, OrganisationId = organisation.Id, CreatedById = orguser.Id }; UnitOfWork.ProjectsRepository.InsertOrUpdate(project); UnitOfWork.Save(); // assign this user to their project. var assignment = new Assignment() { ProjectId = project.Id, OrgUserId = orguser.Id, CanView = true, CanAdd = true, CanEdit = true, CanDelete = true, CanExportPdf = true, // temporary. turn off in production. CanExportZip = true // temporary. turn off in production. }; UnitOfWork.AssignmentsRepository.InsertOrUpdate(assignment); // assign organisation admin to this project if (organisation.RootUser != null) { UnitOfWork.AssignmentsRepository.InsertOrUpdate(new Assignment { ProjectId = project.Id, OrgUserId = organisation.RootUserId.Value, CanView = true, CanAdd = true, CanEdit = true, CanDelete = true, CanExportPdf = true, CanExportZip = true }); } UnitOfWork.Save(); // set user's current project var _orgUser = UnitOfWork.OrgUsersRepository.Find(orguser.Id); _orgUser.CurrentProjectId = project.Id; UnitOfWork.OrgUsersRepository.InsertOrUpdate(_orgUser); UnitOfWork.Save(); // subscribe this user to the current organization if (!_orgUser.Subscriptions.Any()) { var subscription = new Subscription { IsActive = true, Type = UserSubscriptionType.Organisation, StartDate = DateTimeService.UtcNow, EndDate = null, Note = $"Joined organisation - {organisation.Name}", OrgUserId = _orgUser.Id, OrganisationId = organisation.Id }; UnitOfWork.SubscriptionsRepository.InsertOrUpdate(subscription); _orgUser.IsSubscribed = true; UnitOfWork.Save(); } // send account confirmation email var code = await UserManager.GenerateEmailConfirmationTokenAsync(orguser.Id); var encodedCode = HttpUtility.UrlEncode(code); var rootIndex = WebHelpers.GetRootIndexPath(); var baseUrl = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}"; var callbackUrl = $"{baseUrl}#!/verify-email?userId={orguser.Id}&code={encodedCode}"; var content = @"<p>Complete your registration by verifying your email address. Click the link below to continue.</p> <p><a href='" + callbackUrl + @"'>Verify Email Address</a></p><br> <p>Your password is <strong>" + randomPassword + @"</strong></p> <p>Make sure to change your password after you've signed in.</p> <p>For more information please read our <a href='https://onrecord.tech/privacy-policy/' target='_blank'>privacy policy</a> guide.</p>"; var emailBody = WebHelpers.GenerateEmailTemplate(content, "Welcome to OnRecord"); await UserManager.SendEmailAsync(orguser.Id, "Confirm your account", emailBody); MemoryCacher.DeleteStartingWith(CACHE_KEY); return(Ok()); }
public IHttpActionResult Post([FromBody] OrgRequestDTO model) { if (CurrentOrgUser.AccountType != AccountType.MobileAccount) { return(BadRequest("organisation requests can only be made by mobile users")); } if (string.IsNullOrEmpty(model.Name)) { return(BadRequest("organisation name is required")); } var existingOrg = UnitOfWork.OrganisationRepository .AllAsNoTracking .Where(x => x.Name == model.Name) .FirstOrDefault(); if (existingOrg != null) { return(BadRequest("an organisation with this name already exists")); } var requestCount = UnitOfWork.OrgRequestsRepository .AllAsNoTracking .Count(x => x.OrgUserId == CurrentOrgUser.Id && x.Name == model.Name); if (requestCount > 0) { return(BadRequest("you have already requested this organisation")); } try { var orgRequest = new OrgRequest { Name = model.Name, Address = model.Address, ContactName = model.ContactName, Email = model.Email, TelNumber = model.TelNumber, Postcode = model.Postcode, OrgUserId = CurrentOrgUser.Id }; UnitOfWork.OrgRequestsRepository.InsertOrUpdate(orgRequest); var onRecord = UnitOfWork.OrganisationRepository .AllAsNoTracking .Where(x => x.Name == "OnRecord") .SingleOrDefault(); var rootIndex = WebHelpers.GetRootIndexPath(); var url = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}#!/organisations/requests/"; var content = @"<p>User name: <b>" + CurrentOrgUser.UserName + @"</b></p> <p>Organisation: <b>" + model.Name + @"</b></p> <p><br></p> <p>View <a href='" + url + @"'>organization requests</a> on the dashboard.</p>"; if (onRecord.RootUserId.HasValue) { var onRecordAdmin = UnitOfWork.OrgUsersRepository.AllAsNoTracking .Where(x => x.Id == onRecord.RootUserId.Value) .SingleOrDefault(); var email = new Email { To = onRecordAdmin.Email, Subject = $"A user has requested an organization", Content = WebHelpers.GenerateEmailTemplate(content, "A user has requested an organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(email); } // find email recipients var recipients = UnitOfWork.EmailRecipientsRepository .AllAsNoTracking .Where(x => x.OrgRequests == true) .ToList(); foreach (var recipient in recipients) { var recipientEmail = new Email { To = recipient.OrgUser.Email, Subject = $"A user has request an organization", Content = WebHelpers.GenerateEmailTemplate(content, "A user has request an organization") }; UnitOfWork.EmailsRepository.InsertOrUpdate(recipientEmail); } UnitOfWork.Save(); MemoryCacher.DeleteStartingWith(CACHE_KEY); return(Ok()); } catch (Exception ex) { return(InternalServerError(ex)); } }
public async Task <IHttpActionResult> Register(RegisterBindingModel model) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var organisation = UnitOfWork.OrganisationRepository.FindByName(model.OrganisationName); if (organisation == null) { ModelState.AddModelError("Organisation", "Organisation was not found!"); return(BadRequest(ModelState)); } var user = new OrgUser() { FirstName = model.FirstName, Surname = model.Surname, UserName = model.Email, Email = model.Email, OrganisationId = organisation.Id, IsRootUser = false, IsActive = true, TypeId = OrgUserTypesRepository.TeamUser.Id, IsMobileUser = true, IsWebUser = true, // this should be 'false' in live production. IsSubscribed = false, AccountType = AccountType.MobileAccount }; if (!string.IsNullOrEmpty(model.Address)) { user.Address = model.Address; } if (!string.IsNullOrEmpty(model.Gender)) { user.Gender = (User.GenderType)Enum.Parse(typeof(User.GenderType), model.Gender); } if (model.Birthdate.HasValue) { var localValue = TimeZone.CurrentTimeZone.ToLocalTime(model.Birthdate.Value); user.Birthdate = new DateTime(localValue.Year, localValue.Month, localValue.Day, 0, 0, 0, DateTimeKind.Utc); } IdentityResult result = await UserManager.CreateAsync(user, model.Password); if (!result.Succeeded) { return(GetErrorResult(result)); } user.Type = UnitOfWork.OrgUserTypesRepository.Find(user.TypeId); UnitOfWork.UserManager.AssignRolesByUserType(user); // create a project for this user var project = new Project() { Name = $"{model.FirstName} {model.Surname}", StartDate = DateTimeService.UtcNow, OrganisationId = organisation.Id, CreatedById = user.Id }; UnitOfWork.ProjectsRepository.InsertOrUpdate(project); UnitOfWork.Save(); // assign this user to their project. var assignment = new Assignment() { ProjectId = project.Id, OrgUserId = user.Id, CanView = true, CanAdd = true, CanEdit = false, CanDelete = false, CanExportPdf = true, // temporary. turn off in production. CanExportZip = true // temporary. turn off in production. }; UnitOfWork.AssignmentsRepository.InsertOrUpdate(assignment); // assign organisation admin to this project if (organisation.RootUser != null) { UnitOfWork.AssignmentsRepository.InsertOrUpdate(new Assignment { ProjectId = project.Id, OrgUserId = organisation.RootUserId.Value, CanView = true, CanAdd = true, CanEdit = true, CanDelete = true, CanExportPdf = true, CanExportZip = true }); } UnitOfWork.Save(); // set user's current project var _orgUser = UnitOfWork.OrgUsersRepository.Find(user.Id); _orgUser.CurrentProjectId = project.Id; UnitOfWork.OrgUsersRepository.InsertOrUpdate(_orgUser); UnitOfWork.Save(); // subscribe this user under OnRecord with full access. if (_orgUser.AccountType == AccountType.MobileAccount && !_orgUser.Subscriptions.Any()) { var onrecord = UnitOfWork.OrganisationRepository.AllAsNoTracking .Where(x => x.Name == "OnRecord") .SingleOrDefault(); var subscription = new Subscription { IsActive = true, Type = UserSubscriptionType.Organisation, StartDate = DateTimeService.UtcNow, EndDate = null, Note = $"Joined organisation - OnRecord", OrgUserId = user.Id, OrganisationId = onrecord.Id }; UnitOfWork.SubscriptionsRepository.InsertOrUpdate(subscription); _orgUser.IsSubscribed = true; UnitOfWork.Save(); } // send account confirmation email var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); var encodedCode = HttpUtility.UrlEncode(code); var rootIndex = WebHelpers.GetRootIndexPath(); var baseUrl = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{rootIndex}"; var callbackUrl = $"{baseUrl}#!/verify-email?userId={user.Id}&code={encodedCode}"; var content = @"<p>Your new account has been created. To complete your registration please confirm your email address by clicking the link below.</p> <p><a href='" + callbackUrl + @"'>Verify Email Address</a></p>"; var messageBody = WebHelpers.GenerateEmailTemplate(content, "Confirm your registration"); await UserManager.SendEmailAsync(user.Id, "Confirm your account", messageBody); // find email recipients var recipients = UnitOfWork.EmailRecipientsRepository.AllAsNoTracking .Where(x => x.NewMobileUsers == true) .ToList(); var url = $"{Request.RequestUri.Scheme}://{Request.RequestUri.Authority}/{WebHelpers.GetRootIndexPath()}#!/users/mobile/"; foreach (var recipient in recipients) { var emailContent = $"<p>First name: {model.FirstName}</p>" + $"<p>Surname: {model.Surname}</p>" + $"<p>Email: {model.Email}</p><br>" + $"<p>View <a href='{url}'>mobile users</a> on the dashboard.</p>"; var recipientEmail = new Email { To = recipient.OrgUser.Email, Subject = "A new mobile user has joined OnRecord", Content = WebHelpers.GenerateEmailTemplate(emailContent, "A new mobile user has joined OnRecord") }; UnitOfWork.EmailsRepository.InsertOrUpdate(recipientEmail); } try { UnitOfWork.Save(); return(Ok()); } catch (Exception ex) { return(InternalServerError(ex)); } }