diff --git a/Ombi.Api.Interfaces/IAppveyorApi.cs b/Ombi.Api.Interfaces/IAppveyorApi.cs
new file mode 100644
index 000000000..d067773fd
--- /dev/null
+++ b/Ombi.Api.Interfaces/IAppveyorApi.cs
@@ -0,0 +1,9 @@
+using Ombi.Api.Models.Appveyor;
+
+namespace Ombi.Api.Interfaces
+{
+ public interface IAppveyorApi
+ {
+ AppveyorProjects GetProjectHistory(string branchName, int records = 10);
+ }
+}
\ No newline at end of file
diff --git a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj
index 172c009e4..cf50e513d 100644
--- a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj
+++ b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj
@@ -54,6 +54,7 @@
+
diff --git a/Ombi.Api.Models/Appveyor/AppveyorProject.cs b/Ombi.Api.Models/Appveyor/AppveyorProject.cs
new file mode 100644
index 000000000..bf94a451a
--- /dev/null
+++ b/Ombi.Api.Models/Appveyor/AppveyorProject.cs
@@ -0,0 +1,114 @@
+#region Copyright
+// /************************************************************************
+// Copyright (c) 2017 Jamie Rees
+// File: AppveyorProject.cs
+// Created By: Jamie Rees
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ************************************************************************/
+#endregion
+
+using System;
+
+namespace Ombi.Api.Models.Appveyor
+{
+ public class AppveyorProjects
+ {
+ public Project project { get; set; }
+ public Build[] builds { get; set; }
+ }
+
+ public class Project
+ {
+ public int projectId { get; set; }
+ public int accountId { get; set; }
+ public string accountName { get; set; }
+ public object[] builds { get; set; }
+ public string name { get; set; }
+ public string slug { get; set; }
+ public string repositoryType { get; set; }
+ public string repositoryScm { get; set; }
+ public string repositoryName { get; set; }
+ public bool isPrivate { get; set; }
+ public bool skipBranchesWithoutAppveyorYml { get; set; }
+ public bool enableSecureVariablesInPullRequests { get; set; }
+ public bool enableSecureVariablesInPullRequestsFromSameRepo { get; set; }
+ public bool enableDeploymentInPullRequests { get; set; }
+ public bool rollingBuilds { get; set; }
+ public bool alwaysBuildClosedPullRequests { get; set; }
+ public string tags { get; set; }
+ public Securitydescriptor securityDescriptor { get; set; }
+ public DateTime created { get; set; }
+ public DateTime updated { get; set; }
+ }
+
+ public class Securitydescriptor
+ {
+ public Accessrightdefinition[] accessRightDefinitions { get; set; }
+ public Roleace[] roleAces { get; set; }
+ }
+
+ public class Accessrightdefinition
+ {
+ public string name { get; set; }
+ public string description { get; set; }
+ }
+
+ public class Roleace
+ {
+ public int roleId { get; set; }
+ public string name { get; set; }
+ public bool isAdmin { get; set; }
+ public Accessright[] accessRights { get; set; }
+ }
+
+ public class Accessright
+ {
+ public string name { get; set; }
+ public bool allowed { get; set; }
+ }
+
+ public class Build
+ {
+ public int buildId { get; set; }
+ public object[] jobs { get; set; }
+ public int buildNumber { get; set; }
+ public string version { get; set; }
+ public string message { get; set; }
+ public string messageExtended { get; set; }
+ public string branch { get; set; }
+ public bool isTag { get; set; }
+ public string commitId { get; set; }
+ public string authorName { get; set; }
+ public string authorUsername { get; set; }
+ public string committerName { get; set; }
+ public string committerUsername { get; set; }
+ public DateTime committed { get; set; }
+ public object[] messages { get; set; }
+ public string status { get; set; }
+ public DateTime started { get; set; }
+ public DateTime finished { get; set; }
+ public DateTime created { get; set; }
+ public DateTime updated { get; set; }
+ public string pullRequestId { get; set; }
+ public string pullRequestName { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/Ombi.Api.Models/Ombi.Api.Models.csproj b/Ombi.Api.Models/Ombi.Api.Models.csproj
index addec5fa1..e13506d5b 100644
--- a/Ombi.Api.Models/Ombi.Api.Models.csproj
+++ b/Ombi.Api.Models/Ombi.Api.Models.csproj
@@ -49,6 +49,7 @@
+
diff --git a/Ombi.Api/AppveyorApi.cs b/Ombi.Api/AppveyorApi.cs
new file mode 100644
index 000000000..8471edbde
--- /dev/null
+++ b/Ombi.Api/AppveyorApi.cs
@@ -0,0 +1,81 @@
+#region Copyright
+// /************************************************************************
+// Copyright (c) 2017 Jamie Rees
+// File: AppveyorApi.cs
+// Created By: Jamie Rees
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ************************************************************************/
+#endregion
+
+using System;
+using System.Collections.Generic;
+using NLog;
+using Ombi.Api.Interfaces;
+using Ombi.Api.Models.Appveyor;
+using Ombi.Helpers;
+using RestSharp;
+
+namespace Ombi.Api
+{
+ public class AppveyorApi : IAppveyorApi
+ {
+ private const string AppveyorApiUrl = "https://ci.appveyor.com/api";
+
+ private const string Key =
+ "48Ku58C0794nBrXra8IxWav+dc6NqgkRw+PZB3/bQwbt/D0IrnJQkgtjzo0bd6nkooLMKsC8M+Ab7jyBO+ROjY14VRuxffpDopX9r0iG/fjBl6mZVvqkm+VTDNstDtzp";
+
+
+ public AppveyorApi()
+ {
+ Api = new ApiRequest();
+ }
+ private ApiRequest Api { get; set; }
+ private static Logger Log = LogManager.GetCurrentClassLogger();
+
+ //https://ci.appveyor.com/api/projects/tidusjar/requestplex/history?recordsNumber=10&branch=eap
+ public AppveyorProjects GetProjectHistory(string branchName, int records = 10)
+ {
+ var request = new RestRequest
+ {
+ Resource = "projects/tidusjar/requestplex/history?recordsNumber={records}&branch={branch}",
+ Method = Method.GET
+ };
+
+ request.AddUrlSegment("records", records.ToString());
+ request.AddUrlSegment("branch", branchName);
+ AddHeaders(request);
+
+ var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetProjectHistory for Appveyor, Retrying {0}", timespan), new[] {
+ TimeSpan.FromSeconds (1),
+ });
+
+ var obj = policy.Execute(() => Api.ExecuteJson(request, new Uri(AppveyorApiUrl)));
+
+ return obj;
+ }
+
+ private void AddHeaders(IRestRequest request)
+ {
+ request.AddHeader("Authorization", $"Bearer {Key}");
+ request.AddHeader("Content-Type", "application/json");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ombi.Api/Ombi.Api.csproj b/Ombi.Api/Ombi.Api.csproj
index c9d00b030..d004e1c3f 100644
--- a/Ombi.Api/Ombi.Api.csproj
+++ b/Ombi.Api/Ombi.Api.csproj
@@ -76,6 +76,7 @@
+
diff --git a/Ombi.Core/Models/RecentUpdatesModel.cs b/Ombi.Core/Models/RecentUpdatesModel.cs
new file mode 100644
index 000000000..51a76700b
--- /dev/null
+++ b/Ombi.Core/Models/RecentUpdatesModel.cs
@@ -0,0 +1,43 @@
+#region Copyright
+// /************************************************************************
+// Copyright (c) 2017 Jamie Rees
+// File: RecentUpdatesModel.cs
+// Created By: Jamie Rees
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ************************************************************************/
+#endregion
+
+using System;
+
+namespace Ombi.Core.Models
+{
+ public class RecentUpdatesModel
+ {
+ public string Version { get; set; }
+ public string Message { get; set; }
+ public bool Installed { get; set; }
+ public DateTime Date { get; set; }
+ public string Branch { get; set; }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/Ombi.Core/Ombi.Core.csproj b/Ombi.Core/Ombi.Core.csproj
index f6562c2fc..49c37b597 100644
--- a/Ombi.Core/Ombi.Core.csproj
+++ b/Ombi.Core/Ombi.Core.csproj
@@ -99,6 +99,7 @@
+
diff --git a/Ombi.Core/SettingModels/SystemSettings.cs b/Ombi.Core/SettingModels/SystemSettings.cs
index d905af2e4..ee2ef4a60 100644
--- a/Ombi.Core/SettingModels/SystemSettings.cs
+++ b/Ombi.Core/SettingModels/SystemSettings.cs
@@ -25,10 +25,12 @@
// ************************************************************************/
#endregion
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Ombi.Core.Models;
+using Ombi.Helpers;
namespace Ombi.Core.SettingModels
{
@@ -50,13 +52,15 @@ namespace Ombi.Core.SettingModels
public enum Branches
{
- [Display(Name = "Stable")]
+ [Branch(DisplayName= "Stable", BranchName = "master")]
Stable,
- [Display(Name = "Early Access Preview")]
+ [Branch(DisplayName = "Early Access Preview", BranchName = "eap")]
EarlyAccessPreview,
- [Display(Name = "Development")]
+ [Branch(DisplayName = "Development", BranchName = "dev")]
Dev,
}
+
+
}
\ No newline at end of file
diff --git a/Ombi.Helpers/EnumHelper.cs b/Ombi.Helpers/EnumHelper.cs
index db1ced9da..65b0de15e 100644
--- a/Ombi.Helpers/EnumHelper.cs
+++ b/Ombi.Helpers/EnumHelper.cs
@@ -82,6 +82,19 @@ namespace Ombi.Helpers
if (descriptionAttributes == null) return string.Empty;
return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
}
+
+ public static BranchAttribute GetBranchValue(T value) where U : BranchAttribute
+ {
+ var fieldInfo = value.GetType().GetField(value.ToString());
+
+ var descriptionAttributes = fieldInfo.GetCustomAttributes(
+ typeof(BranchAttribute), false) as BranchAttribute[];
+
+ return descriptionAttributes?.FirstOrDefault();
+ }
+
+
+
public static string GetDisplayDescription(T value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
@@ -127,4 +140,9 @@ namespace Ombi.Helpers
return Enum.GetValues(typeof(T)).Cast().Sum();
}
}
+ public class BranchAttribute : Attribute
+ {
+ public string DisplayName { get; set; }
+ public string BranchName { get; set; }
+ }
}
\ No newline at end of file
diff --git a/Ombi.UI/Modules/Admin/SystemStatusModule.cs b/Ombi.UI/Modules/Admin/SystemStatusModule.cs
index cce157985..56c6aa5d3 100644
--- a/Ombi.UI/Modules/Admin/SystemStatusModule.cs
+++ b/Ombi.UI/Modules/Admin/SystemStatusModule.cs
@@ -35,8 +35,10 @@ using MarkdownSharp;
using Nancy;
using Nancy.ModelBinding;
using Nancy.Responses.Negotiation;
+using Ombi.Api.Interfaces;
using Ombi.Common.Processes;
using Ombi.Core;
+using Ombi.Core.Models;
using Ombi.Core.SettingModels;
using Ombi.Core.StatusChecker;
using Ombi.Helpers;
@@ -50,11 +52,13 @@ namespace Ombi.UI.Modules.Admin
{
public class SystemStatusModule : BaseModule
{
- public SystemStatusModule(ISettingsService settingsService, ICacheProvider cache, ISettingsService ss, ISecurityExtensions security, IAnalytics a) : base("admin", settingsService, security)
+ public SystemStatusModule(ISettingsService settingsService, ICacheProvider cache, ISettingsService ss,
+ ISecurityExtensions security, IAnalytics a, IAppveyorApi appveyor) : base("admin", settingsService, security)
{
Cache = cache;
SystemSettings = ss;
Analytics = a;
+ AppveyorApi = appveyor;
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
@@ -62,11 +66,13 @@ namespace Ombi.UI.Modules.Admin
Post["/save", true] = async (x, ct) => await Save();
Post["/autoupdate"] = x => AutoUpdate();
+ Get["/changes", true] = async (x, ct) => await GetLatestChanges();
}
private ICacheProvider Cache { get; }
private ISettingsService SystemSettings { get; }
private IAnalytics Analytics { get; }
+ private IAppveyorApi AppveyorApi { get; }
private async Task Status()
{
@@ -82,19 +88,19 @@ namespace Ombi.UI.Modules.Admin
{
new BranchDropdown
{
- Name = EnumHelper.GetDisplayValue(Branches.Stable),
+ Name =EnumHelper.GetBranchValue(Branches.Stable).DisplayName,
Value = Branches.Stable,
Selected = settings.Branch == Branches.Stable
},
new BranchDropdown
{
- Name = EnumHelper.GetDisplayValue(Branches.EarlyAccessPreview),
+ Name = EnumHelper.GetBranchValue(Branches.EarlyAccessPreview).DisplayName,
Value = Branches.EarlyAccessPreview,
Selected = settings.Branch == Branches.EarlyAccessPreview
},
new BranchDropdown
{
- Name = EnumHelper.GetDisplayValue(Branches.Dev),
+ Name = EnumHelper.GetBranchValue(Branches.Dev).DisplayName,
Value = Branches.Dev,
Selected = settings.Branch == Branches.Dev
},
@@ -103,6 +109,34 @@ namespace Ombi.UI.Modules.Admin
return View["Status", settings];
}
+ public async Task GetLatestChanges()
+ {
+ var settings = await SystemSettings.GetSettingsAsync();
+ var branchName = EnumHelper.GetBranchValue(settings.Branch).BranchName;
+ var changes = AppveyorApi.GetProjectHistory(branchName);
+ var currentVersion = AssemblyHelper.GetProductVersion();
+ var model = new List();
+
+ foreach (var build in changes.builds)
+ {
+ model.Add(new RecentUpdatesModel
+ {
+ Date = build.finished,
+ Message = BuildAppveyorMessage(build.message, build.messageExtended),
+ Version = build.version,
+ Installed = currentVersion.Equals(build.version, StringComparison.CurrentCultureIgnoreCase) ,
+ Branch = branchName
+ });
+ }
+
+ return Response.AsJson(model);
+ }
+
+ private string BuildAppveyorMessage(string message, string extended)
+ {
+ return extended == null ? message : $"{message} {extended}";
+ }
+
private async Task Save()
{
diff --git a/Ombi.UI/NinjectModules/ApiModule.cs b/Ombi.UI/NinjectModules/ApiModule.cs
index 8ca7c5dbd..d8b40cb33 100644
--- a/Ombi.UI/NinjectModules/ApiModule.cs
+++ b/Ombi.UI/NinjectModules/ApiModule.cs
@@ -51,6 +51,7 @@ namespace Ombi.UI.NinjectModules
Bind().To();
Bind().To();
Bind().To();
+ Bind().To();
}
}
}
\ No newline at end of file
diff --git a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml
index a93a452d3..03d533097 100644
--- a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml
+++ b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml
@@ -40,7 +40,7 @@
@Html.GetSidebarUrl(Context, "/admin/logs", "Logs", "fa fa-edit")
- @Html.GetSidebarUrl(Context, "/admin/status", "Status", "fa fa-dashboard")
+ @Html.GetSidebarUrl(Context, "/admin/status", "Updates", "fa fa-dashboard")
@Html.GetSidebarUrl(Context, "/admin/scheduledjobs", "Scheduled Jobs", "fa fa-hand-spock-o")
@Html.GetSidebarUrl(Context, "/admin/faultqueue", "Request Fault Queue", "fa fa-history")
diff --git a/Ombi.UI/Views/SystemStatus/Status.cshtml b/Ombi.UI/Views/SystemStatus/Status.cshtml
index 4ef61a2e6..232a29a78 100644
--- a/Ombi.UI/Views/SystemStatus/Status.cshtml
+++ b/Ombi.UI/Views/SystemStatus/Status.cshtml
@@ -4,78 +4,127 @@