diff --git a/Disco.BI/Disco.BI.csproj b/Disco.BI/Disco.BI.csproj index bd1e8151..b1ab4d5e 100644 --- a/Disco.BI/Disco.BI.csproj +++ b/Disco.BI/Disco.BI.csproj @@ -149,6 +149,8 @@ + + diff --git a/Disco.BI/Properties/AssemblyInfo.cs b/Disco.BI/Properties/AssemblyInfo.cs index cb24ca64..1c519291 100644 --- a/Disco.BI/Properties/AssemblyInfo.cs +++ b/Disco.BI/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0208.1156")] -[assembly: AssemblyFileVersion("1.2.0208.1156")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Client/Package Creation/PreparationClient.zip b/Disco.Client/Package Creation/PreparationClient.zip index 88a7cb7d..d9590ec0 100644 Binary files a/Disco.Client/Package Creation/PreparationClient.zip and b/Disco.Client/Package Creation/PreparationClient.zip differ diff --git a/Disco.Client/Properties/AssemblyInfo.cs b/Disco.Client/Properties/AssemblyInfo.cs index 548e5036..5c68f96a 100644 --- a/Disco.Client/Properties/AssemblyInfo.cs +++ b/Disco.Client/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.ClientBootstrapper/Properties/AssemblyInfo.cs b/Disco.ClientBootstrapper/Properties/AssemblyInfo.cs index e65978c9..88d029a9 100644 --- a/Disco.ClientBootstrapper/Properties/AssemblyInfo.cs +++ b/Disco.ClientBootstrapper/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Data/Properties/AssemblyInfo.cs b/Disco.Data/Properties/AssemblyInfo.cs index 29a49287..28c0cc1c 100644 --- a/Disco.Data/Properties/AssemblyInfo.cs +++ b/Disco.Data/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Models/Disco.Models.csproj b/Disco.Models/Disco.Models.csproj index f7b59d36..b1382e2e 100644 --- a/Disco.Models/Disco.Models.csproj +++ b/Disco.Models/Disco.Models.csproj @@ -1,114 +1,120 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {FBC05512-FCCA-4B16-9E76-8C413C5DE6C9} - Library - Properties - Disco.Models - Disco.Models - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {FBC05512-FCCA-4B16-9E76-8C413C5DE6C9} + Library + Properties + Disco.Models + Disco.Models + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Disco.Models/Properties/AssemblyInfo.cs b/Disco.Models/Properties/AssemblyInfo.cs index aa936558..af2c3ad5 100644 --- a/Disco.Models/Properties/AssemblyInfo.cs +++ b/Disco.Models/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Services/Disco.Services.csproj b/Disco.Services/Disco.Services.csproj index 4372233e..fd2f0725 100644 --- a/Disco.Services/Disco.Services.csproj +++ b/Disco.Services/Disco.Services.csproj @@ -101,23 +101,6 @@ - - - - - - - - - - - - - - - - - @@ -168,7 +151,7 @@ - + diff --git a/Disco.Services/Plugins/InstallPluginTask.cs b/Disco.Services/Plugins/InstallPluginTask.cs index d6056eee..db794974 100644 --- a/Disco.Services/Plugins/InstallPluginTask.cs +++ b/Disco.Services/Plugins/InstallPluginTask.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; using Disco.Data.Repository; @@ -17,12 +18,38 @@ namespace Disco.Services.Plugins protected override void ExecuteTask() { + string packageUrlPath = (string)this.ExecutionContext.JobDetail.JobDataMap["PackageUrl"]; string packageFilePath = (string)this.ExecutionContext.JobDetail.JobDataMap["PackageFilePath"]; bool DeletePackageAfterInstall = (bool)this.ExecutionContext.JobDetail.JobDataMap["DeletePackageAfterInstall"]; if (!Plugins.PluginsLoaded) throw new InvalidOperationException("Plugins have not been initialized"); + if (!string.IsNullOrEmpty(packageUrlPath)) + { + this.Status.UpdateStatus(0, "Downloading Plugin Package", "Connecting..."); + + if (File.Exists(packageFilePath)) + File.Delete(packageFilePath); + + if (!Directory.Exists(Path.GetDirectoryName(packageFilePath))) + Directory.CreateDirectory(Path.GetDirectoryName(packageFilePath)); + + // Need to Download the Package + WebClient downloader = new WebClient(); + DateTime progressExpires = DateTime.Now; + downloader.DownloadProgressChanged += (sender, e) => + { + Console.WriteLine(e.ProgressPercentage); + if (progressExpires <= DateTime.Now) + { + this.Status.UpdateStatus(e.ProgressPercentage, string.Format("{0} of {1} KB downloaded", e.BytesReceived / 1024, e.TotalBytesToReceive / 1024)); + progressExpires = DateTime.Now.AddMilliseconds(250); + } + }; + downloader.DownloadFileTaskAsync(new Uri(packageUrlPath), packageFilePath).Wait(); + } + this.Status.UpdateStatus(10, "Opening Plugin Package", Path.GetFileName(packageFilePath)); using (var packageStream = File.OpenRead(packageFilePath)) @@ -44,7 +71,7 @@ namespace Disco.Services.Plugins this.Status.UpdateStatus(20, string.Format("{0} [{1} v{2}] by {3}", packageManifest.Name, packageManifest.Id, packageManifest.Version.ToString(4), packageManifest.Author), "Initializing Install Environment"); PluginsLog.LogInstalling(packageManifest); - + lock (Plugins._PluginLock) { if (!Plugins.PluginsLoaded) @@ -58,6 +85,12 @@ namespace Disco.Services.Plugins { string packagePath = Path.Combine(dbContext.DiscoConfiguration.PluginsLocation, packageManifest.Id); + // Check for Compatibility + var compatibilityData = Plugins.LoadCompatibilityData(dbContext); + var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version)); + if (pluginCompatibility != null && !pluginCompatibility.Compatible) + throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason)); + // Force Delete of Existing Folder if (Directory.Exists(packagePath)) { @@ -117,12 +150,16 @@ namespace Disco.Services.Plugins File.Delete(packageFilePath); } - public static ScheduledTaskStatus InstallPlugin(string PackageFilePath, bool DeletePackageAfterInstall) + public static ScheduledTaskStatus InstallLocalPlugin(string PackageFilePath, bool DeletePackageAfterInstall) + { + return InstallPlugin(null, PackageFilePath, DeletePackageAfterInstall); + } + public static ScheduledTaskStatus InstallPlugin(string PackageUrl, string PackageFilePath, bool DeletePackageAfterInstall) { if (ScheduledTasks.GetTaskStatuses(typeof(InstallPluginTask)).Where(s => s.IsRunning).Count() > 0) throw new InvalidOperationException("A plugin is already being Installed"); - JobDataMap taskData = new JobDataMap() { { "PackageFilePath", PackageFilePath }, { "DeletePackageAfterInstall", DeletePackageAfterInstall } }; + JobDataMap taskData = new JobDataMap() { { "PackageUrl", PackageUrl }, { "PackageFilePath", PackageFilePath }, { "DeletePackageAfterInstall", DeletePackageAfterInstall } }; var instance = new InstallPluginTask(); diff --git a/Disco.Services/Plugins/PluginAttribute.cs b/Disco.Services/Plugins/PluginAttribute.cs index f9cbf4bc..70c87bdb 100644 --- a/Disco.Services/Plugins/PluginAttribute.cs +++ b/Disco.Services/Plugins/PluginAttribute.cs @@ -1,16 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Disco.Services.Plugins -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - public class PluginAttribute : Attribute - { - public string Id { get; set; } - public string Name { get; set; } - public string Author { get; set; } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Services.Plugins +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class PluginAttribute : Attribute + { + public string Id { get; set; } + public string Name { get; set; } + public string Author { get; set; } + public string Url { get; set; } + public string HostVersionMin { get; set; } + public string HostVersionMax { get; set; } + } +} diff --git a/Disco.Services/Plugins/PluginManifest.cs b/Disco.Services/Plugins/PluginManifest.cs index f860b3d9..8b266078 100644 --- a/Disco.Services/Plugins/PluginManifest.cs +++ b/Disco.Services/Plugins/PluginManifest.cs @@ -11,16 +11,27 @@ using System.Web.Mvc; using Disco.Data.Repository; using Disco.Services.Tasks; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Disco.Services.Plugins { public class PluginManifest { + [JsonProperty] public string Id { get; set; } + [JsonProperty] public string Name { get; set; } + [JsonProperty] public string Author { get; set; } + [JsonProperty] + public string Url { get; set; } + [JsonProperty] public Version Version { get; set; } [JsonProperty] + public Version HostVersionMin { get; set; } + [JsonProperty] + public Version HostVersionMax { get; set; } + [JsonProperty] internal string AssemblyPath { get; set; } [JsonProperty] private string TypeName { get; set; } @@ -49,6 +60,16 @@ namespace Disco.Services.Plugins [JsonIgnore] public string StorageLocation { get; private set; } + [JsonIgnore] + public string VersionFormatted + { + get + { + var v = Version; + return string.Format("{0}.{1}.{2:0000}.{3:0000}", v.Major, v.Minor, v.Build, v.Revision); + } + } + [JsonIgnore] private bool environmentInitalized { get; set; } @@ -83,7 +104,7 @@ namespace Disco.Services.Plugins return manifest; } } - + /// /// Deserializes a Json Manifest /// @@ -98,7 +119,7 @@ namespace Disco.Services.Plugins manifestString = manifestStreamReader.ReadToEnd(); } - var manifest = JsonConvert.DeserializeObject(manifestString); + var manifest = JsonConvert.DeserializeObject(manifestString, new VersionConverter()); manifest.PluginLocation = PluginLocation; @@ -129,6 +150,10 @@ namespace Disco.Services.Plugins var pluginId = pluginAttributes.Id; var pluginName = pluginAttributes.Name; var pluginAuthor = pluginAttributes.Author; + var pluginUrl = pluginAttributes.Url; + + var pluginHostVersionMin = pluginAttributes.HostVersionMin == null ? null : Version.Parse(pluginAttributes.HostVersionMin); + var pluginHostVersionMax = pluginAttributes.HostVersionMax == null ? null : Version.Parse(pluginAttributes.HostVersionMax); var pluginVersion = assemblyName.Version; var pluginAssemblyPath = Path.GetFileName(assembly.Location); @@ -167,6 +192,9 @@ namespace Disco.Services.Plugins Name = pluginName, Author = pluginAuthor, Version = pluginVersion, + Url = pluginUrl, + HostVersionMin = pluginHostVersionMin, + HostVersionMax = pluginHostVersionMax, AssemblyPath = pluginAssemblyPath, TypeName = pluginTypeName, AssemblyReferences = pluginAssemblyReferences, @@ -188,7 +216,7 @@ namespace Disco.Services.Plugins public string ToManifestFile() { - return JsonConvert.SerializeObject(this, Formatting.Indented); + return JsonConvert.SerializeObject(this, Formatting.Indented, new VersionConverter()); } private bool InitializePluginEnvironment(DiscoDataContext dbContext) { @@ -362,7 +390,7 @@ namespace Disco.Services.Plugins var fileDateCheck = System.IO.File.GetLastWriteTime(resourcePath); if (fileDateCheck == resourceHash.Item2) #endif - return new Tuple(resourcePath, resourceHash.Item1); + return new Tuple(resourcePath, resourceHash.Item1); } if (!File.Exists(resourcePath)) diff --git a/Disco.Services/Plugins/Plugins.cs b/Disco.Services/Plugins/Plugins.cs index 8456c526..968534ed 100644 --- a/Disco.Services/Plugins/Plugins.cs +++ b/Disco.Services/Plugins/Plugins.cs @@ -7,6 +7,9 @@ using System.Text; using System.Threading.Tasks; using Disco.Data.Repository; using System.IO.Compression; +using Disco.Models.BI.Interop.Community; +using System.Web; +using Newtonsoft.Json; namespace Disco.Services.Plugins { @@ -42,6 +45,15 @@ namespace Disco.Services.Plugins } } + public static bool PluginInstalled(string PluginId) + { + if (_PluginManifests == null) + throw new InvalidOperationException("Plugins have not been initialized"); + + PluginManifest manifest; + return _PluginManifests.TryGetValue(PluginId, out manifest); + } + public static PluginManifest GetPlugin(string PluginId, Type ContainsCategoryType) { if (_PluginManifests == null) @@ -145,6 +157,81 @@ namespace Disco.Services.Plugins throw new InvalidOperationException(string.Format("Unknown Plugin Feature Category Type: [{0}]", FeatureCategoryType.Name)); } + public static string CatalogueFile(DiscoDataContext dbContext) + { + return Path.Combine(dbContext.DiscoConfiguration.PluginPackagesLocation, "Catalogue.json"); + } + public static string CompatibilityFile(DiscoDataContext dbContext) + { + return Path.Combine(dbContext.DiscoConfiguration.PluginPackagesLocation, "Compatibility.json"); + } + + public static PluginLibraryUpdateResponse LoadCatalogue(DiscoDataContext dbContext) + { + var catalogueFile = CatalogueFile(dbContext); + + if (!File.Exists(catalogueFile)) + return null; + + return JsonConvert.DeserializeObject(File.ReadAllText(catalogueFile)); + } + + public static PluginLibraryCompatibilityResponse LoadCompatibilityData(DiscoDataContext dbContext) + { + var pluginAssembly = typeof(Plugins).Assembly; + Version hostVersion = pluginAssembly.GetName().Version; + PluginLibraryCompatibilityResponse Data = null; + var localCompatFile = Path.Combine(Path.GetDirectoryName(pluginAssembly.Location), "ReleasePluginCompatibility.json"); + var serverCompatFile = CompatibilityFile(dbContext); + + if (File.Exists(localCompatFile)) + { + Data = JsonConvert.DeserializeObject(File.ReadAllText(localCompatFile)); + Data.HostVersion = hostVersion.ToString(4); + } + if (File.Exists(serverCompatFile)) + { + var serverData = JsonConvert.DeserializeObject(File.ReadAllText(serverCompatFile)); + if (Version.Parse(serverData.HostVersion) == hostVersion) + { + if (Data == null) + { + // No Local Compatibility File + Data = serverData; + } + else + { + // Join Compatibility Files + var localItems = Data.Plugins; + var localItemVersions = localItems.ToDictionary(i => i, i => Version.Parse(i.Version)); + var joinedItems = localItems.ToList(); + Data.ResponseTimestamp = serverData.ResponseTimestamp; + foreach (var serverItem in serverData.Plugins) + { + var serverItemVersion = Version.Parse(serverItem.Version); + var localItem = localItems.FirstOrDefault(i => i.Id.Equals(serverItem.Id, StringComparison.InvariantCultureIgnoreCase) && serverItemVersion == localItemVersions[i]); + if (localItem != null) + joinedItems.Remove(localItem); + + joinedItems.Add(serverItem); + } + Data.Plugins = joinedItems; + } + } + } + if (Data == null) + { + Data = new PluginLibraryCompatibilityResponse() + { + HostVersion = hostVersion.ToString(4), + Plugins = new List(), + ResponseTimestamp = new DateTime(2011, 7, 1) + }; + } + + return Data; + } + public static void InitalizePlugins(DiscoDataContext dbContext) { if (_PluginManifests == null) @@ -153,6 +240,8 @@ namespace Disco.Services.Plugins { if (_PluginManifests == null) { + Version hostVersion = typeof(Plugins).Assembly.GetName().Version; + var compatibilityData = new Lazy(() => LoadCompatibilityData(dbContext)); Dictionary loadedPlugins = new Dictionary(); PluginPath = dbContext.DiscoConfiguration.PluginsLocation; @@ -185,11 +274,21 @@ namespace Disco.Services.Plugins if (File.Exists(updatePackagePath)) { // Update Plugin - pluginManifest = UpdatePlugin(dbContext, pluginManifest, updatePackagePath); + pluginManifest = UpdatePlugin(dbContext, pluginManifest, updatePackagePath, compatibilityData.Value); } if (pluginManifest != null) { + // Check Version Compatibility + var pluginCompatibility = compatibilityData.Value.Plugins.FirstOrDefault(i => i.Id.Equals(pluginManifest.Id, StringComparison.InvariantCultureIgnoreCase) && pluginManifest.Version == Version.Parse(i.Version)); + if (pluginCompatibility != null && !pluginCompatibility.Compatible) + throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", pluginManifest.Id, pluginManifest.VersionFormatted, pluginCompatibility.Reason)); + + if (pluginManifest.HostVersionMin != null && pluginManifest.HostVersionMin > hostVersion) + throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] does not support this version of Disco (Requires v{2} or greater)", pluginManifest.Id, pluginManifest.VersionFormatted, pluginManifest.HostVersionMin.ToString())); + if (pluginManifest.HostVersionMax != null && pluginManifest.HostVersionMax < hostVersion) + throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] does not support this version of Disco (Support expired as of v{2})", pluginManifest.Id, pluginManifest.VersionFormatted, pluginManifest.HostVersionMax.ToString())); + pluginManifest.InitializePlugin(dbContext); loadedPlugins[pluginManifest.Id] = pluginManifest; } @@ -251,13 +350,13 @@ namespace Disco.Services.Plugins _PluginAssemblyManifests = _PluginManifests.Values.ToDictionary(p => p.PluginAssembly, p => p); } - public static PluginManifest UpdatePlugin(DiscoDataContext dbContext, PluginManifest ExistingManifest, String UpdatePluginPackageFilePath) + public static PluginManifest UpdatePlugin(DiscoDataContext dbContext, PluginManifest ExistingManifest, String UpdatePluginPackageFilePath, PluginLibraryCompatibilityResponse CompatibilityData = null) { PluginManifest updatedManifest; using (var packageStream = File.OpenRead(UpdatePluginPackageFilePath)) { - updatedManifest = UpdatePlugin(dbContext, ExistingManifest, packageStream); + updatedManifest = UpdatePlugin(dbContext, ExistingManifest, packageStream, CompatibilityData); } // Remove Update after processing @@ -266,7 +365,7 @@ namespace Disco.Services.Plugins return updatedManifest; } - public static PluginManifest UpdatePlugin(DiscoDataContext dbContext, PluginManifest ExistingManifest, Stream UpdatePluginPackage) + public static PluginManifest UpdatePlugin(DiscoDataContext dbContext, PluginManifest ExistingManifest, Stream UpdatePluginPackage, PluginLibraryCompatibilityResponse CompatibilityData = null) { using (MemoryStream packageStream = new MemoryStream()) { @@ -301,6 +400,13 @@ namespace Disco.Services.Plugins throw new InvalidDataException("A newer version of this plugin is already installed"); } + // Check Compatibility + if (CompatibilityData == null) + CompatibilityData = LoadCompatibilityData(dbContext); + var pluginCompatibility = CompatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version)); + if (pluginCompatibility != null && !pluginCompatibility.Compatible) + throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason)); + string packagePath = Path.Combine(dbContext.DiscoConfiguration.PluginsLocation, packageManifest.Id); // Force Delete of Existing Folder diff --git a/Disco.Services/Properties/AssemblyInfo.cs b/Disco.Services/Properties/AssemblyInfo.cs index bced427e..99c249f0 100644 --- a/Disco.Services/Properties/AssemblyInfo.cs +++ b/Disco.Services/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Web.Extensions/Properties/AssemblyInfo.cs b/Disco.Web.Extensions/Properties/AssemblyInfo.cs index 1f6dccef..c4bb3bd6 100644 --- a/Disco.Web.Extensions/Properties/AssemblyInfo.cs +++ b/Disco.Web.Extensions/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2.0207.1727")] -[assembly: AssemblyFileVersion("1.2.0207.1727")] +[assembly: AssemblyVersion("1.2.0212.1702")] +[assembly: AssemblyFileVersion("1.2.0212.1702")] diff --git a/Disco.Web/Areas/API/Controllers/PluginController.cs b/Disco.Web/Areas/API/Controllers/PluginController.cs index f65872cc..b9384b0c 100644 --- a/Disco.Web/Areas/API/Controllers/PluginController.cs +++ b/Disco.Web/Areas/API/Controllers/PluginController.cs @@ -4,12 +4,21 @@ using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; +using Disco.BI.Interop.Community; using Disco.Services.Plugins; namespace Disco.Web.Areas.API.Controllers { public partial class PluginController : dbAdminController { + public virtual ActionResult UpdateLibraryCatalogue() + { + var status = PluginLibraryUpdateTask.ScheduleNow(); + + status.SetFinishedUrl(Url.Action(MVC.Config.Plugins.Install())); + + return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId)); + } public virtual ActionResult Uninstall(string id, bool UninstallData) { @@ -23,7 +32,29 @@ namespace Disco.Web.Areas.API.Controllers return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId)); } - public virtual ActionResult Install(HttpPostedFileBase Plugin) + public virtual ActionResult Install(string PluginId) + { + if (string.IsNullOrEmpty(PluginId)) + throw new ArgumentNullException("PluginId", "A PluginId must be supplied"); + + var catalogue = Plugins.LoadCatalogue(dbContext); + var plugin = catalogue.Plugins.FirstOrDefault(p => p.Id.Equals(PluginId)); + + if (plugin == null) + throw new ArgumentNullException("PluginId", "Plugin not found in catalogue"); + + // Already Installed? + if (Plugins.PluginInstalled(plugin.Id)) + throw new InvalidOperationException("This plugin is already installed"); + + var tempPluginLocation = Path.Combine(dbContext.DiscoConfiguration.PluginPackagesLocation, string.Format("{0}.discoPlugin", plugin.Id)); + + var status = InstallPluginTask.InstallPlugin(plugin.LatestDownloadUrl, tempPluginLocation, true); + + return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId)); + } + + public virtual ActionResult InstallLocal(HttpPostedFileBase Plugin) { if (Plugin == null || Plugin.ContentLength <= 0 || string.IsNullOrWhiteSpace(Plugin.FileName)) throw new ArgumentException("A discoPlugin file must be uploaded", "Plugin"); @@ -36,10 +67,9 @@ namespace Disco.Web.Areas.API.Controllers if (System.IO.File.Exists(tempPluginLocation)) System.IO.File.Delete(tempPluginLocation); - Plugin.SaveAs(tempPluginLocation); - var status = InstallPluginTask.InstallPlugin(tempPluginLocation, true); + var status = InstallPluginTask.InstallLocalPlugin(tempPluginLocation, true); return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId)); } diff --git a/Disco.Web/Areas/Config/ConfigAreaRegistration.cs b/Disco.Web/Areas/Config/ConfigAreaRegistration.cs index 48685e89..e9d0537a 100644 --- a/Disco.Web/Areas/Config/ConfigAreaRegistration.cs +++ b/Disco.Web/Areas/Config/ConfigAreaRegistration.cs @@ -1,122 +1,127 @@ -using System.Web.Mvc; - -namespace Disco.Web.Areas.Config -{ - public class ConfigAreaRegistration : AreaRegistration - { - public override string AreaName - { - get - { - return "Config"; - } - } - - public override void RegisterArea(AreaRegistrationContext context) - { - context.MapRoute( - "Config_DeviceModel_GenericComponents", - "Config/DeviceModel/GenericComponents", - new { controller = "DeviceModel", action = "GenericComponents" } - ); - context.MapRoute( - "Config_DeviceModel", - "Config/DeviceModel/{id}", - new { controller = "DeviceModel", action = "Index", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DeviceBatch_Create", - "Config/DeviceBatch/Create", - new { controller = "DeviceBatch", action = "Create", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DeviceBatch_Timeline", - "Config/DeviceBatch/Timeline", - new { controller = "DeviceBatch", action = "Timeline" } - ); - context.MapRoute( - "Config_DeviceBatch", - "Config/DeviceBatch/{id}", - new { controller = "DeviceBatch", action = "Index", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DeviceProfile_Create", - "Config/DeviceProfile/Create", - new { controller = "DeviceProfile", action = "Create" } - ); - context.MapRoute( - "Config_DeviceProfile_Defaults", - "Config/DeviceProfile/Defaults", - new { controller = "DeviceProfile", action = "Defaults" } - ); - context.MapRoute( - "Config_DeviceProfile", - "Config/DeviceProfile/{id}", - new { controller = "DeviceProfile", action = "Index", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_AttachmentType_Create", - "Config/AttachmentType/Create", - new { controller = "AttachmentType", action = "Create" } - ); - context.MapRoute( - "Config_AttachmentType_ExpressionBrowser_Type", - "Config/AttachmentType/ExpressionBrowser/{type}", - new { controller = "AttachmentType", action = "ExpressionBrowser", type = UrlParameter.Optional } - ); - context.MapRoute( - "Config_AttachmentType", - "Config/AttachmentType/{id}", - new { controller = "AttachmentType", action = "Index", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DocumentTemplate_Create", - "Config/DocumentTemplate/Create", - new { controller = "DocumentTemplate", action = "Create", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DocumentTemplate_ImportStatus", - "Config/DocumentTemplate/ImportStatus", - new { controller = "DocumentTemplate", action = "ImportStatus", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DocumentTemplate_UndetectedPages", - "Config/DocumentTemplate/UndetectedPages", - new { controller = "DocumentTemplate", action = "UndetectedPages", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DocumentTemplate_ExpressionBrowser", - "Config/DocumentTemplate/ExpressionBrowser", - new { controller = "DocumentTemplate", action = "ExpressionBrowser", id = UrlParameter.Optional } - ); - context.MapRoute( - "Config_DocumentTemplate", - "Config/DocumentTemplate/{id}", - new { controller = "DocumentTemplate", action = "Index", id = UrlParameter.Optional } - ); - - context.MapRoute( - "Config_Warranty", - "Config/Warranty/{id}", - new { controller = "Warranty", action = "Index", id = UrlParameter.Optional } - ); - - context.MapRoute( - "Config_Plugins", - "Config/Plugins", - new { controller = "Plugins", action = "Index"} - ); - context.MapRoute( - "Config_Plugins_Configure", - "Config/Plugins/{PluginId}", - new { controller = "Plugins", action = "Configure" } - ); - - context.MapRoute( - "Config_default", - "Config/{controller}/{action}/{id}", - new { controller = "Config", action = "Index", id = UrlParameter.Optional } - ); - } - } -} +using System.Web.Mvc; + +namespace Disco.Web.Areas.Config +{ + public class ConfigAreaRegistration : AreaRegistration + { + public override string AreaName + { + get + { + return "Config"; + } + } + + public override void RegisterArea(AreaRegistrationContext context) + { + context.MapRoute( + "Config_DeviceModel_GenericComponents", + "Config/DeviceModel/GenericComponents", + new { controller = "DeviceModel", action = "GenericComponents" } + ); + context.MapRoute( + "Config_DeviceModel", + "Config/DeviceModel/{id}", + new { controller = "DeviceModel", action = "Index", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DeviceBatch_Create", + "Config/DeviceBatch/Create", + new { controller = "DeviceBatch", action = "Create", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DeviceBatch_Timeline", + "Config/DeviceBatch/Timeline", + new { controller = "DeviceBatch", action = "Timeline" } + ); + context.MapRoute( + "Config_DeviceBatch", + "Config/DeviceBatch/{id}", + new { controller = "DeviceBatch", action = "Index", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DeviceProfile_Create", + "Config/DeviceProfile/Create", + new { controller = "DeviceProfile", action = "Create" } + ); + context.MapRoute( + "Config_DeviceProfile_Defaults", + "Config/DeviceProfile/Defaults", + new { controller = "DeviceProfile", action = "Defaults" } + ); + context.MapRoute( + "Config_DeviceProfile", + "Config/DeviceProfile/{id}", + new { controller = "DeviceProfile", action = "Index", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_AttachmentType_Create", + "Config/AttachmentType/Create", + new { controller = "AttachmentType", action = "Create" } + ); + context.MapRoute( + "Config_AttachmentType_ExpressionBrowser_Type", + "Config/AttachmentType/ExpressionBrowser/{type}", + new { controller = "AttachmentType", action = "ExpressionBrowser", type = UrlParameter.Optional } + ); + context.MapRoute( + "Config_AttachmentType", + "Config/AttachmentType/{id}", + new { controller = "AttachmentType", action = "Index", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DocumentTemplate_Create", + "Config/DocumentTemplate/Create", + new { controller = "DocumentTemplate", action = "Create", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DocumentTemplate_ImportStatus", + "Config/DocumentTemplate/ImportStatus", + new { controller = "DocumentTemplate", action = "ImportStatus", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DocumentTemplate_UndetectedPages", + "Config/DocumentTemplate/UndetectedPages", + new { controller = "DocumentTemplate", action = "UndetectedPages", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DocumentTemplate_ExpressionBrowser", + "Config/DocumentTemplate/ExpressionBrowser", + new { controller = "DocumentTemplate", action = "ExpressionBrowser", id = UrlParameter.Optional } + ); + context.MapRoute( + "Config_DocumentTemplate", + "Config/DocumentTemplate/{id}", + new { controller = "DocumentTemplate", action = "Index", id = UrlParameter.Optional } + ); + + context.MapRoute( + "Config_Warranty", + "Config/Warranty/{id}", + new { controller = "Warranty", action = "Index", id = UrlParameter.Optional } + ); + + context.MapRoute( + "Config_Plugins", + "Config/Plugins", + new { controller = "Plugins", action = "Index"} + ); + context.MapRoute( + "Config_Plugins_Install", + "Config/Plugins/Install", + new { controller = "Plugins", action = "Install" } + ); + context.MapRoute( + "Config_Plugins_Configure", + "Config/Plugins/{PluginId}", + new { controller = "Plugins", action = "Configure" } + ); + + context.MapRoute( + "Config_default", + "Config/{controller}/{action}/{id}", + new { controller = "Config", action = "Index", id = UrlParameter.Optional } + ); + } + } +} diff --git a/Disco.Web/Areas/Config/Controllers/LoggingController.cs b/Disco.Web/Areas/Config/Controllers/LoggingController.cs index e5e44cc1..b6574702 100644 --- a/Disco.Web/Areas/Config/Controllers/LoggingController.cs +++ b/Disco.Web/Areas/Config/Controllers/LoggingController.cs @@ -1,53 +1,43 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using Disco.Services.Logging; -using Disco.Services.Logging.Models; - -namespace Disco.Web.Areas.Config.Controllers -{ - public partial class LoggingController : dbAdminController - { - // - // GET: /Config/Logs/ - - public virtual ActionResult Index() - { - var m = new Models.Logging.IndexModel() - { - LogModules = new Dictionary>() - }; - foreach (var logModule in LogContext.LogModules.Values) - { - m.LogModules.Add(logModule, logModule.EventTypes.Values.Where(et => et.UsePersist).ToList()); - } - - return View(m); - } - - public virtual ActionResult TaskStatus(string id) - { - - if (string.IsNullOrEmpty(id)) - { - string sessionId; - do - { - System.Threading.Thread.Sleep(100); - sessionId = Disco.Services.Tasks.ScheduledTasks.GetTaskStatuses(typeof(Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob)).Select(t => t.SessionId).FirstOrDefault(); - } while (sessionId == null); - - return View(new Models.Logging.TaskStatusModel() { SessionId = sessionId }); - } - else - { - var taskStatus = Disco.Services.Tasks.ScheduledTasks.GetTaskStatus(id); - return View(new Models.Logging.TaskStatusModel() { SessionId = taskStatus.SessionId }); - } - - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using Disco.Services.Logging; +using Disco.Services.Logging.Models; + +namespace Disco.Web.Areas.Config.Controllers +{ + public partial class LoggingController : dbAdminController + { + // + // GET: /Config/Logs/ + + public virtual ActionResult Index() + { + var m = new Models.Logging.IndexModel() + { + LogModules = new Dictionary>() + }; + foreach (var logModule in LogContext.LogModules.Values) + { + m.LogModules.Add(logModule, logModule.EventTypes.Values.Where(et => et.UsePersist).ToList()); + } + + return View(m); + } + + public virtual ActionResult TaskStatus(string id) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException("id", "A Task Status Id is required"); + + var taskStatus = Disco.Services.Tasks.ScheduledTasks.GetTaskStatus(id); + if (taskStatus == null) + return RedirectToAction(MVC.Config.Logging.Index()); + + return View(new Models.Logging.TaskStatusModel() { SessionId = taskStatus.SessionId }); + } + + } +} diff --git a/Disco.Web/Areas/Config/Controllers/PluginsController.cs b/Disco.Web/Areas/Config/Controllers/PluginsController.cs index 5d27c66b..32442b2c 100644 --- a/Disco.Web/Areas/Config/Controllers/PluginsController.cs +++ b/Disco.Web/Areas/Config/Controllers/PluginsController.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Web; using System.Web.Mvc; using Disco.Services.Plugins; +using Disco.Services.Tasks; using Disco.Web.Areas.Config.Models.Plugins; namespace Disco.Web.Areas.Config.Controllers @@ -65,5 +66,27 @@ namespace Disco.Web.Areas.Config.Controllers } #endregion + public virtual ActionResult Install() + { + // Check for recent catalogue + + var catalogue = Plugins.LoadCatalogue(dbContext); + + if (catalogue == null || catalogue.ResponseTimestamp < DateTime.Now.AddMinutes(-15)) + { + // Need to Update Catalogue + return RedirectToAction(MVC.API.Plugin.UpdateLibraryCatalogue()); + } + else + { + var model = new Models.Plugins.InstallModel() + { + Catalogue = catalogue + }; + + return View(model); + } + } + } } diff --git a/Disco.Web/Areas/Config/Models/Plugins/InstallModel.cs b/Disco.Web/Areas/Config/Models/Plugins/InstallModel.cs new file mode 100644 index 00000000..8f59c960 --- /dev/null +++ b/Disco.Web/Areas/Config/Models/Plugins/InstallModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Disco.Models.BI.Interop.Community; + +namespace Disco.Web.Areas.Config.Models.Plugins +{ + public class InstallModel + { + public PluginLibraryUpdateResponse Catalogue { get; set; } + } +} \ No newline at end of file diff --git a/Disco.Web/Areas/Config/Models/Plugins/ProviderConfigurationViewModel.cs b/Disco.Web/Areas/Config/Models/Plugins/PluginConfigurationViewModel.cs similarity index 96% rename from Disco.Web/Areas/Config/Models/Plugins/ProviderConfigurationViewModel.cs rename to Disco.Web/Areas/Config/Models/Plugins/PluginConfigurationViewModel.cs index 22965677..2d599287 100644 --- a/Disco.Web/Areas/Config/Models/Plugins/ProviderConfigurationViewModel.cs +++ b/Disco.Web/Areas/Config/Models/Plugins/PluginConfigurationViewModel.cs @@ -1,23 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using Disco.Services.Plugins; - -namespace Disco.Web.Areas.Config.Models.Plugins -{ - public class PluginConfigurationViewModel - { - public PluginManifest Manifest { get; set; } - public Type PluginViewType { get; set; } - public object PluginViewModel { get; set; } - - public PluginConfigurationViewModel(PluginConfigurationHandler.PluginConfigurationHandlerGetResponse response) - { - this.Manifest = response.Manifest; - - this.PluginViewType = response.ViewType; - this.PluginViewModel = response.ViewModel; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Disco.Services.Plugins; + +namespace Disco.Web.Areas.Config.Models.Plugins +{ + public class PluginConfigurationViewModel + { + public PluginManifest Manifest { get; set; } + public Type PluginViewType { get; set; } + public object PluginViewModel { get; set; } + + public PluginConfigurationViewModel(PluginConfigurationHandler.PluginConfigurationHandlerGetResponse response) + { + this.Manifest = response.Manifest; + + this.PluginViewType = response.ViewType; + this.PluginViewModel = response.ViewModel; + } + } } \ No newline at end of file diff --git a/Disco.Web/Areas/Config/Views/Expressions/Editor.cshtml b/Disco.Web/Areas/Config/Views/Expressions/Editor.cshtml index c682686a..d169b56b 100644 --- a/Disco.Web/Areas/Config/Views/Expressions/Editor.cshtml +++ b/Disco.Web/Areas/Config/Views/Expressions/Editor.cshtml @@ -1,52 +1,52 @@ -@model Disco.Web.Areas.Config.Models.Expressions.EditorModel -@{ - ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Expressions"); - Html.BundleDeferred("~/ClientScripts/Modules/Disco-ExpressionEditor"); -} -
-
-
-
-

- Parse Error:

-
-
-
- - @if (false) - { } - -
+@model Disco.Web.Areas.Config.Models.Expressions.EditorModel +@{ + ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Expressions"); + Html.BundleDeferred("~/ClientScripts/Modules/Disco-ExpressionEditor"); +} +
+
+
+
+

+ Parse Error:

+
+
+
+ +@* @if (false) + { }*@ + +
diff --git a/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs b/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs index 5d26562e..7e777b55 100644 --- a/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs +++ b/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs @@ -1,169 +1,141 @@ -#pragma warning disable 1591 -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.17929 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Disco.Web.Areas.Config.Views.Expressions -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net; - using System.Text; - using System.Web; - using System.Web.Helpers; - using System.Web.Mvc; - using System.Web.Mvc.Ajax; - using System.Web.Mvc.Html; - using System.Web.Routing; - using System.Web.Security; - using System.Web.UI; - using System.Web.WebPages; - using Disco.BI.Extensions; - using Disco.Models.Repository; - using Disco.Web; - using Disco.Web.Extensions; - - [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "1.5.0.0")] - [System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Expressions/Editor.cshtml")] - public class Editor : System.Web.Mvc.WebViewPage - { - public Editor() - { - } - public override void Execute() - { - - #line 2 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - - ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Expressions"); - Html.BundleDeferred("~/ClientScripts/Modules/Disco-ExpressionEditor"); - - - #line default - #line hidden -WriteLiteral("\r\n\r\n \r\n \r\n \r\n

\r\n Parse Error:

\r\n \r\n \r\n \r\n \r\n Validate\r\n"); - - - #line 17 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - - - #line default - #line hidden - - #line 17 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - if (false) - { - - #line default - #line hidden -WriteLiteral(" "); - - - #line 18 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" \r\n $(function () {\r\n var initExpression = \'"); - - - #line 21 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - Write(Model.Expression); - - - #line default - #line hidden -WriteLiteral("\';\r\n var hostSrcUrl = \'"); - - - #line 22 "..\..\Areas\Config\Views\Expressions\Editor.cshtml" - Write(Links.ClientSource.Style.ExpressionEditor_htm); - - - #line default - #line hidden -WriteLiteral(@"'; - var host = $('