/// <summary> /// Insert a new User Account, or adds the user with this business account to the business's role /// </summary> /// <param name="userAccount">The new user account to create</param> /// <param name="roleId">The role</param> public void Post(Guid roleId, UserAccount userAccount) { var currentUserAccount = CoreEntitiesContainer.CurrentUserAccount(); //check for admin abilities var businessAccount = CoreEntitiesContainer.Owner(roleId, new[] { RoleType.Administrator }).Include(ba => ba.OwnedRoles).FirstOrDefault(); if (businessAccount == null) throw Request.NotAuthorized(); //find the role in the BusinessAccount that matches the name of the one passed in var role = CoreEntitiesContainer.Roles.FirstOrDefault(r => r.OwnerBusinessAccountId == businessAccount.Id && r.Name == userAccount.Role); if (role == null) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, "This role does not exist on the business account. Please contact customer support")); //Check to be sure that the time zone passed is valid var engine = EntityRules.SetupTimeZoneRules(); var errors = EntityRules.ValidateAndReturnErrors(engine, userAccount.TimeZone); if (errors != null) Request.BadRequest(errors); var user = GetUser(userAccount.EmailAddress); var newUser = user == null; //if the user does not exist, create a new one if (newUser) { user = new Core.Models.CoreEntities.UserAccount { Id = Guid.NewGuid(), EmailAddress = userAccount.EmailAddress.Trim(), FirstName = userAccount.FirstName, LastName = userAccount.LastName, TimeZone = "Eastern Standard Time", CreatedDate = DateTime.UtcNow, LastModifyingUserId = CoreEntitiesContainer.CurrentUserAccount().Id, //PasswordHash and PasswordSalt are not nullable //set temporary values (even though they will not be used) PasswordHash = EmailPasswordTools.GeneratePassword(), PasswordSalt = EncryptionTools.GenerateSalt() }; } //If the user does exist, track the changes else { user.LastModified = DateTime.UtcNow; user.LastModifyingUserId = currentUserAccount.Id; } //add the user to the role user.RoleMembership.Add(role); //setup the employee link SetupEmployee(userAccount.EmployeeId, user, businessAccount, currentUserAccount.Id); SaveWithRetry(); if (newUser) { //Send new user email var sender = CoreEntitiesContainer.CurrentUserAccount().DisplayName; var recipient = user.FirstName; var subject = "Your FoundOPS invite from " + sender; var body = "Hi " + recipient + ", \r\n\r\n" + sender + " has created a user account for you in FoundOPS. \r\n\r\n" + "FoundOPS is an easy to use tool that helps field services teams communicate and provide the best possible service to their clients. \r\n\r\n" + "Click here to accept the invite: \r\n " + @"{0}" + "\r\n\r\n" + "If you have any difficulty accepting the invitation, email us at [email protected]. This invitation expires in 7 days. \r\n\r\n\r\n" + "The FoundOPS Team"; CoreEntitiesMembershipProvider.ResetAccount(user.EmailAddress, subject, body, TimeSpan.FromDays(7)); } //TODO consider sending an email for existing users (they were given access to...) }
/// <summary> /// If roleId is set, changing properties on behalf of a business account. Can only change role and employee link. /// If roleId is null, changing properties on behalf of the current user. Can only change user properties: FirstName, LastName, Email Address, TimeZone, Password /// </summary> /// <param name="userAccount">The UserAccount</param> /// <param name="roleId">(Optional) The role of the business to change</param> /// <param name="newPass">(Optional) For resetting the password: the users new password</param> /// <param name="oldPass">(Optional) For resetting the password: the users old password</param> public void Put(UserAccount userAccount, Guid? roleId = null, string newPass = null, string oldPass = null) { var currentUserAccount = CoreEntitiesContainer.CurrentUserAccount(); if (currentUserAccount == null) throw Request.NotAuthorized(); //changing properties on behalf of a business account if (roleId.HasValue) { //used for changing roles var businessAccount = CoreEntitiesContainer.Owner(roleId.Value, new[] { RoleType.Administrator }).FirstOrDefault(); if (businessAccount == null) throw Request.NotAuthorized(); //Check to be sure that the time zone passed is valid var engine = EntityRules.SetupTimeZoneRules(); var errors = EntityRules.ValidateAndReturnErrors(engine, userAccount.TimeZone); if (errors != null) Request.BadRequest(errors); var user = CoreEntitiesContainer.Parties.OfType<Core.Models.CoreEntities.UserAccount>() .Include(u => u.RoleMembership).Include(u => u.LinkedEmployees).First(ua => ua.Id == userAccount.Id); //Get the users current role for this business account var userRole = CoreEntitiesContainer.Roles.FirstOrDefault(r => r.OwnerBusinessAccountId == businessAccount.Id && r.MemberParties.Any(p => p.Id == user.Id)); //If a new role has been selected for the user, remove all old ones and assign the new one if (userRole != null && userRole.Name != userAccount.Role) { user.RoleMembership.Remove(userRole); //Find the new role to be added for the user var newRole = CoreEntitiesContainer.Roles.FirstOrDefault(r => r.OwnerBusinessAccountId == businessAccount.Id && r.Name == userAccount.Role); //Add the new role for the user if (newRole != null) user.RoleMembership.Add(newRole); } SetupEmployee(userAccount.EmployeeId, user, businessAccount, currentUserAccount.Id); //TODO CR these lines are common w below. Merge //TODO CR Make extension method on ITrackable to do this user.LastModified = DateTime.UtcNow; user.LastModifyingUserId = currentUserAccount.Id; SaveWithRetry(); } //changing properties on behalf of the current user else { //if the user is not editing itself, and if it does not have admin access to the business account //throw not authorized if (userAccount != null && currentUserAccount.Id != userAccount.Id) throw Request.NotAuthorized(); if (userAccount != null) //can be null if just changing the password { //if the email address changed, check it does not conflict if (userAccount.EmailAddress != currentUserAccount.EmailAddress && GetUser(userAccount.EmailAddress) != null) throw ApiExceptions.Create(Request.CreateResponse(HttpStatusCode.Conflict, "This email address already exists")); //update properties currentUserAccount.FirstName = userAccount.FirstName; currentUserAccount.LastName = userAccount.LastName; currentUserAccount.EmailAddress = userAccount.EmailAddress; //check the time zone is acceptable try { TimeZoneInfo.FindSystemTimeZoneById(userAccount.TimeZone.Id); } catch (Exception) { throw Request.BadRequest("TimeZone not acceptable"); } currentUserAccount.TimeZone = userAccount.TimeZone.Id; } //try to change the password if (newPass != null && oldPass != null) { if (!CoreEntitiesMembershipProvider.ChangePassword(currentUserAccount.EmailAddress, oldPass, newPass)) throw Request.BadRequest("The password was incorrect, or the new password is not acceptable"); } //TODO CR Make extension method on ITrackable to do this currentUserAccount.LastModified = DateTime.UtcNow; currentUserAccount.LastModifyingUserId = currentUserAccount.Id; SaveWithRetry(); } }