From 621230afe9d9040536b43241e63117c9bb34beaa Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Wed, 11 Dec 2019 20:57:30 +0200 Subject: Implemented Jobs, JobRuns & Machine Events Synchronization. Added synchronizations to Updates view on Machine Designer. Removed request response events logging from machine studio. Fixed issue with exception throwing from machine service. Implemented "New jobs synchronized" notification item to PPC. Added synchronization to PPC settings. Added Synchronization view to technician module. Implemented PPC Schema synchronizer utility. Added custom query support to EntityCollectionBuilder. Added synchronization status to TangoUpdate. Removed FK from Jobs and Job runs. --- .../Tango.MachineStudio.UI/ViewModelLocator.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs') diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs index 3fffd69fd..25843d1c3 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using Tango.Core.DI; using Tango.Integration.ExternalBridge; @@ -71,7 +72,16 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Unregister(); - TangoIOC.Default.Register(new MachineStudioWebClient()); + + if (App.StartupArgs.Contains("-webDebug")) + { + TangoIOC.Default.Register(new MachineStudioWebClient("http://localhost:1111", null)); + } + else + { + TangoIOC.Default.Register(new MachineStudioWebClient()); + } + TangoIOC.Default.Register(new DefaultDispatcherProvider(Application.Current.Dispatcher)); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -84,7 +94,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); - + TangoIOC.Default.Register(); TangoIOC.Default.Register(); -- cgit v1.3.1 From 74d6b86d46819376f0389d6fd4055e40e4e01598 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Tue, 17 Dec 2019 20:04:34 +0200 Subject: Started working on Action Logs !!! --- Software/DB/PPC/Tango.mdf | Bin 75497472 -> 75497472 bytes Software/DB/PPC/Tango_log.ldf | Bin 53673984 -> 53673984 bytes Software/DB/Tango.mdf | Bin 75497472 -> 75497472 bytes Software/DB/Tango_log.ldf | Bin 22675456 -> 22675456 bytes .../ViewModels/MainViewVM.cs | 12 +- .../Tango.MachineStudio.UI/ViewModelLocator.cs | 3 + .../Tango.BL/ActionLogs/BasicActionLogComparer.cs | 181 +++++++++++++ .../Tango.BL/ActionLogs/DefaultActionLogManager.cs | 122 +++++++++ .../Tango.BL/ActionLogs/IActionLogComparable.cs | 21 ++ .../Tango.BL/ActionLogs/IActionLogManager.cs | 23 ++ .../Visual_Studio/Tango.BL/DTO/ActionLogDTO.cs | 14 + .../Visual_Studio/Tango.BL/DTO/ActionLogDTOBase.cs | 73 ++++++ .../Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs | 5 +- Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs | 7 + .../Visual_Studio/Tango.BL/Entities/ActionLog.cs | 60 +++++ .../Tango.BL/Entities/ActionLogBase.cs | 282 +++++++++++++++++++++ Software/Visual_Studio/Tango.BL/Entities/Job.cs | 2 + .../Visual_Studio/Tango.BL/Entities/UserBase.cs | 38 +++ .../Tango.BL/Enumerations/ActionLogType.cs | 90 +++++++ .../Visual_Studio/Tango.BL/ObservableEntity.cs | 28 +- .../Visual_Studio/Tango.BL/ObservableEntityDTO.cs | 24 +- .../Visual_Studio/Tango.BL/ObservablesContext.cs | 8 + .../ObservablesEntitiesAdapterExtension.cs | 38 +++ .../ObservablesStaticCollectionsExtension.cs | 38 +++ Software/Visual_Studio/Tango.BL/Tango.BL.csproj | 12 +- .../Tango.BL/ValueObjects/ActionLogDifference.cs | 16 ++ .../Tango.DAL.Remote/DB/ACTION_LOGS.cs | 29 +++ .../Tango.DAL.Remote/DB/RemoteADO.Context.cs | 1 + .../Tango.DAL.Remote/DB/RemoteADO.Designer.cs | 2 +- .../Tango.DAL.Remote/DB/RemoteADO.edmx | 79 ++++++ .../Tango.DAL.Remote/DB/RemoteADO.edmx.diagram | 156 ++++++------ Software/Visual_Studio/Tango.DAL.Remote/DB/USER.cs | 3 + .../Tango.DAL.Remote/Tango.DAL.Remote.csproj | 5 +- 33 files changed, 1288 insertions(+), 84 deletions(-) create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs create mode 100644 Software/Visual_Studio/Tango.BL/DTO/ActionLogDTO.cs create mode 100644 Software/Visual_Studio/Tango.BL/DTO/ActionLogDTOBase.cs create mode 100644 Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs create mode 100644 Software/Visual_Studio/Tango.BL/Entities/ActionLogBase.cs create mode 100644 Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs create mode 100644 Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs create mode 100644 Software/Visual_Studio/Tango.DAL.Remote/DB/ACTION_LOGS.cs (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs') diff --git a/Software/DB/PPC/Tango.mdf b/Software/DB/PPC/Tango.mdf index 41603a45f..4d696d2c1 100644 Binary files a/Software/DB/PPC/Tango.mdf and b/Software/DB/PPC/Tango.mdf differ diff --git a/Software/DB/PPC/Tango_log.ldf b/Software/DB/PPC/Tango_log.ldf index 12b0bd50c..9e60e0704 100644 Binary files a/Software/DB/PPC/Tango_log.ldf and b/Software/DB/PPC/Tango_log.ldf differ diff --git a/Software/DB/Tango.mdf b/Software/DB/Tango.mdf index 5d5ff5ddb..a4bdfc14b 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 4ff9f3fd3..2fe319056 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/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs index ceb093be2..d598e2458 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs @@ -51,6 +51,8 @@ using Tango.ColorConversion; using Tango.PMR.Exports; using Microsoft.WindowsAPICodePack.Dialogs; using Tango.BL.Enumerations; +using Tango.BL.DTO; +using Tango.BL.ActionLogs; namespace Tango.MachineStudio.Developer.ViewModels { @@ -86,6 +88,8 @@ namespace Tango.MachineStudio.Developer.ViewModels private TaskItem _preparingTaskItem; private IColorConverter _converter; private string _current_job_string; + private JobDTO _beforeSaveJobDTO; + private IActionLogManager _actionLogManager; #region Properties @@ -748,7 +752,7 @@ namespace Tango.MachineStudio.Developer.ViewModels /// /// The application manager. /// The notification provider. - public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, INavigationManager navigationManager, IAuthenticationProvider authentication, IEventLogger eventLogger, ISpeechProvider speech) + public MainViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, IDiagnosticsFrameProvider diagnosticsFrameProvider, IVideoCaptureProvider videoCaptureProvider, DeveloperNavigationManager navigation, INavigationManager navigationManager, IAuthenticationProvider authentication, IEventLogger eventLogger, ISpeechProvider speech, IActionLogManager actionLogManager) { _converter = new DefaultColorConverter(); @@ -757,6 +761,7 @@ namespace Tango.MachineStudio.Developer.ViewModels AuthenticationProvider = authentication; + _actionLogManager = actionLogManager; _notification = notificationProvider; _speech = speech; _navigation = navigation; @@ -1848,6 +1853,7 @@ namespace Tango.MachineStudio.Developer.ViewModels //_activeJobDbContext.IdsPacks.Where(x => x.ConfigurationGuid == ActiveJob.Machine.ConfigurationGuid).ToList(); + _beforeSaveJobDTO = JobDTO.FromObservable(ActiveJob); LogManager.Log("Setting selected segment..."); @@ -1921,6 +1927,10 @@ namespace Tango.MachineStudio.Developer.ViewModels ActiveJob.MarkModified(_activeJobDbContext); _activeJobDbContext.SaveChanges(); + var afterJobDTO = JobDTO.FromObservable(ActiveJob); + _actionLogManager.InsertLog(ActionLogType.JobSaved, AuthenticationProvider.CurrentUser, _beforeSaveJobDTO.Name, _beforeSaveJobDTO, afterJobDTO, "Job saved from research module in Machine Studio.").GetAwaiter().GetResult(); + _beforeSaveJobDTO = afterJobDTO; + _machineDbContext.Entry(SelectedMachineJob).Reload(); _machineDbContext.Entry(SelectedMachineJob).Collection(x => x.Segments).Load(); diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs index 25843d1c3..a61f14746 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Windows; +using Tango.BL.ActionLogs; using Tango.Core.DI; using Tango.Integration.ExternalBridge; using Tango.Logging; @@ -70,6 +71,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); @@ -93,6 +95,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(new DefaultActionLogManager() { ThrowExceptions = false }); TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs new file mode 100644 index 000000000..61fc373a8 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.ValueObjects; + +namespace Tango.BL.ActionLogs +{ + public class BasicActionLogComparer + { + public Task> Compare(IActionLogComparable before, IActionLogComparable after) + { + return Task.Factory.StartNew>(() => + { + List diffs = new List(); + + Compare(diffs, before, after, null); + + return diffs; + }); + } + + private void Compare(List diffs, Object before, Object after, HashSet scannedObjects) + { + if (scannedObjects == null) + { + scannedObjects = new HashSet(); + } + + if (before == null && after == null) return; + + if (before != null) + { + if (scannedObjects.Contains(before)) return; + scannedObjects.Add(before); + } + + if (after != null) + { + if (scannedObjects.Contains(after)) return; + scannedObjects.Add(after); + } + + String component = GetComponentName(before, after); + + foreach (var prop in GetProperties(before, after)) + { + if (GetShouldIgnore(prop, before, after)) continue; + + if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) + { + object beforeValue = null; + object afterValue = null; + + if (before != null) + { + beforeValue = prop.GetValue(before); + } + + if (after != null) + { + afterValue = prop.GetValue(after); + } + + if (afterValue == null && beforeValue != null) AddDiff(diffs, component, prop.Name, beforeValue, afterValue); + if (afterValue != null && beforeValue == null) AddDiff(diffs, component, prop.Name, beforeValue, afterValue); + + if (afterValue != null && beforeValue != null) + { + if (!afterValue.Equals(beforeValue)) + { + AddDiff(diffs, component, prop.Name, beforeValue, afterValue); + } + } + } + else if (!prop.PropertyType.IsGenericType) + { + object beforePropInstance = null; + object afterPropInstance = null; + + if (before != null) + { + beforePropInstance = prop.GetValue(before); + } + + if (after != null) + { + afterPropInstance = prop.GetValue(after); + } + + Compare(diffs, beforePropInstance, afterPropInstance, scannedObjects); + } + else + { + IList beforeCollection = null; + IList afterCollection = null; + + if (before != null) + { + beforeCollection = prop.GetValue(before) as IList; + } + + if (after != null) + { + afterCollection = prop.GetValue(after) as IList; + } + + if (beforeCollection != null && beforeCollection == null) + { + for (int i = 0; i < beforeCollection.Count; i++) + { + Compare(diffs, beforeCollection[i], null, scannedObjects); + } + } + else if (beforeCollection == null && afterCollection != null) + { + for (int i = 0; i < afterCollection.Count; i++) + { + Compare(diffs, null, afterCollection[i], scannedObjects); + } + } + + if (beforeCollection != null && afterCollection != null) + { + for (int i = 0; i < Math.Max(beforeCollection.Count, afterCollection.Count); i++) + { + var beforeItem = i < beforeCollection.Count ? beforeCollection[i] : null; + var afterItem = i < afterCollection.Count ? afterCollection[i] : null; + Compare(diffs, beforeItem, afterItem, scannedObjects); + } + } + } + } + } + + private void AddDiff(List diffs, String component, String property, object before, object after) + { + diffs.Add(new ActionLogDifference() + { + Component = component, + Property = property, + Before = before, + After = after + }); + } + + private String GetComponentName(Object before, Object after) + { + return after != null ? after.GetType().Name : before.GetType().Name; + } + + private PropertyInfo GetProperty(String name, Object before, Object after) + { + return after != null ? after.GetType().GetProperty(name) : before.GetType().GetProperty(name); + } + + private List GetProperties(BindingFlags flags, Object before, Object after) + { + return after != null ? after.GetType().GetProperties(flags).ToList() : before.GetType().GetProperties(flags).ToList(); + } + + private List GetProperties(Object before, Object after) + { + return after != null ? after.GetType().GetProperties().ToList() : before.GetType().GetProperties().ToList(); + } + + private bool GetShouldIgnore(PropertyInfo prop, Object before, Object after) + { + var beforeCast = before as IActionLogComparable; + var afterCast = after as IActionLogComparable; + + if (beforeCast != null) return beforeCast.ShouldActionLogIgnore(prop.Name); + if (afterCast != null) return afterCast.ShouldActionLogIgnore(prop.Name); + + return false; + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs new file mode 100644 index 000000000..23562bee0 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; +using Tango.Core; +using Tango.Core.ExtensionMethods; + +namespace Tango.BL.ActionLogs +{ + public class DefaultActionLogManager : ExtendedObject, IActionLogManager + { + public bool ThrowExceptions { get; set; } + + public DefaultActionLogManager() + { + ThrowExceptions = true; + } + + public async Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, List differences, string message = null) + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + try + { + ActionLog log = new ActionLog(); + log.ActionType = type; + log.LastUpdated = DateTime.UtcNow; + log.UserGuid = userGuid; + log.RelatedObjectName = relatedObjectName; + log.RelatedObjectGuid = relatedObjectGuid; + log.Message = message; + log.Differences = differences; + + db.ActionLogs.Add(log); + + await db.SaveChangesAsync(); + + LogManager.Log($"Action log '{type}' inserted."); + + if (differences != null && differences.Count > 0) + { + Debug.WriteLine($"Action log differences:\n{differences.ToJsonString()}"); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error inserting action log '{type}'."); + + if (ThrowExceptions) + { + throw ex; + } + } + } + } + + public async Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) + { + List diffs = null; + + try + { + if (relatedObjectAfter != null) + { + diffs = await relatedObjectAfter.CompareTo(relatedObjectBefore); + } + else + { + diffs = await relatedObjectBefore.CompareTo(relatedObjectAfter); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error while comparing for action log '{type}'."); + + if (ThrowExceptions) + { + throw ex; + } + } + + if (diffs.Count > 0) + { + await InsertLog(type, userGuid, relatedObjectName, relatedObjectAfter.Guid, diffs, message); + } + else + { + LogManager.Log($"Action log '{type}' was about to be inserted but skipped due to no differences."); + } + } + + public Task InsertLog(ActionLogType type, User user, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) + { + return InsertLog(type, user.Guid, relatedObjectName, relatedObjectBefore, relatedObjectAfter, message); + } + + public Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, string message = null) + { + return InsertLog(type, userGuid, relatedObjectName, relatedObjectGuid, null, message); + } + + public Task InsertLog(ActionLogType type, User user, string relatedObjectName, IObservableEntity relatedObject, string message = null) + { + return InsertLog(type, user.Guid, relatedObjectName, relatedObject?.Guid, message); + } + + public Task InsertLog(ActionLogType type, string userGuid, string message = null) + { + return InsertLog(type, userGuid, null, null, message); + } + + public Task InsertLog(ActionLogType type, User user, string message = null) + { + return InsertLog(type, user.Guid, message); + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs new file mode 100644 index 000000000..de534141b --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.ValueObjects; + +namespace Tango.BL.ActionLogs +{ + public interface IActionLogComparable + { + String Guid { get; } + Task> CompareTo(IActionLogComparable before); + bool ShouldActionLogIgnore(String propName); + } + + public interface IActionLogComparable : IActionLogComparable where T : class + { + Task> CompareTo(T before); + } +} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs new file mode 100644 index 000000000..fd903bbba --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; + +namespace Tango.BL.ActionLogs +{ + public interface IActionLogManager + { + bool ThrowExceptions { get; set; } + Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, List differences, String message = null); + Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); + Task InsertLog(ActionLogType type, User user, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); + Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, String message = null); + Task InsertLog(ActionLogType type, User user, String relatedObjectName, IObservableEntity relatedObject, String message = null); + Task InsertLog(ActionLogType type, String userGuid, String message = null); + Task InsertLog(ActionLogType type, User user, String message = null); + } +} diff --git a/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTO.cs new file mode 100644 index 000000000..a847c6f24 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTO.cs @@ -0,0 +1,14 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL.DTO +{ + public class ActionLogDTO : ActionLogDTOBase + { + + } +} diff --git a/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTOBase.cs b/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTOBase.cs new file mode 100644 index 000000000..24cf4e94f --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/DTO/ActionLogDTOBase.cs @@ -0,0 +1,73 @@ + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Tango Observables Generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. Do not modify! +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; + +namespace Tango.BL.DTO +{ + public abstract class ActionLogDTOBase : ObservableEntityDTO + { + + /// + /// type + /// + public Int32 Type + { + get; set; + } + + /// + /// user guid + /// + public String UserGuid + { + get; set; + } + + /// + /// related object name + /// + public String RelatedObjectName + { + get; set; + } + + /// + /// related object guid + /// + public String RelatedObjectGuid + { + get; set; + } + + /// + /// message + /// + public String Message + { + get; set; + } + + /// + /// difference + /// + public String Difference + { + get; set; + } + + } +} diff --git a/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs index 447509ba7..585f2f2ee 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs @@ -9,6 +9,9 @@ namespace Tango.BL.DTO { public class BrushStopDTO : BrushStopDTOBase { - + protected override bool OnShouldActionLogIgnore(string propName) + { + return propName == nameof(Corrected); + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs index 7ee6c9bb0..36f7ea9be 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs @@ -15,5 +15,12 @@ namespace Tango.BL.DTO { Segments = new List(); } + + protected override bool OnShouldActionLogIgnore(string propName) + { + return propName == nameof(JobDTO.LastRun) || + propName == nameof(JobDTO.Status) || + propName == nameof(JobDTO.IsSynchronized); + } } } diff --git a/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs b/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs new file mode 100644 index 000000000..af88ee7f1 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs @@ -0,0 +1,60 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; + +namespace Tango.BL.Entities +{ + public class ActionLog : ActionLogBase + { + private List _differences; + + [NotMapped] + [JsonIgnore] + public ActionLogType ActionType + { + get { return (ActionLogType)Type; } + set { Type = value.ToInt32(); RaisePropertyChanged(nameof(ActionType)); } + } + + [NotMapped] + [JsonIgnore] + public List Differences + { + get + { + if (_differences != null) + { + try + { + _differences = JsonConvert.DeserializeObject>(Difference); + } + catch + { + _differences = new List(); + } + } + else + { + _differences = new List(); + } + + return _differences; + } + set + { + _differences = value; + + if (_differences != null) + { + Difference = JsonConvert.SerializeObject(_differences); + } + } + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/Entities/ActionLogBase.cs b/Software/Visual_Studio/Tango.BL/Entities/ActionLogBase.cs new file mode 100644 index 000000000..077c834d2 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/Entities/ActionLogBase.cs @@ -0,0 +1,282 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Tango Observables Generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. Do not modify! +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Xml.Serialization; +using Newtonsoft.Json; +using System.Linq; +using Tango.DAL.Remote.DB; +using Tango.Core; +using System.ComponentModel; + +namespace Tango.BL.Entities +{ + [Table("ACTION_LOGS")] + public abstract class ActionLogBase : ObservableEntity + { + + public event EventHandler TypeChanged; + + public event EventHandler RelatedObjectNameChanged; + + public event EventHandler MessageChanged; + + public event EventHandler DifferenceChanged; + + public event EventHandler UserChanged; + + protected Int32 _type; + + /// + /// Gets or sets the actionlogbase type. + /// + + [Column("TYPE")] + + public Int32 Type + { + get + { + return _type; + } + + set + { + if (_type != value) + { + _type = value; + + OnTypeChanged(value); + + } + } + } + + protected String _userguid; + + /// + /// Gets or sets the actionlogbase user guid. + /// + + [Column("USER_GUID")] + [ForeignKey("User")] + + public String UserGuid + { + get + { + return _userguid; + } + + set + { + if (_userguid != value) + { + _userguid = value; + + } + } + } + + protected String _relatedobjectname; + + /// + /// Gets or sets the actionlogbase related object name. + /// + + [Column("RELATED_OBJECT_NAME")] + + public String RelatedObjectName + { + get + { + return _relatedobjectname; + } + + set + { + if (_relatedobjectname != value) + { + _relatedobjectname = value; + + OnRelatedObjectNameChanged(value); + + } + } + } + + protected String _relatedobjectguid; + + /// + /// Gets or sets the actionlogbase related object guid. + /// + + [Column("RELATED_OBJECT_GUID")] + + public String RelatedObjectGuid + { + get + { + return _relatedobjectguid; + } + + set + { + if (_relatedobjectguid != value) + { + _relatedobjectguid = value; + + } + } + } + + protected String _message; + + /// + /// Gets or sets the actionlogbase message. + /// + + [Column("MESSAGE")] + + public String Message + { + get + { + return _message; + } + + set + { + if (_message != value) + { + _message = value; + + OnMessageChanged(value); + + } + } + } + + protected String _difference; + + /// + /// Gets or sets the actionlogbase difference. + /// + + [Column("DIFFERENCE")] + + public String Difference + { + get + { + return _difference; + } + + set + { + if (_difference != value) + { + _difference = value; + + OnDifferenceChanged(value); + + } + } + } + + protected User _user; + + /// + /// Gets or sets the actionlogbase user. + /// + + [XmlIgnore] + [JsonIgnore] + public virtual User User + { + get + { + return _user; + } + + set + { + if (_user != value) + { + _user = value; + + if (User != null) + { + UserGuid = User.Guid; + } + + OnUserChanged(value); + + } + } + } + + /// + /// Called when the Type has changed. + /// + protected virtual void OnTypeChanged(Int32 type) + { + TypeChanged?.Invoke(this, type); + RaisePropertyChanged(nameof(Type)); + } + + /// + /// Called when the RelatedObjectName has changed. + /// + protected virtual void OnRelatedObjectNameChanged(String relatedobjectname) + { + RelatedObjectNameChanged?.Invoke(this, relatedobjectname); + RaisePropertyChanged(nameof(RelatedObjectName)); + } + + /// + /// Called when the Message has changed. + /// + protected virtual void OnMessageChanged(String message) + { + MessageChanged?.Invoke(this, message); + RaisePropertyChanged(nameof(Message)); + } + + /// + /// Called when the Difference has changed. + /// + protected virtual void OnDifferenceChanged(String difference) + { + DifferenceChanged?.Invoke(this, difference); + RaisePropertyChanged(nameof(Difference)); + } + + /// + /// Called when the User has changed. + /// + protected virtual void OnUserChanged(User user) + { + UserChanged?.Invoke(this, user); + RaisePropertyChanged(nameof(User)); + } + + /// + /// Initializes a new instance of the class. + /// + public ActionLogBase() : base() + { + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/Entities/Job.cs b/Software/Visual_Studio/Tango.BL/Entities/Job.cs index c4847c5e9..1a5883557 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/Job.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/Job.cs @@ -10,8 +10,10 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; +using Tango.BL.ActionLogs; using Tango.BL.Builders; using Tango.BL.Enumerations; +using Tango.BL.ValueObjects; using Tango.Core; using Tango.Core.ExtensionMethods; using Tango.Logging; diff --git a/Software/Visual_Studio/Tango.BL/Entities/UserBase.cs b/Software/Visual_Studio/Tango.BL/Entities/UserBase.cs index 5445b2980..805cf9d57 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/UserBase.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/UserBase.cs @@ -34,6 +34,8 @@ namespace Tango.BL.Entities public event EventHandler> LastLoginChanged; + public event EventHandler> ActionLogsChanged; + public event EventHandler
AddressChanged; public event EventHandler ContactChanged; @@ -236,6 +238,31 @@ namespace Tango.BL.Entities } } + protected SynchronizedObservableCollection _actionlogs; + + /// + /// Gets or sets the userbase action logs. + /// + + public virtual SynchronizedObservableCollection ActionLogs + { + get + { + return _actionlogs; + } + + set + { + if (_actionlogs != value) + { + _actionlogs = value; + + OnActionLogsChanged(value); + + } + } + } + protected Address _address; /// @@ -493,6 +520,15 @@ namespace Tango.BL.Entities RaisePropertyChanged(nameof(LastLogin)); } + /// + /// Called when the ActionLogs has changed. + /// + protected virtual void OnActionLogsChanged(SynchronizedObservableCollection actionlogs) + { + ActionLogsChanged?.Invoke(this, actionlogs); + RaisePropertyChanged(nameof(ActionLogs)); + } + /// /// Called when the Address has changed. /// @@ -571,6 +607,8 @@ namespace Tango.BL.Entities public UserBase() : base() { + ActionLogs = new SynchronizedObservableCollection(); + Jobs = new SynchronizedObservableCollection(); MachineStudioVersions = new SynchronizedObservableCollection(); diff --git a/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs b/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs new file mode 100644 index 000000000..94eb07cda --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL.Enumerations +{ + public enum ActionLogType + { + //Organizations and Users + [Description("Organization Created")] + OrganizationCreated = 1, + [Description("Organization Deleted")] + OrganizationDeleted = 2, + [Description("Organization Saved")] + OrganizationSaved = 3, + [Description("User Created")] + UserCreated = 4, + [Description("User Deleted")] + UserDeleted = 5, + [Description("User Saved")] + UserSaved = 6, + [Description("User Login")] + UserLogin = 7, + [Description("User Logout")] + UserLogout = 8, + + //Hardware Version + [Description("Hardware Version Created")] + HardwareVersionCreated = 100, + [Description("Hardware Version Deleted")] + HardwareVersionDeleted = 101, + [Description("Hardware Version Saved")] + HardwareVersionSaved = 102, + + //RML + [Description("RML Created")] + RmlCreated = 200, + [Description("RML Deleted")] + RmlDeleted = 201, + [Description("RML Saved")] + RmlSaved = 202, + + //Jobs + [Description("Job Created")] + JobCreated = 300, + [Description("Job Deleted")] + JobDeleted = 301, + [Description("Job Saved")] + JobSaved = 302, + + //Machines + [Description("Machine Created")] + MachineCreated = 400, + [Description("Machine Deleted")] + MachineDeleted = 401, + [Description("Machine Saved")] + MachineSaved = 402, + + //Catalogs + [Description("Catalog Created")] + CatalogCreated = 500, + [Description("Catalog Deleted")] + CatalogDeleted = 501, + [Description("Catalog Saved")] + CatalogSaved = 502, + + //Sites + [Description("Site Created")] + SiteCreated = 600, + [Description("Site Deleted")] + SiteDeleted = 601, + [Description("Site Saved")] + SiteSaved = 602, + + //Dispensers + [Description("Dispenser Created")] + DispenserCreated = 700, + [Description("Dispenser Deleted")] + DispenserDeleted = 701, + [Description("Dispenser Saved")] + DispenserSaved = 702, + + //Firmware + [Description("Firmware Upgraded")] + FirmwareUpgraded = 800, + } +} diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs index 4f03263d9..11aca0e99 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs @@ -27,6 +27,8 @@ using Tango.Core.Json; using Newtonsoft.Json.Converters; using Tango.BL.Serialization; using Newtonsoft.Json.Linq; +using Tango.BL.ActionLogs; +using Tango.BL.ValueObjects; namespace Tango.BL { @@ -50,7 +52,7 @@ namespace Tango.BL /// /// [Serializable] - public abstract class ObservableEntity : ExtendedObject, IObservableEntity where T : class, IObservableEntity + public abstract class ObservableEntity : ExtendedObject, IObservableEntity, IActionLogComparable where T : class, IObservableEntity { #region Events @@ -658,5 +660,29 @@ namespace Tango.BL } #endregion + + #region Action Log + + public Task> CompareTo(T before) + { + return new BasicActionLogComparer().Compare(before as IActionLogComparable, this); + } + + Task> IActionLogComparable.CompareTo(IActionLogComparable before) + { + return CompareTo(before as T); + } + + bool IActionLogComparable.ShouldActionLogIgnore(string propName) + { + return propName == nameof(LastUpdated) || OnShouldActionLogIgnore(propName); + } + + protected virtual bool OnShouldActionLogIgnore(string propName) + { + return false; + } + + #endregion } } diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs index 5950a3cd2..f587147e1 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs @@ -5,10 +5,12 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using Tango.BL.ActionLogs; +using Tango.BL.ValueObjects; namespace Tango.BL { - public abstract class ObservableEntityDTO : IObservableEntityDTO, IEquatable where T : IObservableEntity where DTO : ObservableEntityDTO + public abstract class ObservableEntityDTO : IObservableEntityDTO, IEquatable, IActionLogComparable where T : IObservableEntity where DTO : ObservableEntityDTO { public int ID { get; set; } @@ -207,5 +209,25 @@ namespace Tango.BL { return EqualsToObservable(observable); } + + public Task> CompareTo(DTO before) + { + return new BasicActionLogComparer().Compare(before, this); + } + + Task> IActionLogComparable.CompareTo(IActionLogComparable before) + { + return CompareTo(before as DTO); + } + + bool IActionLogComparable.ShouldActionLogIgnore(string propName) + { + return propName == nameof(LastUpdated) || OnShouldActionLogIgnore(propName); + } + + protected virtual bool OnShouldActionLogIgnore(string propName) + { + return false; + } } } diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContext.cs b/Software/Visual_Studio/Tango.BL/ObservablesContext.cs index 4eaf256d2..3511a7624 100644 --- a/Software/Visual_Studio/Tango.BL/ObservablesContext.cs +++ b/Software/Visual_Studio/Tango.BL/ObservablesContext.cs @@ -30,6 +30,14 @@ namespace Tango.BL get; set; } + /// + /// Gets or sets the ActionLogs. + /// + public DbSet ActionLogs + { + get; set; + } + /// /// Gets or sets the Addresses. /// diff --git a/Software/Visual_Studio/Tango.BL/ObservablesEntitiesAdapterExtension.cs b/Software/Visual_Studio/Tango.BL/ObservablesEntitiesAdapterExtension.cs index c86933713..cccc2fcae 100644 --- a/Software/Visual_Studio/Tango.BL/ObservablesEntitiesAdapterExtension.cs +++ b/Software/Visual_Studio/Tango.BL/ObservablesEntitiesAdapterExtension.cs @@ -53,6 +53,42 @@ namespace Tango.BL } + private ObservableCollection _actionlogs; + /// + /// Gets or sets the ActionLogs. + /// + public ObservableCollection ActionLogs + { + get + { + return _actionlogs; + } + + set + { + _actionlogs = value; RaisePropertyChanged(nameof(ActionLogs)); + } + + } + + private ICollectionView _actionlogsViewSource; + /// + /// Gets or sets the ActionLogs View Source. + /// + public ICollectionView ActionLogsViewSource + { + get + { + return _actionlogsViewSource; + } + + set + { + _actionlogsViewSource = value; RaisePropertyChanged(nameof(ActionLogsViewSource)); + } + + } + private ObservableCollection
_addresses; /// /// Gets or sets the Addresses. @@ -2833,6 +2869,8 @@ namespace Tango.BL SyncConfigurationsViewSource = CreateCollectionView(SyncConfigurations); + ActionLogsViewSource = CreateCollectionView(ActionLogs); + AddressesViewSource = CreateCollectionView(Addresses); ApplicationDisplayPanelVersionsViewSource = CreateCollectionView(ApplicationDisplayPanelVersions); diff --git a/Software/Visual_Studio/Tango.BL/ObservablesStaticCollectionsExtension.cs b/Software/Visual_Studio/Tango.BL/ObservablesStaticCollectionsExtension.cs index efa188fec..4e108deb2 100644 --- a/Software/Visual_Studio/Tango.BL/ObservablesStaticCollectionsExtension.cs +++ b/Software/Visual_Studio/Tango.BL/ObservablesStaticCollectionsExtension.cs @@ -53,6 +53,42 @@ namespace Tango.BL } + private ObservableCollection _actionlogs; + /// + /// Gets or sets the ActionLogs. + /// + public ObservableCollection ActionLogs + { + get + { + return _actionlogs; + } + + set + { + _actionlogs = value; RaisePropertyChanged(nameof(ActionLogs)); + } + + } + + private ICollectionView _actionlogsViewSource; + /// + /// Gets or sets the ActionLogs View Source. + /// + public ICollectionView ActionLogsViewSource + { + get + { + return _actionlogsViewSource; + } + + set + { + _actionlogsViewSource = value; RaisePropertyChanged(nameof(ActionLogsViewSource)); + } + + } + private ObservableCollection
_addresses; /// /// Gets or sets the Addresses. @@ -2833,6 +2869,8 @@ namespace Tango.BL SyncConfigurationsViewSource = CreateCollectionView(SyncConfigurations); + ActionLogsViewSource = CreateCollectionView(ActionLogs); + AddressesViewSource = CreateCollectionView(Addresses); ApplicationDisplayPanelVersionsViewSource = CreateCollectionView(ApplicationDisplayPanelVersions); diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index 6111a1a35..469e23165 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -84,6 +84,10 @@ GlobalVersionInfo.cs + + + + @@ -115,6 +119,8 @@ + + @@ -269,6 +275,8 @@ + + @@ -368,6 +376,7 @@ + @@ -500,6 +509,7 @@ + @@ -580,7 +590,7 @@ - + \ No newline at end of file diff --git a/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs new file mode 100644 index 000000000..a89348249 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL.ValueObjects +{ + public class ActionLogDifference + { + public String Component { get; set; } + public String Property { get; set; } + public Object Before { get; set; } + public Object After { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/ACTION_LOGS.cs b/Software/Visual_Studio/Tango.DAL.Remote/DB/ACTION_LOGS.cs new file mode 100644 index 000000000..7bfa1fa2c --- /dev/null +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/ACTION_LOGS.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// +// This code was generated from a template. +// +// Manual changes to this file may cause unexpected behavior in your application. +// Manual changes to this file will be overwritten if the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Tango.DAL.Remote.DB +{ + using System; + using System.Collections.Generic; + + public partial class ACTION_LOGS + { + public int ID { get; set; } + public string GUID { get; set; } + public System.DateTime LAST_UPDATED { get; set; } + public int TYPE { get; set; } + public string USER_GUID { get; set; } + public string RELATED_OBJECT_NAME { get; set; } + public string RELATED_OBJECT_GUID { get; set; } + public string MESSAGE { get; set; } + public string DIFFERENCE { get; set; } + + public virtual USER USER { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Context.cs b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Context.cs index 3ef793f7f..2a158ad49 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Context.cs +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Context.cs @@ -26,6 +26,7 @@ namespace Tango.DAL.Remote.DB } public virtual DbSet SYNC_CONFIGURATIONS { get; set; } + public virtual DbSet ACTION_LOGS { get; set; } public virtual DbSet
ADDRESSES { get; set; } public virtual DbSet APPLICATION_DISPLAY_PANEL_VERSIONS { get; set; } public virtual DbSet APPLICATION_FIRMWARE_VERSIONS { get; set; } diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Designer.cs b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Designer.cs index d26e67908..17bc2683d 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Designer.cs +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.Designer.cs @@ -1,4 +1,4 @@ -// T4 code generation is enabled for model 'C:\DATA\Development\Tango\Software\Visual_Studio\Tango.DAL.Remote\DB\RemoteADO.edmx'. +// T4 code generation is enabled for model 'D:\Development\Tango\Software\Visual_Studio\Tango.DAL.Remote\DB\RemoteADO.edmx'. // To enable legacy code generation, change the value of the 'Code Generation Strategy' designer // property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model // is open in the designer. diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx index f8f4f9505..eb161228c 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx @@ -5,6 +5,20 @@ + + + + + + + + + + + + + + @@ -1155,6 +1169,18 @@ + + + + + + + + + + + + @@ -2204,6 +2230,7 @@ + @@ -2282,6 +2309,10 @@ + + + + @@ -2613,6 +2644,7 @@ + @@ -2690,6 +2722,10 @@ + + + + @@ -3023,6 +3059,21 @@ + + + + + + + + + + + + + + + @@ -4294,6 +4345,7 @@ + @@ -4327,6 +4379,18 @@ + + + + + + + + + + + + @@ -5390,6 +5454,21 @@ + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram index f13138208..a9ff9aacf 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/RemoteADO.edmx.diagram @@ -5,83 +5,85 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/Tango.DAL.Remote/DB/USER.cs b/Software/Visual_Studio/Tango.DAL.Remote/DB/USER.cs index f8c124d43..e71c100ff 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/DB/USER.cs +++ b/Software/Visual_Studio/Tango.DAL.Remote/DB/USER.cs @@ -17,6 +17,7 @@ namespace Tango.DAL.Remote.DB [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public USER() { + this.ACTION_LOGS = new HashSet(); this.JOBS = new HashSet(); this.MACHINE_STUDIO_VERSIONS = new HashSet(); this.MACHINES_EVENTS = new HashSet(); @@ -35,6 +36,8 @@ namespace Tango.DAL.Remote.DB public string ADDRESS_GUID { get; set; } public Nullable LAST_LOGIN { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public virtual ICollection ACTION_LOGS { get; set; } public virtual ADDRESS ADDRESS { get; set; } public virtual CONTACT CONTACT { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] diff --git a/Software/Visual_Studio/Tango.DAL.Remote/Tango.DAL.Remote.csproj b/Software/Visual_Studio/Tango.DAL.Remote/Tango.DAL.Remote.csproj index 75fa9179c..0a0cad6e2 100644 --- a/Software/Visual_Studio/Tango.DAL.Remote/Tango.DAL.Remote.csproj +++ b/Software/Visual_Studio/Tango.DAL.Remote/Tango.DAL.Remote.csproj @@ -66,6 +66,9 @@ GlobalVersionInfo.cs + + RemoteADO.tt + RemoteADO.tt @@ -365,7 +368,7 @@ - + \ No newline at end of file -- cgit v1.3.1 From 41b950b3f3f7fa0384cccd13ed4ef38119bbcbcf Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Wed, 18 Dec 2019 15:52:25 +0200 Subject: Fixed ContinueThreadLoadingResponse. Refactored ActionLog Difference data structure to node tree. --- .../ContinueThreadLoadingResponse.proto | 5 +- .../ViewModels/MainViewVM.cs | 19 ++- .../ViewModels/MainViewVM.cs | 23 +++- .../Tango.MachineStudio.UI/ViewModelLocator.cs | 2 +- .../Tango.BL/ActionLogs/BasicActionLogComparer.cs | 82 +++++++++---- .../Tango.BL/ActionLogs/DefaultActionLogManager.cs | 132 +++++++++++---------- .../Tango.BL/ActionLogs/IActionLogComparable.cs | 5 +- .../Tango.BL/ActionLogs/IActionLogManager.cs | 15 ++- .../Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs | 5 + .../Visual_Studio/Tango.BL/DTO/ColorCatalogDTO.cs | 10 ++ .../Tango.BL/DTO/ColorCatalogsGroupDTO.cs | 10 ++ .../Tango.BL/DTO/ColorCatalogsItemDTO.cs | 5 + .../Tango.BL/DTO/ColorCatalogsItemsRecipeDTO.cs | 5 +- Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs | 5 + Software/Visual_Studio/Tango.BL/DTO/SegmentDTO.cs | 5 + .../Visual_Studio/Tango.BL/Entities/ActionLog.cs | 20 ++-- .../Tango.BL/Enumerations/ActionLogType.cs | 2 + .../Visual_Studio/Tango.BL/ObservableEntity.cs | 14 ++- .../Visual_Studio/Tango.BL/ObservableEntityDTO.cs | 14 ++- Software/Visual_Studio/Tango.BL/Tango.BL.csproj | 3 +- .../Tango.BL/ValueObjects/ActionLogDifference.cs | 26 +++- .../ValueObjects/ActionLogDifferenceValue.cs | 26 ++++ 22 files changed, 311 insertions(+), 122 deletions(-) create mode 100644 Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifferenceValue.cs (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs') diff --git a/Software/PMR/Messages/ThreadLoading/ContinueThreadLoadingResponse.proto b/Software/PMR/Messages/ThreadLoading/ContinueThreadLoadingResponse.proto index 5763dbb2c..b937fbb34 100644 --- a/Software/PMR/Messages/ThreadLoading/ContinueThreadLoadingResponse.proto +++ b/Software/PMR/Messages/ThreadLoading/ContinueThreadLoadingResponse.proto @@ -1,12 +1,9 @@ syntax = "proto3"; -import "ThreadLoadingState.proto"; - package Tango.PMR.ThreadLoading; option java_package = "com.twine.tango.pmr.threadloading"; message ContinueThreadLoadingResponse { - ThreadLoadingState State = 1; - string ErrorReason = 2; + } \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs index 4d88a71d9..404a459d3 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs @@ -17,6 +17,10 @@ using Microsoft.Win32; using Tango.Core.Helpers; using System.IO; using Tango.MachineStudio.Catalogs.Excel; +using Tango.BL.ActionLogs; +using Tango.MachineStudio.Common.Authentication; +using Tango.BL.Enumerations; +using Tango.BL.DTO; namespace Tango.MachineStudio.Catalogs.ViewModels { @@ -25,6 +29,9 @@ namespace Tango.MachineStudio.Catalogs.ViewModels private ObservablesContext _catalogsContext; private ObservablesContext _activeCatalogContext; private INotificationProvider _notification; + private IActionLogManager _actionLogManager; + private IAuthenticationProvider _authentication; + private ColorCatalogDTO _catalogBeforeSave; #region Properties @@ -151,9 +158,11 @@ namespace Tango.MachineStudio.Catalogs.ViewModels /// Initializes a new instance of the class. ///
/// The notification provider. - public MainViewVM(INotificationProvider notificationProvider) : this() + public MainViewVM(INotificationProvider notificationProvider, IActionLogManager actionLogManager, IAuthenticationProvider authenticationProvider) : this() { + _actionLogManager = actionLogManager; _notification = notificationProvider; + _authentication = authenticationProvider; } #endregion @@ -206,6 +215,8 @@ namespace Tango.MachineStudio.Catalogs.ViewModels SelectedItem = SelectedGroup.ColorCatalogsItems.FirstOrDefault(); } + _catalogBeforeSave = ColorCatalogDTO.FromObservable(ActiveCatalog); + View.NavigateTo(CatalogsNavigationView.CatalogView); } catch (Exception ex) @@ -233,6 +244,7 @@ namespace Tango.MachineStudio.Catalogs.ViewModels { IsFree = false; await SelectedCatalog.DeleteCascadeAsync(_catalogsContext); + _actionLogManager.InsertLog(ActionLogType.CatalogDeleted, _authentication.CurrentUser, SelectedCatalog.Name, SelectedCatalog, "Catalog deleted using Machine Studio."); SelectedCatalog = null; } catch (Exception ex) @@ -265,6 +277,7 @@ namespace Tango.MachineStudio.Catalogs.ViewModels newCatalog.Company = "Twine"; _catalogsContext.ColorCatalogs.Add(newCatalog); await _catalogsContext.SaveChangesAsync(); + _actionLogManager.InsertLog(ActionLogType.CatalogCreated, _authentication.CurrentUser, newCatalog.Name, newCatalog, "Catalog created using Machine Studio."); SelectedCatalog = newCatalog; EditSelectedCatalog(); } @@ -308,6 +321,10 @@ namespace Tango.MachineStudio.Catalogs.ViewModels ActiveCatalog.LastUpdated = DateTime.UtcNow; await _activeCatalogContext.SaveChangesAsync(); await LoadCatalogs(); + + var activeCatalogDTO = ColorCatalogDTO.FromObservable(ActiveCatalog); + _actionLogManager.InsertLog(ActionLogType.CatalogSaved, _authentication.CurrentUser, ActiveCatalog.Name, _catalogBeforeSave, activeCatalogDTO, "Catalog created using Machine Studio."); + _catalogBeforeSave = activeCatalogDTO; _notification.ShowInfo("Catalog updated successfully."); } catch (Exception ex) diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs index d598e2458..4b276462e 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs @@ -1928,7 +1928,7 @@ namespace Tango.MachineStudio.Developer.ViewModels _activeJobDbContext.SaveChanges(); var afterJobDTO = JobDTO.FromObservable(ActiveJob); - _actionLogManager.InsertLog(ActionLogType.JobSaved, AuthenticationProvider.CurrentUser, _beforeSaveJobDTO.Name, _beforeSaveJobDTO, afterJobDTO, "Job saved from research module in Machine Studio.").GetAwaiter().GetResult(); + _actionLogManager.InsertLog(ActionLogType.JobSaved, AuthenticationProvider.CurrentUser, _beforeSaveJobDTO.Name, _beforeSaveJobDTO, afterJobDTO, "Job saved from research module in Machine Studio."); _beforeSaveJobDTO = afterJobDTO; _machineDbContext.Entry(SelectedMachineJob).Reload(); @@ -2191,6 +2191,8 @@ namespace Tango.MachineStudio.Developer.ViewModels { if (_notification.ShowQuestion("Are you sure you want to delete the selected jobs?")) { + var jobsToReport = SelectedJobs.Select(x => JobDTO.FromObservable(x)).ToList(); + LogManager.Log(String.Format("Removing {0} jobs...", SelectedJobs.Count)); SelectedJobs.ToList().ForEach(x => { @@ -2202,6 +2204,11 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); } + + foreach (var job in jobsToReport) + { + _actionLogManager.InsertLog(ActionLogType.JobDeleted, AuthenticationProvider.CurrentUser, job.Name, job, "Job deleted using Machine Studio.", true); + } } } } @@ -2258,6 +2265,7 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); + _actionLogManager.InsertLog(ActionLogType.JobCreated, AuthenticationProvider.CurrentUser, newJob.Name, newJob, "Job created using Machine Studio."); SelectedMachineJob = newJob; LoadSelectedJob(); } @@ -2388,6 +2396,11 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log("Saving selected machine to database..."); await SelectedMachine.SaveAsync(_machineDbContext); + foreach (var job in SelectedJobs) + { + _actionLogManager.InsertLog(ActionLogType.JobCreated, AuthenticationProvider.CurrentUser, job.Name, job, "Job created using Machine Studio."); + } + CanWork = true; } } @@ -2611,6 +2624,8 @@ namespace Tango.MachineStudio.Developer.ViewModels LogManager.Log($"Importing job files..."); + List jobsToReport = new List(); + foreach (var file in dlg.FileNames) { var bytes = File.ReadAllBytes(file); @@ -2619,10 +2634,16 @@ namespace Tango.MachineStudio.Developer.ViewModels job.JobSource = JobSource.Remote; _machineDbContext.Jobs.Add(job); + jobsToReport.Add(job); } await _machineDbContext.SaveChangesAsync(); + foreach (var job in jobsToReport) + { + _actionLogManager.InsertLog(ActionLogType.JobImported, AuthenticationProvider.CurrentUser, job.Name, job, "New job imported using Machine Studio."); + } + IsFree = true; _notification.ShowInfo($"Jobs imported successfully."); diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs index a61f14746..6c550ffda 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs @@ -95,7 +95,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); - TangoIOC.Default.Register(new DefaultActionLogManager() { ThrowExceptions = false }); + TangoIOC.Default.Register(); TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs index 61fc373a8..af52bf394 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs @@ -11,19 +11,36 @@ namespace Tango.BL.ActionLogs { public class BasicActionLogComparer { - public Task> Compare(IActionLogComparable before, IActionLogComparable after) + public Task Compare(IActionLogComparable before, IActionLogComparable after) { - return Task.Factory.StartNew>(() => + return Task.Factory.StartNew(() => { - List diffs = new List(); + ActionLogDifference diff = new ActionLogDifference(); + diff.Name = GetComponentName(before, after); - Compare(diffs, before, after, null); + Compare(diff, before, after, null); + RemoveNoDifferences(diff); - return diffs; + return diff; }); } - private void Compare(List diffs, Object before, Object after, HashSet scannedObjects) + private void RemoveNoDifferences(ActionLogDifference diff) + { + foreach (var child in diff.Children.ToList()) + { + if (!child.HasDifference) + { + diff.Children.Remove(child); + } + else + { + RemoveNoDifferences(child); + } + } + } + + private void Compare(ActionLogDifference diff, Object before, Object after, HashSet scannedObjects) { if (scannedObjects == null) { @@ -46,7 +63,7 @@ namespace Tango.BL.ActionLogs String component = GetComponentName(before, after); - foreach (var prop in GetProperties(before, after)) + foreach (var prop in GetProperties(before, after).OrderByDescending(x => x.PropertyType.IsPrimitive || x.PropertyType.IsValueType || x.PropertyType == typeof(String))) { if (GetShouldIgnore(prop, before, after)) continue; @@ -65,14 +82,14 @@ namespace Tango.BL.ActionLogs afterValue = prop.GetValue(after); } - if (afterValue == null && beforeValue != null) AddDiff(diffs, component, prop.Name, beforeValue, afterValue); - if (afterValue != null && beforeValue == null) AddDiff(diffs, component, prop.Name, beforeValue, afterValue); + if (afterValue == null && beforeValue != null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); + if (afterValue != null && beforeValue == null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); if (afterValue != null && beforeValue != null) { if (!afterValue.Equals(beforeValue)) { - AddDiff(diffs, component, prop.Name, beforeValue, afterValue); + AddValueDiff(diff, prop.Name, beforeValue, afterValue); } } } @@ -91,7 +108,7 @@ namespace Tango.BL.ActionLogs afterPropInstance = prop.GetValue(after); } - Compare(diffs, beforePropInstance, afterPropInstance, scannedObjects); + Compare(AddChildDiff(diff, prop.Name), beforePropInstance, afterPropInstance, scannedObjects); } else { @@ -108,18 +125,18 @@ namespace Tango.BL.ActionLogs afterCollection = prop.GetValue(after) as IList; } - if (beforeCollection != null && beforeCollection == null) + if (beforeCollection != null && afterCollection == null) { for (int i = 0; i < beforeCollection.Count; i++) { - Compare(diffs, beforeCollection[i], null, scannedObjects); + Compare(AddChildDiff(diff, GetActionLogName(beforeCollection[i],prop.Name)), beforeCollection[i], null, scannedObjects); } } else if (beforeCollection == null && afterCollection != null) { for (int i = 0; i < afterCollection.Count; i++) { - Compare(diffs, null, afterCollection[i], scannedObjects); + Compare(AddChildDiff(diff, GetActionLogName(afterCollection[i], prop.Name)), null, afterCollection[i], scannedObjects); } } @@ -129,27 +146,52 @@ namespace Tango.BL.ActionLogs { var beforeItem = i < beforeCollection.Count ? beforeCollection[i] : null; var afterItem = i < afterCollection.Count ? afterCollection[i] : null; - Compare(diffs, beforeItem, afterItem, scannedObjects); + Compare(AddChildDiff(diff, GetActionLogName(beforeItem, prop.Name)), beforeItem, afterItem, scannedObjects); } } } } } - private void AddDiff(List diffs, String component, String property, object before, object after) + private void AddValueDiff(ActionLogDifference diff, String property, object before, object after) { - diffs.Add(new ActionLogDifference() + diff.Children.Add(new ActionLogDifferenceValue() { - Component = component, - Property = property, + Name = property, Before = before, After = after }); } + private ActionLogDifference AddChildDiff(ActionLogDifference diff, String property) + { + ActionLogDifference childDiff = new ActionLogDifference(); + childDiff.Name = property; + diff.Children.Add(childDiff); + return childDiff; + } + private String GetComponentName(Object before, Object after) { - return after != null ? after.GetType().Name : before.GetType().Name; + var afterCast = after as IActionLogComparable; + var beforeCast = before as IActionLogComparable; + + var name = afterCast != null ? afterCast.GetActionName() : beforeCast.GetActionName(); + + return name; + } + + private String GetActionLogName(Object obj, String defaultName) + { + var objCast = obj as IActionLogComparable; + if (objCast != null) + { + return objCast.GetActionName(); + } + else + { + return defaultName; + } } private PropertyInfo GetProperty(String name, Object before, Object after) diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs index 23562bee0..9d632bccc 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs @@ -14,109 +14,113 @@ namespace Tango.BL.ActionLogs { public class DefaultActionLogManager : ExtendedObject, IActionLogManager { - public bool ThrowExceptions { get; set; } - - public DefaultActionLogManager() + public void InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, ActionLogDifference difference, string message = null) { - ThrowExceptions = true; - } - - public async Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, List differences, string message = null) - { - using (ObservablesContext db = ObservablesContext.CreateDefault()) + Task.Factory.StartNew(() => { - try + using (ObservablesContext db = ObservablesContext.CreateDefault()) { - ActionLog log = new ActionLog(); - log.ActionType = type; - log.LastUpdated = DateTime.UtcNow; - log.UserGuid = userGuid; - log.RelatedObjectName = relatedObjectName; - log.RelatedObjectGuid = relatedObjectGuid; - log.Message = message; - log.Differences = differences; + try + { + ActionLog log = new ActionLog(); + log.ActionType = type; + log.LastUpdated = DateTime.UtcNow; + log.UserGuid = userGuid; + log.RelatedObjectName = relatedObjectName; + log.RelatedObjectGuid = relatedObjectGuid; + log.Message = message; + log.DifferenceObject = difference; - db.ActionLogs.Add(log); + db.ActionLogs.Add(log); - await db.SaveChangesAsync(); + db.SaveChanges(); - LogManager.Log($"Action log '{type}' inserted."); + LogManager.Log($"Action log '{type}' inserted."); - if (differences != null && differences.Count > 0) - { - Debug.WriteLine($"Action log differences:\n{differences.ToJsonString()}"); + if (difference != null && difference.Children.Count > 0) + { + Debug.WriteLine($"Action log differences:\n{difference.ToJsonString()}"); + } } - } - catch (Exception ex) - { - LogManager.Log(ex, $"Error inserting action log '{type}'."); - - if (ThrowExceptions) + catch (Exception ex) { - throw ex; + LogManager.Log(ex, $"Error inserting action log '{type}'."); } } - } + }); } - public async Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) + public void InsertLog(ActionLogType type, string userGuid, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) { - List diffs = null; - - try + Task.Factory.StartNew(() => { - if (relatedObjectAfter != null) + ActionLogDifference diff = null; + + try { - diffs = await relatedObjectAfter.CompareTo(relatedObjectBefore); + diff = new BasicActionLogComparer().Compare(relatedObjectBefore, relatedObjectAfter).Result; } - else + catch (Exception ex) { - diffs = await relatedObjectBefore.CompareTo(relatedObjectAfter); + LogManager.Log(ex, $"Error while comparing for action log '{type}'."); } - } - catch (Exception ex) - { - LogManager.Log(ex, $"Error while comparing for action log '{type}'."); - if (ThrowExceptions) + if (diff.Children.Count > 0) { - throw ex; + InsertLog(type, userGuid, relatedObjectName, GetRelatedObjectGuid(relatedObjectBefore, relatedObjectAfter), diff, message); } - } + else + { + LogManager.Log($"Action log '{type}' was about to be inserted but skipped due to no differences."); + } + }); + } + + public void InsertLog(ActionLogType type, User user, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) + { + InsertLog(type, user.Guid, relatedObjectName, relatedObjectBefore, relatedObjectAfter, message); + } + + public void InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, string message = null) + { + InsertLog(type, userGuid, relatedObjectName, relatedObjectGuid, null, message); + } - if (diffs.Count > 0) + public void InsertLog(ActionLogType type, User user, string relatedObjectName, IActionLogComparable relatedObject, string message = null, bool serializeRelatedObject = false) + { + if (serializeRelatedObject) { - await InsertLog(type, userGuid, relatedObjectName, relatedObjectAfter.Guid, diffs, message); + InsertLog(type, user.Guid, relatedObjectName, relatedObject, null, message); } else { - LogManager.Log($"Action log '{type}' was about to be inserted but skipped due to no differences."); + InsertLog(type, user.Guid, relatedObjectName, relatedObject?.Guid, message); } } - public Task InsertLog(ActionLogType type, User user, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) + public void InsertLog(ActionLogType type, string userGuid, string message = null) { - return InsertLog(type, user.Guid, relatedObjectName, relatedObjectBefore, relatedObjectAfter, message); + InsertLog(type, userGuid, null, null, message); } - public Task InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, string message = null) + public void InsertLog(ActionLogType type, User user, string message = null) { - return InsertLog(type, userGuid, relatedObjectName, relatedObjectGuid, null, message); + InsertLog(type, user.Guid, message); } - public Task InsertLog(ActionLogType type, User user, string relatedObjectName, IObservableEntity relatedObject, string message = null) + private String GetRelatedObjectGuid(IActionLogComparable before, IActionLogComparable after) { - return InsertLog(type, user.Guid, relatedObjectName, relatedObject?.Guid, message); - } + if (before != null) + { + return before.Guid; + } - public Task InsertLog(ActionLogType type, string userGuid, string message = null) - { - return InsertLog(type, userGuid, null, null, message); - } + if (after != null) + { + return after.Guid; + } - public Task InsertLog(ActionLogType type, User user, string message = null) - { - return InsertLog(type, user.Guid, message); + return null; } } } diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs index de534141b..d98dd9122 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs @@ -10,12 +10,13 @@ namespace Tango.BL.ActionLogs public interface IActionLogComparable { String Guid { get; } - Task> CompareTo(IActionLogComparable before); + Task CompareTo(IActionLogComparable before); bool ShouldActionLogIgnore(String propName); + String GetActionName(); } public interface IActionLogComparable : IActionLogComparable where T : class { - Task> CompareTo(T before); + Task CompareTo(T before); } } diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs index fd903bbba..36fb62ed4 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs @@ -11,13 +11,12 @@ namespace Tango.BL.ActionLogs { public interface IActionLogManager { - bool ThrowExceptions { get; set; } - Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, List differences, String message = null); - Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); - Task InsertLog(ActionLogType type, User user, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); - Task InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, String message = null); - Task InsertLog(ActionLogType type, User user, String relatedObjectName, IObservableEntity relatedObject, String message = null); - Task InsertLog(ActionLogType type, String userGuid, String message = null); - Task InsertLog(ActionLogType type, User user, String message = null); + void InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, ActionLogDifference diffference, String message = null); + void InsertLog(ActionLogType type, String userGuid, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); + void InsertLog(ActionLogType type, User user, String relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, String message = null); + void InsertLog(ActionLogType type, String userGuid, String relatedObjectName, String relatedObjectGuid, String message = null); + void InsertLog(ActionLogType type, User user, String relatedObjectName, IActionLogComparable relatedObject, String message = null, bool serializeRelatedObject = false); + void InsertLog(ActionLogType type, String userGuid, String message = null); + void InsertLog(ActionLogType type, User user, String message = null); } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs index 585f2f2ee..fd1d707b5 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/BrushStopDTO.cs @@ -13,5 +13,10 @@ namespace Tango.BL.DTO { return propName == nameof(Corrected); } + + protected override string OnGetActionLogName() + { + return $"BrushStop '{StopIndex}'"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogDTO.cs index 012e7aede..7daa98aca 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogDTO.cs @@ -9,6 +9,16 @@ namespace Tango.BL.DTO { public class ColorCatalogDTO : ColorCatalogDTOBase { + public List ColorCatalogsGroups { get; set; } + public ColorCatalogDTO() + { + ColorCatalogsGroups = new List(); + } + + protected override string OnGetActionLogName() + { + return $"'{Name}' Catalog"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsGroupDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsGroupDTO.cs index 8115923e5..50c5e051e 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsGroupDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsGroupDTO.cs @@ -9,6 +9,16 @@ namespace Tango.BL.DTO { public class ColorCatalogsGroupDTO : ColorCatalogsGroupDTOBase { + public List ColorCatalogsItems { get; set; } + public ColorCatalogsGroupDTO() + { + ColorCatalogsItems = new List(); + } + + protected override string OnGetActionLogName() + { + return $"Color Group '{Name}'"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemDTO.cs index 46b33b715..5e0fd3115 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemDTO.cs @@ -9,6 +9,11 @@ namespace Tango.BL.DTO { public class ColorCatalogsItemDTO : ColorCatalogsItemDTOBase { + public List ColorCatalogsItemsRecipes { get; set; } + protected override string OnGetActionLogName() + { + return $"Color Item '{Name}'"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemsRecipeDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemsRecipeDTO.cs index 07c7695e1..34b061df8 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemsRecipeDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/ColorCatalogsItemsRecipeDTO.cs @@ -9,6 +9,9 @@ namespace Tango.BL.DTO { public class ColorCatalogsItemsRecipeDTO : ColorCatalogsItemsRecipeDTOBase { - + protected override string OnGetActionLogName() + { + return $"Color Recipe for RML '{RmlGuid}'"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs index 36f7ea9be..176d97251 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/JobDTO.cs @@ -22,5 +22,10 @@ namespace Tango.BL.DTO propName == nameof(JobDTO.Status) || propName == nameof(JobDTO.IsSynchronized); } + + protected override string OnGetActionLogName() + { + return $"'{Name}' Job"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/DTO/SegmentDTO.cs b/Software/Visual_Studio/Tango.BL/DTO/SegmentDTO.cs index 09f581db2..00d74ec30 100644 --- a/Software/Visual_Studio/Tango.BL/DTO/SegmentDTO.cs +++ b/Software/Visual_Studio/Tango.BL/DTO/SegmentDTO.cs @@ -15,5 +15,10 @@ namespace Tango.BL.DTO { BrushStops = new List(); } + + protected override string OnGetActionLogName() + { + return $"Segment '{SegmentIndex}'"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs b/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs index af88ee7f1..bb122872f 100644 --- a/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs +++ b/Software/Visual_Studio/Tango.BL/Entities/ActionLog.cs @@ -12,7 +12,7 @@ namespace Tango.BL.Entities { public class ActionLog : ActionLogBase { - private List _differences; + private ActionLogDifference _differenceObject; [NotMapped] [JsonIgnore] @@ -24,35 +24,35 @@ namespace Tango.BL.Entities [NotMapped] [JsonIgnore] - public List Differences + public ActionLogDifference DifferenceObject { get { - if (_differences != null) + if (_differenceObject != null) { try { - _differences = JsonConvert.DeserializeObject>(Difference); + _differenceObject = JsonConvert.DeserializeObject(Difference); } catch { - _differences = new List(); + _differenceObject = new ActionLogDifference(); } } else { - _differences = new List(); + _differenceObject = new ActionLogDifference(); } - return _differences; + return _differenceObject; } set { - _differences = value; + _differenceObject = value; - if (_differences != null) + if (_differenceObject != null) { - Difference = JsonConvert.SerializeObject(_differences); + Difference = JsonConvert.SerializeObject(_differenceObject); } } } diff --git a/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs b/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs index 94eb07cda..5114538ef 100644 --- a/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs +++ b/Software/Visual_Studio/Tango.BL/Enumerations/ActionLogType.cs @@ -50,6 +50,8 @@ namespace Tango.BL.Enumerations JobDeleted = 301, [Description("Job Saved")] JobSaved = 302, + [Description("Job Imported")] + JobImported = 303, //Machines [Description("Machine Created")] diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs index 11aca0e99..36e1a4ef8 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs @@ -663,12 +663,12 @@ namespace Tango.BL #region Action Log - public Task> CompareTo(T before) + public Task CompareTo(T before) { return new BasicActionLogComparer().Compare(before as IActionLogComparable, this); } - Task> IActionLogComparable.CompareTo(IActionLogComparable before) + Task IActionLogComparable.CompareTo(IActionLogComparable before) { return CompareTo(before as T); } @@ -683,6 +683,16 @@ namespace Tango.BL return false; } + string IActionLogComparable.GetActionName() + { + return OnGetActionLogName(); + } + + protected virtual String OnGetActionLogName() + { + return this.GetType().Name; + } + #endregion } } diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs index f587147e1..cb49f3769 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs @@ -210,12 +210,12 @@ namespace Tango.BL return EqualsToObservable(observable); } - public Task> CompareTo(DTO before) + public Task CompareTo(DTO before) { return new BasicActionLogComparer().Compare(before, this); } - Task> IActionLogComparable.CompareTo(IActionLogComparable before) + Task IActionLogComparable.CompareTo(IActionLogComparable before) { return CompareTo(before as DTO); } @@ -229,5 +229,15 @@ namespace Tango.BL { return false; } + + string IActionLogComparable.GetActionName() + { + return OnGetActionLogName(); + } + + protected virtual String OnGetActionLogName() + { + return this.GetType().Name; + } } } diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index 469e23165..2f9cf489e 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -510,6 +510,7 @@ + @@ -590,7 +591,7 @@ - + \ No newline at end of file diff --git a/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs index a89348249..d15ddc9c7 100644 --- a/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs +++ b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifference.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,9 +9,24 @@ namespace Tango.BL.ValueObjects { public class ActionLogDifference { - public String Component { get; set; } - public String Property { get; set; } - public Object Before { get; set; } - public Object After { get; set; } + public String Name { get; set; } + + public List Children { get; set; } + + [JsonIgnore] + public virtual bool HasDifference + { + get { return Children.Any(x => x.HasDifference); } + } + + public ActionLogDifference() + { + Children = new List(); + } + + public override string ToString() + { + return $"{Name} | Children[{Children.Count}]"; + } } } diff --git a/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifferenceValue.cs b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifferenceValue.cs new file mode 100644 index 000000000..145fcd9b7 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ValueObjects/ActionLogDifferenceValue.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL.ValueObjects +{ + public class ActionLogDifferenceValue : ActionLogDifference + { + public Object Before { get; set; } + public Object After { get; set; } + + [JsonIgnore] + public override bool HasDifference + { + get { return Before != After; } + } + + public override string ToString() + { + return $"{Name}: Before: {Before} != After: {After}"; + } + } +} -- cgit v1.3.1 From 68916b0c7e3322ff1ca8b45ed789973a23ccac51 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Wed, 18 Dec 2019 19:55:31 +0200 Subject: Improved architecture of ActionLogs. --- .../ViewModels/MainViewVM.cs | 4 +- .../Tango.MachineStudio.UI/ViewModelLocator.cs | 2 +- .../Tango.BL/ActionLogs/BasicActionLogComparer.cs | 234 --------------------- .../ActionLogs/DefaultActionLogComparer.cs | 234 +++++++++++++++++++++ .../Tango.BL/ActionLogs/DefaultActionLogManager.cs | 74 +++++-- .../Tango.BL/ActionLogs/IActionLogComparable.cs | 20 -- .../Tango.BL/ActionLogs/IActionLogComparer.cs | 23 ++ .../Tango.BL/ActionLogs/IActionLogManager.cs | 10 + .../Visual_Studio/Tango.BL/ObservableEntity.cs | 26 +-- .../Visual_Studio/Tango.BL/ObservableEntityDTO.cs | 26 +-- Software/Visual_Studio/Tango.BL/Tango.BL.csproj | 9 +- 11 files changed, 337 insertions(+), 325 deletions(-) delete mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogComparer.cs create mode 100644 Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparer.cs (limited to 'Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs') diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs index 404a459d3..ae763167b 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Catalogs/ViewModels/MainViewVM.cs @@ -320,11 +320,13 @@ namespace Tango.MachineStudio.Catalogs.ViewModels IsFree = false; ActiveCatalog.LastUpdated = DateTime.UtcNow; await _activeCatalogContext.SaveChangesAsync(); - await LoadCatalogs(); var activeCatalogDTO = ColorCatalogDTO.FromObservable(ActiveCatalog); _actionLogManager.InsertLog(ActionLogType.CatalogSaved, _authentication.CurrentUser, ActiveCatalog.Name, _catalogBeforeSave, activeCatalogDTO, "Catalog created using Machine Studio."); _catalogBeforeSave = activeCatalogDTO; + + await LoadCatalogs(); + _notification.ShowInfo("Catalog updated successfully."); } catch (Exception ex) diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs index 6c550ffda..9539037f1 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs @@ -95,7 +95,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); - TangoIOC.Default.Register(); + TangoIOC.Default.Register(new DefaultActionLogManager() { IsAsync = true }); TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs deleted file mode 100644 index de07f6678..000000000 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/BasicActionLogComparer.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.ValueObjects; - -namespace Tango.BL.ActionLogs -{ - /// - /// Represents a basic ActionLog comparison engine. - /// - public class BasicActionLogComparer - { - /// - /// Compares two instances of . - /// - /// The object before the change. - /// The object after the change. - /// - public Task Compare(IActionLogComparable before, IActionLogComparable after) - { - return Task.Factory.StartNew(() => - { - ActionLogDifference diff = new ActionLogDifference(); - diff.Name = GetComponentName(before, after); - - Compare(diff, before, after, null); - RemoveNoDifferences(diff); - - return diff; - }); - } - - #region Helpers - - private void Compare(ActionLogDifference diff, Object before, Object after, HashSet scannedObjects) - { - if (scannedObjects == null) - { - scannedObjects = new HashSet(); - } - - if (before == null && after == null) return; - - if (before != null) - { - if (scannedObjects.Contains(before)) return; - scannedObjects.Add(before); - } - - if (after != null) - { - if (scannedObjects.Contains(after)) return; - scannedObjects.Add(after); - } - - foreach (var prop in GetProperties(before, after).OrderByDescending(x => x.PropertyType.IsPrimitive || x.PropertyType.IsValueType || x.PropertyType == typeof(String))) - { - if (GetShouldIgnore(prop, before, after)) continue; - - if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) - { - object beforeValue = null; - object afterValue = null; - - if (before != null) - { - beforeValue = prop.GetValue(before); - } - - if (after != null) - { - afterValue = prop.GetValue(after); - } - - if (afterValue == null && beforeValue != null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); - if (afterValue != null && beforeValue == null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); - - if (afterValue != null && beforeValue != null) - { - if (!afterValue.Equals(beforeValue)) - { - AddValueDiff(diff, prop.Name, beforeValue, afterValue); - } - } - } - else if (!prop.PropertyType.IsGenericType) - { - object beforePropInstance = null; - object afterPropInstance = null; - - if (before != null) - { - beforePropInstance = prop.GetValue(before); - } - - if (after != null) - { - afterPropInstance = prop.GetValue(after); - } - - Compare(AddChildDiff(diff, prop.Name), beforePropInstance, afterPropInstance, scannedObjects); - } - else - { - IList beforeCollection = null; - IList afterCollection = null; - - if (before != null) - { - beforeCollection = prop.GetValue(before) as IList; - } - - if (after != null) - { - afterCollection = prop.GetValue(after) as IList; - } - - if (beforeCollection != null && afterCollection == null) - { - for (int i = 0; i < beforeCollection.Count; i++) - { - Compare(AddChildDiff(diff, GetActionLogName(beforeCollection[i], prop.Name)), beforeCollection[i], null, scannedObjects); - } - } - else if (beforeCollection == null && afterCollection != null) - { - for (int i = 0; i < afterCollection.Count; i++) - { - Compare(AddChildDiff(diff, GetActionLogName(afterCollection[i], prop.Name)), null, afterCollection[i], scannedObjects); - } - } - - if (beforeCollection != null && afterCollection != null) - { - for (int i = 0; i < Math.Max(beforeCollection.Count, afterCollection.Count); i++) - { - var beforeItem = i < beforeCollection.Count ? beforeCollection[i] : null; - var afterItem = i < afterCollection.Count ? afterCollection[i] : null; - Compare(AddChildDiff(diff, GetActionLogName(beforeItem, prop.Name)), beforeItem, afterItem, scannedObjects); - } - } - } - } - } - - private void AddValueDiff(ActionLogDifference diff, String property, object before, object after) - { - diff.Children.Add(new ActionLogDifferenceValue() - { - Name = property, - Before = before, - After = after - }); - } - - private ActionLogDifference AddChildDiff(ActionLogDifference diff, String property) - { - ActionLogDifference childDiff = new ActionLogDifference(); - childDiff.Name = property; - diff.Children.Add(childDiff); - return childDiff; - } - - private void RemoveNoDifferences(ActionLogDifference diff) - { - foreach (var child in diff.Children.ToList()) - { - if (!child.HasDifference) - { - diff.Children.Remove(child); - } - else - { - RemoveNoDifferences(child); - } - } - } - - private String GetComponentName(Object before, Object after) - { - var afterCast = after as IActionLogComparable; - var beforeCast = before as IActionLogComparable; - - var name = afterCast != null ? afterCast.GetActionLogName() : beforeCast.GetActionLogName(); - - return name; - } - - private String GetActionLogName(Object obj, String defaultName) - { - var objCast = obj as IActionLogComparable; - if (objCast != null) - { - return objCast.GetActionLogName(); - } - else - { - return defaultName; - } - } - - private PropertyInfo GetProperty(String name, Object before, Object after) - { - return after != null ? after.GetType().GetProperty(name) : before.GetType().GetProperty(name); - } - - private List GetProperties(BindingFlags flags, Object before, Object after) - { - return after != null ? after.GetType().GetProperties(flags).ToList() : before.GetType().GetProperties(flags).ToList(); - } - - private List GetProperties(Object before, Object after) - { - return after != null ? after.GetType().GetProperties().ToList() : before.GetType().GetProperties().ToList(); - } - - private bool GetShouldIgnore(PropertyInfo prop, Object before, Object after) - { - var beforeCast = before as IActionLogComparable; - var afterCast = after as IActionLogComparable; - - if (beforeCast != null) return beforeCast.ShouldActionLogIgnore(prop.Name); - if (afterCast != null) return afterCast.ShouldActionLogIgnore(prop.Name); - - return false; - } - - #endregion - } -} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogComparer.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogComparer.cs new file mode 100644 index 000000000..542aba0e4 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogComparer.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.ValueObjects; + +namespace Tango.BL.ActionLogs +{ + /// + /// Represents the default implementation of . + /// + public class DefaultActionLogComparer : IActionLogComparer + { + /// + /// Compares the specified object before and after changes and returns the difference tree. + /// + /// The object before the change. + /// The object after the change. + /// + public Task Compare(IActionLogComparable before, IActionLogComparable after) + { + return Task.Factory.StartNew(() => + { + ActionLogDifference diff = new ActionLogDifference(); + diff.Name = GetComponentName(before, after); + + Compare(diff, before, after, null); + RemoveNoDifferences(diff); + + return diff; + }); + } + + #region Helpers + + private void Compare(ActionLogDifference diff, Object before, Object after, HashSet scannedObjects) + { + if (scannedObjects == null) + { + scannedObjects = new HashSet(); + } + + if (before == null && after == null) return; + + if (before != null) + { + if (scannedObjects.Contains(before)) return; + scannedObjects.Add(before); + } + + if (after != null) + { + if (scannedObjects.Contains(after)) return; + scannedObjects.Add(after); + } + + foreach (var prop in GetProperties(before, after).OrderByDescending(x => x.PropertyType.IsPrimitive || x.PropertyType.IsValueType || x.PropertyType == typeof(String))) + { + if (GetShouldIgnore(prop, before, after)) continue; + + if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) + { + object beforeValue = null; + object afterValue = null; + + if (before != null) + { + beforeValue = prop.GetValue(before); + } + + if (after != null) + { + afterValue = prop.GetValue(after); + } + + if (afterValue == null && beforeValue != null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); + if (afterValue != null && beforeValue == null) AddValueDiff(diff, prop.Name, beforeValue, afterValue); + + if (afterValue != null && beforeValue != null) + { + if (!afterValue.Equals(beforeValue)) + { + AddValueDiff(diff, prop.Name, beforeValue, afterValue); + } + } + } + else if (!prop.PropertyType.IsGenericType) + { + object beforePropInstance = null; + object afterPropInstance = null; + + if (before != null) + { + beforePropInstance = prop.GetValue(before); + } + + if (after != null) + { + afterPropInstance = prop.GetValue(after); + } + + Compare(AddChildDiff(diff, prop.Name), beforePropInstance, afterPropInstance, scannedObjects); + } + else + { + IList beforeCollection = null; + IList afterCollection = null; + + if (before != null) + { + beforeCollection = prop.GetValue(before) as IList; + } + + if (after != null) + { + afterCollection = prop.GetValue(after) as IList; + } + + if (beforeCollection != null && afterCollection == null) + { + for (int i = 0; i < beforeCollection.Count; i++) + { + Compare(AddChildDiff(diff, GetActionLogName(beforeCollection[i], prop.Name)), beforeCollection[i], null, scannedObjects); + } + } + else if (beforeCollection == null && afterCollection != null) + { + for (int i = 0; i < afterCollection.Count; i++) + { + Compare(AddChildDiff(diff, GetActionLogName(afterCollection[i], prop.Name)), null, afterCollection[i], scannedObjects); + } + } + + if (beforeCollection != null && afterCollection != null) + { + for (int i = 0; i < Math.Max(beforeCollection.Count, afterCollection.Count); i++) + { + var beforeItem = i < beforeCollection.Count ? beforeCollection[i] : null; + var afterItem = i < afterCollection.Count ? afterCollection[i] : null; + Compare(AddChildDiff(diff, GetActionLogName(beforeItem, prop.Name)), beforeItem, afterItem, scannedObjects); + } + } + } + } + } + + private void AddValueDiff(ActionLogDifference diff, String property, object before, object after) + { + diff.Children.Add(new ActionLogDifferenceValue() + { + Name = property, + Before = before, + After = after + }); + } + + private ActionLogDifference AddChildDiff(ActionLogDifference diff, String property) + { + ActionLogDifference childDiff = new ActionLogDifference(); + childDiff.Name = property; + diff.Children.Add(childDiff); + return childDiff; + } + + private void RemoveNoDifferences(ActionLogDifference diff) + { + foreach (var child in diff.Children.ToList()) + { + if (!child.HasDifference) + { + diff.Children.Remove(child); + } + else + { + RemoveNoDifferences(child); + } + } + } + + private String GetComponentName(Object before, Object after) + { + var afterCast = after as IActionLogComparable; + var beforeCast = before as IActionLogComparable; + + var name = afterCast != null ? afterCast.GetActionLogName() : beforeCast.GetActionLogName(); + + return name; + } + + private String GetActionLogName(Object obj, String defaultName) + { + var objCast = obj as IActionLogComparable; + if (objCast != null) + { + return objCast.GetActionLogName(); + } + else + { + return defaultName; + } + } + + private PropertyInfo GetProperty(String name, Object before, Object after) + { + return after != null ? after.GetType().GetProperty(name) : before.GetType().GetProperty(name); + } + + private List GetProperties(BindingFlags flags, Object before, Object after) + { + return after != null ? after.GetType().GetProperties(flags).ToList() : before.GetType().GetProperties(flags).ToList(); + } + + private List GetProperties(Object before, Object after) + { + return after != null ? after.GetType().GetProperties().ToList() : before.GetType().GetProperties().ToList(); + } + + private bool GetShouldIgnore(PropertyInfo prop, Object before, Object after) + { + var beforeCast = before as IActionLogComparable; + var afterCast = after as IActionLogComparable; + + if (beforeCast != null) return beforeCast.ShouldActionLogIgnore(prop.Name); + if (afterCast != null) return afterCast.ShouldActionLogIgnore(prop.Name); + + return false; + } + + #endregion + } +} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs index 9ffdcbc22..d95f4cd54 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/DefaultActionLogManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Tango.BL.Entities; using Tango.BL.Enumerations; @@ -19,6 +20,25 @@ namespace Tango.BL.ActionLogs /// public class DefaultActionLogManager : ExtendedObject, IActionLogManager { + /// + /// Gets or sets the action log comparer used to compare related objects. + /// + public IActionLogComparer ActionLogComparer { get; set; } + + /// + /// Gets or sets a value indicating whether to perform the logging operations asynchronously. + /// + public bool IsAsync { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public DefaultActionLogManager() + { + IsAsync = true; + ActionLogComparer = new DefaultActionLogComparer(); + } + /// /// Inserts a new action log (main entry point). /// @@ -30,7 +50,7 @@ namespace Tango.BL.ActionLogs /// The message. public void InsertLog(ActionLogType type, string userGuid, string relatedObjectName, string relatedObjectGuid, ActionLogDifference difference, string message = null) { - Task.Factory.StartNew(() => + Task task = new Task(() => { using (ObservablesContext db = ObservablesContext.CreateDefault()) { @@ -62,6 +82,15 @@ namespace Tango.BL.ActionLogs } } }); + + if (IsAsync) + { + task.Start(); + } + else + { + task.RunSynchronously(); + } } /// @@ -75,28 +104,45 @@ namespace Tango.BL.ActionLogs /// The message. public void InsertLog(ActionLogType type, string userGuid, string relatedObjectName, IActionLogComparable relatedObjectBefore, IActionLogComparable relatedObjectAfter, string message = null) { - Task.Factory.StartNew(() => + Task task = new Task(() => { - ActionLogDifference diff = null; + ActionLogDifference diff = new ActionLogDifference(); - try + if (ActionLogComparer != null) { - diff = new BasicActionLogComparer().Compare(relatedObjectBefore, relatedObjectAfter).Result; - } - catch (Exception ex) - { - LogManager.Log(ex, $"Error while comparing for action log '{type}'."); - } + try + { + diff = ActionLogComparer.Compare(relatedObjectBefore, relatedObjectAfter).Result; + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error while comparing for action log '{type}'."); + } - if (diff.Children.Count > 0) - { - InsertLog(type, userGuid, relatedObjectName, GetRelatedObjectGuid(relatedObjectBefore, relatedObjectAfter), diff, message); + if (diff.Children.Count > 0) + { + InsertLog(type, userGuid, relatedObjectName, GetRelatedObjectGuid(relatedObjectBefore, relatedObjectAfter), diff, message); + } + else + { + LogManager.Log($"Action log '{type}' was about to be inserted but skipped due to no differences."); + } } else { - LogManager.Log($"Action log '{type}' was about to be inserted but skipped due to no differences."); + Debug.WriteLine("No comparer defined for action log."); + InsertLog(type, userGuid, relatedObjectName, GetRelatedObjectGuid(relatedObjectBefore, relatedObjectAfter), diff, message); } }); + + if (IsAsync) + { + task.Start(); + } + else + { + task.RunSynchronously(); + } } /// diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs index b9416635f..255f5a407 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparable.cs @@ -17,13 +17,6 @@ namespace Tango.BL.ActionLogs /// String Guid { get; } - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// A tree of differences. - Task CompareTo(IActionLogComparable before); - /// /// Returns true if the specified property should be ignored during ActionLog comparison. /// @@ -37,17 +30,4 @@ namespace Tango.BL.ActionLogs /// String GetActionLogName(); } - - /// - /// Represents a type which is supported for ActionLog difference comparison. - /// - public interface IActionLogComparable : IActionLogComparable where T : class - { - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// A tree of differences. - Task CompareTo(T before); - } } diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparer.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparer.cs new file mode 100644 index 000000000..94db259b0 --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogComparer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.ValueObjects; + +namespace Tango.BL.ActionLogs +{ + /// + /// Represents an comparer. + /// + public interface IActionLogComparer + { + /// + /// Compares the specified object before and after changes and returns the difference tree. + /// + /// The object before the change. + /// The object after the change. + /// + Task Compare(IActionLogComparable before, IActionLogComparable after); + } +} diff --git a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs index 150116c97..6fdca98a7 100644 --- a/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs +++ b/Software/Visual_Studio/Tango.BL/ActionLogs/IActionLogManager.cs @@ -14,6 +14,16 @@ namespace Tango.BL.ActionLogs /// public interface IActionLogManager { + /// + /// Gets or sets the action log comparer used to compare related objects. + /// + IActionLogComparer ActionLogComparer { get; set; } + + /// + /// Gets or sets a value indicating whether to perform the logging operations asynchronously. + /// + bool IsAsync { get; set; } + /// /// Inserts a new action log (main entry point). /// diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs index 211450614..e3bba77bd 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs @@ -52,7 +52,7 @@ namespace Tango.BL /// /// [Serializable] - public abstract class ObservableEntity : ExtendedObject, IObservableEntity, IActionLogComparable where T : class, IObservableEntity + public abstract class ObservableEntity : ExtendedObject, IObservableEntity, IActionLogComparable where T : class, IObservableEntity { #region Events @@ -663,30 +663,6 @@ namespace Tango.BL #region Action Log - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// - /// A tree of differences. - /// - public Task CompareTo(T before) - { - return new BasicActionLogComparer().Compare(before as IActionLogComparable, this); - } - - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// - /// A tree of differences. - /// - Task IActionLogComparable.CompareTo(IActionLogComparable before) - { - return CompareTo(before as T); - } - /// /// Returns true if the specified property should be ignored during ActionLog comparison. /// diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs index 15ba1b24e..720d6b9b7 100644 --- a/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs +++ b/Software/Visual_Studio/Tango.BL/ObservableEntityDTO.cs @@ -18,7 +18,7 @@ namespace Tango.BL /// /// /// - public abstract class ObservableEntityDTO : IObservableEntityDTO, IEquatable, IActionLogComparable where T : IObservableEntity where DTO : ObservableEntityDTO + public abstract class ObservableEntityDTO : IObservableEntityDTO, IEquatable, IActionLogComparable where T : IObservableEntity where DTO : ObservableEntityDTO { /// /// Gets or sets the ID of the entity. @@ -250,30 +250,6 @@ namespace Tango.BL return EqualsToObservable(observable); } - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// - /// A tree of differences. - /// - public Task CompareTo(DTO before) - { - return new BasicActionLogComparer().Compare(before, this); - } - - /// - /// Compares this instance to another ActionLog comparable instance. - /// - /// The before. - /// - /// A tree of differences. - /// - Task IActionLogComparable.CompareTo(IActionLogComparable before) - { - return CompareTo(before as DTO); - } - /// /// Returns true if the specified property should be ignored during ActionLog comparison. /// diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index 2f9cf489e..f1bdf94ec 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -84,9 +84,10 @@ GlobalVersionInfo.cs - + + @@ -578,9 +579,7 @@ Tango.Settings - - - + @@ -591,7 +590,7 @@ - + \ No newline at end of file -- cgit v1.3.1