Merge branch 'feature/v4' of https://github.com/tidusjar/Ombi into feature/v4

pull/3840/head
tidusjar 4 years ago
commit ae414f4815

@ -0,0 +1,15 @@
namespace Ombi.Helpers
{
public class StartupSingleton
{
private static StartupSingleton instance;
private StartupSingleton() { }
public static StartupSingleton Instance => instance ?? (instance = new StartupSingleton());
public string StoragePath { get; set; }
public string SecurityKey { get; set; }
}
}

@ -1,13 +0,0 @@
namespace Ombi.Helpers
{
public class StoragePathSingleton
{
private static StoragePathSingleton instance;
private StoragePathSingleton() { }
public static StoragePathSingleton Instance => instance ?? (instance = new StoragePathSingleton());
public string StoragePath { get; set; }
}
}

@ -17,6 +17,7 @@ namespace Ombi.Store.Entities
TheMovieDb = 4,
StoragePath = 5,
Notification = 6,
BaseUrl=7,
BaseUrl = 7,
SecurityToken = 8
}
}

@ -36,7 +36,7 @@
"angular-router-loader": "^0.8.5",
"angularx-qrcode": "^2.1.0",
"bootstrap": "^4.2.1",
"chart.js": "2.5.0",
"chart.js": "2.9.4",
"core-js": "^2.5.4",
"eventemitter2": "^5.0.1",
"font-awesome": "^4.7.0",

@ -1,13 +1,13 @@
<div class="small-middle-container">
<div class="row justify-content-end">
<div class="btn-group col-12 col-md-3 small-space" style="float:left;" role="group">
<div class="btn-group col-12 col-md-3 small-space discover-layout"role="group">
<mat-button-toggle-group *ngIf="displayOption">
<mat-button-toggle [ngClass]="displayOption === DisplayOption.Card ? 'mat-button-toggle-checked' : ''" (click)="changeView(DisplayOption.Card)"><mat-icon>dashboard</mat-icon></mat-button-toggle>
<mat-button-toggle [ngClass]="displayOption === DisplayOption.List ? 'mat-button-toggle-checked' : ''" (click)="changeView(DisplayOption.List)"><mat-icon>calendar_view_day</mat-icon></mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>
<div class="row justify-content-md-center">
<div class="row justify-content-md-center small-space">
<div class="btn-group" role="group">
<button type="button" (click)="switchDiscoverMode(DiscoverOption.Movie)" [attr.color]="popularActive ? 'accent' : 'primary'" [ngClass]="discoverOptions === DiscoverOption.Movie ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Discovery.Movies' | translate}}</button>
<button type="button" (click)="switchDiscoverMode(DiscoverOption.Combined)" [attr.color]="trendingActive ? 'accent' : 'primary'" [ngClass]="discoverOptions === DiscoverOption.Combined ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow"
@ -39,4 +39,4 @@
<div *ngIf="loadingFlag" class="row justify-content-md-center top-spacing loading-spinner">
<mat-spinner [color]="'accent'"></mat-spinner>
</div>
</div>
</div>

@ -26,6 +26,13 @@
padding-top: 1%;
}
.discover-layout {
position: absolute;
float: right;
margin-right: 36px;
z-index: 1;
}
::ng-deep .mat-card-image {
height: 75%;
object-fit: cover;
@ -195,4 +202,9 @@
max-width: 11.111111%;
min-width: 11.111111%;
}
}
@media (max-width: 420px) {
.discover-layout{
display: none;
}
}

@ -18,4 +18,7 @@ export class SystemService extends ServiceHelpers {
public getLog(logName: string): Observable<string> {
return this.http.get(`${this.url}logs/${logName}`, {responseType: 'text'});
}
public getNews(): Observable<string> {
return this.http.get(`${this.url}news`, {responseType: 'text'});
}
}

@ -1,7 +1,8 @@
<settings-menu></settings-menu>
<div *ngIf="about" class="small-middle-container">
<legend>About</legend>
<div class="row">
<div class="col-md-8">
<div class="mat-table">
<div class="mat-row" style="background:red;" *ngIf="notSupported">
<div class="mat-cell" style="text-align: center;"><b>NOT SUPPORTED OS. Please use the docker image available on the Container Station (It's free)</b></div>
@ -91,6 +92,11 @@
</div>
</div>
</div>
<div class="col-md-4">
<h2>News</h2>
<div [innerHTML]="newsHtml"></div>
</div>
</div>
</div>

@ -23,4 +23,18 @@
margin: auto;
width: 85%;
margin-top:10px;
}
:host ::ng-deep strong {
color: #fff;
background-color: #007bff;
display: inline-block;
padding: 0.25em 0.4em;
font-size: 75%;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.25rem;
}

@ -1,6 +1,6 @@
import { Component, OnInit } from "@angular/core";
import { IAbout } from "../../interfaces/ISettings";
import { JobService, SettingsService, HubService } from "../../services";
import { JobService, SettingsService, HubService, SystemService } from "../../services";
import { IConnectedUser } from "../../interfaces";
@Component({
@ -12,14 +12,16 @@ export class AboutComponent implements OnInit {
public about: IAbout;
public newUpdate: boolean;
public connectedUsers: IConnectedUser[];
public newsHtml: string;
constructor(private readonly settingsService: SettingsService,
private readonly jobService: JobService,
private readonly hubService: HubService) { }
private readonly jobService: JobService,
private readonly hubService: HubService,
private readonly systemService: SystemService) { }
public async ngOnInit() {
this.settingsService.about().subscribe(x => this.about = x);
this.newsHtml = await this.systemService.getNews().toPromise();
// TODO
// this.jobService.getCachedUpdate().subscribe(x => {

@ -38,7 +38,7 @@
html,
body {
min-height: 100vh;
overflow: auto;
overflow: initial;
scrollbar-color: #616161 #303030; //firefox
scrollbar-width: thin; //firefox
-webkit-overflow-scrolling: touch;
@ -138,4 +138,4 @@ table {
::ng-deep .mat-form-field.mat-focused .mat-form-field-label {
color: $accent;
}
}

@ -2331,25 +2331,28 @@ chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
chart.js@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.5.0.tgz#fe6e751a893769f56e72bee5ad91207e1c592957"
chart.js@2.9.4:
version "2.9.4"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==
dependencies:
chartjs-color "^2.0.0"
moment "^2.10.6"
chartjs-color "^2.1.0"
moment "^2.10.2"
chartjs-color-string@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz#8d3752d8581d86687c35bfe2cb80ac5213ceb8c1"
chartjs-color-string@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
dependencies:
color-name "^1.0.0"
chartjs-color@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.2.0.tgz#84a2fb755787ed85c39dd6dd8c7b1d88429baeae"
chartjs-color@^2.1.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0"
integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==
dependencies:
chartjs-color-string "^0.5.0"
color-convert "^0.5.3"
chartjs-color-string "^0.6.0"
color-convert "^1.9.3"
"chokidar@>=2.0.0 <4.0.0":
version "3.3.1"
@ -2582,11 +2585,7 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
color-convert@^1.9.0, color-convert@^1.9.1:
color-convert@^1.9.0, color-convert@^1.9.1, color-convert@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
dependencies:
@ -5661,10 +5660,15 @@ moment-timezone@^0.5.23:
dependencies:
moment ">= 2.9.0"
"moment@>= 2.9.0", moment@^2.10.6, moment@^2.23.0:
"moment@>= 2.9.0", moment@^2.23.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
moment@^2.10.2:
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"

@ -117,7 +117,7 @@ namespace Ombi.Controllers.V1
public AboutViewModel About()
{
var dbConfiguration = DatabaseExtensions.GetDatabaseConfiguration();
var storage = StoragePathSingleton.Instance;
var storage = StartupSingleton.Instance;
var model = new AboutViewModel
{
FrameworkDescription = RuntimeInformation.FrameworkDescription,

@ -136,7 +136,7 @@ namespace Ombi.Controllers.V1
};
claims.AddRange(roles.Select(role => new Claim("role", role)));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenAuthenticationOptions.SecretKey));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(StartupSingleton.Instance.SecurityKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

@ -1,7 +1,9 @@
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Markdig;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Ombi.Attributes;
@ -12,16 +14,27 @@ namespace Ombi.Controllers.V2
public class SystemController : V2Controller
{
private readonly IWebHostEnvironment _hosting;
private readonly HttpClient _client;
public SystemController(IWebHostEnvironment hosting)
public SystemController(IWebHostEnvironment hosting, IHttpClientFactory httpClientFactory)
{
_hosting = hosting;
_client = httpClientFactory.CreateClient();
}
[HttpGet("news")]
public async Task<IActionResult> GetNews()
{
var result = await _client.GetAsync("https://raw.githubusercontent.com/tidusjar/Ombi.News/main/README.md");
var content = await result.Content.ReadAsStringAsync();
var md = Markdown.ToHtml(content);
return Ok(md);
}
[HttpGet("logs")]
public IActionResult GetLogFiles()
{
var logsFolder = Path.Combine(_hosting.ContentRootPath, "Logs");
var logsFolder = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs");
var files = Directory
.EnumerateFiles(logsFolder, "*.txt", SearchOption.TopDirectoryOnly)
.Select(Path.GetFileName)
@ -33,7 +46,7 @@ namespace Ombi.Controllers.V2
[HttpGet("logs/{logFileName}")]
public async Task<IActionResult> ReadLogFile(string logFileName, CancellationToken token)
{
var logFile = Path.Combine(_hosting.ContentRootPath, "Logs", logFileName);
var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName);
using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader reader = new StreamReader(fs))
{
@ -44,7 +57,7 @@ namespace Ombi.Controllers.V2
[HttpGet("logs/download/{logFileName}")]
public IActionResult Download(string logFileName, CancellationToken token)
{
var logFile = Path.Combine(_hosting.ContentRootPath, "Logs", logFileName);
var logFile = Path.Combine(string.IsNullOrEmpty(Ombi.Helpers.StartupSingleton.Instance.StoragePath) ? _hosting.ContentRootPath : Helpers.StartupSingleton.Instance.StoragePath, "Logs", logFileName);
using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader reader = new StreamReader(fs))
{

@ -62,7 +62,7 @@ namespace Ombi.Extensions
public static DatabaseConfiguration GetDatabaseConfiguration()
{
var i = StoragePathSingleton.Instance;
var i = StartupSingleton.Instance;
if (string.IsNullOrEmpty(i.StoragePath))
{
i.StoragePath = string.Empty;

@ -83,7 +83,7 @@ namespace Ombi
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOptions.GetValue("SecretKey", string.Empty))),
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(StartupSingleton.Instance.SecurityKey)),
RequireExpirationTime = true,
ValidateLifetime = true,

@ -18,7 +18,7 @@ using Ombi.Store.Context.Sqlite;
namespace Ombi
{
public class Program
public static class Program
{
private static string UrlArgs { get; set; }
@ -50,13 +50,11 @@ namespace Ombi
UrlArgs = host;
var urlValue = string.Empty;
var instance = StoragePathSingleton.Instance;
var instance = StartupSingleton.Instance;
var demoInstance = DemoSingleton.Instance;
demoInstance.Demo = demo;
instance.StoragePath = storagePath ?? string.Empty;
// Check if we need to migrate the settings
DeleteSchedules();
//CheckAndMigrate();
var services = new ServiceCollection();
services.ConfigureDatabases(null);
@ -67,6 +65,8 @@ namespace Ombi
var config = settingsDb.ApplicationConfigurations.ToList();
var url = config.FirstOrDefault(x => x.Type == ConfigurationTypes.Url);
var dbBaseUrl = config.FirstOrDefault(x => x.Type == ConfigurationTypes.BaseUrl);
var securityToken = config.FirstOrDefault(x => x.Type == ConfigurationTypes.SecurityToken);
CheckSecurityToken(securityToken, settingsDb, instance);
if (url == null)
{
url = new ApplicationConfiguration
@ -136,18 +136,25 @@ namespace Ombi
}
}
private static void DeleteSchedules()
private static void CheckSecurityToken(ApplicationConfiguration securityToken, SettingsContext ctx, StartupSingleton instance)
{
try
if (securityToken == null || string.IsNullOrEmpty(securityToken.Value))
{
if (File.Exists("Schedules.db"))
securityToken = new ApplicationConfiguration
{
Type = ConfigurationTypes.SecurityToken,
Value = Guid.NewGuid().ToString("N")
};
using (var tran = ctx.Database.BeginTransaction())
{
File.Delete("Schedules.db");
ctx.ApplicationConfigurations.Add(securityToken);
ctx.SaveChanges();
tran.Commit();
}
}
catch (Exception)
{
}
instance.SecurityKey = securityToken.Value;
}
public static IHostBuilder CreateHostBuilder(string[] args) =>

@ -22,7 +22,7 @@
},
"Ombi": {
"commandName": "Project",
"commandLineArgs": "--host http://localhost:3577 --baseurl /ombi",
"commandLineArgs": "--host http://localhost:3577 ",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},

@ -35,7 +35,7 @@ namespace Ombi
{
public class Startup
{
public static StoragePathSingleton StoragePath => StoragePathSingleton.Instance;
public static StartupSingleton StoragePath => StartupSingleton.Instance;
public Startup(IWebHostEnvironment env)
{
@ -84,6 +84,7 @@ namespace Ombi
// setup.AddHealthCheckEndpoint("Ombi", "/health");
//});
services.AddMemoryCache();
services.AddHttpClient();
services.AddJwtAuthentication(Configuration);
@ -164,7 +165,7 @@ namespace Ombi
var baseUrl = appConfig.Get(ConfigurationTypes.BaseUrl);
if (baseUrl != null)
{
if (baseUrl.Value.HasValue() && settings.BaseUrl != baseUrl.Value)
if (baseUrl.Value.HasValue())
{
settings.BaseUrl = baseUrl.Value;
ombiService.SaveSettings(settings);

@ -0,0 +1,14 @@
{
"OmbiDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Database=app.ombi.io;User=ombi"
},
"SettingsDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Database=app.ombi.io;User=ombi"
},
"ExternalDatabase": {
"Type": "MySQL",
"ConnectionString": "Server=192.168.68.118;Database=app.ombi.io;User=ombi"
}
}
Loading…
Cancel
Save