using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.FSE.UsersAndRoles.Models; using Tango.FSE.UsersAndRoles.Navigation; using Tango.FSE.UsersAndRoles.Views; using Tango.SharedUI.Components; using static Tango.FSE.UsersAndRoles.ViewModels.UserDetailsViewVM; namespace Tango.FSE.UsersAndRoles.ViewModels { public class UserDetailsViewVM : UsersAndRolesViewModel, INavigationObjectReceiver { private String userToLoadGuid; private bool _requiresLoading; public class NavigationObject { public Organization Organization { get; set; } public User User { get; set; } public bool IsNewUser { get; set; } } private Organization _organization; public Organization Organization { get { return _organization; } set { _organization = value; RaisePropertyChangedAuto(); } } private bool _isResetUserPassword; public bool IsResetUserPassword { get { return _isResetUserPassword; } set { _isResetUserPassword = value; RaisePropertyChangedAuto(); } } private String _resetPassword; public String ResetPassword { get { return _resetPassword; } set { _resetPassword = value; RaisePropertyChangedAuto(); } } private bool _isNewUser; public bool IsNewUser { get { return _isNewUser; } set { _isNewUser = value; RaisePropertyChangedAuto(); } } private User _user; public User User { get { return _user; } set { _user = value; RaisePropertyChangedAuto(); OnUserChanged(); } } private String _firstName; [Required(ErrorMessage = "First name is required")] public String FirstName { get { return _firstName; } set { _firstName = value; RaisePropertyChangedAuto(); } } private String _lastName; [Required(ErrorMessage = "Last name is required")] public String LastName { get { return _lastName; } set { _lastName = value; RaisePropertyChangedAuto(); } } private String _email; [Required(ErrorMessage = "Email is required")] [EmailAddress(ErrorMessage = "Please enter a valid email address")] public String Email { get { return _email; } set { _email = value; RaisePropertyChangedAuto(); OnEmailChanged(); } } private String _password; public String Password { get { return _password; } set { _password = value; RaisePropertyChangedAuto(); } } private bool _isCheckingEmail; public bool IsCheckingEmail { get { return _isCheckingEmail; } set { _isCheckingEmail = value; RaisePropertyChangedAuto(); } } private bool _isEmailTaken; public bool IsEmailTaken { get { return _isEmailTaken; } set { _isEmailTaken = value; RaisePropertyChangedAuto(); } } private RolesCollection _rolesCollection; public RolesCollection RolesCollection { get { return _rolesCollection; } set { _rolesCollection = value; RaisePropertyChangedAuto(); } } private bool _sendInvitation; public bool SendInvitation { get { return _sendInvitation; } set { _sendInvitation = value; RaisePropertyChangedAuto(); } } private bool _canSetPreventRemoteMachineAccess; public bool CanSetRemoteMachineAccess { get { return _canSetPreventRemoteMachineAccess; } set { _canSetPreventRemoteMachineAccess = value; RaisePropertyChangedAuto(); } } public RelayCommand SaveCommand { get; set; } public RelayCommand GeneratePasswordCommand { get; set; } public RelayCommand ResetPasswordCommand { get; set; } public RelayCommand GenerateResetPasswordCommand { get; set; } public UserDetailsViewVM() { SaveCommand = new RelayCommand(Save, () => IsFree); GeneratePasswordCommand = new RelayCommand(GeneratePassword); SendInvitation = true; ResetPasswordCommand = new RelayCommand(() => { IsResetUserPassword = true; GenerateResetPassword(); }); GenerateResetPasswordCommand = new RelayCommand(GenerateResetPassword); } private void GenerateResetPassword() { if (IsResetUserPassword) { ResetPassword = Services.OrganizationsService.GenerateRandomPassword(); } } private void GeneratePassword() { if (IsNewUser) { Password = Services.OrganizationsService.GenerateRandomPassword(); } } public async override void OnNavigatedTo() { base.OnNavigatedTo(); if (!IsNewUser) { if (_requiresLoading) { await LoadUserDetails(); } } else { await CreateNewUser(); GeneratePassword(); } CanSetRemoteMachineAccess = CurrentUser.HasRole(Roles.FSEAdministrator); _requiresLoading = false; } private async Task CreateNewUser() { try { IsFree = false; var user = new User(); user.Address = new Address(); user.Contact = new Contact(); User = user; var roles = await Services.OrganizationsService.GetAllRoles(); InitRolesCollection(User, roles, true); } catch (Exception ex) { LogManager.Log(ex, $"Error initializing new user creation."); await NotificationProvider.ShowError($"Error initializing new user details.\n{ex.FlattenMessage()}"); await NavigationManager.NavigateBack(); } finally { IsFree = true; } } private void InitRolesCollection(User user, List roles, bool isNew = false) { bool user_is_current_user_and_fse_admin_and_not_twine_admin = user.Guid == CurrentUser.Guid && user.HasRole(Roles.FSEAdministrator) && !user.HasRole(Roles.FSETwineAdministrator); var collection = new RolesCollection(); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETechnician)) { IsSelected = isNew }); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSEAdvancedTechnician), Roles.FSETechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSEAdministrator), Roles.FSETechnician, Roles.FSEAdvancedTechnician) { IsEnabled = !user_is_current_user_and_fse_admin_and_not_twine_admin }); if (CurrentUser.HasRole(Roles.FSETwineAdministrator)) { collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTechnician), Roles.FSETechnician, Roles.FSEAdvancedTechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineAdministrator), Roles.FSETechnician, Roles.FSEAdvancedTechnician, Roles.FSEAdministrator, Roles.FSETwineTechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineProcedureDesigner), Roles.FSETechnician, Roles.FSEAdvancedTechnician, Roles.FSETwineTechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineProcedurePublisher), Roles.FSETechnician, Roles.FSEAdvancedTechnician, Roles.FSETwineTechnician, Roles.FSETwineProcedureDesigner)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineDataStoreDeveloper), Roles.FSETechnician, Roles.FSEAdvancedTechnician, Roles.FSETwineTechnician)); collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineDeveloper), Roles.FSETechnician, Roles.FSEAdvancedTechnician, Roles.FSETwineTechnician) { IsVisible = CurrentUser.HasRole(Roles.FSETwineDeveloper) }); } collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineRSMUser))); collection.ToList().ForEach(x => x.IsSelected = user.FSERoles.Any(y => y.Code == x.Role.Code)); RolesCollection = collection; } private async Task LoadUserDetails() { try { IsFree = false; User = await Services.OrganizationsService.GetUserDetails(userToLoadGuid); var roles = await Services.OrganizationsService.GetAllRoles(); InitRolesCollection(User, roles); Validate(); } catch (Exception ex) { LogManager.Log(ex, $"Error loading user details for user '{userToLoadGuid}'"); await NotificationProvider.ShowError($"Error loading the selected user details.\n{ex.FlattenMessage()}"); await NavigationManager.NavigateBack(); } finally { IsFree = true; } } private async void Save() { try { if (!Validate()) return; IsFree = false; using (var task = NotificationProvider.PushTaskItem("Saving user details...")) { var rolesToAdd = RolesCollection.Where(x => x.IsSelected).ToList().Where(x => !User.FSERoles.Exists(y => y.Guid == x.Role.Guid)).ToList(); var rolesToRemove = User.FSERoles.ToList().Where(x => !RolesCollection.Where(z => z.IsSelected).ToList().Exists(y => y.Role.Guid == x.Guid)).ToList(); foreach (var role in rolesToAdd.Select(x => x.Role)) { User.UsersRoles.Add(new UsersRole() { UserGuid = User.Guid, RoleGuid = role.Guid, Role = role, User = User, }); } foreach (var role in rolesToRemove) { var userRole = User.UsersRoles.SingleOrDefault(x => x.RoleGuid == role.Guid); if (userRole != null) { User.UsersRoles.Remove(userRole); } } User.Contact.FirstName = FirstName; User.Contact.LastName = LastName; if (!IsNewUser) { await Services.OrganizationsService.UpdateUser(User, IsResetUserPassword, ResetPassword); } else { User.OrganizationGuid = Organization.Guid; User.Email = Email; User.Password = Password; await Services.OrganizationsService.InsertUser(User); if (SendInvitation) { bool invitationSent = false; task.UpdateProgress("Sending email invitation..."); while (!invitationSent) { try { await Services.OrganizationsService.SendNewUserInvitationEmail(User.Guid, Password); await Task.Delay(2000); invitationSent = true; } catch (Exception ex) { if (!await NotificationProvider.ShowWarningQuestion($"The user was created but an error occurred while trying to send the invitation via email.{ex.Message}\nWould you like to try again?")) { break; } } } } task.Dispose(); await NotificationProvider.ShowSuccess("User created successfully!"); IsNewUser = false; Password = null; userToLoadGuid = User.Guid; } await LoadUserDetails(); await ModularNavigationManager.NavigateTo(UsersAndRolesView.OrganizationUsersView, new OrganizationUsersViewVM.NavigationObject() { Organization = User.Organization, SelectedUser = User }, false); } } catch (Exception ex) { LogManager.Log(ex, $"Error saving user details for '{User.Email}'."); await NotificationProvider.ShowError($"Error saving user details.\n{ex.FlattenMessage()}"); } finally { IsFree = true; } } private void OnUserChanged() { if (User != null) { FirstName = User.Contact.FirstName; LastName = User.Contact.LastName; IsEmailTaken = false; Email = User.Email; } else { FirstName = null; LastName = null; Email = null; Password = null; } } private async void OnEmailChanged() { if (IsNewUser && Email.IsNotNullOrEmpty()) { try { IsCheckingEmail = true; await Task.Delay(500); IsEmailTaken = !await Services.OrganizationsService.CheckEmailAvailable(Email); } catch (Exception ex) { LogManager.Log(ex, "Error checking for email availability."); IsEmailTaken = false; } finally { IsCheckingEmail = false; } } } protected override void OnValidating() { base.OnValidating(); if (IsEmailTaken) { InsertError(nameof(Email), "Email address is already registered."); } } public void OnNavigatedToWithObject(NavigationObject obj) { IsResetUserPassword = false; ResetPassword = null; User = null; IsNewUser = obj.IsNewUser; Organization = obj.Organization; if (!IsNewUser) { userToLoadGuid = obj.User.Guid; _requiresLoading = true; } } } }