From e317a7943e47c34e731729eacc46f8ce48905927 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Wed, 7 Mar 2018 16:28:54 +0200 Subject: Working on Users & Roles Module. --- .../ViewModels/MainViewVM.cs | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels') diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..9c10dc126 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.UsersAndRoles.Navigation; +using Tango.SharedUI; + +namespace Tango.MachineStudio.UsersAndRoles.ViewModels +{ + public class MainViewVM : ViewModel + { + private ObservablesContext _organizationsContext; + private ObservablesContext _manageContext; + private ObservablesContext _userContext; + private UsersAndRolesNavigationManager _navigation; + private INotificationProvider _notification; + + private ObservableCollection _organizations; + public ObservableCollection Organizations + { + get { return _organizations; } + set { _organizations = value; RaisePropertyChangedAuto(); } + } + + private Organization _selectedOrganization; + public Organization SelectedOrganization + { + get { return _selectedOrganization; } + set { _selectedOrganization = value; RaisePropertyChangedAuto(); } + } + + private Organization _managedOrganization; + public Organization ManagedOrganization + { + get { return _managedOrganization; } + set { _managedOrganization = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection _roles; + public ObservableCollection Roles + { + get { return _roles; } + set { _roles = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection _permissions; + public ObservableCollection Permissions + { + get { return _permissions; } + set { _permissions = value; RaisePropertyChangedAuto(); } + } + + private User _selectedUser; + public User SelectedUser + { + get { return _selectedUser; } + set { _selectedUser = value; RaisePropertyChangedAuto(); } + } + + private User _managedUser; + public User ManagedUser + { + get { return _managedUser; } + set { _managedUser = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand ManageOrganizationCommand { get; set; } + + public RelayCommand BackToOrganizationsCommand { get; set; } + + public RelayCommand ManageUserCommand { get; set; } + + public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification) + { + _navigation = navigation; + _notification = notification; + + LoadOrganizations(); + + ManageOrganizationCommand = new RelayCommand(ManageOrganization, () => SelectedOrganization != null); + BackToOrganizationsCommand = new RelayCommand(BackToOrganizations); + ManageUserCommand = new RelayCommand(ManageUser, () => SelectedUser != null); + } + + private void ManageUser() + { + using (_notification.PushTaskItem("Loading user details...")) + { + Task.Factory.StartNew(() => + { + _userContext = ObservablesContext.CreateDefault(); + ManagedUser = _manageContext.Users.SingleOrDefault(x => x.Guid == SelectedUser.Guid); + + InvokeUI(() => _navigation.NavigateTo(UsersAndRolesNavigationView.UserManagementView)); + }); + } + } + + private void BackToOrganizations() + { + _navigation.NavigateTo(UsersAndRolesNavigationView.OrganizationSelectionView); + } + + private void ManageOrganization() + { + using (_notification.PushTaskItem("Loading organization...")) + { + Task.Factory.StartNew(() => + { + _manageContext = ObservablesContext.CreateDefault(); + ManagedOrganization = _manageContext.Organizations.SingleOrDefault(x => x.Guid == SelectedOrganization.Guid); + + InvokeUI(() => _navigation.NavigateTo(UsersAndRolesNavigationView.OrganizationManagementView)); + }); + } + } + + private void LoadOrganizations() + { + _organizationsContext = ObservablesContext.CreateDefault(); + _organizationsContext.Configuration.LazyLoadingEnabled = false; + + _organizationsContext.Users.ToList(); + _organizationsContext.Contacts.ToList(); + _organizationsContext.Addresses.ToList(); + _organizationsContext.Machines.ToList(); + + Organizations = _organizationsContext.Organizations.ToObservableCollection(); + } + + protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) + { + base.RaisePropertyChangedAuto(caller); + InvalidateRelayCommands(); + } + } +} -- cgit v1.3.1 From cf3c535fb0ef3140cc7a3a3c74cadd9b1d519bcf Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Wed, 7 Mar 2018 18:30:49 +0200 Subject: Working on users & roles module. --- Software/DB/Tango.mdf | Bin 75497472 -> 75497472 bytes Software/DB/Tango_log.ldf | Bin 1048576 -> 1048576 bytes Software/Graphics/roles.png | Bin 0 -> 3875 bytes Software/Graphics/user.png | Bin 0 -> 20100 bytes .../Images/roles.png | Bin 0 -> 3875 bytes .../Images/user.png | Bin 0 -> 20100 bytes .../Tango.MachineStudio.UsersAndRoles.csproj | 10 ++ .../ViewModels/MainViewVM.cs | 61 ++++++++- .../Views/ContactView.xaml | 2 +- .../Views/OrganizationManagementView.xaml | 12 +- .../Views/UserManagementView.xaml | 143 ++++++++++++++++++++- .../Views/UserManagementView.xaml.cs | 23 ++++ .../Tango.SharedUI/Controls/TableGrid.cs | 16 ++- 13 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 Software/Graphics/roles.png create mode 100644 Software/Graphics/user.png create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/roles.png create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/user.png (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels') diff --git a/Software/DB/Tango.mdf b/Software/DB/Tango.mdf index cd8aeb6d6..c81a777ab 100644 Binary files a/Software/DB/Tango.mdf and b/Software/DB/Tango.mdf differ diff --git a/Software/DB/Tango_log.ldf b/Software/DB/Tango_log.ldf index 0ef97d776..b1b7ed7e4 100644 Binary files a/Software/DB/Tango_log.ldf and b/Software/DB/Tango_log.ldf differ diff --git a/Software/Graphics/roles.png b/Software/Graphics/roles.png new file mode 100644 index 000000000..e7955be04 Binary files /dev/null and b/Software/Graphics/roles.png differ diff --git a/Software/Graphics/user.png b/Software/Graphics/user.png new file mode 100644 index 000000000..c8b7a3b40 Binary files /dev/null and b/Software/Graphics/user.png differ diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/roles.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/roles.png new file mode 100644 index 000000000..e7955be04 Binary files /dev/null and b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/roles.png differ diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/user.png b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/user.png new file mode 100644 index 000000000..c8b7a3b40 Binary files /dev/null and b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Images/user.png differ diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj index cfba775b8..fb134fdfd 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj @@ -142,6 +142,10 @@ {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {b112d89a-a106-41ae-a0c1-4abc84c477f5} + Tango.DragAndDrop + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} Tango.Logging @@ -194,5 +198,11 @@ + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs index 9c10dc126..fdb0f8983 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs @@ -50,11 +50,11 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels set { _roles = value; RaisePropertyChangedAuto(); } } - private ObservableCollection _permissions; - public ObservableCollection Permissions + private ObservableCollection _managedUserRoles; + public ObservableCollection ManagedUserRoles { - get { return _permissions; } - set { _permissions = value; RaisePropertyChangedAuto(); } + get { return _managedUserRoles; } + set { _managedUserRoles = value; RaisePropertyChangedAuto(); } } private User _selectedUser; @@ -77,6 +77,10 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels public RelayCommand ManageUserCommand { get; set; } + public RelayCommand SaveOrganizationCommand { get; set; } + + public RelayCommand AddOrganizationCommand { get; set; } + public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification) { _navigation = navigation; @@ -87,6 +91,40 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels ManageOrganizationCommand = new RelayCommand(ManageOrganization, () => SelectedOrganization != null); BackToOrganizationsCommand = new RelayCommand(BackToOrganizations); ManageUserCommand = new RelayCommand(ManageUser, () => SelectedUser != null); + SaveOrganizationCommand = new RelayCommand(SaveOrganization); + AddOrganizationCommand = new RelayCommand(AddOrganization); + } + + private async void AddOrganization() + { + String name = _notification.ShowTextInput("Enter organization name", "Name"); + + if (!String.IsNullOrWhiteSpace(name)) + { + using (_notification.PushTaskItem("Adding new organization...")) + { + Organization org = new Organization(); + org.Name = name; + org.Address = new Address(); + org.Contact = new Contact(); + _organizationsContext.Organizations.Add(org); + await org.SaveAsync(_organizationsContext); + Organizations = _organizationsContext.Organizations.ToObservableCollection(); + SelectedOrganization = org; + ManageOrganization(); + } + } + } + + private async void SaveOrganization() + { + using (_notification.PushTaskItem("Saving organization address and contact...")) + { + ManagedOrganization.Contact.FullName = ManagedOrganization.Contact.FirstName + " " + ManagedOrganization.Contact.LastName; + await ManagedOrganization.SaveAsync(_manageContext); + LoadOrganizations(); + SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); + } } private void ManageUser() @@ -96,7 +134,9 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels Task.Factory.StartNew(() => { _userContext = ObservablesContext.CreateDefault(); + Roles = _manageContext.Roles.ToObservableCollection(); ManagedUser = _manageContext.Users.SingleOrDefault(x => x.Guid == SelectedUser.Guid); + ManagedUserRoles = ManagedUser.Roles.ToObservableCollection(); InvokeUI(() => _navigation.NavigateTo(UsersAndRolesNavigationView.UserManagementView)); }); @@ -135,6 +175,19 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels Organizations = _organizationsContext.Organizations.ToObservableCollection(); } + public void OnDropRole(Role role) + { + ManagedUser.UsersRoles.Add(new UsersRole() + { + Role = role, + RoleGuid = role.Guid, + User = ManagedUser, + UserGuid = ManagedUser.Guid, + }); + + ManagedUserRoles.Add(role); + } + protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) { base.RaisePropertyChangedAuto(caller); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/ContactView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/ContactView.xaml index dfff19f12..cdfa28c50 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/ContactView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/ContactView.xaml @@ -17,7 +17,7 @@ FIRST NAME LAST NAME - + EMAIL PHONE NUMBER diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml index b91a22750..7769f65ed 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml @@ -37,15 +37,23 @@ ADDRESS - + CONTACT - + + + + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml index 0a3fec2ff..eaeb180ab 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml @@ -6,6 +6,7 @@ xmlns:global="clr-namespace:Tango.MachineStudio.UsersAndRoles" xmlns:vm="clr-namespace:Tango.MachineStudio.UsersAndRoles.ViewModels" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:dragAndDrop="clr-namespace:Tango.DragAndDrop;assembly=Tango.DragAndDrop" xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls" @@ -13,8 +14,146 @@ xmlns:local="clr-namespace:Tango.MachineStudio.UsersAndRoles.Views" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" mc:Ignorable="d" - d:DesignHeight="1080" d:DesignWidth="1920" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}" Background="Transparent"> + d:DesignHeight="1080" d:DesignWidth="1920" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + - + + + + + + + + + + + + + + + + + + + ADDRESS + + + + + + CONTACT + + + + + + + + + + + + + + ROLES + + DRAG & DROP ROLES + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AVAILABLE ROLES + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs index 88319cbb3..b26f0ea03 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs @@ -12,6 +12,9 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using Tango.BL.Entities; +using Tango.DragAndDrop; +using Tango.MachineStudio.UsersAndRoles.ViewModels; namespace Tango.MachineStudio.UsersAndRoles.Views { @@ -20,9 +23,29 @@ namespace Tango.MachineStudio.UsersAndRoles.Views /// public partial class UserManagementView : UserControl { + private MainViewVM _vm; + + public DraggingSurface DraggingSurface + { + get { return (DraggingSurface)GetValue(DraggingSurfaceProperty); } + set { SetValue(DraggingSurfaceProperty, value); } + } + public static readonly DependencyProperty DraggingSurfaceProperty = + DependencyProperty.Register("DraggingSurface", typeof(DraggingSurface), typeof(UserManagementView), new PropertyMetadata(null)); + public UserManagementView() { InitializeComponent(); + DraggingSurface = dragSurface; + Loaded += (_, __) => _vm = DataContext as MainViewVM; + } + + private void OnDropRole(object sender, DropEventArgs e) + { + if (e.Draggable.DataContext is Role) + { + _vm.OnDropRole(e.Draggable.DataContext as Role); + } } } } diff --git a/Software/Visual_Studio/Tango.SharedUI/Controls/TableGrid.cs b/Software/Visual_Studio/Tango.SharedUI/Controls/TableGrid.cs index 356320a0c..454d8dfac 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Controls/TableGrid.cs +++ b/Software/Visual_Studio/Tango.SharedUI/Controls/TableGrid.cs @@ -10,6 +10,17 @@ namespace Tango.SharedUI.Controls { public class TableGrid : Grid { + public GridLength RowHeight + { + get { return (GridLength)GetValue(RowHeightProperty); } + set { SetValue(RowHeightProperty, value); } + } + public static readonly DependencyProperty RowHeightProperty = + DependencyProperty.Register("RowHeight", typeof(GridLength), typeof(TableGrid), new PropertyMetadata(new GridLength(1, GridUnitType.Star))); + + + + public TableGrid() { ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); @@ -25,6 +36,7 @@ namespace Tango.SharedUI.Controls protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved) { base.OnVisualChildrenChanged(visualAdded, visualRemoved); + InvalidateGrid(); } protected override Size ArrangeOverride(Size arrangeSize) @@ -35,7 +47,7 @@ namespace Tango.SharedUI.Controls private void InvalidateGrid() { RowDefinitions.Clear(); - RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50, GridUnitType.Pixel) }); + RowDefinitions.Add(new RowDefinition() { Height = RowHeight }); int currentRow = 0; @@ -48,7 +60,7 @@ namespace Tango.SharedUI.Controls SetColumn(Children[i], 1); (Children[i] as FrameworkElement).Margin = new Thickness(20, 0, 0, 0); currentRow++; - RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50, GridUnitType.Pixel) }); + RowDefinitions.Add(new RowDefinition() { Height = RowHeight }); } (Children[i] as FrameworkElement).VerticalAlignment = VerticalAlignment.Bottom; -- cgit v1.3.1 From c923d6611ffa64605879779c490a979e03daa189 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Sun, 11 Mar 2018 14:03:02 +0200 Subject: Working on Users & Roles module ! --- .../Cascade Machine Delete To Configuration.sql | Bin 0 -> 2824 bytes .../Cascade User Delete To Contact and Address.sql | Bin 0 -> 3816 bytes Software/DB/Tango.mdf | Bin 75497472 -> 75497472 bytes Software/DB/Tango_log.ldf | Bin 1048576 -> 1048576 bytes .../ViewModels/MainViewVM.cs | 61 ++++++++++-- .../Views/UserManagementView.xaml | 103 +++++++++++++++++---- .../Tango.BL/EntitiesExtensions/Contact.cs | 16 ++++ .../Visual_Studio/Tango.BL/IObservableEntity.cs | 5 + .../Visual_Studio/Tango.BL/ObservableEntity.cs | 17 ++++ Software/Visual_Studio/Tango.BL/Tango.BL.csproj | 1 + .../ExtensionMethods/StringExtensions.cs | 22 +++++ 11 files changed, 201 insertions(+), 24 deletions(-) create mode 100644 Software/DB/Change Scripts/Cascade Machine Delete To Configuration.sql create mode 100644 Software/DB/Change Scripts/Cascade User Delete To Contact and Address.sql create mode 100644 Software/Visual_Studio/Tango.BL/EntitiesExtensions/Contact.cs (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels') diff --git a/Software/DB/Change Scripts/Cascade Machine Delete To Configuration.sql b/Software/DB/Change Scripts/Cascade Machine Delete To Configuration.sql new file mode 100644 index 000000000..a0a38b6dc Binary files /dev/null and b/Software/DB/Change Scripts/Cascade Machine Delete To Configuration.sql differ diff --git a/Software/DB/Change Scripts/Cascade User Delete To Contact and Address.sql b/Software/DB/Change Scripts/Cascade User Delete To Contact and Address.sql new file mode 100644 index 000000000..052655968 Binary files /dev/null and b/Software/DB/Change Scripts/Cascade User Delete To Contact and Address.sql differ diff --git a/Software/DB/Tango.mdf b/Software/DB/Tango.mdf index 598a7c37e..cb00adf1a 100644 Binary files a/Software/DB/Tango.mdf and b/Software/DB/Tango.mdf differ diff --git a/Software/DB/Tango_log.ldf b/Software/DB/Tango_log.ldf index 1411d7c4e..972799de3 100644 Binary files a/Software/DB/Tango_log.ldf and b/Software/DB/Tango_log.ldf differ diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs index fdb0f8983..9478014b7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs @@ -81,6 +81,14 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels public RelayCommand AddOrganizationCommand { get; set; } + public RelayCommand RemoveOrganizationCommand { get; set; } + + public RelayCommand BackToManagedOrganizationCommand { get; set; } + + public RelayCommand RemoveRoleCommand { get; set; } + + public RelayCommand SaveManagedUserCommand { get; set; } + public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification) { _navigation = navigation; @@ -88,11 +96,15 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels LoadOrganizations(); - ManageOrganizationCommand = new RelayCommand(ManageOrganization, () => SelectedOrganization != null); + ManageOrganizationCommand = new RelayCommand(LoadSelectedOrganization, () => SelectedOrganization != null); BackToOrganizationsCommand = new RelayCommand(BackToOrganizations); ManageUserCommand = new RelayCommand(ManageUser, () => SelectedUser != null); SaveOrganizationCommand = new RelayCommand(SaveOrganization); AddOrganizationCommand = new RelayCommand(AddOrganization); + RemoveOrganizationCommand = new RelayCommand(RemoveOrganization, () => SelectedOrganization != null); + BackToManagedOrganizationCommand = new RelayCommand(BackToManagedOrganization); + RemoveRoleCommand = new RelayCommand(RemoveUserRole); + SaveManagedUserCommand = new RelayCommand(SaveManagedUser); } private async void AddOrganization() @@ -111,7 +123,19 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels await org.SaveAsync(_organizationsContext); Organizations = _organizationsContext.Organizations.ToObservableCollection(); SelectedOrganization = org; - ManageOrganization(); + LoadSelectedOrganization(); + } + } + } + + private async void RemoveOrganization() + { + if (_notification.ShowQuestion("Are you sure you want to remove " + SelectedOrganization.Name + " organization?")) + { + using (_notification.PushTaskItem("Removing organization...")) + { + await SelectedOrganization.DeleteCascadeAsync(_organizationsContext); + LoadOrganizations(); } } } @@ -120,7 +144,7 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels { using (_notification.PushTaskItem("Saving organization address and contact...")) { - ManagedOrganization.Contact.FullName = ManagedOrganization.Contact.FirstName + " " + ManagedOrganization.Contact.LastName; + ManagedOrganization.Contact.SetFullName(); await ManagedOrganization.SaveAsync(_manageContext); LoadOrganizations(); SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); @@ -134,8 +158,8 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels Task.Factory.StartNew(() => { _userContext = ObservablesContext.CreateDefault(); - Roles = _manageContext.Roles.ToObservableCollection(); - ManagedUser = _manageContext.Users.SingleOrDefault(x => x.Guid == SelectedUser.Guid); + Roles = _userContext.Roles.ToObservableCollection(); + ManagedUser = _userContext.Users.SingleOrDefault(x => x.Guid == SelectedUser.Guid); ManagedUserRoles = ManagedUser.Roles.ToObservableCollection(); InvokeUI(() => _navigation.NavigateTo(UsersAndRolesNavigationView.UserManagementView)); @@ -148,7 +172,32 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels _navigation.NavigateTo(UsersAndRolesNavigationView.OrganizationSelectionView); } - private void ManageOrganization() + private void BackToManagedOrganization() + { + _navigation.NavigateTo(UsersAndRolesNavigationView.OrganizationManagementView); + } + + private void RemoveUserRole(Role role) + { + ManagedUserRoles.Remove(role); + + foreach (var userRole in ManagedUser.UsersRoles.Where(x => x.Role == role).ToList()) + { + userRole.DefferedDelete(_userContext); + } + } + + private async void SaveManagedUser() + { + using (_notification.PushTaskItem("Saving user details...")) + { + ManagedUser.Contact.SetFullName(); + await ManagedUser.SaveAsync(_userContext); + LoadSelectedOrganization(); + } + } + + private void LoadSelectedOrganization() { using (_notification.PushTaskItem("Loading organization...")) { diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml index eaeb180ab..b92682b84 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml @@ -20,7 +20,7 @@ - + @@ -29,21 +29,27 @@ - - + + + - + ADDRESS - - + + CONTACT - - + + @@ -51,7 +57,7 @@ - @@ -105,7 +145,7 @@ - + @@ -117,6 +157,21 @@ + + + + + + + + + + + + + + + @@ -128,21 +183,31 @@ - + - + + - - + + + + + + + + + + + @@ -151,6 +216,8 @@ + + diff --git a/Software/Visual_Studio/Tango.BL/EntitiesExtensions/Contact.cs b/Software/Visual_Studio/Tango.BL/EntitiesExtensions/Contact.cs new file mode 100644 index 000000000..6ededa330 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/EntitiesExtensions/Contact.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL.Entities +{ + public partial class Contact + { + public void SetFullName() + { + FullName = FirstName + " " + LastName; + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs index 9e0a8801d..586d4da21 100644 --- a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs @@ -78,5 +78,10 @@ namespace Tango.BL /// Deletes this entity from the database. /// Task DeleteAsync(ObservablesContext context); + + /// + /// Deletes this entity using an SQL statement which will cause the database delete cascade effect. + /// + Task DeleteCascadeAsync(ObservablesContext context); } } diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs index add6877cb..43d5c06de 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs @@ -123,6 +123,18 @@ namespace Tango.BL { if (context == ObservablesEntitiesAdapter.Instance.Context) { + var tableName = this.GetType().GetCustomAttribute().Name; + + String propName = tableName.FromDalNameToTitleCase(); + + DbSet set = ObservablesEntitiesAdapter.Instance.Context.GetType().GetProperty(propName, BindingFlags.Instance | BindingFlags.Public).GetValue(context) as DbSet; + ObservableCollection obs = ObservablesEntitiesAdapter.Instance.GetType().GetProperty(propName, BindingFlags.Instance | BindingFlags.Public).GetValue(ObservablesEntitiesAdapter.Instance) as ObservableCollection; + + if (!obs.Contains(this as T)) + { + set.Add(this as T); + } + ObservablesEntitiesAdapter.Instance.SaveChanges(); } else @@ -284,6 +296,11 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa return me == other; } + public Task DeleteCascadeAsync(ObservablesContext context) + { + return context.Database.ExecuteSqlCommandAsync(String.Format("DELETE FROM {0} WHERE GUID='{1}'", this.GetType().GetCustomAttribute().Name, Guid)); + } + #region Operator Overloading //public static bool operator ==(ObservableEntity observable1, ObservableEntity observable2) diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index b9565630d..8159e0f3b 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -85,6 +85,7 @@ + diff --git a/Software/Visual_Studio/Tango.Core/ExtensionMethods/StringExtensions.cs b/Software/Visual_Studio/Tango.Core/ExtensionMethods/StringExtensions.cs index 048e942d5..e31456871 100644 --- a/Software/Visual_Studio/Tango.Core/ExtensionMethods/StringExtensions.cs +++ b/Software/Visual_Studio/Tango.Core/ExtensionMethods/StringExtensions.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Data.Entity.Design.PluralizationServices; +using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; /// @@ -54,6 +56,26 @@ public static class StringExtensions return titleRegEx.Replace(str, " "); } + /// + /// Formats the string as title case. + /// + /// The string. + /// + public static String ToTitleCase(this String str) + { + return Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(str.ToLower()); + } + + /// + /// Converts the specified database conventional name to the observables conventional name. + /// + /// DAL name. + /// + public static String FromDalNameToTitleCase(this String dalName) + { + return String.Join("", dalName.Split('_').Select(x => ToTitleCase(x))); + } + /// /// Singularizes the string. /// -- cgit v1.3.1 From e75cf513acb73558e948d6012b45f221c718dcf7 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Mon, 12 Mar 2018 17:03:38 +0200 Subject: Added cascade delete for Machine -> Jobs. Added addresses auto complete to users & roles. Maybe Users & Roles module is complete.. --- Software/DB/Tango.mdf | Bin 75497472 -> 75497472 bytes Software/DB/Tango_log.ldf | Bin 1048576 -> 1048576 bytes .../Views/JobView.xaml.cs | 1 + .../Providers/Place.cs | 31 +++++ .../Providers/PlaceAddress.cs | 53 +++++++++ .../Providers/PlacesProvider.cs | 47 ++++++++ .../Tango.MachineStudio.UsersAndRoles.csproj | 14 +++ .../ViewModels/MainViewVM.cs | 132 ++++++++++++++++++++- .../Views/AddressView.xaml | 8 +- .../Views/OrganizationManagementView.xaml | 10 +- .../Views/OrganizationManagementView.xaml.cs | 8 +- .../Views/UserManagementView.xaml | 27 ++++- .../Views/UserManagementView.xaml.cs | 8 +- .../Views/UserView.xaml | 23 ++++ .../Views/UserView.xaml.cs | 28 +++++ .../Tango.MachineStudio.UsersAndRoles/app.config | 11 ++ .../packages.config | 1 + .../Tango.MachineStudio.UI/Views/MainView.xaml.cs | 1 + .../Tango.AutoComplete/Editors/Themes/Generic.xaml | 3 +- .../Tango.BL/EntitiesExtensions/Contact.cs | 38 +++++- .../Tango.BL/EntitiesExtensions/User.cs | 31 +++++ .../Visual_Studio/Tango.BL/IObservableEntity.cs | 7 ++ .../Visual_Studio/Tango.BL/ObservableEntity.cs | 17 ++- Software/Visual_Studio/Tango.BL/Tango.BL.csproj | 3 + Software/Visual_Studio/Tango.BL/packages.config | 1 + .../Tango.SharedUI/Helpers/PasswordHelper.cs | 98 +++++++++++++++ .../Tango.SharedUI/Tango.SharedUI.csproj | 1 + 27 files changed, 583 insertions(+), 19 deletions(-) create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/Place.cs create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlaceAddress.cs create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlacesProvider.cs create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml.cs create mode 100644 Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/app.config create mode 100644 Software/Visual_Studio/Tango.SharedUI/Helpers/PasswordHelper.cs (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels') diff --git a/Software/DB/Tango.mdf b/Software/DB/Tango.mdf index cb00adf1a..a1dced350 100644 Binary files a/Software/DB/Tango.mdf and b/Software/DB/Tango.mdf differ diff --git a/Software/DB/Tango_log.ldf b/Software/DB/Tango_log.ldf index 972799de3..2b587c81f 100644 Binary files a/Software/DB/Tango_log.ldf and b/Software/DB/Tango_log.ldf differ diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs index 0c99dfe5f..044046450 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/Views/JobView.xaml.cs @@ -82,6 +82,7 @@ namespace Tango.MachineStudio.Developer.Views } jobBrushList.ItemsSource = segments; + UpdateGradientBrushDisplay(); } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/Place.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/Place.cs new file mode 100644 index 000000000..a2ac2a9b7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/Place.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace Tango.MachineStudio.UsersAndRoles.Providers +{ + public class Place + { + [XmlElement("address")] + [JsonProperty("address")] + public PlaceAddress Address { get; set; } + + [XmlAttribute("display_name")] + [JsonProperty("display_name")] + public String DisplayName { get; set; } + + public Place() + { + Address = new PlaceAddress(); + } + + public override string ToString() + { + return DisplayName; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlaceAddress.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlaceAddress.cs new file mode 100644 index 000000000..5b25794d1 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlaceAddress.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Serialization; + +namespace Tango.MachineStudio.UsersAndRoles.Providers +{ + public class PlaceAddress + { + [XmlElement("road")] + [JsonProperty("road")] + public String Road { get; set; } + + [XmlElement("village")] + [JsonProperty("village")] + public String Village + { + get { return City; } + set { City = value; } + } + + [XmlElement("town")] + [JsonProperty("town")] + public String Town + { + get { return City; } + set { City = value; } + } + + [XmlElement("city")] + [JsonProperty("city")] + public String City { get; set; } + + [XmlElement("state")] + [JsonProperty("state")] + public String State { get; set; } + + [XmlElement("postcode")] + [JsonProperty("postcode")] + public String PostalCode { get; set; } + + [XmlElement("country")] + [JsonProperty("country")] + public String Country { get; set; } + + [XmlElement("country_code")] + [JsonProperty("country_code")] + public String CountryCode { get; set; } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlacesProvider.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlacesProvider.cs new file mode 100644 index 000000000..681815d4c --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Providers/PlacesProvider.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Tango.AutoComplete.Editors; +using Tango.Logging; + +namespace Tango.MachineStudio.UsersAndRoles.Providers +{ + public class PlacesProvider : ISuggestionProvider + { + public IEnumerable GetSuggestions(string filter) + { + List places = new List(); + + using (WebClient web = new WebClient()) + { + try + { + String json = null; + + web.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"); + web.Headers.Add(HttpRequestHeader.ContentType, "application/json"); + web.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US"); + + json = web.DownloadString(String.Format("https://nominatim.openstreetmap.org/search?q={0}&format=json&addressdetails=1", filter)); + + if (json != null) + { + List results = JsonConvert.DeserializeObject>(json); + places.AddRange(results); + } + } + catch (Exception ex) + { + LogManager.Default.Log(ex, LogCategory.Debug); + } + } + + return places; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj index a64c536ed..9064519c0 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Tango.MachineStudio.UsersAndRoles.csproj @@ -58,6 +58,9 @@ ..\..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + + ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + @@ -83,6 +86,9 @@ + + + @@ -104,6 +110,9 @@ UserManagementView.xaml + + UserView.xaml + @@ -123,6 +132,7 @@ ResXFileCodeGenerator Resources.Designer.cs + SettingsSingleFileGenerator @@ -188,6 +198,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs index 9478014b7..7d82cbbbc 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/ViewModels/MainViewVM.cs @@ -10,6 +10,7 @@ using Tango.BL.Entities; using Tango.Core.Commands; using Tango.MachineStudio.Common.Notifications; using Tango.MachineStudio.UsersAndRoles.Navigation; +using Tango.MachineStudio.UsersAndRoles.Providers; using Tango.SharedUI; namespace Tango.MachineStudio.UsersAndRoles.ViewModels @@ -71,6 +72,36 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels set { _managedUser = value; RaisePropertyChangedAuto(); } } + private Place _selectedUserPlace; + public Place SelectedUserPlace + { + get { return _selectedUserPlace; } + set + { + _selectedUserPlace = value; + + if (_selectedUserPlace != null && _selectedUserPlace.Address != null) + { + SetUserPlace(value); + } + } + } + + private Place _selectedOrganizationPlace; + public Place SelectedOrganizationPlace + { + get { return _selectedOrganizationPlace; } + set + { + _selectedOrganizationPlace = value; + + if (_selectedOrganizationPlace != null && _selectedOrganizationPlace.Address != null) + { + SetOrganizationPlace(value); + } + } + } + public RelayCommand ManageOrganizationCommand { get; set; } public RelayCommand BackToOrganizationsCommand { get; set; } @@ -89,6 +120,10 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels public RelayCommand SaveManagedUserCommand { get; set; } + public RelayCommand AddUserCommand { get; set; } + + public RelayCommand RemoveUserCommand { get; set; } + public MainViewVM(UsersAndRolesNavigationManager navigation, INotificationProvider notification) { _navigation = navigation; @@ -98,13 +133,15 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels ManageOrganizationCommand = new RelayCommand(LoadSelectedOrganization, () => SelectedOrganization != null); BackToOrganizationsCommand = new RelayCommand(BackToOrganizations); - ManageUserCommand = new RelayCommand(ManageUser, () => SelectedUser != null); + ManageUserCommand = new RelayCommand(LoadSelectedUser, () => SelectedUser != null); SaveOrganizationCommand = new RelayCommand(SaveOrganization); AddOrganizationCommand = new RelayCommand(AddOrganization); RemoveOrganizationCommand = new RelayCommand(RemoveOrganization, () => SelectedOrganization != null); BackToManagedOrganizationCommand = new RelayCommand(BackToManagedOrganization); RemoveRoleCommand = new RelayCommand(RemoveUserRole); SaveManagedUserCommand = new RelayCommand(SaveManagedUser); + AddUserCommand = new RelayCommand(AddNewUser); + RemoveUserCommand = new RelayCommand(RemoveSelectedUser, () => SelectedUser != null); } private async void AddOrganization() @@ -144,14 +181,13 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels { using (_notification.PushTaskItem("Saving organization address and contact...")) { - ManagedOrganization.Contact.SetFullName(); await ManagedOrganization.SaveAsync(_manageContext); LoadOrganizations(); SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); } } - private void ManageUser() + private void LoadSelectedUser() { using (_notification.PushTaskItem("Loading user details...")) { @@ -189,9 +225,18 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels private async void SaveManagedUser() { + try + { + ManagedUser.Validate(_userContext); + } + catch (Exception ex) + { + _notification.ShowError(ex.Message); + return; + } + using (_notification.PushTaskItem("Saving user details...")) { - ManagedUser.Contact.SetFullName(); await ManagedUser.SaveAsync(_userContext); LoadSelectedOrganization(); } @@ -237,6 +282,85 @@ namespace Tango.MachineStudio.UsersAndRoles.ViewModels ManagedUserRoles.Add(role); } + private async void RemoveSelectedUser() + { + if (_notification.ShowQuestion("Are you sure you want to remove the selected user?")) + { + using (_notification.PushTaskItem("Removing user...")) + { + await SelectedUser.DeleteCascadeAsync(_manageContext); + LoadSelectedOrganization(); + } + } + } + + private async void AddNewUser() + { + String email = _notification.ShowTextInput("Enter user email", "email"); + + if (!String.IsNullOrWhiteSpace(email)) + { + User user = new User(); + user.Email = email; + user.Password = "1111"; + user.Contact = new Contact() + { + FirstName = "Twine", + LastName = "User", + Email = email, + }; + + user.UsersRoles.Add(new UsersRole() + { + User = user, + Role = _manageContext.Roles.SingleOrDefault(x => x.Code == (int)BL.Enumerations.Roles.User) + }); + + try + { + user.Validate(_manageContext); + } + catch (Exception ex) + { + _notification.ShowError(ex.Message); + return; + } + + user.Address = new Address(); + + ManagedOrganization.Users.Add(user); + + using (_notification.PushTaskItem("Adding new user...")) + { + await ManagedOrganization.SaveAsync(_manageContext); + LoadOrganizations(); + SelectedOrganization = Organizations.SingleOrDefault(x => x.Guid == ManagedOrganization.Guid); + } + } + } + + private void SetUserPlace(Place place) + { + ManagedUser.Address.AddressString = place.Address.Road; + ManagedUser.Address.City = place.Address.City; + ManagedUser.Address.Country = place.Address.Country; + ManagedUser.Address.CountryCode = place.Address.CountryCode; + ManagedUser.Address.Locality = place.Address.CountryCode; + ManagedUser.Address.PostalCode = place.Address.PostalCode; + ManagedUser.Address.State = place.Address.State; + } + + private void SetOrganizationPlace(Place place) + { + ManagedOrganization.Address.AddressString = place.Address.Road; + ManagedOrganization.Address.City = place.Address.City; + ManagedOrganization.Address.Country = place.Address.Country; + ManagedOrganization.Address.CountryCode = place.Address.CountryCode; + ManagedOrganization.Address.Locality = place.Address.CountryCode; + ManagedOrganization.Address.PostalCode = place.Address.PostalCode; + ManagedOrganization.Address.State = place.Address.State; + } + protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null) { base.RaisePropertyChangedAuto(caller); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/AddressView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/AddressView.xaml index 41f7871e2..937cf14dd 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/AddressView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/AddressView.xaml @@ -15,17 +15,17 @@ - + - + - + - + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml index 7769f65ed..64b05769a 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml @@ -9,6 +9,7 @@ xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:mahApps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:providers="clr-namespace:Tango.MachineStudio.UsersAndRoles.Providers" xmlns:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" xmlns:local="clr-namespace:Tango.MachineStudio.UsersAndRoles.Views" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" @@ -17,6 +18,7 @@ + @@ -38,7 +40,13 @@ ADDRESS - + + + + + + + CONTACT diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml.cs index 76b256d62..e2c44a584 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/OrganizationManagementView.xaml.cs @@ -12,17 +12,23 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using static Tango.SharedUI.Controls.MultiTransitionControl; namespace Tango.MachineStudio.UsersAndRoles.Views { /// /// Interaction logic for OrganizationManagementView.xaml /// - public partial class OrganizationManagementView : UserControl + public partial class OrganizationManagementView : UserControl , ITransitionView { public OrganizationManagementView() { InitializeComponent(); } + + public void OnTransitionCompleted() + { + address_auto.Text = ""; + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml index b92682b84..ccb38b198 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.MachineStudio.UsersAndRoles" xmlns:vm="clr-namespace:Tango.MachineStudio.UsersAndRoles.ViewModels" + xmlns:providers="clr-namespace:Tango.MachineStudio.UsersAndRoles.Providers" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:dragAndDrop="clr-namespace:Tango.DragAndDrop;assembly=Tango.DragAndDrop" xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" @@ -16,6 +17,10 @@ mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + + + + @@ -39,19 +44,31 @@ - + - ADDRESS - - + LOGIN + + CONTACT - + + + ADDRESS + + + + + + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs index b26f0ea03..f2ff25637 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserManagementView.xaml.cs @@ -15,13 +15,14 @@ using System.Windows.Shapes; using Tango.BL.Entities; using Tango.DragAndDrop; using Tango.MachineStudio.UsersAndRoles.ViewModels; +using static Tango.SharedUI.Controls.MultiTransitionControl; namespace Tango.MachineStudio.UsersAndRoles.Views { /// /// Interaction logic for UserManagementView.xaml /// - public partial class UserManagementView : UserControl + public partial class UserManagementView : UserControl, ITransitionView { private MainViewVM _vm; @@ -47,5 +48,10 @@ namespace Tango.MachineStudio.UsersAndRoles.Views _vm.OnDropRole(e.Draggable.DataContext as Role); } } + + public void OnTransitionCompleted() + { + address_auto.Text = ""; + } } } diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml new file mode 100644 index 000000000..6c7596015 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml.cs new file mode 100644 index 000000000..b617bdbc4 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/Views/UserView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.MachineStudio.UsersAndRoles.Views +{ + /// + /// Interaction logic for UserView.xaml + /// + public partial class UserView : UserControl + { + public UserView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/app.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/app.config new file mode 100644 index 000000000..cacd4cd77 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config index cf0df03c8..6b8afad69 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.UsersAndRoles/packages.config @@ -6,4 +6,5 @@ + \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml.cs index c40904173..e0ae60b87 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml.cs @@ -76,6 +76,7 @@ namespace Tango.MachineStudio.UI.Views { Tag = module.Name, Content = grid, + Visibility = Visibility.Hidden, }); _loader.UserModules.Add(module); diff --git a/Software/Visual_Studio/SideChains/Tango.AutoComplete/Editors/Themes/Generic.xaml b/Software/Visual_Studio/SideChains/Tango.AutoComplete/Editors/Themes/Generic.xaml index a3c124841..25667d1d1 100644 --- a/Software/Visual_Studio/SideChains/Tango.AutoComplete/Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/SideChains/Tango.AutoComplete/Editors/Themes/Generic.xaml @@ -93,7 +93,8 @@ x.Role).ToList().SelectMany(x => x.RolesPermissions).Select(x => x.Permission).ToList(); } } + + public override void Validate(ObservablesContext context) + { + var users = context.Users.ToList(); + + if (users.Exists(x => x.Guid != Guid && x.Email.ToLower() == Email.ToLower())) + { + throw new ArgumentException("The specified email is already taken by another account."); + } + + if (!Email.IsEmail()) + { + throw new ArgumentException("The specified email address is invalid."); + } + + if (!Password.IsBetweenLength(4, 30)) + { + throw new ArgumentException("A user password must be at least 4 characters long and maximum 30."); + } + + if (Contact != null) + { + Contact.Validate(context); + } + + if (Address != null) + { + Address.Validate(context); + } + } } } diff --git a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs index 586d4da21..265b51179 100644 --- a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs @@ -83,5 +83,12 @@ namespace Tango.BL /// Deletes this entity using an SQL statement which will cause the database delete cascade effect. /// Task DeleteCascadeAsync(ObservablesContext context); + + /// + /// Performs entity field validation. + /// Will throw an exception with the proper message if one of the fields is invalid. + /// + /// The context. + void Validate(ObservablesContext context); } } diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs index 43d5c06de..e46e54ad3 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs @@ -166,7 +166,7 @@ namespace Tango.BL /// public Task SaveAsync(ObservablesContext context) { - return Task.Factory.StartNew(() => + return Task.Factory.StartNew(() => { Save(context); }); @@ -296,11 +296,26 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa return me == other; } + /// + /// Deletes this entity using an SQL statement which will cause the database delete cascade effect. + /// + /// + /// public Task DeleteCascadeAsync(ObservablesContext context) { return context.Database.ExecuteSqlCommandAsync(String.Format("DELETE FROM {0} WHERE GUID='{1}'", this.GetType().GetCustomAttribute().Name, Guid)); } + /// + /// Performs entity field validation. + /// Will throw an exception with the proper message if one of the fields is invalid. + /// + /// The context. + public virtual void Validate(ObservablesContext context) + { + + } + #region Operator Overloading //public static bool operator ==(ObservableEntity observable1, ObservableEntity observable2) diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index 8159e0f3b..a3f952644 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -45,6 +45,9 @@ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\SimpleValidator.0.6.1.0\lib\net40\SimpleValidator.dll + diff --git a/Software/Visual_Studio/Tango.BL/packages.config b/Software/Visual_Studio/Tango.BL/packages.config index dcc94a0a3..ed5d800c9 100644 --- a/Software/Visual_Studio/Tango.BL/packages.config +++ b/Software/Visual_Studio/Tango.BL/packages.config @@ -3,6 +3,7 @@ + diff --git a/Software/Visual_Studio/Tango.SharedUI/Helpers/PasswordHelper.cs b/Software/Visual_Studio/Tango.SharedUI/Helpers/PasswordHelper.cs new file mode 100644 index 000000000..b87faf08f --- /dev/null +++ b/Software/Visual_Studio/Tango.SharedUI/Helpers/PasswordHelper.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace Tango.SharedUI.Helpers +{ + public class PasswordHelper + { + public static readonly DependencyProperty PasswordProperty = + DependencyProperty.RegisterAttached("Password", + typeof(string), typeof(PasswordHelper), + new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged)); + + public static readonly DependencyProperty AttachProperty = + DependencyProperty.RegisterAttached("Attach", + typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, Attach)); + + private static readonly DependencyProperty IsUpdatingProperty = + DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), + typeof(PasswordHelper)); + + + public static void SetAttach(DependencyObject dp, bool value) + { + dp.SetValue(AttachProperty, value); + } + + public static bool GetAttach(DependencyObject dp) + { + return (bool)dp.GetValue(AttachProperty); + } + + public static string GetPassword(DependencyObject dp) + { + return (string)dp.GetValue(PasswordProperty); + } + + public static void SetPassword(DependencyObject dp, string value) + { + dp.SetValue(PasswordProperty, value); + } + + private static bool GetIsUpdating(DependencyObject dp) + { + return (bool)dp.GetValue(IsUpdatingProperty); + } + + private static void SetIsUpdating(DependencyObject dp, bool value) + { + dp.SetValue(IsUpdatingProperty, value); + } + + private static void OnPasswordPropertyChanged(DependencyObject sender, + DependencyPropertyChangedEventArgs e) + { + PasswordBox passwordBox = sender as PasswordBox; + passwordBox.PasswordChanged -= PasswordChanged; + + if (!(bool)GetIsUpdating(passwordBox)) + { + passwordBox.Password = (string)e.NewValue; + } + passwordBox.PasswordChanged += PasswordChanged; + } + + private static void Attach(DependencyObject sender, + DependencyPropertyChangedEventArgs e) + { + PasswordBox passwordBox = sender as PasswordBox; + + if (passwordBox == null) + return; + + if ((bool)e.OldValue) + { + passwordBox.PasswordChanged -= PasswordChanged; + } + + if ((bool)e.NewValue) + { + passwordBox.PasswordChanged += PasswordChanged; + } + } + + private static void PasswordChanged(object sender, RoutedEventArgs e) + { + PasswordBox passwordBox = sender as PasswordBox; + SetIsUpdating(passwordBox, true); + SetPassword(passwordBox, passwordBox.Password); + SetIsUpdating(passwordBox, false); + } + } + +} diff --git a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj index 1a751fda2..49590dcf5 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj +++ b/Software/Visual_Studio/Tango.SharedUI/Tango.SharedUI.csproj @@ -120,6 +120,7 @@ ParameterizedEditor.xaml + -- cgit v1.3.1