diff --git a/dist/build-package.ps1 b/dist/build-package.ps1 index 53502f83..1617c9c5 100644 --- a/dist/build-package.ps1 +++ b/dist/build-package.ps1 @@ -68,6 +68,7 @@ dotnet pack ..\uSync.Core\uSync.Core.csproj --no-restore --no-build -c $env -o $ dotnet pack ..\uSync.Community.Contrib\uSync.Community.Contrib.csproj --no-build --no-restore -c $env -o $outFolder -p:Version=$fullVersion -p:ContinuousIntegrationBuild=true dotnet pack ..\uSync.Community.DataTypeSerializers\uSync.Community.DataTypeSerializers.csproj --no-build --no-restore -c $env -o $outFolder -p:Version=$fullVersion -p:ContinuousIntegrationBuild=true dotnet pack ..\uSync.BackOffice\uSync.BackOffice.csproj --no-build --no-restore -c $env -o $outFolder -p:Version=$fullVersion -p:ContinuousIntegrationBuild=true +dotnet pack ..\uSync.History\uSync.History.csproj --no-build --no-restore -c $env -o $outFolder -p:Version=$fullVersion -p:ContinuousIntegrationBuild=true dotnet pack ..\uSync.AutoTemplates\uSync.AutoTemplates.csproj --no-build --no-restore -c $env -o $outFolder -p:Version=$fullVersion -p:ContinuousIntegrationBuild=true diff --git a/uSync.History/Controllers/uSyncHistoryController.cs b/uSync.History/Controllers/uSyncHistoryController.cs new file mode 100644 index 00000000..c971af2b --- /dev/null +++ b/uSync.History/Controllers/uSyncHistoryController.cs @@ -0,0 +1,71 @@ +using Newtonsoft.Json; +using Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete; +using Umbraco.Cms.Web.BackOffice.Controllers; +using Umbraco.Cms.Web.Common.Attributes; +using uSync.BackOffice; +using uSync.BackOffice.Configuration; +using uSync.BackOffice.Services; + +namespace uSync.History.Controllers +{ + [PluginController("uSync")] + public class uSyncHistoryController : UmbracoAuthorizedApiController + { + private readonly uSyncConfigService _configService; + private readonly SyncFileService _syncFileService; + + public uSyncHistoryController(uSyncConfigService configService, SyncFileService syncFileService) + { + _configService = configService; + _syncFileService = syncFileService; + } + + public bool GetApi() => true; + + public IEnumerable GetHistory() + { + var rootFolder = _syncFileService.GetAbsPath(_configService.GetRootFolder()); + var historyFolder = Path.GetFullPath(Path.Combine(rootFolder, "..", "history")); + var files = _syncFileService.GetFiles(historyFolder, "*.json") + .Select(x => x.Substring(historyFolder.Length + 1)); + + var list = new List(); + foreach (var file in files) + { + list.Add(LoadHistory(file)); + } + + return list.OrderByDescending(x => x.Date); + } + + public bool ClearHistory() + { + // 1. get history folder + var rootFolder = _syncFileService.GetAbsPath(_configService.GetRootFolder()); + var historyFolder = Path.GetFullPath(Path.Combine(rootFolder, "..", "history")); + // 2. get history files + var files = _syncFileService.GetFiles(historyFolder, "*.json"); + // 3. delet this + foreach (var file in files) + { + _syncFileService.DeleteFile(file); + } + // 4. truth + return true; + } + + public HistoryInfo LoadHistory(string filePath) + { + var rootFolder = _syncFileService.GetAbsPath(_configService.GetRootFolder()); + var historyFolder = Path.GetFullPath(Path.Combine(rootFolder, "..", "history")); + var fullPath = Path.Combine(historyFolder, filePath); + string contents = _syncFileService.LoadContent(fullPath); + + var actions = JsonConvert.DeserializeObject(contents); + + actions.FilePath = filePath; + + return actions; + } + } +} diff --git a/uSync.History/HistoryInfo.cs b/uSync.History/HistoryInfo.cs new file mode 100644 index 00000000..9f0e6452 --- /dev/null +++ b/uSync.History/HistoryInfo.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using uSync.BackOffice; + +namespace uSync.History +{ + [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))] + + public class HistoryInfo + { + public IEnumerable Actions { get; set; } + + public DateTime Date { get; set; } + + public string Username { get; set; } + + public string Method { get; set; } + + public string FilePath { get; set; } + } +} diff --git a/uSync.History/uSync.History.csproj b/uSync.History/uSync.History.csproj new file mode 100644 index 00000000..335b6514 --- /dev/null +++ b/uSync.History/uSync.History.csproj @@ -0,0 +1,30 @@ + + + + net7.0 + enable + App_Plugins + + + uSync.History + uSync.History + uSync.History + + Kevin Jump and Henry Jump + Jumoo + + umbraco usync + + https://github.com/KevinJump/uSync + + Sync Umbraco to and from disk and between instances + + true + false + snupkg + + + + + + diff --git a/uSync.History/uSyncHistory.cs b/uSync.History/uSyncHistory.cs new file mode 100644 index 00000000..96ef351b --- /dev/null +++ b/uSync.History/uSyncHistory.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using uSync.BackOffice.Models; + +namespace uSync.History +{ + public class uSyncHistory : ISyncAddOn + { + public string Name => "uSync History"; + + public string Version => "1.0"; + + public string Icon => "icon-calendar-alt"; + + public string View => "/App_Plugins/uSyncHistory/dashboard.html"; + + public string Alias => "uSyncHistory"; + + public string DisplayName => "History"; + + public int SortOrder => 20; + } +} diff --git a/uSync.History/uSyncHistoryComposer.cs b/uSync.History/uSyncHistoryComposer.cs new file mode 100644 index 00000000..83801cfc --- /dev/null +++ b/uSync.History/uSyncHistoryComposer.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Routing; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Infrastructure.WebAssets; +using Umbraco.Extensions; +using uSync.BackOffice; +using uSync.BackOffice.Configuration; +using uSync.BackOffice.Controllers; +using uSync.BackOffice.Hubs; +using uSync.History.Controllers; + +namespace uSync.History +{ + public class uSyncHistoryComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + + builder.AddNotificationHandler(); + builder.AddNotificationHandler(); + // don't add if the filter is already there . + if (!builder.ManifestFilters().Has()) + { + // add the package manifest programatically. + builder.ManifestFilters().Append(); + } + } + } + + internal class uSyncHistoryServerVariablesHandler : INotificationHandler + { + private readonly uSyncConfigService _uSyncConfig; + private readonly LinkGenerator _linkGenerator; + private readonly uSyncHubRoutes _uSyncHubRoutes; + private readonly IBackOfficeSecurityAccessor _securityAccessor; + + /// + public uSyncHistoryServerVariablesHandler(LinkGenerator linkGenerator, + uSyncConfigService uSyncConfigService, + uSyncHubRoutes hubRoutes, + IBackOfficeSecurityAccessor securityAccessor) + { + _linkGenerator = linkGenerator; + _uSyncConfig = uSyncConfigService; + _uSyncHubRoutes = hubRoutes; + _securityAccessor = securityAccessor; + } + + + /// + public void Handle(ServerVariablesParsingNotification notification) + { + notification.ServerVariables.Add("uSyncHistory", new Dictionary + { + { "Service", _linkGenerator.GetUmbracoApiServiceBaseUrl(controller => controller.GetApi()) }, + }); + } + } +} diff --git a/uSync.History/uSyncHistoryManifestFilter.cs b/uSync.History/uSyncHistoryManifestFilter.cs new file mode 100644 index 00000000..c242ca7f --- /dev/null +++ b/uSync.History/uSyncHistoryManifestFilter.cs @@ -0,0 +1,23 @@ +using Umbraco.Cms.Core.Manifest; + +namespace uSync.History +{ + internal class uSyncHistoryManifestFilter : IManifestFilter + { + public void Filter(List manifests) + { + manifests.Add(new PackageManifest + { + PackageId = "uSyncHistory", + PackageName = "uSync History", + Version = "1.0", + AllowPackageTelemetry = true, + BundleOptions = BundleOptions.Independent, + Scripts = new[] + { + "/App_Plugins/uSyncHistory/dashboard.controller.js" + } + }); + } + } +} diff --git a/uSync.History/uSyncHistoryNotificationHandler.cs b/uSync.History/uSyncHistoryNotificationHandler.cs new file mode 100644 index 00000000..09059625 --- /dev/null +++ b/uSync.History/uSyncHistoryNotificationHandler.cs @@ -0,0 +1,69 @@ +using Newtonsoft.Json; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Security; +using uSync.BackOffice; +using uSync.BackOffice.Configuration; +using uSync.BackOffice.Services; + +namespace uSync.History +{ + internal class uSyncHistoryNotificationHandler + : INotificationHandler, + INotificationHandler + { + private readonly uSyncConfigService _configService; + private readonly SyncFileService _syncFileService; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + + public uSyncHistoryNotificationHandler(uSyncConfigService configService, SyncFileService syncFileService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) + { + _configService = configService; + _syncFileService = syncFileService; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + } + + public void Handle(uSyncImportCompletedNotification notification) + { + var changeActions = notification.Actions + .Where(x => x.Change > Core.ChangeType.NoChange && x.Change < Core.ChangeType.Hidden) + .ToList(); + + if (changeActions.Any()) + { + SaveActions(changeActions, "Import"); + } + } + + public void Handle(uSyncExportCompletedNotification notification) + { + var changeActions = notification.Actions + .Where(x => x.Change > Core.ChangeType.NoChange && x.Change < Core.ChangeType.Hidden) + .ToList(); + + if (changeActions.Any()) + { + SaveActions(changeActions, "Export"); + } + } + + private void SaveActions(IEnumerable actions, string method) + { + var historyInfo = new HistoryInfo + { + Actions = actions, + Date = DateTime.Now, + Username = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser?.Username ?? "Background Process", + Method = method + }; + + var historyJson = JsonConvert.SerializeObject(historyInfo, Formatting.Indented); + + var rootFolder = _syncFileService.GetAbsPath(_configService.GetRootFolder()); + var historyFile = Path.Combine(rootFolder, "..", "history", DateTime.Now.ToString("dd_MM_yyyy_HH_mm_ss") + ".json"); + + _syncFileService.CreateFoldersForFile(historyFile); + + _syncFileService.SaveFile(historyFile, historyJson); + } + } +} diff --git a/uSync.History/wwwroot/uSyncHistory/Lang/en-us.xml b/uSync.History/wwwroot/uSyncHistory/Lang/en-us.xml new file mode 100644 index 00000000..2235f200 --- /dev/null +++ b/uSync.History/wwwroot/uSyncHistory/Lang/en-us.xml @@ -0,0 +1,14 @@ + + + + Jumoo + http://jumoo.uk + + + History + Things you have done. + u have not Synced anything. + Are you sure? + All history files will be permanently deleted. + + \ No newline at end of file diff --git a/uSync.History/wwwroot/uSyncHistory/dashboard.controller.js b/uSync.History/wwwroot/uSyncHistory/dashboard.controller.js new file mode 100644 index 00000000..db67d961 --- /dev/null +++ b/uSync.History/wwwroot/uSyncHistory/dashboard.controller.js @@ -0,0 +1,86 @@ +(function () { + 'use strict'; + + function historyController($http, $scope, editorService, eventsService, localizationService, overlayService) { + var vm = this; + var evts = []; + vm.loadHistory = loadHistory; + vm.actions = {}; + vm.clearHistory = clearHistory; + + vm.$onInit = function () { + evts.push( + eventsService.on("usync-dashboard.tab.change", function (name, item) { + if (item.alias == "uSyncHistory") + { + getHistoryFiles(); + } + })); + } + $scope.$on('$destroy', function () { + for (var e in evts) { eventsService.unsubscribe(evts[e]); } + }); + function getHistoryFiles() { + $http.get(Umbraco.Sys.ServerVariables.uSyncHistory.Service+"GetHistory") + .then(function (result) { + vm.history = result.data; + }); + } + + function clearHistory() { + localizationService.localizeMany([ + "uSyncHistory_clearTitle", + "uSyncHistory_clearMessage"]) + .then(function (data) { + var options = { + title: data[0], + content: data[1], + disableBackdropClick: true, + disableEscKey: true, + confirmType: 'delete', + submit: function () { + doClear(); + overlayService.close(); + } + }; + overlayService.confirm(options); + }); + } + function doClear(){ + $http.get("/umbraco/backoffice/usync/usynchistory/ClearHistory") + .then(function (result) { + getHistoryFiles(); + }); + } + + function loadHistory(item) { + var niceDate = moment(item.date).format("LLLL"); + var options = { + title: "History - "+item.method, + description: item.username+" on "+niceDate, + view: "/App_Plugins/uSyncHistory/history.html", + actions: item.actions, + submit: function (model) { + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + editorService.open(options); + + //console.log(item); + //item.selected = true; + //vm.historyFile = []; + //// call the thing - get the contents of a history file. + //$http.get("/umbraco/backoffice/usync/usynchistory/LoadHistory?filePath="+item.filePath) + // .then(function (result) { + // console.log(result.data); + // vm.historyFile = result.data; + // }); + } + } + + angular.module('umbraco') + .controller('uSyncHistoryController', historyController); +})(); \ No newline at end of file diff --git a/uSync.History/wwwroot/uSyncHistory/dashboard.html b/uSync.History/wwwroot/uSyncHistory/dashboard.html new file mode 100644 index 00000000..958dcb11 --- /dev/null +++ b/uSync.History/wwwroot/uSyncHistory/dashboard.html @@ -0,0 +1,51 @@ +
+ + + + + + +
+
+
+
+
+ + +
+
+ + +
+
+
+ {{item.username}} +
+
+
+ {{item.date | date:'medium'}} +
+
+
+
+
+
+
+
+ + +
+ +

+
+ +
+
+
\ No newline at end of file diff --git a/uSync.History/wwwroot/uSyncHistory/history.html b/uSync.History/wwwroot/uSyncHistory/history.html new file mode 100644 index 00000000..ffe13a08 --- /dev/null +++ b/uSync.History/wwwroot/uSyncHistory/history.html @@ -0,0 +1,39 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/uSync/packages.lock.json b/uSync/packages.lock.json index a2e49d8f..4825d38b 100644 --- a/uSync/packages.lock.json +++ b/uSync/packages.lock.json @@ -2208,6 +2208,12 @@ "dependencies": { "Umbraco.Cms.Web.Website": "[12.0.1, )" } + }, + "usync.history": { + "type": "Project", + "dependencies": { + "uSync.BackOffice": "[12.0.0, )" + } } } } diff --git a/uSync/uSync.csproj b/uSync/uSync.csproj index bb6bcef3..1fbe3088 100644 --- a/uSync/uSync.csproj +++ b/uSync/uSync.csproj @@ -35,6 +35,7 @@ + diff --git a/uSync_12.sln b/uSync_12.sln index cea76c71..3e8b3886 100644 --- a/uSync_12.sln +++ b/uSync_12.sln @@ -34,7 +34,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "uSync.BackOffice.Assets", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "uSync.BackOffice.Targets", "uSync.BackOffice.Targets\uSync.BackOffice.Targets.csproj", "{B09F319A-7066-4B1B-B97D-F609B558C9F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "uSync.Site", "uSync.Site\uSync.Site.csproj", "{FC7B29E3-7C1A-47F5-9A49-1DB2C02771F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "uSync.Site", "uSync.Site\uSync.Site.csproj", "{FC7B29E3-7C1A-47F5-9A49-1DB2C02771F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "uSync.History", "uSync.History\uSync.History.csproj", "{E1C572B6-218E-4152-97D2-392B9CA60F39}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -86,6 +88,10 @@ Global {FC7B29E3-7C1A-47F5-9A49-1DB2C02771F2}.Debug|Any CPU.Build.0 = Debug|Any CPU {FC7B29E3-7C1A-47F5-9A49-1DB2C02771F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {FC7B29E3-7C1A-47F5-9A49-1DB2C02771F2}.Release|Any CPU.Build.0 = Release|Any CPU + {E1C572B6-218E-4152-97D2-392B9CA60F39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1C572B6-218E-4152-97D2-392B9CA60F39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1C572B6-218E-4152-97D2-392B9CA60F39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1C572B6-218E-4152-97D2-392B9CA60F39}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE