#1513 Added the update available icon

pull/1529/head
tidusjar 7 years ago
parent 057683d97a
commit f689af82f0

@ -1,111 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Ombi.Core.Update
{
public class UpdateEngine
{
public async Task Update(UpdateOptions options)
{
if (options.Status == UpdateStatus.UptoDate)
{
// We don't need to update...
return;
}
// Download zip into temp location
var path = await Download(options);
Extract(path);
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
var current = Path.GetDirectoryName(location);
// TODO Run the Update.exe and pass in the args
var start = new ProcessStartInfo
{
UseShellExecute = false,
CreateNoWindow = true,
FileName = Path.Combine(current, "Ombi.Updater.exe")
};
using (var proc = new Process { StartInfo = start })
{
proc.Start();
}
}
private void Extract(string path)
{
using (var zip = ZipFile.OpenRead(path))
{
path = Path.GetDirectoryName(path);
foreach (var entry in zip.Entries.Skip(1))
{
var fullname = string.Empty;
if (entry.FullName.Contains("publish/")) // Don't extract the publish folder, we are already in there
{
fullname = entry.FullName.Replace("publish/", string.Empty);
}
var fullPath = Path.Combine(path, fullname);
if (string.IsNullOrEmpty(entry.Name))
{
Directory.CreateDirectory(fullPath);
}
else
{
entry.ExtractToFile(fullPath, true);
Console.WriteLine("Restored {0}", entry.FullName);
}
}
}
}
/// <summary>
/// Downloads the specified zip from the options and returns the zip path.
/// </summary>
/// <param name="options">The options.</param>
/// <returns></returns>
private async Task<string> Download(UpdateOptions options)
{
// Create temp path
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
var current = Path.GetDirectoryName(location);
var tempDir = Directory.CreateDirectory(Path.Combine(current, "UpdateTemp"));
var tempZip = Path.Combine(tempDir.FullName, "Ombi.zip");
if (File.Exists(tempZip))
{
return tempZip;
}
using (var httpClient = new HttpClient())
using (var contentStream = await httpClient.GetStreamAsync(options.DownloadUrl))
using (var fileStream = new FileStream(tempZip, FileMode.Create, FileAccess.Write, FileShare.None, 1048576, true))
{
await contentStream.CopyToAsync(fileStream);
}
return tempZip;
}
public UpdateOptions CheckForUpdate()
{
return new UpdateOptions
{
Status = UpdateStatus.Available,
DownloadUrl = "https://ci.appveyor.com/api/buildjobs/t500indclt3etd50/artifacts/Ombi_windows.zip",
UpdateDate = DateTime.Now,
Version = "3.0.0"
};
}
}
}

@ -1,12 +0,0 @@
using System;
namespace Ombi.Core.Update
{
public class UpdateOptions
{
public UpdateStatus Status { get; set; }
public string DownloadUrl { get; set; }
public string Version { get; set; }
public DateTime UpdateDate { get; set; }
}
}

@ -1,8 +0,0 @@
namespace Ombi.Core.Update
{
public enum UpdateStatus
{
Available,
UptoDate
}
}

@ -6,6 +6,6 @@ namespace Ombi.Helpers
{
public static class CacheKeys
{
public const string RadarrCacher = nameof(RadarrCacher);
public const string Update = nameof(Update);
}
}

@ -0,0 +1,54 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2017 Jamie Rees
// File: MemoryCacheHelper.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 Microsoft.Extensions.Caching.Memory;
namespace Ombi.Helpers
{
public static class MemoryCacheHelper
{
public static IMemoryCache TryAdd(this IMemoryCache cache, object cacheObject, TimeSpan slidingExpiration)
{
object cachedObject;
if (!cache.TryGetValue(CacheKeys.Update, out cachedObject))
{
// Key not in cache, so get data.
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(slidingExpiration);
// Save data in cache.
cache.Set(CacheKeys.Update, cacheObject, cacheEntryOptions);
}
return cache;
}
}
}

@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="EasyCrypto" Version="3.3.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />

@ -33,7 +33,14 @@
<ul class="nav navbar-nav navbar-right">
<li *ngIf="hasRole('Admin') " [routerLinkActive]="['active']"><a [routerLink]="['/Settings/About']"><i class="fa fa-cog"></i> Settings</a></li>
<li *ngIf="hasRole('Admin') " [routerLinkActive]="['active']"><a [routerLink]="['/Settings/About']">
<i *ngIf="!updateAvailable" class="fa fa-cog"></i>
<i *ngIf="updateAvailable" class="fa fa-warning" style="color:#f57f17" pTooltip="Update Available!" tooltipPosition="left" [tooltipZIndex]="999999"></i>
Settings
</a></li>
<li [routerLinkActive]="['active']" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> Welcome {{user.name}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">

@ -3,7 +3,7 @@ import { Router } from "@angular/router";
import { AuthService } from "./auth/auth.service";
import { ILocalUser } from "./auth/IUserLogin";
import { NotificationService } from "./services";
import { SettingsService } from "./services";
import { JobService, SettingsService } from "./services";
import { ICustomizationSettings } from "./interfaces";
@ -17,8 +17,13 @@ export class AppComponent implements OnInit {
public customizationSettings: ICustomizationSettings;
public user: ILocalUser;
public showNav: boolean;
public updateAvailable: boolean;
constructor(public notificationService: NotificationService, public authService: AuthService, private router: Router, private settingsService: SettingsService) { }
constructor(public notificationService: NotificationService,
public authService: AuthService,
private readonly router: Router,
private readonly settingsService: SettingsService,
private readonly jobService: JobService) { }
public ngOnInit() {
this.user = this.authService.claims();
@ -29,6 +34,8 @@ export class AppComponent implements OnInit {
this.user = this.authService.claims();
this.showNav = this.authService.loggedIn();
});
this.jobService.getCachedUpdate().subscribe(x => this.updateAvailable = x);
}
public hasRole(role: string): boolean {

@ -17,6 +17,10 @@ export class JobService extends ServiceAuthHelpers {
return this.http.get(`${this.url}update/`).map(this.extractData);
}
public getCachedUpdate(): Observable<boolean> {
return this.http.get(`${this.url}updateCached/`).map(this.extractData);
}
public runPlexImporter(): Observable<boolean> {
return this.http.post(`${this.url}plexUserImporter/`, { headers: this.headers }).map(this.extractData);
}

@ -15,7 +15,7 @@ export class AboutComponent implements OnInit {
public ngOnInit() {
this.settingsService.about().subscribe(x => this.about = x);
this.jobService.checkForNewUpdate().subscribe(x => {
this.jobService.getCachedUpdate().subscribe(x => {
if (x === true) {
this.newUpdate = true;
}

@ -21,14 +21,7 @@
</div>
</div>-->
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="allowExternalUsersToAuthenticate" allowExternalUsersToAuthenticate="allowExternalUsersToAuthenticate" formControlName="allowExternalUsersToAuthenticate"
pTooltip="This will allow Plex Friends and Emby users to log into Ombi.">
<label for="allowExternalUsersToAuthenticate">Allow media server users to authenticate</label>
</div>
</div>
<div class="form-group">
<label for="baseUrl" class="control-label">Base Url</label>
<div>

@ -1,8 +1,11 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Hangfire;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Ombi.Api.Service;
using Ombi.Attributes;
using Ombi.Helpers;
using Ombi.Schedule.Jobs.Plex;
using Ombi.Schedule.Ombi;
@ -13,14 +16,17 @@ namespace Ombi.Controllers
[Produces("application/json")]
public class JobController : Controller
{
public JobController(IOmbiAutomaticUpdater updater, IPlexUserImporter userImporter)
public JobController(IOmbiAutomaticUpdater updater, IPlexUserImporter userImporter,
IMemoryCache mem)
{
_updater = updater;
_plexUserImporter = userImporter;
_memCache = mem;
}
private readonly IOmbiAutomaticUpdater _updater;
private readonly IPlexUserImporter _plexUserImporter;
private readonly IMemoryCache _memCache;
[HttpPost("update")]
public bool ForceUpdate()
@ -40,6 +46,22 @@ namespace Ombi.Controllers
return updateAvailable;
}
[HttpGet("updateCached")]
public async Task<bool> CheckForUpdateCached()
{
var val = await _memCache.GetOrCreateAsync(CacheKeys.Update, async entry =>
{
entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(1);
var productArray = _updater.GetVersion();
var version = productArray[0];
var branch = productArray[1];
var updateAvailable = await _updater.UpdateAvailable(branch, version);
return updateAvailable;
});
return val;
}
[HttpPost("plexuserimporter")]
public bool PlexUserImporter()
{

@ -30,8 +30,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models;
using Ombi.Core.Update;
using Ombi.Settings.Settings.Models;
namespace Ombi.Controllers
@ -72,15 +70,5 @@ namespace Ombi.Controllers
return new { Result = settings?.Wizard ?? false};
}
[AllowAnonymous]
[HttpGet("Update")]
public async Task Update()
{
var u = new UpdateEngine();
var result = u.CheckForUpdate();
await u.Update(result);
}
}
}

@ -99,8 +99,7 @@ namespace Ombi
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -._@+";
});
services.AddDataProtection();
services.AddMemoryCache();
services.AddJwtAuthentication(Configuration);

Loading…
Cancel
Save