From 81f410d7828ecbe17f26241aa493b02c6f50b662 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sun, 4 Apr 2021 23:35:38 +0100 Subject: [PATCH] Ombi will now tell you when there is an update available in the settings, clicking that will also provide you with the changelog and links to manually download the binaries. Also removed references to the custom HTTP client implimentation and we now use the inbuilt IHttpClientFactory, this means we have removed the "Ignore Certificate Errors" option in Ombi as it's no longer needed. --- src/Ombi.Api/Api.cs | 4 +- src/Ombi.Api/IOmbiHttpClient.cs | 14 -- src/Ombi.Api/Ombi.Api.csproj | 1 + src/Ombi.Api/OmbiHttpClient.cs | 110 ------------- src/Ombi.DependencyInjection/IocExtensions.cs | 17 +- .../Ombi.DependencyInjection.csproj | 1 + .../Ombi/Interfaces/IOmbiAutomaticUpdater.cs | 2 +- .../Jobs/Ombi/OmbiAutomaticUpdater.cs | 6 +- src/Ombi.Schedule/Processor/AppVeyor.cs | 4 +- .../Processor/ChangeLogProcessor.cs | 153 +++--------------- .../Processor/IChangeLogProcessor.cs | 2 +- .../Settings/Models/OmbiSettings.cs | 1 - .../ClientApp/src/app/interfaces/ISettings.ts | 17 +- .../src/app/services/update.service.ts | 18 +++ .../app/settings/about/about.component.html | 4 +- .../src/app/settings/about/about.component.ts | 30 ++-- .../about/update-dialog.component.html | 28 ++++ .../about/update-dialog.component.scss | 40 +++++ .../settings/about/update-dialog.component.ts | 16 ++ .../src/app/settings/ombi/ombi.component.html | 5 - .../src/app/settings/ombi/ombi.component.ts | 1 - .../src/app/settings/settings.module.ts | 8 +- src/Ombi/Controllers/V1/JobController.cs | 12 +- src/Ombi/Controllers/V1/UpdateController.cs | 6 +- src/Ombi/Ombi.csproj | 2 + src/Ombi/Program.cs | 7 +- src/Ombi/databadse.json | 14 ++ 27 files changed, 220 insertions(+), 303 deletions(-) delete mode 100644 src/Ombi.Api/IOmbiHttpClient.cs delete mode 100644 src/Ombi.Api/OmbiHttpClient.cs create mode 100644 src/Ombi/ClientApp/src/app/services/update.service.ts create mode 100644 src/Ombi/ClientApp/src/app/settings/about/update-dialog.component.html create mode 100644 src/Ombi/ClientApp/src/app/settings/about/update-dialog.component.scss create mode 100644 src/Ombi/ClientApp/src/app/settings/about/update-dialog.component.ts create mode 100644 src/Ombi/databadse.json diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index 764da5a13..7a8e7678b 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -16,14 +16,14 @@ namespace Ombi.Api { public class Api : IApi { - public Api(ILogger log, IOmbiHttpClient client) + public Api(ILogger log, HttpClient client) { Logger = log; _client = client; } private ILogger Logger { get; } - private readonly IOmbiHttpClient _client; + private readonly HttpClient _client; public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { diff --git a/src/Ombi.Api/IOmbiHttpClient.cs b/src/Ombi.Api/IOmbiHttpClient.cs deleted file mode 100644 index 1f6ff9514..000000000 --- a/src/Ombi.Api/IOmbiHttpClient.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -namespace Ombi.Api -{ - public interface IOmbiHttpClient - { - Task SendAsync(HttpRequestMessage request); - Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); - Task GetStringAsync(Uri requestUri); - } -} \ No newline at end of file diff --git a/src/Ombi.Api/Ombi.Api.csproj b/src/Ombi.Api/Ombi.Api.csproj index 98da29c2a..91821c83b 100644 --- a/src/Ombi.Api/Ombi.Api.csproj +++ b/src/Ombi.Api/Ombi.Api.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Ombi.Api/OmbiHttpClient.cs b/src/Ombi.Api/OmbiHttpClient.cs deleted file mode 100644 index 978476cf7..000000000 --- a/src/Ombi.Api/OmbiHttpClient.cs +++ /dev/null @@ -1,110 +0,0 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2017 Jamie Rees -// File: OmbiHttpClient.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.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Ombi.Core.Settings; -using Ombi.Helpers; -using Ombi.Settings.Settings.Models; - -namespace Ombi.Api -{ - /// - /// The purpose of this class is simple, keep one instance of the HttpClient in play. - /// There are many articles related to when using multiple HttpClient's keeping the socket in a WAIT state - /// https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/ - /// https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ - /// - public class OmbiHttpClient : IOmbiHttpClient - { - public OmbiHttpClient(ICacheService cache, ISettingsService s) - { - _cache = cache; - _settings = s; - _runtimeVersion = AssemblyHelper.GetRuntimeVersion(); - } - - private static HttpClient _client; - private static HttpMessageHandler _handler; - - private readonly ICacheService _cache; - private readonly ISettingsService _settings; - private readonly string _runtimeVersion; - - - public async Task SendAsync(HttpRequestMessage request) - { - await Setup(); - return await _client.SendAsync(request); - } - - public async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - await Setup(); - return await _client.SendAsync(request, cancellationToken); - } - - public async Task GetStringAsync(Uri requestUri) - { - await Setup(); - return await _client.GetStringAsync(requestUri); - } - - private async Task Setup() - { - if (_client == null) - { - if (_handler == null) - { - // Get the handler - _handler = await GetHandler(); - } - _client = new HttpClient(_handler); - _client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{_runtimeVersion} (https://ombi.io/)"); - } - } - - private async Task GetHandler() - { - if (_cache == null) - { - return new HttpClientHandler(); - } - var settings = await _cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await _settings.GetSettingsAsync(), DateTime.Now.AddHours(1)); - if (settings.IgnoreCertificateErrors) - { - return new HttpClientHandler - { - ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true, - }; - } - return new HttpClientHandler(); - } - } -} \ No newline at end of file diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index ef9c9230c..73a69203a 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -23,7 +23,6 @@ using Ombi.Notifications; using Ombi.Schedule; using Ombi.Schedule.Jobs; using Ombi.Settings.Settings; -using Ombi.Store.Context; using Ombi.Store.Repository; using Ombi.Notifications.Agents; using Ombi.Schedule.Jobs.Radarr; @@ -68,6 +67,8 @@ using Ombi.Api.MusicBrainz; using Ombi.Api.Twilio; using Ombi.Api.CloudService; using Ombi.Api.RottenTomatoes; +using System.Net.Http; +using Microsoft.Extensions.Logging; namespace Ombi.DependencyInjection { @@ -119,14 +120,24 @@ namespace Ombi.DependencyInjection public static void RegisterHttp(this IServiceCollection services) { + var runtimeVersion = AssemblyHelper.GetRuntimeVersion(); services.AddSingleton(); services.AddScoped(sp => sp.GetService().HttpContext.User); + services.AddHttpClient("OmbiClient", client => + { + client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{runtimeVersion} (https://ombi.io/)"); + }).ConfigurePrimaryHttpMessageHandler(() => + { + var httpClientHandler = new HttpClientHandler(); + httpClientHandler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true; + + return httpClientHandler; + }); } public static void RegisterApi(this IServiceCollection services) { - services.AddScoped(); - services.AddScoped(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/ + services.AddScoped(s => new Api.Api(s.GetRequiredService>(), s.GetRequiredService().CreateClient("OmbiClient"))); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index ed1e9e4a2..49d1dd194 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Ombi.Schedule/Jobs/Ombi/Interfaces/IOmbiAutomaticUpdater.cs b/src/Ombi.Schedule/Jobs/Ombi/Interfaces/IOmbiAutomaticUpdater.cs index 85765b6c6..4c856c9cd 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/Interfaces/IOmbiAutomaticUpdater.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/Interfaces/IOmbiAutomaticUpdater.cs @@ -5,6 +5,6 @@ namespace Ombi.Schedule.Jobs.Ombi public interface IOmbiAutomaticUpdater : IBaseJob { string[] GetVersion(); - Task UpdateAvailable(string branch, string currentVersion); + Task UpdateAvailable(string currentVersion); } } \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Ombi/OmbiAutomaticUpdater.cs b/src/Ombi.Schedule/Jobs/Ombi/OmbiAutomaticUpdater.cs index e44728698..c2cf42441 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/OmbiAutomaticUpdater.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/OmbiAutomaticUpdater.cs @@ -49,10 +49,10 @@ namespace Ombi.Schedule.Jobs.Ombi var productArray = productVersion.Split('-'); return productArray; } - public async Task UpdateAvailable(string branch, string currentVersion) + public async Task UpdateAvailable(string currentVersion) { - var updates = await Processor.Process(branch); + var updates = await Processor.Process(); var serverVersion = updates.UpdateVersionString; return !serverVersion.Equals(currentVersion, StringComparison.CurrentCultureIgnoreCase); @@ -88,7 +88,7 @@ namespace Ombi.Schedule.Jobs.Ombi Logger.LogDebug(LoggingEvents.Updater, "Looking for updates now"); //TODO this fails because the branch = featureupdater when it should be feature/updater - var updates = await Processor.Process(branch); + var updates = await Processor.Process(); Logger.LogDebug(LoggingEvents.Updater, "Updates: {0}", updates); diff --git a/src/Ombi.Schedule/Processor/AppVeyor.cs b/src/Ombi.Schedule/Processor/AppVeyor.cs index 6bb4e001c..5a760c50c 100644 --- a/src/Ombi.Schedule/Processor/AppVeyor.cs +++ b/src/Ombi.Schedule/Processor/AppVeyor.cs @@ -109,8 +109,8 @@ namespace Ombi.Core.Processor public string UpdateVersionString { get; set; } public int UpdateVersion { get; set; } public DateTime UpdateDate { get; set; } - - public List ChangeLogs { get; set; } + public bool UpdateAvailable { get; set; } + public string ChangeLogs { get; set; } public List Downloads { get; set; } } diff --git a/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs b/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs index a34bd89e1..89a6519e6 100644 --- a/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs +++ b/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs @@ -16,94 +16,41 @@ namespace Ombi.Schedule.Processor { public class ChangeLogProcessor : IChangeLogProcessor { - public ChangeLogProcessor(IApi api, IOmbiHttpClient client) + public ChangeLogProcessor(IApi api, IHttpClientFactory client) { _api = api; - _client = client; + _client = client.CreateClient("OmbiClient"); } private readonly IApi _api; - private readonly IOmbiHttpClient _client; + private readonly HttpClient _client; private const string _changeLogUrl = "https://raw.githubusercontent.com/tidusjar/Ombi/{0}/CHANGELOG.md"; private const string AppveyorApiUrl = "https://ci.appveyor.com/api"; private string ChangeLogUrl(string branch) => string.Format(_changeLogUrl, branch); - public async Task Process(string branch) + public async Task Process() { - var masterBranch = branch.Equals("master", StringComparison.CurrentCultureIgnoreCase); - string githubChangeLog; - - githubChangeLog = await _client.GetStringAsync(new Uri(ChangeLogUrl(branch))); - - - var html = Markdown.ToHtml(githubChangeLog); - - - var doc = new HtmlDocument(); - doc.LoadHtml(html); - - HtmlNode latestRelease; - if (masterBranch) - { - latestRelease = doc.DocumentNode.Descendants("h2") - .FirstOrDefault(x => x.InnerText != "(unreleased)"); - } - else - { - latestRelease = doc.DocumentNode.Descendants("h2") - .FirstOrDefault(x => x.InnerText == "(unreleased)"); - - if (latestRelease == null) - { - latestRelease = doc.DocumentNode.Descendants("h2") - .FirstOrDefault(x => x.InnerText != "(unreleased)"); - } - } - - var newFeatureList = latestRelease.NextSibling.NextSibling.NextSibling.NextSibling; - var featuresString = newFeatureList.ChildNodes.Where(x => x.Name != "#text").Select(x => x.InnerText.Replace("\\n", "")).ToList(); - var fixes = newFeatureList.NextSibling.NextSibling.NextSibling.NextSibling; - var fixesString = fixes.ChildNodes.Where(x => x.Name != "#text").Select(x => x.InnerText.Replace("\\n", "")).ToList(); - - // Cleanup - var featuresList = featuresString.Distinct().ToList(); - var fixesList = fixesString.Distinct().ToList(); - - // Get release var release = new Release { - Version = latestRelease.InnerText, - Features = featuresList, - Fixes = fixesList, Downloads = new List() }; - if (masterBranch) - { - var releaseTag = latestRelease.InnerText.Substring(0, 9); - await GetGitubRelease(release, releaseTag); - } - else - { - // Get AppVeyor - await GetAppVeyorRelease(release, branch); - } - - - return TransformUpdate(release,!masterBranch); - + await GetGitubRelease(release); + + return TransformUpdate(release); } - private UpdateModel TransformUpdate(Release release, bool develop) + private UpdateModel TransformUpdate(Release release) { var newUpdate = new UpdateModel { - UpdateVersionString = develop ? release.Version : release.Version.Substring(1,8), - UpdateVersion = release.Version == "(unreleased)" ? 0 : int.Parse(release.Version.Substring(1, 5).Replace(".", "")), + UpdateVersionString = release.Version, + UpdateVersion = int.Parse(release.Version.Substring(1, 5).Replace(".", "")), UpdateDate = DateTime.Now, - ChangeLogs = new List(), - Downloads = new List() - }; + ChangeLogs = release.Description, + Downloads = new List(), + UpdateAvailable = release.Version != AssemblyHelper.GetRuntimeVersion() + }; foreach (var dl in release.Downloads) { @@ -114,75 +61,16 @@ namespace Ombi.Schedule.Processor }); } - foreach (var f in release.Features) - { - var change = new ChangeLog - { - Descripion = f, - Type = "New", - }; - - newUpdate.ChangeLogs.Add(change); - } - - foreach (var f in release.Fixes) - { - var change = new ChangeLog - { - Descripion = f, - Type = "Fixed", - }; - - newUpdate.ChangeLogs.Add(change); - } - return newUpdate; } - private async Task GetAppVeyorRelease(Release release, string branch) + private async Task GetGitubRelease(Release release) { - var request = new Request($"/projects/tidusjar/requestplex/branch/{branch}", AppVeyorApi.AppveyorApiUrl, HttpMethod.Get); - request.ApplicationJsonContentType(); + var client = new GitHubClient(Octokit.ProductHeaderValue.Parse("OmbiV4")); - var builds = await _api.Request(request); - var jobId = builds.build.jobs.FirstOrDefault()?.jobId ?? string.Empty; + var releases = await client.Repository.Release.GetAll("ombi-app", "ombi"); + var latest = releases.OrderByDescending(x => x.CreatedAt).FirstOrDefault(); - if (builds.build.finished == DateTime.MinValue || builds.build.status.Equals("failed")) - { - return; - } - release.Version = builds.build.version; - // get the artifacts - request = new Request($"/buildjobs/{jobId}/artifacts", AppVeyorApi.AppveyorApiUrl, HttpMethod.Get); - request.ApplicationJsonContentType(); - - var artifacts = await _api.Request>(request); - - foreach (var item in artifacts) - { - var d = new Downloads - { - Name = item.fileName, - Url = $"{AppveyorApiUrl}/buildjobs/{jobId}/artifacts/{item.fileName}" - }; - release.Downloads.Add(d); - } - } - - private async Task GetGitubRelease(Release release, string releaseTag) - { - var client = new GitHubClient(Octokit.ProductHeaderValue.Parse("OmbiV3")); - - var releases = await client.Repository.Release.GetAll("tidusjar", "ombi"); - var latest = releases.FirstOrDefault(x => x.TagName.Equals(releaseTag, StringComparison.InvariantCultureIgnoreCase)); - if (latest.Name.Contains("V2", CompareOptions.IgnoreCase)) - { - latest = null; - } - if (latest == null) - { - latest = releases.OrderByDescending(x => x.CreatedAt).FirstOrDefault(); - } foreach (var item in latest.Assets) { var d = new Downloads @@ -192,6 +80,8 @@ namespace Ombi.Schedule.Processor }; release.Downloads.Add(d); } + release.Description = Markdown.ToHtml(latest.Body); + release.Version = latest.TagName; } } public class Release @@ -199,8 +89,7 @@ namespace Ombi.Schedule.Processor public string Version { get; set; } public string CheckinVersion { get; set; } public List Downloads { get; set; } - public List Features { get; set; } - public List Fixes { get; set; } + public string Description { get; set; } } public class Downloads diff --git a/src/Ombi.Schedule/Processor/IChangeLogProcessor.cs b/src/Ombi.Schedule/Processor/IChangeLogProcessor.cs index 97780245f..434faedd2 100644 --- a/src/Ombi.Schedule/Processor/IChangeLogProcessor.cs +++ b/src/Ombi.Schedule/Processor/IChangeLogProcessor.cs @@ -4,6 +4,6 @@ namespace Ombi.Core.Processor { public interface IChangeLogProcessor { - Task Process(string branch); + Task Process(); } } \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs index 36b540026..6c622f2ce 100644 --- a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs +++ b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs @@ -6,7 +6,6 @@ public bool CollectAnalyticData { get; set; } public bool Wizard { get; set; } public string ApiKey { get; set; } - public bool IgnoreCertificateErrors { get; set; } public bool DoNotSendNotificationsForAutoApprove { get; set; } public bool HideRequestsUsers { get; set; } public bool DisableHealthChecks { get; set; } diff --git a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts index c5b29adff..7fa710248 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts @@ -12,7 +12,6 @@ export interface IOmbiSettings extends ISettings { collectAnalyticData: boolean; wizard: boolean; apiKey: string; - ignoreCertificateErrors: boolean; doNotSendNotificationsForAutoApprove: boolean; hideRequestsUsers: boolean; defaultLanguageCode: string; @@ -285,3 +284,19 @@ export interface ITheMovieDbSettings extends ISettings { showAdultMovies: boolean; excludedKeywordIds: number[]; } + +export interface IUpdateModel +{ + updateVersionString: string; + updateVersion: number; + updateDate: Date, + updateAvailable: boolean; + changeLogs: string; + downloads: IUpdateDonloads[]; +} + +export interface IUpdateDonloads +{ + name: string; + url: string +} diff --git a/src/Ombi/ClientApp/src/app/services/update.service.ts b/src/Ombi/ClientApp/src/app/services/update.service.ts new file mode 100644 index 000000000..d1e84cfaf --- /dev/null +++ b/src/Ombi/ClientApp/src/app/services/update.service.ts @@ -0,0 +1,18 @@ +import { PlatformLocation, APP_BASE_HREF } from "@angular/common"; +import { Injectable, Inject } from "@angular/core"; + +import { HttpClient } from "@angular/common/http"; +import { Observable } from "rxjs"; + +import { ServiceHelpers } from "./service.helpers"; +import { IUpdateModel } from "../interfaces"; + +@Injectable() +export class UpdateService extends ServiceHelpers { + constructor(http: HttpClient, @Inject(APP_BASE_HREF) href:string) { + super(http, "/api/v1/Update/", href); + } + public checkForUpdate(): Observable { + return this.http.get(`${this.url}`, {headers: this.headers}); + } +} diff --git a/src/Ombi/ClientApp/src/app/settings/about/about.component.html b/src/Ombi/ClientApp/src/app/settings/about/about.component.html index e6eb05cb4..f4872eda7 100644 --- a/src/Ombi/ClientApp/src/app/settings/about/about.component.html +++ b/src/Ombi/ClientApp/src/app/settings/about/about.component.html @@ -13,8 +13,8 @@
Version
-
{{about.version}} (New Update Available)
+
{{about.version}} (New Update Available)