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

pull/1520/head
tidusjar 7 years ago
commit edd15e54b6

@ -108,7 +108,16 @@ namespace Ombi.Core.Engine
// Remove the ID since this is a new child
tvBuilder.ChildRequest.Id = 0;
return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest);
if (!tvBuilder.ChildRequest.SeasonRequests.Any())
{
// Looks like we have removed them all! They were all duplicates...
return new RequestEngineResult
{
RequestAdded = false,
ErrorMessage = "They have already been requestsed"
};
}
return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest);
}
// This is a new request

@ -202,7 +202,6 @@ namespace Ombi.Core.Engine
}
}
}
}
if (plexSettings.Enable)
{
@ -230,12 +229,15 @@ namespace Ombi.Core.Engine
}
}
}
}
if (item.SeasonRequests.Any() && item.SeasonRequests.All(x => x.Episodes.All(e => e.Approved)))
{
item.FullyAvailable = true;
}
if (item.Id > 0)
{
// TODO need to check if the episodes are available
var tvdbid = item.Id;
if (existingRequests.ContainsKey(tvdbid))
{
@ -269,6 +271,7 @@ namespace Ombi.Core.Engine
}
}
}
// TODO CHECK SONARR/RADARR
//if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid))
// // compare to the sonarr/sickrage db
//{

@ -49,5 +49,10 @@ namespace Ombi.Core.Models.Search
public bool FirstSeason { get; set; }
public bool LatestSeason { get; set; }
/// <summary>
/// This is where we have EVERY Episode for that series
/// </summary>
public bool FullyAvailable { get; set; }
}
}

@ -34,7 +34,7 @@ namespace Ombi.Schedule.Jobs.Plex
public async Task Start()
{
var userManagementSettings = await _userManagementSettings.GetSettingsAsync();
if (!userManagementSettings.ImportMediaServerUsers)
if (!userManagementSettings.ImportPlexUsers)
{
return;
}

@ -2,7 +2,7 @@
{
public class OmbiSettings : Models.Settings
{
//public string BaseUrl { get; set; }
public string BaseUrl { get; set; }
public bool CollectAnalyticData { get; set; }
public bool Wizard { get; set; }
public string ApiKey { get; set; }

@ -4,7 +4,8 @@ namespace Ombi.Settings.Settings.Models
{
public class UserManagementSettings : Settings
{
public bool ImportMediaServerUsers { get; set; }
public bool ImportPlexUsers { get; set; }
public bool ImportEmbyUsers { get; set; }
public List<string> DefaultRoles { get; set; }
}
}

@ -16,3 +16,8 @@ export interface IQuality {
id: number;
name: string;
}
export interface ICheckbox {
value: string;
enabled: boolean;
}

@ -1,4 +1,4 @@
import { ISeasonRequests } from "./IRequestModel";
import { INewSeasonRequests } from "./IRequestModel";
export interface ISearchTvResult {
id: number;
@ -21,7 +21,7 @@ export interface ISearchTvResult {
siteRating: number;
trailer: string;
homepage: string;
seasonsRequests: ISeasonRequests[];
seasonRequests: INewSeasonRequests[];
requestAll: boolean;
approved: boolean;
requested: boolean;

@ -1,4 +1,5 @@
import { ISettings } from "./ICommon";
import { ICheckbox } from "./index";
export interface IExternalSettings extends ISettings {
ssl: boolean;
@ -9,7 +10,7 @@ export interface IExternalSettings extends ISettings {
export interface IOmbiSettings extends ISettings {
port: number;
//baseUrl:string,
baseUrl: string;
collectAnalyticData: boolean;
wizard: boolean;
apiKey: string;
@ -102,6 +103,12 @@ export interface IAuthenticationSettings extends ISettings {
requireUppercase: boolean;
}
export interface IUserManagementSettings extends ISettings {
importPlexUsers: boolean;
importEmbyUsers: boolean;
defaultClaims: ICheckbox[];
}
export interface IAbout {
version: string;
branch: string;

@ -1,4 +1,6 @@
export interface IUser {
import { ICheckbox } from "./index";
export interface IUser {
id: string;
username: string;
alias: string;
@ -17,11 +19,6 @@ export enum UserType {
EmbyUser = 3,
}
export interface ICheckbox {
value: string;
enabled: boolean;
}
export interface IIdentityResult {
errors: string[];
successful: boolean;

@ -46,8 +46,15 @@ export class SeriesInformationComponent implements OnInit, OnDestroy {
if (this.result.requestAdded) {
this.notificationService.success("Request Added",
`Request for ${this.series.title} has been added successfully`);
this.series.seasonRequests.forEach((season) => {
season.episodes.forEach((ep) => {
ep.selected = false;
});
});
} else {
this.notificationService.warning("Request Added", this.result.message);
this.notificationService.warning("Request Added", this.result.errorMessage ? this.result.errorMessage : this.result.message);
}
});
}

@ -80,24 +80,7 @@
<div class="col-sm-2">
<input name="{{type}}Id" type="text" value="{{node.data.id}}" hidden="hidden" />
<!--<div *ngIf="node.data.requested; then requestedBtn else notRequestedBtn"></div>
<template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
</template>
<template #notRequestedBtn>
<button id="{{node.data.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
</template>-->
<!--{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}}
@*//TODO Not used yet*@
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br/>
{{else}}
{{#if_eq enableTvRequestsForOnlySeries true}}
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button>
{{else}}
-->
<div class="dropdown">
<div *ngIf="!node.data.fullyAvailable" class="dropdown">
<button class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Request
<span class="caret"></span>
@ -109,7 +92,10 @@
<li><a (click)="openClosestTab($event)">Select ...</a></li>
</ul>
</div>
<div *ngIf="node.data.fullyAvailable">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> Available</button>
</div>
<!--
<br/>
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>

@ -20,6 +20,7 @@ import {
ISlackNotificationSettings,
ISonarrSettings,
IUpdateSettings,
IUserManagementSettings,
} from "../interfaces";
import { ServiceAuthHelpers } from "./service.helpers";
@ -182,4 +183,14 @@ export class SettingsService extends ServiceAuthHelpers {
.post(`${this.url}/update`, JSON.stringify(settings), { headers: this.headers })
.map(this.extractData).catch(this.handleError);
}
public getUserManagementSettings(): Observable<IUserManagementSettings> {
return this.httpAuth.get(`${this.url}/UserManagement`).map(this.extractData).catch(this.handleError);
}
public saveUserManagementSettings(settings: IUserManagementSettings): Observable<boolean> {
return this.httpAuth
.post(`${this.url}/UserManagement`, JSON.stringify(settings), { headers: this.headers })
.map(this.extractData).catch(this.handleError);
}
}

@ -12,7 +12,7 @@
<div class="form-group">
<label for="logo" class="control-label">Custom Logo</label>
<div>
<input type="text" [(ngModel)]="settings.logo" class="form-control form-control-custom " id="logo" name="logo" value="{{settings.logo}}" tooltipPosition="top" pTooltip="This will be used on all of the notifications e.g. Newsletter, email notification and also the Landing page">
<input type="text" [(ngModel)]="settings.logo" class="form-control form-control-custom " id="logo" name="logo" value="{{settings.logo}}" tooltipPosition="top" pTooltip="Use a URL e.g. www.google.com/logo.png">
</div>
</div>

@ -20,7 +20,7 @@
<input type="text" class="form-control form-control-custom " id="externalUrl" name="externalUrl" placeholder="http://ombi.io/" formControlName="externalUrl" tooltipPosition="top" pTooltip="This will be the link that will be in any emails/notifications sent to the users.">
</div>
</div>-->
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="allowExternalUsersToAuthenticate" allowExternalUsersToAuthenticate="allowExternalUsersToAuthenticate" formControlName="allowExternalUsersToAuthenticate"
@ -28,6 +28,13 @@
<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>
<input type="text" class="form-control form-control-custom" id="baseUrl" name="baseUrl" placeholder="/ombi" formControlName="baseUrl">
</div>
</div>
<div class="form-group">
<label for="ApiKey" class="control-label">Api Key</label>
@ -56,5 +63,6 @@
<button [disabled]="form.invalid" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</div>
</form>
</fieldset>

@ -23,6 +23,7 @@ export class OmbiComponent implements OnInit {
apiKey: [x.apiKey],
externalUrl: [x.externalUrl],
allowExternalUsersToAuthenticate: [x.allowExternalUsersToAuthenticate],
baseUrl: [x.baseUrl],
});
});
}

@ -1,6 +1,5 @@
<ul class="nav nav-tabs">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/About']"><i class="fa fa-question" aria-hidden="true"></i> About</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Ombi']">Ombi</a></li>
<li class="dropdown" [routerLinkActive]="['active']">
@ -69,6 +68,7 @@
<i class="fa fa-tachometer" aria-hidden="true"></i> System <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/About']">About</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Update']">Update</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Logs']">Logs (Not available)</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/ScheduledJobs']">Scheduled Jobs (Not available)</a></li>

@ -18,7 +18,6 @@ export class UpdateComponent implements OnInit {
private fb: FormBuilder) { }
public ngOnInit() {
this.settingsService.getUpdateSettings()
.subscribe(x => {
this.form = this.fb.group({
@ -29,9 +28,11 @@ export class UpdateComponent implements OnInit {
public checkForUpdate() {
this.updateService.checkForNewUpdate().subscribe(x => {
if (x) {
if (x === true) {
this.updateAvailable = true;
this.notificationService.success("Update", "There is a new update available");
} else {
this.notificationService.success("Update", "You are on the latest version!");
}
});
}

@ -1 +1,43 @@
<settings-menu></settings-menu>
<fieldset>
<legend>User Management Settings</legend>
<div class="col-md-6">
<div *ngIf="plexEnabled">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="importPlex" formControlName="importPlexUsers">
<label for="importPlexUsers">Import Plex Users</label>
</div>
</div>
</div>
<div *ngIf="embyEnabled">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="importEmbyUsers" formControlName="importEmbyUsers">
<label for="importEmbyUsers">Import Emby Users</label>
</div>
</div>
</div>
</div>
<div class="col-md-6" >
<h4>Default Roles</h4>
<div *ngFor="let c of claims">
<div class="form-group">
<div class="checkbox">
<input type="checkbox" [(ngModel)]="c.enabled" [value]="c.value" id="create{{c.value}}" [attr.name]="'create' + c.value" ng-checked="c.enabled">
<label for="create{{c.value}}">{{c.value}}</label>
</div>
</div>
</div>
</div>
</fieldset>

@ -1,6 +1,42 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { ICheckbox, IUserManagementSettings } from "../../interfaces";
import { IdentityService, SettingsService } from "../../services";
@Component({
templateUrl: "./usermanagement.component.html",
})
export class UserManagementComponent { }
export class UserManagementComponent implements OnInit {
public plexEnabled: boolean;
public embyEnabled: boolean;
public settings: IUserManagementSettings;
public claims: ICheckbox[];
constructor(private settingsService: SettingsService,
//private notificationService: NotificationService,
private identityService: IdentityService) {
}
public ngOnInit(): void {
this.settingsService.getUserManagementSettings().subscribe(x => {
this.settings = x;
this.identityService.getAllAvailableClaims().subscribe(c => {
this.claims = c;
this.claims.forEach((claim) => {
if (this.settings.defaultClaims) {
const hasClaim = this.settings.defaultClaims.some((item) => {
return item.value === claim.value && item.enabled;
});
claim.enabled = hasClaim;
}
});
});
});
this.settingsService.getPlex().subscribe(x => this.plexEnabled = x.enable);
this.settingsService.getEmby().subscribe(x => this.embyEnabled = x.enable);
}
}

@ -2,8 +2,7 @@
import { Router } from "@angular/router";
import { ICheckbox, IUser, UserType } from "../interfaces";
import { IdentityService } from "../services";
import { NotificationService } from "../services";
import { IdentityService, NotificationService } from "../services";
@Component({
templateUrl: "./usermanagement-add.component.html",

@ -306,6 +306,27 @@ namespace Ombi.Controllers
return await Save(settings);
}
/// <summary>
/// Gets the UserManagement Settings.
/// </summary>
/// <returns></returns>
[HttpGet("UserManagement")]
public async Task<UserManagementSettings> UserManagementSettings()
{
return await Get<UserManagementSettings>();
}
/// <summary>
/// Save the UserManagement settings.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
[HttpPost("UserManagement")]
public async Task<bool> UserManagementSettings([FromBody]UserManagementSettings settings)
{
return await Save(settings);
}
/// <summary>
/// Gets the Update Settings.
/// </summary>

@ -45,7 +45,7 @@ using Swashbuckle.AspNetCore.Swagger;
namespace Ombi
{
public partial class Startup
public class Startup
{
public Startup(IHostingEnvironment env)
{
@ -167,7 +167,7 @@ namespace Ombi
app.UseAuthentication();
//ApiKeyMiddlewear(app, serviceProvider);
ApiKeyMiddlewear(app, serviceProvider);
app.UseSwagger();
app.UseSwaggerUI(c =>
{
@ -210,11 +210,7 @@ namespace Ombi
else
{
var identity = new GenericIdentity("API");
identity.AddClaim(new System.Security.Claims.Claim("Origin", "Api"));
identity.AddClaim(new System.Security.Claims.Claim("role", "Admin"));
var principal = new GenericPrincipal(identity, new[] { "ApiUser" });
// TODO need to think about if I require a JWT Token here.
var principal = new GenericPrincipal(identity, new[] {"Admin", "ApiUser"});
context.User = principal;
await next();
}

@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Razor.TagHelpers;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
namespace Ombi.TagHelpers
{
public class ReverseProxyTagHelper : TagHelper
{
public ReverseProxyTagHelper(ISettingsService<OmbiSettings> c)
{
_ctx = c;
}
private readonly ISettingsService<OmbiSettings> _ctx;
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "base";
var s = _ctx.GetSettings();
var baseUrl = string.IsNullOrEmpty(s.BaseUrl) ? "/" : s.BaseUrl;
output.Attributes.SetAttribute("href", baseUrl);
}
}
}

@ -1,18 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ombi</title>
<base href="/" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="~/loading.css" asp-append-version="true" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />
<script src="~/dist/vendor.js" asp-append-version="true" defer></script>
<script src="~/dist/main.js" asp-append-version="true" defer></script>
<mini-profiler />
</head>
<body>
@RenderBody()
</body>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ombi</title>
<Reverse-Proxy></Reverse-Proxy>
<link rel="SHORTCUT ICON" href="~/images/favicon/favicon.ico" />
<link rel="icon" href="~/images/favicon/favicon.ico" type="image/ico" />
<link rel="apple-touch-icon" sizes="57x57" href="~/images/favicon/apple-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="60x60" href="~/images/favicon/apple-icon-60x60.png" />
<link rel="apple-touch-icon" sizes="72x72" href="~/images/favicon/apple-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="76x76" href="~/images/favicon/apple-icon-76x76.png" />
<link rel="apple-touch-icon" sizes="114x114" href="~/images/favicon/apple-icon-114x114.png" />
<link rel="apple-touch-icon" sizes="120x120" href="~/images/favicon/apple-icon-120x120.png" />
<link rel="apple-touch-icon" sizes="144x144" href="~/images/favicon/apple-icon-144x144.png" />
<link rel="apple-touch-icon" sizes="152x152" href="~/images/favicon/apple-icon-152x152.png" />
<link rel="apple-touch-icon" sizes="180x180" href="~/images/favicon/apple-icon-180x180.png" />
<link rel="icon" type="image/png" sizes="192x192" href="~/images/favicon/android-icon-192x192.png" />
<link rel="icon" type="image/png" sizes="32x32" href="~/images/favicon/favicon-32x32.png"/>
<link rel="icon" type="image/png" sizes="96x96" href="~/images/favicon/favicon-96x96.png"/>
<link rel="icon" type="image/png" sizes="16x16" href="~/images/favicon/favicon-16x16.png"/>
<link rel="manifest" href="~/images/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-TileImage" content="~/images/favicon/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="~/loading.css" asp-append-version="true" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />
<script src="~/dist/vendor.js" asp-append-version="true" defer></script>
<script src="~/dist/main.js" asp-append-version="true" defer></script>
</head>
<body>
@RenderBody()
</body>
</html>

@ -1,4 +1,4 @@
@using Ombi
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
@*@addTagHelper *, MiniProfiler.AspNetCore.Mvc*@
@addTagHelper *, Ombi

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,41 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Loading…
Cancel
Save