mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -07:00
#1513 Added the update available icon
This commit is contained in:
parent
057683d97a
commit
f689af82f0
14 changed files with 104 additions and 160 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
54
src/Ombi.Helpers/MemoryCacheHelper.cs
Normal file
54
src/Ombi.Helpers/MemoryCacheHelper.cs
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue