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);
            }
        }
Пример #3
0
        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);
            }
        }
Пример #5
0
        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());
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }
Пример #10
0
        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);
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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());
        }
Пример #13
0
        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;
            }
        }
Пример #14
0
        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());
        }
Пример #15
0
        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));
            }
        }
Пример #16
0
        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));
            }
        }