mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-21 05:43:19 -07:00
Upstream Merge
This commit is contained in:
commit
7298aea8d5
104 changed files with 2099 additions and 341 deletions
10
src/Ombi.Api.Mattermost/IMattermostApi.cs
Normal file
10
src/Ombi.Api.Mattermost/IMattermostApi.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Mattermost.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Mattermost
|
||||||
|
{
|
||||||
|
public interface IMattermostApi
|
||||||
|
{
|
||||||
|
Task<string> PushAsync(string webhook, MattermostBody message);
|
||||||
|
}
|
||||||
|
}
|
27
src/Ombi.Api.Mattermost/MattermostApi.cs
Normal file
27
src/Ombi.Api.Mattermost/MattermostApi.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Mattermost.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Mattermost
|
||||||
|
{
|
||||||
|
public class MattermostApi : IMattermostApi
|
||||||
|
{
|
||||||
|
public MattermostApi(IApi api)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IApi _api;
|
||||||
|
|
||||||
|
public async Task<string> PushAsync(string webhook, MattermostBody message)
|
||||||
|
{
|
||||||
|
var request = new Request(string.Empty, webhook, HttpMethod.Post);
|
||||||
|
|
||||||
|
request.AddJsonBody(message);
|
||||||
|
|
||||||
|
var result = await _api.RequestContent(request);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/Ombi.Api.Mattermost/Models/MattermostBody.cs
Normal file
45
src/Ombi.Api.Mattermost/Models/MattermostBody.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: MattermostBody.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 Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Mattermost.Models
|
||||||
|
{
|
||||||
|
public class MattermostBody
|
||||||
|
{
|
||||||
|
[JsonConstructor]
|
||||||
|
public MattermostBody()
|
||||||
|
{
|
||||||
|
username = "Ombi";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string username { get; set; } = "Ombi";
|
||||||
|
public string channel { get; set; }
|
||||||
|
public string text { get; set; }
|
||||||
|
public string icon_url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj
Normal file
15
src/Ombi.Api.Mattermost/Ombi.Api.Mattermost.csproj
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard1.6</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -10,10 +10,11 @@ namespace Ombi.Api.Plex
|
||||||
Task<PlexStatus> GetStatus(string authToken, string uri);
|
Task<PlexStatus> GetStatus(string authToken, string uri);
|
||||||
Task<PlexAuthentication> SignIn(UserRequest user);
|
Task<PlexAuthentication> SignIn(UserRequest user);
|
||||||
Task<PlexServer> GetServer(string authToken);
|
Task<PlexServer> GetServer(string authToken);
|
||||||
Task<PlexLibraries> GetLibrarySections(string authToken, string plexFullHost);
|
Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost);
|
||||||
Task<PlexLibraries> GetLibrary(string authToken, string plexFullHost, string libraryId);
|
Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId);
|
||||||
Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, string ratingKey);
|
Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, int ratingKey);
|
||||||
Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId);
|
Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId);
|
||||||
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey);
|
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey);
|
||||||
|
Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ namespace Ombi.Api.Plex.Models
|
||||||
public class Mediacontainer
|
public class Mediacontainer
|
||||||
{
|
{
|
||||||
public int size { get; set; }
|
public int size { get; set; }
|
||||||
|
public int totalSize { get; set; }
|
||||||
public bool allowSync { get; set; }
|
public bool allowSync { get; set; }
|
||||||
public string identifier { get; set; }
|
public string identifier { get; set; }
|
||||||
public string mediaTagPrefix { get; set; }
|
public string mediaTagPrefix { get; set; }
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace Ombi.Api.Plex.Models
|
||||||
{
|
{
|
||||||
public class Metadata
|
public class Metadata
|
||||||
{
|
{
|
||||||
public string ratingKey { get; set; }
|
public int ratingKey { get; set; }
|
||||||
public string key { get; set; }
|
public string key { get; set; }
|
||||||
public string studio { get; set; }
|
public string studio { get; set; }
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
|
@ -28,8 +28,8 @@ namespace Ombi.Api.Plex.Models
|
||||||
public Genre[] Genre { get; set; }
|
public Genre[] Genre { get; set; }
|
||||||
public Role[] Role { get; set; }
|
public Role[] Role { get; set; }
|
||||||
public string primaryExtraKey { get; set; }
|
public string primaryExtraKey { get; set; }
|
||||||
public string parentRatingKey { get; set; }
|
public int parentRatingKey { get; set; }
|
||||||
public string grandparentRatingKey { get; set; }
|
public int grandparentRatingKey { get; set; }
|
||||||
public string guid { get; set; }
|
public string guid { get; set; }
|
||||||
public int librarySectionID { get; set; }
|
public int librarySectionID { get; set; }
|
||||||
public string librarySectionKey { get; set; }
|
public string librarySectionKey { get; set; }
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
namespace Ombi.Api.Plex.Models
|
namespace Ombi.Api.Plex.Models
|
||||||
{
|
{
|
||||||
public class PlexLibraries
|
public class PlexContainer
|
||||||
{
|
{
|
||||||
public Mediacontainer MediaContainer { get; set; }
|
public Mediacontainer MediaContainer { get; set; }
|
||||||
}
|
}
|
|
@ -60,18 +60,18 @@ namespace Ombi.Api.Plex
|
||||||
return await Api.Request<PlexServer>(request);
|
return await Api.Request<PlexServer>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexLibraries> GetLibrarySections(string authToken, string plexFullHost)
|
public async Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost)
|
||||||
{
|
{
|
||||||
var request = new Request("library/sections", plexFullHost, HttpMethod.Get);
|
var request = new Request("library/sections", plexFullHost, HttpMethod.Get);
|
||||||
AddHeaders(request, authToken);
|
AddHeaders(request, authToken);
|
||||||
return await Api.Request<PlexLibraries>(request);
|
return await Api.Request<PlexContainer>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexLibraries> GetLibrary(string authToken, string plexFullHost, string libraryId)
|
public async Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId)
|
||||||
{
|
{
|
||||||
var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get);
|
var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get);
|
||||||
AddHeaders(request, authToken);
|
AddHeaders(request, authToken);
|
||||||
return await Api.Request<PlexLibraries>(request);
|
return await Api.Request<PlexContainer>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -85,27 +85,47 @@ namespace Ombi.Api.Plex
|
||||||
/// <param name="plexFullHost"></param>
|
/// <param name="plexFullHost"></param>
|
||||||
/// <param name="ratingKey"></param>
|
/// <param name="ratingKey"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, string ratingKey)
|
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, int ratingKey)
|
||||||
{
|
{
|
||||||
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
|
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
|
||||||
AddHeaders(request, authToken);
|
AddHeaders(request, authToken);
|
||||||
return await Api.Request<PlexMetadata>(request);
|
return await Api.Request<PlexMetadata>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId)
|
public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId)
|
||||||
{
|
{
|
||||||
var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get);
|
var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get);
|
||||||
AddHeaders(request, authToken);
|
AddHeaders(request, authToken);
|
||||||
return await Api.Request<PlexMetadata>(request);
|
return await Api.Request<PlexMetadata>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey)
|
public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey)
|
||||||
{
|
{
|
||||||
var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get);
|
var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get);
|
||||||
AddHeaders(request, authToken);
|
AddHeaders(request, authToken);
|
||||||
return await Api.Request<PlexMetadata>(request);
|
return await Api.Request<PlexMetadata>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all episodes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="authToken">The authentication token.</param>
|
||||||
|
/// <param name="host">The host.</param>
|
||||||
|
/// <param name="section">The section.</param>
|
||||||
|
/// <param name="start">The start count.</param>
|
||||||
|
/// <param name="retCount">The return count, how many items you want returned.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount)
|
||||||
|
{
|
||||||
|
var request = new Request($"/library/sections/{section}/all", host, HttpMethod.Get);
|
||||||
|
|
||||||
|
request.AddQueryString("type", "4");
|
||||||
|
AddLimitHeaders(request, start, retCount);
|
||||||
|
AddHeaders(request, authToken);
|
||||||
|
|
||||||
|
return await Api.Request<PlexContainer>(request);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the required headers and also the authorization header
|
/// Adds the required headers and also the authorization header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -129,5 +149,11 @@ namespace Ombi.Api.Plex
|
||||||
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
|
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
|
||||||
request.AddHeader("Accept", "application/json");
|
request.AddHeader("Accept", "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddLimitHeaders(Request request, int from, int to)
|
||||||
|
{
|
||||||
|
request.AddHeader("X-Plex-Container-Start", from.ToString());
|
||||||
|
request.AddHeader("X-Plex-Container-Size", to.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/Ombi.Api.Pushover/IPushoverApi.cs
Normal file
10
src/Ombi.Api.Pushover/IPushoverApi.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Pushover.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Pushover
|
||||||
|
{
|
||||||
|
public interface IPushoverApi
|
||||||
|
{
|
||||||
|
Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken);
|
||||||
|
}
|
||||||
|
}
|
12
src/Ombi.Api.Pushover/Models/PushoverResponse.cs
Normal file
12
src/Ombi.Api.Pushover/Models/PushoverResponse.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Pushover.Models
|
||||||
|
{
|
||||||
|
public class PushoverResponse
|
||||||
|
{
|
||||||
|
public int status { get; set; }
|
||||||
|
public string request { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj
Normal file
11
src/Ombi.Api.Pushover/Ombi.Api.Pushover.csproj
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard1.6</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
26
src/Ombi.Api.Pushover/PushoverApi.cs
Normal file
26
src/Ombi.Api.Pushover/PushoverApi.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Api.Pushover.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api.Pushover
|
||||||
|
{
|
||||||
|
public class PushoverApi : IPushoverApi
|
||||||
|
{
|
||||||
|
public PushoverApi(IApi api)
|
||||||
|
{
|
||||||
|
_api = api;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IApi _api;
|
||||||
|
private const string PushoverEndpoint = "https://api.pushover.net/1";
|
||||||
|
|
||||||
|
public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken)
|
||||||
|
{
|
||||||
|
var request = new Request($"messages.json?token={accessToken}&user={userToken}&message={message}", PushoverEndpoint, HttpMethod.Post);
|
||||||
|
|
||||||
|
var result = await _api.Request<PushoverResponse>(request);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,7 +98,7 @@ namespace Ombi.Api.Radarr
|
||||||
}
|
}
|
||||||
catch (JsonSerializationException jse)
|
catch (JsonSerializationException jse)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.RadarrApiException, jse, "Error When adding movie to Radarr");
|
Logger.LogError(LoggingEvents.RadarrApi, jse, "Error When adding movie to Radarr");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,4 @@
|
||||||
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
|
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
|
|
||||||
<HintPath>..\..\..\..\..\.nuget\packages\microsoft.extensions.logging.abstractions\1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
|
@ -61,7 +61,7 @@ namespace Ombi.Api.TvMaze
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.ApiException, e, "Exception when calling ShowLookupByTheTvDbId with id:{0}",theTvDbId);
|
Logger.LogError(LoggingEvents.Api, e, "Exception when calling ShowLookupByTheTvDbId with id:{0}",theTvDbId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace Ombi.Api
|
||||||
{
|
{
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
// do something with the response
|
// do something with the response
|
||||||
var data = httpResponseMessage.Content;
|
var data = httpResponseMessage.Content;
|
||||||
|
@ -89,7 +89,7 @@ namespace Ombi.Api
|
||||||
{
|
{
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
// do something with the response
|
// do something with the response
|
||||||
var data = httpResponseMessage.Content;
|
var data = httpResponseMessage.Content;
|
||||||
|
@ -123,7 +123,7 @@ namespace Ombi.Api
|
||||||
{
|
{
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
|
|
||||||
<PackageReference Include="Moq" Version="4.7.10" />
|
<PackageReference Include="Moq" Version="4.7.10" />
|
||||||
<PackageReference Include="xunit" Version="2.2.0" />
|
<PackageReference Include="xunit" Version="2.3.0-beta4-build3742" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta4-build3742" />
|
||||||
|
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta4-build3742" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -26,8 +26,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, true);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -37,8 +37,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, true);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -48,8 +48,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, true);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -59,8 +59,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, true);
|
Assert.True(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -69,8 +69,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.Movie };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, false);
|
Assert.False(request.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -79,8 +79,8 @@ namespace Ombi.Core.Tests.Rule.Request
|
||||||
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
var request = new BaseRequest() { RequestType = Store.Entities.RequestType.TvShow };
|
||||||
var result = await Rule.Execute(request);
|
var result = await Rule.Execute(request);
|
||||||
|
|
||||||
Assert.Equal(result.Success, true);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(request.Approved, false);
|
Assert.False(request.Approved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
Approved = true
|
Approved = true
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||||
var search = new SearchMovieViewModel
|
var search = new SearchMovieViewModel
|
||||||
{
|
{
|
||||||
Id = 123,
|
Id = 123,
|
||||||
|
@ -42,7 +42,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
var result = await Rule.Execute(search);
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(search.Approved, true);
|
Assert.False(search.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -54,7 +54,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
Approved = true
|
Approved = true
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
MovieMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||||
var search = new SearchMovieViewModel
|
var search = new SearchMovieViewModel
|
||||||
{
|
{
|
||||||
Id = 999,
|
Id = 999,
|
||||||
|
@ -63,7 +63,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
var result = await Rule.Execute(search);
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(search.Approved, false);
|
Assert.False(search.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -82,7 +82,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TvMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
TvMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||||
var search = new SearchTvShowViewModel
|
var search = new SearchTvShowViewModel
|
||||||
{
|
{
|
||||||
Id = 123,
|
Id = 123,
|
||||||
|
@ -91,7 +91,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
var result = await Rule.Execute(search);
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(search.Approved, true);
|
Assert.True(search.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -111,7 +111,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TvMock.Setup(x => x.GetRequest(123)).ReturnsAsync(list);
|
TvMock.Setup(x => x.GetRequest(123)).Returns(list);
|
||||||
var search = new SearchTvShowViewModel()
|
var search = new SearchTvShowViewModel()
|
||||||
{
|
{
|
||||||
Id = 999,
|
Id = 999,
|
||||||
|
@ -120,7 +120,7 @@ namespace Ombi.Core.Tests.Rule.Search
|
||||||
var result = await Rule.Execute(search);
|
var result = await Rule.Execute(search);
|
||||||
|
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.Equal(search.Approved, false);
|
Assert.False(search.Approved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
public const string PowerUser = nameof(PowerUser);
|
public const string PowerUser = nameof(PowerUser);
|
||||||
public const string RequestTv = nameof(RequestTv);
|
public const string RequestTv = nameof(RequestTv);
|
||||||
public const string RequestMovie = nameof(RequestMovie);
|
public const string RequestMovie = nameof(RequestMovie);
|
||||||
|
public const string Disabled = nameof(Disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -148,10 +148,18 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
|
var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id);
|
||||||
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
viewMovie.Id = showInfo.Id; // TheMovieDbId
|
||||||
|
viewMovie.ImdbId = showInfo.ImdbId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// So when we run the rule to check if it's available in Plex we need the ImdbId
|
||||||
|
// But we only pass down the SearchViewModel that doesn't contain this
|
||||||
|
// So set the ImdbId to viewMovie.Id and then set it back afterwards
|
||||||
|
var oldId = viewMovie.Id;
|
||||||
|
viewMovie.CustomId = viewMovie.ImdbId ?? string.Empty;
|
||||||
|
|
||||||
await RunSearchRules(viewMovie);
|
await RunSearchRules(viewMovie);
|
||||||
|
|
||||||
|
viewMovie.Id = oldId;
|
||||||
return viewMovie;
|
return viewMovie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,12 +141,9 @@ namespace Ombi.Core.Engine
|
||||||
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
|
||||||
{
|
{
|
||||||
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
|
||||||
var allRequests = TvRepository.GetChild();
|
|
||||||
var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id);
|
|
||||||
|
|
||||||
// TODO need to check if we need to approve any child requests since they may have updated
|
await TvRepository.UpdateChild(request);
|
||||||
await TvRepository.UpdateChild(results);
|
return request;
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveTvChild(int requestId)
|
public async Task RemoveTvChild(int requestId)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Ombi.Core.Models.Search
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.Search
|
||||||
{
|
{
|
||||||
public class SearchViewModel
|
public class SearchViewModel
|
||||||
{
|
{
|
||||||
|
@ -7,5 +9,16 @@
|
||||||
public bool Requested { get; set; }
|
public bool Requested { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
public string PlexUrl { get; set; }
|
public string PlexUrl { get; set; }
|
||||||
|
public string Quality { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for the PlexAvailabilityCheck rule
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The custom identifier.
|
||||||
|
/// </value>
|
||||||
|
[NotMapped]
|
||||||
|
public string CustomId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
21
src/Ombi.Core/Models/UI/MattermostNotificationsViewModel.cs
Normal file
21
src/Ombi.Core/Models/UI/MattermostNotificationsViewModel.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The view model for the notification settings page
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="SlackNotificationSettings" />
|
||||||
|
public class MattermostNotificationsViewModel : MattermostNotificationSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification templates.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The notification templates.
|
||||||
|
/// </value>
|
||||||
|
public List<NotificationTemplates> NotificationTemplates { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
src/Ombi.Core/Models/UI/PushoverNotificationViewModel.cs
Normal file
23
src/Ombi.Core/Models/UI/PushoverNotificationViewModel.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Models.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The view model for the notification settings page
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="DiscordNotificationSettings" />
|
||||||
|
public class PushoverNotificationViewModel : PushoverSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notification templates.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The notification templates.
|
||||||
|
/// </value>
|
||||||
|
public List<NotificationTemplates> NotificationTemplates { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,9 +19,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
private IMovieRequestRepository Movie { get; }
|
private IMovieRequestRepository Movie { get; }
|
||||||
private ITvRequestRepository Tv { get; }
|
private ITvRequestRepository Tv { get; }
|
||||||
|
|
||||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
public Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
var movieRequests = await Movie.GetRequest(obj.Id);
|
var movieRequests = Movie.GetRequest(obj.Id);
|
||||||
if (movieRequests != null) // Do we already have a request for this?
|
if (movieRequests != null) // Do we already have a request for this?
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
obj.Approved = movieRequests.Approved;
|
obj.Approved = movieRequests.Approved;
|
||||||
obj.Available = movieRequests.Available;
|
obj.Available = movieRequests.Available;
|
||||||
|
|
||||||
return Success();
|
return Task.FromResult(Success());
|
||||||
}
|
}
|
||||||
|
|
||||||
var tvRequests = await Tv.GetRequest(obj.Id);
|
var tvRequests = Tv.GetRequest(obj.Id);
|
||||||
if (tvRequests != null) // Do we already have a request for this?
|
if (tvRequests != null) // Do we already have a request for this?
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
|
||||||
obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
|
obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
|
||||||
|
|
||||||
return Success();
|
return Task.FromResult(Success());
|
||||||
}
|
}
|
||||||
return Success();
|
return Task.FromResult(Success());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,11 +16,12 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
public async Task<RuleResult> Execute(SearchViewModel obj)
|
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
var item = await PlexContentRepository.Get(obj.Id.ToString());
|
var item = await PlexContentRepository.Get(obj.CustomId);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
obj.Available = true;
|
obj.Available = true;
|
||||||
obj.PlexUrl = item.Url;
|
obj.PlexUrl = item.Url;
|
||||||
|
obj.Quality = item.Quality;
|
||||||
}
|
}
|
||||||
return Success();
|
return Success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Models.Search;
|
using Ombi.Core.Models.Search;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Store.Context;
|
using Ombi.Store.Context;
|
||||||
|
@ -15,16 +16,16 @@ namespace Ombi.Core.Rule.Rules.Search
|
||||||
|
|
||||||
private readonly IOmbiContext _ctx;
|
private readonly IOmbiContext _ctx;
|
||||||
|
|
||||||
public Task<RuleResult> Execute(SearchViewModel obj)
|
public async Task<RuleResult> Execute(SearchViewModel obj)
|
||||||
{
|
{
|
||||||
// Check if it's in Radarr
|
// Check if it's in Radarr
|
||||||
var result = _ctx.RadarrCache.FirstOrDefault(x => x.TheMovieDbId == obj.Id);
|
var result = await _ctx.RadarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == obj.Id);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
obj.Approved = true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something?
|
obj.Approved = true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something?
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(Success());
|
return Success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -68,7 +68,7 @@ namespace Ombi.Core
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(result.Error?.message))
|
if (!string.IsNullOrEmpty(result.Error?.message))
|
||||||
{
|
{
|
||||||
Log.LogError(LoggingEvents.RadarrCacherException,result.Error.message);
|
Log.LogError(LoggingEvents.RadarrCacher,result.Error.message);
|
||||||
return new MovieSenderResult { Success = false, Message = result.Error.message, MovieSent = false };
|
return new MovieSenderResult { Success = false, Message = result.Error.message, MovieSent = false };
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(result.title))
|
if (!string.IsNullOrEmpty(result.title))
|
||||||
|
|
|
@ -185,7 +185,7 @@ namespace Ombi.Core.Senders
|
||||||
{
|
{
|
||||||
var sonarrSeason = sonarrEpisodes.Where(x => x.seasonNumber == season.SeasonNumber);
|
var sonarrSeason = sonarrEpisodes.Where(x => x.seasonNumber == season.SeasonNumber);
|
||||||
var sonarrEpCount = sonarrSeason.Count();
|
var sonarrEpCount = sonarrSeason.Count();
|
||||||
var ourRequestCount = season.Episodes.Count();
|
var ourRequestCount = season.Episodes.Count;
|
||||||
|
|
||||||
if (sonarrEpCount == ourRequestCount)
|
if (sonarrEpCount == ourRequestCount)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
using Ombi.Api.Discord;
|
using Ombi.Api.Discord;
|
||||||
|
@ -28,11 +29,14 @@ using Ombi.Notifications.Agents;
|
||||||
using Ombi.Schedule.Jobs.Radarr;
|
using Ombi.Schedule.Jobs.Radarr;
|
||||||
using Ombi.Api;
|
using Ombi.Api;
|
||||||
using Ombi.Api.FanartTv;
|
using Ombi.Api.FanartTv;
|
||||||
|
using Ombi.Api.Mattermost;
|
||||||
using Ombi.Api.Pushbullet;
|
using Ombi.Api.Pushbullet;
|
||||||
|
using Ombi.Api.Pushover;
|
||||||
using Ombi.Api.Service;
|
using Ombi.Api.Service;
|
||||||
using Ombi.Api.Slack;
|
using Ombi.Api.Slack;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Core.Senders;
|
using Ombi.Core.Senders;
|
||||||
|
using Ombi.Schedule.Jobs.Plex;
|
||||||
using Ombi.Schedule.Ombi;
|
using Ombi.Schedule.Ombi;
|
||||||
using Ombi.Store.Repository.Requests;
|
using Ombi.Store.Repository.Requests;
|
||||||
using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher;
|
using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher;
|
||||||
|
@ -78,13 +82,15 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IPushbulletApi, PushbulletApi>();
|
services.AddTransient<IPushbulletApi, PushbulletApi>();
|
||||||
services.AddTransient<IOmbiService, OmbiService>();
|
services.AddTransient<IOmbiService, OmbiService>();
|
||||||
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
services.AddTransient<IFanartTvApi, FanartTvApi>();
|
||||||
|
services.AddTransient<IPushoverApi, PushoverApi>();
|
||||||
|
services.AddTransient<IMattermostApi, MattermostApi>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterStore(this IServiceCollection services)
|
public static void RegisterStore(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
services.AddEntityFrameworkSqlite().AddDbContext<OmbiContext>();
|
||||||
|
|
||||||
services.AddScoped<IOmbiContext, OmbiContext>();
|
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
|
||||||
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
services.AddTransient<ISettingsRepository, SettingsJsonRepository>();
|
||||||
services.AddTransient<ISettingsResolver, SettingsResolver>();
|
services.AddTransient<ISettingsResolver, SettingsResolver>();
|
||||||
services.AddTransient<IPlexContentRepository, PlexContentRepository>();
|
services.AddTransient<IPlexContentRepository, PlexContentRepository>();
|
||||||
|
@ -109,11 +115,16 @@ namespace Ombi.DependencyInjection
|
||||||
services.AddTransient<IEmailNotification, EmailNotification>();
|
services.AddTransient<IEmailNotification, EmailNotification>();
|
||||||
services.AddTransient<IPushbulletNotification, PushbulletNotification>();
|
services.AddTransient<IPushbulletNotification, PushbulletNotification>();
|
||||||
services.AddTransient<ISlackNotification, SlackNotification>();
|
services.AddTransient<ISlackNotification, SlackNotification>();
|
||||||
|
services.AddTransient<ISlackNotification, SlackNotification>();
|
||||||
|
services.AddTransient<IMattermostNotification, MattermostNotification>();
|
||||||
|
services.AddTransient<IPushoverNotification, PushoverNotification>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterJobs(this IServiceCollection services)
|
public static void RegisterJobs(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient<IPlexContentCacher, PlexContentCacher>();
|
services.AddTransient<IPlexContentCacher, PlexContentCacher>();
|
||||||
|
services.AddTransient<IPlexEpisodeCacher, PlexEpisodeCacher>();
|
||||||
|
services.AddTransient<IPlexAvailabilityChecker, PlexAvailabilityChecker>();
|
||||||
services.AddTransient<IJobSetup, JobSetup>();
|
services.AddTransient<IJobSetup, JobSetup>();
|
||||||
services.AddTransient<IRadarrCacher, RadarrCacher>();
|
services.AddTransient<IRadarrCacher, RadarrCacher>();
|
||||||
services.AddTransient<IOmbiAutomaticUpdater, OmbiAutomaticUpdater>();
|
services.AddTransient<IOmbiAutomaticUpdater, OmbiAutomaticUpdater>();
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
|
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Pushover\Ombi.Api.Pushover.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Service\Ombi.Api.Service.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
|
||||||
|
|
|
@ -6,11 +6,12 @@ namespace Ombi.Helpers
|
||||||
{
|
{
|
||||||
public static EventId Authentication => new EventId(500);
|
public static EventId Authentication => new EventId(500);
|
||||||
|
|
||||||
public static EventId ApiException => new EventId(1000);
|
public static EventId Api => new EventId(1000);
|
||||||
public static EventId RadarrApiException => new EventId(1001);
|
public static EventId RadarrApi => new EventId(1001);
|
||||||
|
|
||||||
public static EventId CacherException => new EventId(2000);
|
public static EventId Cacher => new EventId(2000);
|
||||||
public static EventId RadarrCacherException => new EventId(2001);
|
public static EventId RadarrCacher => new EventId(2001);
|
||||||
|
public static EventId PlexEpisodeCacher => new EventId(2001);
|
||||||
|
|
||||||
public static EventId MovieSender => new EventId(3000);
|
public static EventId MovieSender => new EventId(3000);
|
||||||
|
|
||||||
|
@ -18,6 +19,8 @@ namespace Ombi.Helpers
|
||||||
public static EventId DiscordNotification => new EventId(4001);
|
public static EventId DiscordNotification => new EventId(4001);
|
||||||
public static EventId PushbulletNotification => new EventId(4002);
|
public static EventId PushbulletNotification => new EventId(4002);
|
||||||
public static EventId SlackNotification => new EventId(4003);
|
public static EventId SlackNotification => new EventId(4003);
|
||||||
|
public static EventId MattermostNotification => new EventId(4004);
|
||||||
|
public static EventId PushoverNotification => new EventId(4005);
|
||||||
|
|
||||||
public static EventId TvSender => new EventId(5000);
|
public static EventId TvSender => new EventId(5000);
|
||||||
public static EventId SonarrSender => new EventId(5001);
|
public static EventId SonarrSender => new EventId(5001);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
Pushbullet,
|
Pushbullet,
|
||||||
Pushover,
|
Pushover,
|
||||||
Telegram,
|
Telegram,
|
||||||
Slack
|
Slack,
|
||||||
|
Mattermost,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -91,7 +91,7 @@ namespace Ombi.Helpers
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPlexMediaUrl(string machineId, string mediaId)
|
public static string GetPlexMediaUrl(string machineId, int mediaId)
|
||||||
{
|
{
|
||||||
var url =
|
var url =
|
||||||
$"https://app.plex.tv/web/app#!/server/{machineId}/details?key=library%2Fmetadata%2F{mediaId}";
|
$"https://app.plex.tv/web/app#!/server/{machineId}/details?key=library%2Fmetadata%2F{mediaId}";
|
||||||
|
|
|
@ -12,6 +12,8 @@ namespace Ombi.Mapping.Profiles
|
||||||
CreateMap<DiscordNotificationsViewModel, DiscordNotificationSettings>().ReverseMap();
|
CreateMap<DiscordNotificationsViewModel, DiscordNotificationSettings>().ReverseMap();
|
||||||
CreateMap<PushbulletNotificationViewModel, PushbulletSettings>().ReverseMap();
|
CreateMap<PushbulletNotificationViewModel, PushbulletSettings>().ReverseMap();
|
||||||
CreateMap<SlackNotificationsViewModel, SlackNotificationSettings>().ReverseMap();
|
CreateMap<SlackNotificationsViewModel, SlackNotificationSettings>().ReverseMap();
|
||||||
|
CreateMap<PushoverNotificationViewModel, PushoverSettings>().ReverseMap();
|
||||||
|
CreateMap<MattermostNotificationsViewModel, MattermostNotificationSettings>().ReverseMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/Ombi.Notifications/Agents/IMattermostNotification.cs
Normal file
6
src/Ombi.Notifications/Agents/IMattermostNotification.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public interface IMattermostNotification : INotification
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
6
src/Ombi.Notifications/Agents/IPushoverNotification.cs
Normal file
6
src/Ombi.Notifications/Agents/IPushoverNotification.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public interface IPushoverNotification : INotification
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
164
src/Ombi.Notifications/Agents/MattermostNotification.cs
Normal file
164
src/Ombi.Notifications/Agents/MattermostNotification.cs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Discord;
|
||||||
|
using Ombi.Api.Discord.Models;
|
||||||
|
using Ombi.Api.Mattermost;
|
||||||
|
using Ombi.Api.Mattermost.Models;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Notifications.Interfaces;
|
||||||
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public class MattermostNotification : BaseNotification<MattermostNotificationSettings>, IMattermostNotification
|
||||||
|
{
|
||||||
|
public MattermostNotification(IMattermostApi api, ISettingsService<MattermostNotificationSettings> sn, ILogger<MattermostNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(sn, r, m, t)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Logger = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string NotificationName => "MattermostNotification";
|
||||||
|
|
||||||
|
private IMattermostApi Api { get; }
|
||||||
|
private ILogger<MattermostNotification> Logger { get; }
|
||||||
|
|
||||||
|
protected override bool ValidateConfiguration(MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(settings.WebhookUrl))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task NewRequest(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Mattermost, NotificationType.NewRequest, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Issue(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Mattermost, NotificationType.Issue, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AddedToRequestQueue(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var user = string.Empty;
|
||||||
|
var title = string.Empty;
|
||||||
|
var image = string.Empty;
|
||||||
|
if (model.RequestType == RequestType.Movie)
|
||||||
|
{
|
||||||
|
user = MovieRequest.RequestedUser.UserAlias;
|
||||||
|
title = MovieRequest.Title;
|
||||||
|
image = MovieRequest.PosterPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = TvRequest.RequestedUser.UserAlias;
|
||||||
|
title = TvRequest.ParentRequest.Title;
|
||||||
|
image = TvRequest.ParentRequest.PosterPath;
|
||||||
|
}
|
||||||
|
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = message
|
||||||
|
};
|
||||||
|
notification.Other.Add("image", image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestDeclined(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Mattermost, NotificationType.RequestDeclined, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestApproved(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Mattermost, NotificationType.RequestApproved, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AvailableRequest(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Mattermost, NotificationType.RequestAvailable, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Send(NotificationMessage model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var body = new MattermostBody
|
||||||
|
{
|
||||||
|
username = string.IsNullOrEmpty(settings.Username) ? "Ombi" : settings.Username,
|
||||||
|
channel = settings.Channel,
|
||||||
|
text = model.Message,
|
||||||
|
icon_url = settings.IconUrl
|
||||||
|
};
|
||||||
|
await Api.PushAsync(settings.WebhookUrl, body);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.MattermostNotification, e, "Failed to send Mattermost Notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Test(NotificationOptions model, MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
145
src/Ombi.Notifications/Agents/PushoverNotification.cs
Normal file
145
src/Ombi.Notifications/Agents/PushoverNotification.cs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Pushbullet;
|
||||||
|
using Ombi.Api.Pushover;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Notifications.Interfaces;
|
||||||
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Notifications.Agents
|
||||||
|
{
|
||||||
|
public class PushoverNotification : BaseNotification<PushoverSettings>, IPushoverNotification
|
||||||
|
{
|
||||||
|
public PushoverNotification(IPushoverApi api, ISettingsService<PushoverSettings> sn, ILogger<PushbulletNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(sn, r, m, t)
|
||||||
|
{
|
||||||
|
Api = api;
|
||||||
|
Logger = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string NotificationName => "PushoverNotification";
|
||||||
|
|
||||||
|
private IPushoverApi Api { get; }
|
||||||
|
private ILogger<PushbulletNotification> Logger { get; }
|
||||||
|
|
||||||
|
protected override bool ValidateConfiguration(PushoverSettings settings)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(settings.AccessToken))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task NewRequest(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Pushover, NotificationType.NewRequest, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Issue(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Pushover, NotificationType.Issue, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AddedToRequestQueue(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
string user;
|
||||||
|
string title;
|
||||||
|
if (model.RequestType == RequestType.Movie)
|
||||||
|
{
|
||||||
|
user = MovieRequest.RequestedUser.UserAlias;
|
||||||
|
title = MovieRequest.Title;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = TvRequest.RequestedUser.UserAlias;
|
||||||
|
title = TvRequest.ParentRequest.Title;
|
||||||
|
}
|
||||||
|
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = message
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestDeclined(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Pushover, NotificationType.RequestDeclined, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task RequestApproved(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Pushover, NotificationType.RequestApproved, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task AvailableRequest(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var parsed = await LoadTemplate(NotificationAgent.Pushover, NotificationType.RequestAvailable, model);
|
||||||
|
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = parsed.Message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Send(NotificationMessage model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Api.PushAsync(settings.AccessToken, model.Message, settings.UserToken);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.PushoverNotification, e, "Failed to send Pushover Notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task Test(NotificationOptions model, PushoverSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!";
|
||||||
|
var notification = new NotificationMessage
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
};
|
||||||
|
await Send(notification, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,9 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Discord\Ombi.Api.Discord.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||||
|
<ProjectReference Include="..\Ombi.Api.Pushover\Ombi.Api.Pushover.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
|
<ProjectReference Include="..\Ombi.Api.Slack\Ombi.Api.Slack.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj" />
|
<ProjectReference Include="..\Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj" />
|
||||||
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />
|
<ProjectReference Include="..\Ombi.Settings\Ombi.Settings.csproj" />
|
||||||
|
|
21
src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj
Normal file
21
src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Moq" Version="4.7.99" />
|
||||||
|
<PackageReference Include="Nunit" Version="3.7.1" />
|
||||||
|
<PackageReference Include="NUnit.ConsoleRunner" Version="3.7.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
|
||||||
|
<packagereference Include="Microsoft.NET.Test.Sdk" Version="15.0.0"></packagereference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
110
src/Ombi.Schedule.Tests/PlexAvailabilityCheckerTests.cs
Normal file
110
src/Ombi.Schedule.Tests/PlexAvailabilityCheckerTests.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Castle.Components.DictionaryAdapter;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Ombi.Schedule.Jobs.Plex;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class PlexAvailabilityCheckerTests
|
||||||
|
{
|
||||||
|
public PlexAvailabilityCheckerTests()
|
||||||
|
{
|
||||||
|
_repo = new Mock<IPlexContentRepository>();
|
||||||
|
_tv = new Mock<ITvRequestRepository>();
|
||||||
|
_movie = new Mock<IMovieRequestRepository>();
|
||||||
|
Checker = new PlexAvailabilityChecker(_repo.Object, _tv.Object, _movie.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Mock<IPlexContentRepository> _repo;
|
||||||
|
private readonly Mock<ITvRequestRepository> _tv;
|
||||||
|
private readonly Mock<IMovieRequestRepository> _movie;
|
||||||
|
private PlexAvailabilityChecker Checker { get; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ProcessMovies_ShouldMarkAvailable_WhenInPlex()
|
||||||
|
{
|
||||||
|
var request = new MovieRequests
|
||||||
|
{
|
||||||
|
ImdbId = "test"
|
||||||
|
};
|
||||||
|
_movie.Setup(x => x.Get()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||||
|
_repo.Setup(x => x.Get("test")).ReturnsAsync(new PlexContent());
|
||||||
|
|
||||||
|
await Checker.Start();
|
||||||
|
|
||||||
|
_movie.Verify(x => x.Save(), Times.Once);
|
||||||
|
|
||||||
|
Assert.True(request.Available);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ProcessMovies_ShouldNotBeAvailable_WhenInNotPlex()
|
||||||
|
{
|
||||||
|
var request = new MovieRequests
|
||||||
|
{
|
||||||
|
ImdbId = "test"
|
||||||
|
};
|
||||||
|
_movie.Setup(x => x.Get()).Returns(new List<MovieRequests> { request }.AsQueryable());
|
||||||
|
|
||||||
|
await Checker.Start();
|
||||||
|
|
||||||
|
_movie.Verify(x => x.Save(), Times.Once);
|
||||||
|
Assert.False(request.Available);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Ignore("EF IAsyncQueryProvider")]
|
||||||
|
public async Task ProcessTv_ShouldMark_Episode_Available_WhenInPlex()
|
||||||
|
{
|
||||||
|
var request = new ChildRequests
|
||||||
|
{
|
||||||
|
ParentRequest = new TvRequests {TvDbId = 1},
|
||||||
|
SeasonRequests = new EditableList<SeasonRequests>
|
||||||
|
{
|
||||||
|
new SeasonRequests
|
||||||
|
{
|
||||||
|
Episodes = new EditableList<EpisodeRequests>
|
||||||
|
{
|
||||||
|
new EpisodeRequests
|
||||||
|
{
|
||||||
|
EpisodeNumber = 1,
|
||||||
|
Season = new SeasonRequests
|
||||||
|
{
|
||||||
|
SeasonNumber = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_tv.Setup(x => x.GetChild()).Returns(new List<ChildRequests> { request }.AsQueryable());
|
||||||
|
_repo.Setup(x => x.GetAllEpisodes()).Returns(new List<PlexEpisode>
|
||||||
|
{
|
||||||
|
new PlexEpisode
|
||||||
|
{
|
||||||
|
Series = new PlexContent
|
||||||
|
{
|
||||||
|
ProviderId = 1.ToString(),
|
||||||
|
},
|
||||||
|
EpisodeNumber = 1,
|
||||||
|
SeasonNumber = 2
|
||||||
|
}
|
||||||
|
}.AsQueryable);
|
||||||
|
|
||||||
|
await Checker.Start();
|
||||||
|
|
||||||
|
_tv.Verify(x => x.Save(), Times.Once);
|
||||||
|
|
||||||
|
Assert.True(request.SeasonRequests[0].Episodes[0].Available);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/Ombi.Schedule.Tests/Properties/launchSettings.json
Normal file
27
src/Ombi.Schedule.Tests/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:62604/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ombi.Schedule.Tests": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:62605/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/Ombi.Schedule/IPlexAvailabilityChecker.cs
Normal file
9
src/Ombi.Schedule/IPlexAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
{
|
||||||
|
public interface IPlexAvailabilityChecker
|
||||||
|
{
|
||||||
|
Task Start();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
{
|
||||||
|
public interface IPlexEpisodeCacher
|
||||||
|
{
|
||||||
|
Task Start();
|
||||||
|
}
|
||||||
|
}
|
84
src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs
Normal file
84
src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
{
|
||||||
|
public class PlexAvailabilityChecker : IPlexAvailabilityChecker
|
||||||
|
{
|
||||||
|
public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies)
|
||||||
|
{
|
||||||
|
_tvRepo = tvRequest;
|
||||||
|
_repo = repo;
|
||||||
|
_movieRepo = movies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ITvRequestRepository _tvRepo;
|
||||||
|
private readonly IMovieRequestRepository _movieRepo;
|
||||||
|
private readonly IPlexContentRepository _repo;
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
await ProcessMovies();
|
||||||
|
await ProcessTv();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessTv()
|
||||||
|
{
|
||||||
|
var tv = _tvRepo.GetChild().Where(x => !x.Available);
|
||||||
|
var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);
|
||||||
|
|
||||||
|
foreach (var child in tv)
|
||||||
|
{
|
||||||
|
var tvDbId = child.ParentRequest.TvDbId;
|
||||||
|
var seriesEpisodes = plexEpisodes.Where(x => x.Series.ProviderId == tvDbId.ToString());
|
||||||
|
foreach (var season in child.SeasonRequests)
|
||||||
|
{
|
||||||
|
foreach (var episode in season.Episodes)
|
||||||
|
{
|
||||||
|
var foundEp = await seriesEpisodes.FirstOrDefaultAsync(
|
||||||
|
x => x.EpisodeNumber == episode.EpisodeNumber &&
|
||||||
|
x.SeasonNumber == episode.Season.SeasonNumber);
|
||||||
|
|
||||||
|
if (foundEp != null)
|
||||||
|
{
|
||||||
|
episode.Available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if all of the episodes in all seasons are available for this request
|
||||||
|
var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
|
||||||
|
if (allAvailable)
|
||||||
|
{
|
||||||
|
// We have fulfulled this request!
|
||||||
|
child.Available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _tvRepo.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessMovies()
|
||||||
|
{
|
||||||
|
// Get all non available
|
||||||
|
var movies = _movieRepo.Get().Where(x => !x.Available);
|
||||||
|
|
||||||
|
foreach (var movie in movies)
|
||||||
|
{
|
||||||
|
var plexContent = await _repo.Get(movie.ImdbId);
|
||||||
|
if (plexContent == null)
|
||||||
|
{
|
||||||
|
// We don't yet have this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
movie.Available = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _movieRepo.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Hangfire;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ombi.Api.Plex;
|
using Ombi.Api.Plex;
|
||||||
using Ombi.Api.Plex.Models;
|
using Ombi.Api.Plex.Models;
|
||||||
|
@ -42,22 +43,25 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
public class PlexContentCacher : IPlexContentCacher
|
public class PlexContentCacher : IPlexContentCacher
|
||||||
{
|
{
|
||||||
public PlexContentCacher(ISettingsService<PlexSettings> plex, IPlexApi plexApi, ILogger<PlexContentCacher> logger, IPlexContentRepository repo)
|
public PlexContentCacher(ISettingsService<PlexSettings> plex, IPlexApi plexApi, ILogger<PlexContentCacher> logger, IPlexContentRepository repo,
|
||||||
|
IPlexEpisodeCacher epsiodeCacher)
|
||||||
{
|
{
|
||||||
Plex = plex;
|
Plex = plex;
|
||||||
PlexApi = plexApi;
|
PlexApi = plexApi;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
Repo = repo;
|
Repo = repo;
|
||||||
|
EpisodeCacher = epsiodeCacher;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<PlexSettings> Plex { get; }
|
private ISettingsService<PlexSettings> Plex { get; }
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
private ILogger<PlexContentCacher> Logger { get; }
|
private ILogger<PlexContentCacher> Logger { get; }
|
||||||
private IPlexContentRepository Repo { get; }
|
private IPlexContentRepository Repo { get; }
|
||||||
|
private IPlexEpisodeCacher EpisodeCacher { get; }
|
||||||
|
|
||||||
public async Task CacheContent()
|
public async Task CacheContent()
|
||||||
{
|
{
|
||||||
var plexSettings = Plex.GetSettings();
|
var plexSettings = await Plex.GetSettingsAsync();
|
||||||
if (!plexSettings.Enable)
|
if (!plexSettings.Enable)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -71,10 +75,12 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await StartTheCache(plexSettings);
|
await StartTheCache(plexSettings);
|
||||||
|
|
||||||
|
BackgroundJob.Enqueue(() => EpisodeCacher.Start());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogWarning(LoggingEvents.CacherException, e, "Exception thrown when attempting to cache the Plex Content");
|
Logger.LogWarning(LoggingEvents.Cacher, e, "Exception thrown when attempting to cache the Plex Content");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,10 +107,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
seasonsContent.Add(new PlexSeasonsContent
|
seasonsContent.Add(new PlexSeasonsContent
|
||||||
{
|
{
|
||||||
ParentKey = int.Parse(season.parentRatingKey),
|
ParentKey = season.parentRatingKey,
|
||||||
SeasonKey = int.Parse(season.ratingKey),
|
SeasonKey = season.ratingKey,
|
||||||
SeasonNumber = season.index,
|
SeasonNumber = season.index,
|
||||||
PlexContentId = int.Parse(show.ratingKey)
|
PlexContentId = show.ratingKey
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +187,8 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
Type = PlexMediaTypeEntity.Movie,
|
Type = PlexMediaTypeEntity.Movie,
|
||||||
Title = movie.title,
|
Title = movie.title,
|
||||||
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
|
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
|
||||||
Seasons = new List<PlexSeasonsContent>()
|
Seasons = new List<PlexSeasonsContent>(),
|
||||||
|
Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty
|
||||||
};
|
};
|
||||||
|
|
||||||
contentToAdd.Add(item);
|
contentToAdd.Add(item);
|
||||||
|
@ -191,8 +198,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
if (contentToAdd.Any())
|
if (contentToAdd.Any())
|
||||||
{
|
{
|
||||||
|
await Repo.AddRange(contentToAdd);
|
||||||
contentToAdd.ForEach(async x => await Repo.Add(x));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -215,15 +221,19 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
foreach (var dir in sections.MediaContainer.Directory ?? new List<Directory>())
|
foreach (var dir in sections.MediaContainer.Directory ?? new List<Directory>())
|
||||||
{
|
{
|
||||||
if (plexSettings.PlexSelectedLibraries.Any())
|
if (plexSettings.PlexSelectedLibraries.Any())
|
||||||
|
{
|
||||||
|
if (plexSettings.PlexSelectedLibraries.Any(x => x.Enabled))
|
||||||
{
|
{
|
||||||
// Only get the enabled libs
|
// Only get the enabled libs
|
||||||
var keys = plexSettings.PlexSelectedLibraries.Where(x => x.Enabled).Select(x => x.Key.ToString()).ToList();
|
var keys = plexSettings.PlexSelectedLibraries.Where(x => x.Enabled)
|
||||||
|
.Select(x => x.Key.ToString()).ToList();
|
||||||
if (!keys.Contains(dir.key))
|
if (!keys.Contains(dir.key))
|
||||||
{
|
{
|
||||||
// We are not monitoring this lib
|
// We are not monitoring this lib
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.key).Result;
|
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.key).Result;
|
||||||
if (lib != null)
|
if (lib != null)
|
||||||
{
|
{
|
||||||
|
|
162
src/Ombi.Schedule/Jobs/Plex/PlexEpisodeCacher.cs
Normal file
162
src/Ombi.Schedule/Jobs/Plex/PlexEpisodeCacher.cs
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Hangfire;
|
||||||
|
using Hangfire.Common;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Api.Plex;
|
||||||
|
using Ombi.Api.Plex.Models;
|
||||||
|
using Ombi.Api.Plex.Models.Server;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Repository;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
{
|
||||||
|
public class PlexEpisodeCacher : IPlexEpisodeCacher
|
||||||
|
{
|
||||||
|
public PlexEpisodeCacher(ISettingsService<PlexSettings> s, ILogger<PlexEpisodeCacher> log, IPlexApi plexApi,
|
||||||
|
IPlexContentRepository repo, IPlexAvailabilityChecker a)
|
||||||
|
{
|
||||||
|
_settings = s;
|
||||||
|
_log = log;
|
||||||
|
_api = plexApi;
|
||||||
|
_repo = repo;
|
||||||
|
_availabilityChecker = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ISettingsService<PlexSettings> _settings;
|
||||||
|
private readonly ILogger<PlexEpisodeCacher> _log;
|
||||||
|
private readonly IPlexApi _api;
|
||||||
|
private readonly IPlexContentRepository _repo;
|
||||||
|
private readonly IPlexAvailabilityChecker _availabilityChecker;
|
||||||
|
|
||||||
|
public async Task Start()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var s = await _settings.GetSettingsAsync();
|
||||||
|
if (!s.Enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var server in s.Servers)
|
||||||
|
{
|
||||||
|
|
||||||
|
await Cache(server);
|
||||||
|
BackgroundJob.Enqueue(() => _availabilityChecker.Start());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Cache(PlexServers settings)
|
||||||
|
{
|
||||||
|
if (!Validate(settings))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the librarys and then get the tv section
|
||||||
|
var sections = await _api.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
|
||||||
|
|
||||||
|
// Filter the libSections
|
||||||
|
var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(Jobs.PlexContentCacher.PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
|
||||||
|
foreach (var section in tvSections)
|
||||||
|
{
|
||||||
|
if (settings.PlexSelectedLibraries.Any())
|
||||||
|
{
|
||||||
|
// Are any enabled?
|
||||||
|
if (settings.PlexSelectedLibraries.Any(x => x.Enabled))
|
||||||
|
{
|
||||||
|
// Make sure we have enabled this
|
||||||
|
var keys = settings.PlexSelectedLibraries.Where(x => x.Enabled).Select(x => x.Key.ToString())
|
||||||
|
.ToList();
|
||||||
|
if (!keys.Contains(section.key))
|
||||||
|
{
|
||||||
|
// We are not monitoring this lib
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the episodes
|
||||||
|
await GetEpisodes(settings, section);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetEpisodes(PlexServers settings, Directory section)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Get the first 50
|
||||||
|
var currentPosition = 0;
|
||||||
|
var ResultCount = 50;
|
||||||
|
var episodes = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, ResultCount);
|
||||||
|
var currentData = _repo.GetAllEpisodes();
|
||||||
|
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.totalSize}");
|
||||||
|
|
||||||
|
await ProcessEpsiodes(episodes, currentData);
|
||||||
|
currentPosition += ResultCount;
|
||||||
|
|
||||||
|
while (currentPosition < episodes.MediaContainer.totalSize)
|
||||||
|
{
|
||||||
|
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
|
||||||
|
ResultCount);
|
||||||
|
await ProcessEpsiodes(ep, currentData);
|
||||||
|
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {ResultCount} more episodes. Total Remaining {currentPosition - episodes.MediaContainer.totalSize}");
|
||||||
|
currentPosition += ResultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessEpsiodes(PlexContainer episodes, IQueryable<PlexEpisode> currentEpisodes)
|
||||||
|
{
|
||||||
|
var ep = new HashSet<PlexEpisode>();
|
||||||
|
foreach (var episode in episodes.MediaContainer.Metadata)
|
||||||
|
{
|
||||||
|
// I don't think we need to get the metadata, we only need to get the metadata if we need the provider id (TheTvDbid). Why do we need it for episodes?
|
||||||
|
// We have the parent and grandparent rating keys to link up to the season and series
|
||||||
|
//var metadata = _api.GetEpisodeMetaData(server.PlexAuthToken, server.FullUri, episode.ratingKey);
|
||||||
|
|
||||||
|
var epExists = currentEpisodes.Any(x => episode.ratingKey == x.Key &&
|
||||||
|
episode.grandparentRatingKey == x.GrandparentKey);
|
||||||
|
if (epExists)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep.Add(new PlexEpisode
|
||||||
|
{
|
||||||
|
EpisodeNumber = episode.index,
|
||||||
|
SeasonNumber = episode.parentIndex,
|
||||||
|
GrandparentKey = episode.grandparentRatingKey,
|
||||||
|
ParentKey = episode.parentRatingKey,
|
||||||
|
Key = episode.ratingKey,
|
||||||
|
Title = episode.title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _repo.AddRange(ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Validate(PlexServers settings)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
||||||
|
{
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -28,6 +29,8 @@ namespace Ombi.Schedule.Jobs.Radarr
|
||||||
private readonly IOmbiContext _ctx;
|
private readonly IOmbiContext _ctx;
|
||||||
|
|
||||||
public async Task CacheContent()
|
public async Task CacheContent()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var settings = RadarrSettings.GetSettings();
|
var settings = RadarrSettings.GetSettings();
|
||||||
if (settings.Enabled)
|
if (settings.Enabled)
|
||||||
|
@ -45,7 +48,7 @@ namespace Ombi.Schedule.Jobs.Radarr
|
||||||
{
|
{
|
||||||
if (m.tmdbId > 0)
|
if (m.tmdbId > 0)
|
||||||
{
|
{
|
||||||
movieIds.Add(new RadarrCache{TheMovieDbId = m.tmdbId});
|
movieIds.Add(new RadarrCache { TheMovieDbId = m.tmdbId });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -59,10 +62,15 @@ namespace Ombi.Schedule.Jobs.Radarr
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.CacherException, ex, "Failed caching queued items from Radarr");
|
Logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Radarr");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogInformation(LoggingEvents.RadarrCacher, "Radarr is not setup, cannot cache episodes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<RadarrCache>> GetCachedContent()
|
public async Task<IEnumerable<RadarrCache>> GetCachedContent()
|
||||||
{
|
{
|
||||||
|
|
22
src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs
Normal file
22
src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Settings.Settings.Models
|
||||||
|
{
|
||||||
|
public class AuthenticationSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This determins if Plex and/or Emby users can log into Ombi
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if [allow external users to authenticate]; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool AllowExternalUsersToAuthenticate { get; set; }
|
||||||
|
|
||||||
|
// Password Options
|
||||||
|
public bool RequireDigit { get; set; }
|
||||||
|
public int RequiredLength { get; set; }
|
||||||
|
public bool RequireLowercase { get; set; }
|
||||||
|
public bool RequireNonAlphanumeric { get; set; }
|
||||||
|
public bool RequireUppercase { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ namespace Ombi.Core.Settings.Models.External
|
||||||
public string PlexAuthToken { get; set; }
|
public string PlexAuthToken { get; set; }
|
||||||
public string MachineIdentifier { get; set; }
|
public string MachineIdentifier { get; set; }
|
||||||
|
|
||||||
public List<PlexSelectedLibraries> PlexSelectedLibraries { get; set; }
|
public List<PlexSelectedLibraries> PlexSelectedLibraries { get; set; } = new List<PlexSelectedLibraries>();
|
||||||
}
|
}
|
||||||
public class PlexSelectedLibraries
|
public class PlexSelectedLibraries
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
|
{
|
||||||
|
public class MattermostNotificationSettings : Settings
|
||||||
|
{
|
||||||
|
public string WebhookUrl { get; set; }
|
||||||
|
public string Channel { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string IconUrl { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Ombi.Settings.Settings.Models.Notifications
|
||||||
|
{
|
||||||
|
public class PushoverSettings : Settings
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
public string UserToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,5 @@
|
||||||
public bool Wizard { get; set; }
|
public bool Wizard { get; set; }
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
|
|
||||||
public bool AllowExternalUsersToAuthenticate { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,13 +40,17 @@ namespace Ombi.Settings.Settings
|
||||||
|
|
||||||
public async Task<T> GetSettingsAsync()
|
public async Task<T> GetSettingsAsync()
|
||||||
{
|
{
|
||||||
var result = await Repo.GetAsync(EntityName).ConfigureAwait(false);
|
var result = await Repo.GetAsync(EntityName);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
return new T();
|
return new T();
|
||||||
}
|
}
|
||||||
result.Content = DecryptSettings(result);
|
result.Content = DecryptSettings(result);
|
||||||
return string.IsNullOrEmpty(result.Content) ? null : JsonConvert.DeserializeObject<T>(result.Content, SerializerSettings.Settings);
|
var obj = string.IsNullOrEmpty(result.Content) ? null : JsonConvert.DeserializeObject<T>(result.Content, SerializerSettings.Settings);
|
||||||
|
|
||||||
|
var model = obj;
|
||||||
|
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SaveSettings(T model)
|
public bool SaveSettings(T model)
|
||||||
|
@ -67,10 +71,10 @@ namespace Ombi.Settings.Settings
|
||||||
|
|
||||||
var modified = model;
|
var modified = model;
|
||||||
modified.Id = entity.Id;
|
modified.Id = entity.Id;
|
||||||
|
entity.Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings);
|
||||||
|
|
||||||
var globalSettings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings), Id = entity.Id };
|
entity.Content = EncryptSettings(entity);
|
||||||
globalSettings.Content = EncryptSettings(globalSettings);
|
Repo.Update(entity);
|
||||||
Repo.Update(globalSettings);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +89,7 @@ namespace Ombi.Settings.Settings
|
||||||
|
|
||||||
var settings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(newEntity, SerializerSettings.Settings) };
|
var settings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(newEntity, SerializerSettings.Settings) };
|
||||||
settings.Content = EncryptSettings(settings);
|
settings.Content = EncryptSettings(settings);
|
||||||
var insertResult = await Repo.InsertAsync(settings).ConfigureAwait(false);
|
var insertResult = await Repo.InsertAsync(settings);
|
||||||
|
|
||||||
return insertResult != null;
|
return insertResult != null;
|
||||||
}
|
}
|
||||||
|
@ -93,9 +97,10 @@ namespace Ombi.Settings.Settings
|
||||||
var modified = model;
|
var modified = model;
|
||||||
modified.Id = entity.Id;
|
modified.Id = entity.Id;
|
||||||
|
|
||||||
var globalSettings = new GlobalSettings { SettingsName = EntityName, Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings), Id = entity.Id };
|
entity.Content = JsonConvert.SerializeObject(modified, SerializerSettings.Settings);
|
||||||
entity.Content = EncryptSettings(globalSettings);
|
|
||||||
await Repo.UpdateAsync(entity).ConfigureAwait(false);
|
entity.Content = EncryptSettings(entity);
|
||||||
|
await Repo.UpdateAsync(entity);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace Ombi.Store.Context
|
||||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||||
DbSet<GlobalSettings> Settings { get; set; }
|
DbSet<GlobalSettings> Settings { get; set; }
|
||||||
DbSet<PlexContent> PlexContent { get; set; }
|
DbSet<PlexContent> PlexContent { get; set; }
|
||||||
|
DbSet<PlexEpisode> PlexEpisode { get; set; }
|
||||||
DbSet<RadarrCache> RadarrCache { get; set; }
|
DbSet<RadarrCache> RadarrCache { get; set; }
|
||||||
DatabaseFacade Database { get; }
|
DatabaseFacade Database { get; }
|
||||||
EntityEntry<T> Entry<T>(T entry) where T : class;
|
EntityEntry<T> Entry<T>(T entry) where T : class;
|
||||||
|
@ -30,5 +31,7 @@ namespace Ombi.Store.Context
|
||||||
DbSet<MovieIssues> MovieIssues { get; set; }
|
DbSet<MovieIssues> MovieIssues { get; set; }
|
||||||
DbSet<TvIssues> TvIssues { get; set; }
|
DbSet<TvIssues> TvIssues { get; set; }
|
||||||
DbSet<Tokens> Tokens { get; set; }
|
DbSet<Tokens> Tokens { get; set; }
|
||||||
|
EntityEntry Update(object entity);
|
||||||
|
EntityEntry<TEntity> Update<TEntity>(TEntity entity) where TEntity : class;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ namespace Ombi.Store.Context
|
||||||
public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
|
public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
|
||||||
public DbSet<GlobalSettings> Settings { get; set; }
|
public DbSet<GlobalSettings> Settings { get; set; }
|
||||||
public DbSet<PlexContent> PlexContent { get; set; }
|
public DbSet<PlexContent> PlexContent { get; set; }
|
||||||
|
public DbSet<PlexEpisode> PlexEpisode { get; set; }
|
||||||
public DbSet<RadarrCache> RadarrCache { get; set; }
|
public DbSet<RadarrCache> RadarrCache { get; set; }
|
||||||
|
|
||||||
public DbSet<MovieRequests> MovieRequests { get; set; }
|
public DbSet<MovieRequests> MovieRequests { get; set; }
|
||||||
|
@ -44,6 +45,16 @@ namespace Ombi.Store.Context
|
||||||
optionsBuilder.UseSqlite("Data Source=Ombi.db");
|
optionsBuilder.UseSqlite("Data Source=Ombi.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Entity<PlexEpisode>()
|
||||||
|
.HasOne(p => p.Series)
|
||||||
|
.WithMany(b => b.Episodes)
|
||||||
|
.HasPrincipalKey(x => x.Key)
|
||||||
|
.HasForeignKey(p => p.GrandparentKey);
|
||||||
|
base.OnModelCreating(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Seed()
|
public void Seed()
|
||||||
{
|
{
|
||||||
|
@ -70,19 +81,23 @@ namespace Ombi.Store.Context
|
||||||
SaveChanges();
|
SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Check if templates exist
|
||||||
// Check if templates exist
|
|
||||||
var templates = NotificationTemplates.ToList();
|
var templates = NotificationTemplates.ToList();
|
||||||
if (templates.Any())
|
//if (templates.Any())
|
||||||
{
|
//{
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
var allAgents = Enum.GetValues(typeof(NotificationAgent)).Cast<NotificationAgent>().ToList();
|
var allAgents = Enum.GetValues(typeof(NotificationAgent)).Cast<NotificationAgent>().ToList();
|
||||||
var allTypes = Enum.GetValues(typeof(NotificationType)).Cast<NotificationType>().ToList();
|
var allTypes = Enum.GetValues(typeof(NotificationType)).Cast<NotificationType>().ToList();
|
||||||
|
|
||||||
foreach (var agent in allAgents)
|
foreach (var agent in allAgents)
|
||||||
{
|
{
|
||||||
|
if (templates.Any(x => x.Agent == agent))
|
||||||
|
{
|
||||||
|
// We have all the templates for this notification agent
|
||||||
|
continue;
|
||||||
|
}
|
||||||
foreach (var notificationType in allTypes)
|
foreach (var notificationType in allTypes)
|
||||||
{
|
{
|
||||||
NotificationTemplates notificationToAdd;
|
NotificationTemplates notificationToAdd;
|
||||||
|
|
|
@ -46,11 +46,14 @@ namespace Ombi.Store.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ICollection<PlexSeasonsContent> Seasons { get; set; }
|
public virtual ICollection<PlexSeasonsContent> Seasons { get; set; }
|
||||||
|
|
||||||
|
public ICollection<PlexEpisode> Episodes { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plex's internal ID for this item
|
/// Plex's internal ID for this item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; set; }
|
public int Key { get; set; }
|
||||||
public DateTime AddedAt { get; set; }
|
public DateTime AddedAt { get; set; }
|
||||||
|
public string Quality { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Table("PlexSeasonsContent")]
|
[Table("PlexSeasonsContent")]
|
||||||
|
|
30
src/Ombi.Store/Entities/PlexEpisode.cs
Normal file
30
src/Ombi.Store/Entities/PlexEpisode.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Entities
|
||||||
|
{
|
||||||
|
[Table("PlexEpisode")]
|
||||||
|
public class PlexEpisode : Entity
|
||||||
|
{
|
||||||
|
public int EpisodeNumber { get; set; }
|
||||||
|
public int SeasonNumber { get; set; }
|
||||||
|
public int Key { get; set; } // RatingKey
|
||||||
|
public string Title { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The Season key
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The parent key.
|
||||||
|
/// </value>
|
||||||
|
public int ParentKey { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The Series key
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The grandparent key.
|
||||||
|
/// </value>
|
||||||
|
public int GrandparentKey { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public PlexContent Series { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ using Ombi.Helpers;
|
||||||
namespace Ombi.Store.Migrations
|
namespace Ombi.Store.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(OmbiContext))]
|
[DbContext(typeof(OmbiContext))]
|
||||||
[Migration("20170811145836_Inital")]
|
[Migration("20170825114646_Inital")]
|
||||||
partial class Inital
|
partial class Inital
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
@ -254,10 +254,12 @@ namespace Ombi.Store.Migrations
|
||||||
|
|
||||||
b.Property<DateTime>("AddedAt");
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
b.Property<string>("Key");
|
b.Property<int>("Key");
|
||||||
|
|
||||||
b.Property<string>("ProviderId");
|
b.Property<string>("ProviderId");
|
||||||
|
|
||||||
|
b.Property<string>("Quality");
|
||||||
|
|
||||||
b.Property<string>("ReleaseYear");
|
b.Property<string>("ReleaseYear");
|
||||||
|
|
||||||
b.Property<string>("Title");
|
b.Property<string>("Title");
|
||||||
|
@ -271,6 +273,30 @@ namespace Ombi.Store.Migrations
|
||||||
b.ToTable("PlexContent");
|
b.ToTable("PlexContent");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber");
|
||||||
|
|
||||||
|
b.Property<int>("GrandparentKey");
|
||||||
|
|
||||||
|
b.Property<int>("Key");
|
||||||
|
|
||||||
|
b.Property<int>("ParentKey");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GrandparentKey");
|
||||||
|
|
||||||
|
b.ToTable("PlexEpisode");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -546,6 +572,15 @@ namespace Ombi.Store.Migrations
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("GrandparentKey")
|
||||||
|
.HasPrincipalKey("Key")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Ombi.Store.Entities.PlexContent")
|
b.HasOne("Ombi.Store.Entities.PlexContent")
|
|
@ -132,8 +132,9 @@ namespace Ombi.Store.Migrations
|
||||||
Id = table.Column<int>(nullable: false)
|
Id = table.Column<int>(nullable: false)
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
AddedAt = table.Column<DateTime>(nullable: false),
|
AddedAt = table.Column<DateTime>(nullable: false),
|
||||||
Key = table.Column<string>(nullable: true),
|
Key = table.Column<int>(nullable: false),
|
||||||
ProviderId = table.Column<string>(nullable: true),
|
ProviderId = table.Column<string>(nullable: true),
|
||||||
|
Quality = table.Column<string>(nullable: true),
|
||||||
ReleaseYear = table.Column<string>(nullable: true),
|
ReleaseYear = table.Column<string>(nullable: true),
|
||||||
Title = table.Column<string>(nullable: true),
|
Title = table.Column<string>(nullable: true),
|
||||||
Type = table.Column<int>(nullable: false),
|
Type = table.Column<int>(nullable: false),
|
||||||
|
@ -142,6 +143,7 @@ namespace Ombi.Store.Migrations
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_PlexContent", x => x.Id);
|
table.PrimaryKey("PK_PlexContent", x => x.Id);
|
||||||
|
table.UniqueConstraint("AK_PlexContent_Key", x => x.Key);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
|
@ -316,6 +318,30 @@ namespace Ombi.Store.Migrations
|
||||||
onDelete: ReferentialAction.Restrict);
|
onDelete: ReferentialAction.Restrict);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PlexEpisode",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
EpisodeNumber = table.Column<int>(nullable: false),
|
||||||
|
GrandparentKey = table.Column<int>(nullable: false),
|
||||||
|
Key = table.Column<int>(nullable: false),
|
||||||
|
ParentKey = table.Column<int>(nullable: false),
|
||||||
|
SeasonNumber = table.Column<int>(nullable: false),
|
||||||
|
Title = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PlexEpisode", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PlexEpisode_PlexContent_GrandparentKey",
|
||||||
|
column: x => x.GrandparentKey,
|
||||||
|
principalTable: "PlexContent",
|
||||||
|
principalColumn: "Key",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "PlexSeasonsContent",
|
name: "PlexSeasonsContent",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
|
@ -511,6 +537,11 @@ namespace Ombi.Store.Migrations
|
||||||
column: "NormalizedUserName",
|
column: "NormalizedUserName",
|
||||||
unique: true);
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PlexEpisode_GrandparentKey",
|
||||||
|
table: "PlexEpisode",
|
||||||
|
column: "GrandparentKey");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_PlexSeasonsContent_PlexContentId",
|
name: "IX_PlexSeasonsContent_PlexContentId",
|
||||||
table: "PlexSeasonsContent",
|
table: "PlexSeasonsContent",
|
||||||
|
@ -596,6 +627,9 @@ namespace Ombi.Store.Migrations
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "NotificationTemplates");
|
name: "NotificationTemplates");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PlexEpisode");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "PlexSeasonsContent");
|
name: "PlexSeasonsContent");
|
||||||
|
|
|
@ -253,10 +253,12 @@ namespace Ombi.Store.Migrations
|
||||||
|
|
||||||
b.Property<DateTime>("AddedAt");
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
b.Property<string>("Key");
|
b.Property<int>("Key");
|
||||||
|
|
||||||
b.Property<string>("ProviderId");
|
b.Property<string>("ProviderId");
|
||||||
|
|
||||||
|
b.Property<string>("Quality");
|
||||||
|
|
||||||
b.Property<string>("ReleaseYear");
|
b.Property<string>("ReleaseYear");
|
||||||
|
|
||||||
b.Property<string>("Title");
|
b.Property<string>("Title");
|
||||||
|
@ -270,6 +272,30 @@ namespace Ombi.Store.Migrations
|
||||||
b.ToTable("PlexContent");
|
b.ToTable("PlexContent");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("EpisodeNumber");
|
||||||
|
|
||||||
|
b.Property<int>("GrandparentKey");
|
||||||
|
|
||||||
|
b.Property<int>("Key");
|
||||||
|
|
||||||
|
b.Property<int>("ParentKey");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GrandparentKey");
|
||||||
|
|
||||||
|
b.ToTable("PlexEpisode");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
|
@ -545,6 +571,15 @@ namespace Ombi.Store.Migrations
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("GrandparentKey")
|
||||||
|
.HasPrincipalKey("Key")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Ombi.Store.Entities.PlexContent")
|
b.HasOne("Ombi.Store.Entities.PlexContent")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
@ -11,7 +12,12 @@ namespace Ombi.Store.Repository
|
||||||
Task<bool> ContentExists(string providerId);
|
Task<bool> ContentExists(string providerId);
|
||||||
Task<IEnumerable<PlexContent>> GetAll();
|
Task<IEnumerable<PlexContent>> GetAll();
|
||||||
Task<PlexContent> Get(string providerId);
|
Task<PlexContent> Get(string providerId);
|
||||||
Task<PlexContent> GetByKey(string key);
|
Task<PlexContent> GetByKey(int key);
|
||||||
Task Update(PlexContent existingContent);
|
Task Update(PlexContent existingContent);
|
||||||
|
IQueryable<PlexEpisode> GetAllEpisodes();
|
||||||
|
Task<PlexEpisode> Add(PlexEpisode content);
|
||||||
|
Task<PlexEpisode> GetEpisodeByKey(int key);
|
||||||
|
Task AddRange(IEnumerable<PlexEpisode> content);
|
||||||
|
IQueryable<PlexContent> Get();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Store.Context;
|
using Ombi.Store.Context;
|
||||||
|
@ -71,7 +72,12 @@ namespace Ombi.Store.Repository
|
||||||
return await Db.PlexContent.FirstOrDefaultAsync(x => x.ProviderId == providerId);
|
return await Db.PlexContent.FirstOrDefaultAsync(x => x.ProviderId == providerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlexContent> GetByKey(string key)
|
public IQueryable<PlexContent> Get()
|
||||||
|
{
|
||||||
|
return Db.PlexContent.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PlexContent> GetByKey(int key)
|
||||||
{
|
{
|
||||||
return await Db.PlexContent.Include(x => x.Seasons).FirstOrDefaultAsync(x => x.Key == key);
|
return await Db.PlexContent.Include(x => x.Seasons).FirstOrDefaultAsync(x => x.Key == key);
|
||||||
}
|
}
|
||||||
|
@ -81,5 +87,26 @@ namespace Ombi.Store.Repository
|
||||||
Db.PlexContent.Update(existingContent);
|
Db.PlexContent.Update(existingContent);
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IQueryable<PlexEpisode> GetAllEpisodes()
|
||||||
|
{
|
||||||
|
return Db.PlexEpisode.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PlexEpisode> Add(PlexEpisode content)
|
||||||
|
{
|
||||||
|
await Db.PlexEpisode.AddAsync(content);
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
public async Task<PlexEpisode> GetEpisodeByKey(int key)
|
||||||
|
{
|
||||||
|
return await Db.PlexEpisode.FirstOrDefaultAsync(x => x.Key == key);
|
||||||
|
}
|
||||||
|
public async Task AddRange(IEnumerable<PlexEpisode> content)
|
||||||
|
{
|
||||||
|
Db.PlexEpisode.AddRange(content);
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,9 @@ namespace Ombi.Store.Repository
|
||||||
Task<MovieRequests> Add(MovieRequests request);
|
Task<MovieRequests> Add(MovieRequests request);
|
||||||
Task Delete(MovieRequests request);
|
Task Delete(MovieRequests request);
|
||||||
IQueryable<MovieRequests> Get();
|
IQueryable<MovieRequests> Get();
|
||||||
Task<MovieRequests> GetRequest(int theMovieDbId);
|
Task<MovieRequests> GetRequestAsync(int theMovieDbId);
|
||||||
|
MovieRequests GetRequest(int theMovieDbId);
|
||||||
Task Update(MovieRequests request);
|
Task Update(MovieRequests request);
|
||||||
|
Task Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,9 +11,11 @@ namespace Ombi.Store.Repository.Requests
|
||||||
Task Delete(TvRequests request);
|
Task Delete(TvRequests request);
|
||||||
Task DeleteChild(ChildRequests request);
|
Task DeleteChild(ChildRequests request);
|
||||||
IQueryable<TvRequests> Get();
|
IQueryable<TvRequests> Get();
|
||||||
Task<TvRequests> GetRequest(int tvDbId);
|
Task<TvRequests> GetRequestAsync(int tvDbId);
|
||||||
|
TvRequests GetRequest(int tvDbId);
|
||||||
Task Update(TvRequests request);
|
Task Update(TvRequests request);
|
||||||
Task UpdateChild(ChildRequests request);
|
Task UpdateChild(ChildRequests request);
|
||||||
IQueryable<ChildRequests> GetChild();
|
IQueryable<ChildRequests> GetChild();
|
||||||
|
Task Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Store.Context;
|
using Ombi.Store.Context;
|
||||||
|
@ -15,12 +17,28 @@ namespace Ombi.Store.Repository.Requests
|
||||||
|
|
||||||
private IOmbiContext Db { get; }
|
private IOmbiContext Db { get; }
|
||||||
|
|
||||||
public async Task<MovieRequests> GetRequest(int theMovieDbId)
|
public async Task<MovieRequests> GetRequestAsync(int theMovieDbId)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return await Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
return await Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||||
.Include(x => x.RequestedUser)
|
.Include(x => x.RequestedUser)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public MovieRequests GetRequest(int theMovieDbId)
|
||||||
|
{
|
||||||
|
return Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
public IQueryable<MovieRequests> Get()
|
public IQueryable<MovieRequests> Get()
|
||||||
{
|
{
|
||||||
|
@ -46,5 +64,10 @@ namespace Ombi.Store.Repository.Requests
|
||||||
{
|
{
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Save()
|
||||||
|
{
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ namespace Ombi.Store.Repository.Requests
|
||||||
|
|
||||||
private IOmbiContext Db { get; }
|
private IOmbiContext Db { get; }
|
||||||
|
|
||||||
public async Task<TvRequests> GetRequest(int tvDbId)
|
public async Task<TvRequests> GetRequestAsync(int tvDbId)
|
||||||
{
|
{
|
||||||
return await Db.TvRequests.Where(x => x.TvDbId == tvDbId)
|
return await Db.TvRequests.Where(x => x.TvDbId == tvDbId)
|
||||||
.Include(x => x.ChildRequests)
|
.Include(x => x.ChildRequests)
|
||||||
|
@ -26,6 +26,17 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TvRequests GetRequest(int tvDbId)
|
||||||
|
{
|
||||||
|
return Db.TvRequests.Where(x => x.TvDbId == tvDbId)
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.RequestedUser)
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
public IQueryable<TvRequests> Get()
|
public IQueryable<TvRequests> Get()
|
||||||
{
|
{
|
||||||
return Db.TvRequests
|
return Db.TvRequests
|
||||||
|
@ -40,11 +51,17 @@ namespace Ombi.Store.Repository.Requests
|
||||||
{
|
{
|
||||||
return Db.ChildRequests
|
return Db.ChildRequests
|
||||||
.Include(x => x.RequestedUser)
|
.Include(x => x.RequestedUser)
|
||||||
|
.Include(x => x.ParentRequest)
|
||||||
.Include(x => x.SeasonRequests)
|
.Include(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Save()
|
||||||
|
{
|
||||||
|
await Db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TvRequests> Add(TvRequests request)
|
public async Task<TvRequests> Add(TvRequests request)
|
||||||
{
|
{
|
||||||
await Db.TvRequests.AddAsync(request);
|
await Db.TvRequests.AddAsync(request);
|
||||||
|
@ -74,11 +91,15 @@ namespace Ombi.Store.Repository.Requests
|
||||||
|
|
||||||
public async Task Update(TvRequests request)
|
public async Task Update(TvRequests request)
|
||||||
{
|
{
|
||||||
|
Db.Attach(request).State = EntityState.Modified;
|
||||||
|
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateChild(ChildRequests request)
|
public async Task UpdateChild(ChildRequests request)
|
||||||
{
|
{
|
||||||
|
Db.Attach(request).State = EntityState.Modified;
|
||||||
|
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -36,27 +37,28 @@ namespace Ombi.Store.Repository
|
||||||
public IEnumerable<GlobalSettings> GetAll()
|
public IEnumerable<GlobalSettings> GetAll()
|
||||||
{
|
{
|
||||||
|
|
||||||
var page = Db.Settings.ToList();
|
var page = Db.Settings.AsNoTracking().ToList();
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<GlobalSettings>> GetAllAsync()
|
public async Task<IEnumerable<GlobalSettings>> GetAllAsync()
|
||||||
{
|
{
|
||||||
var page = await Db.Settings.ToListAsync();
|
var page = await Db.Settings.AsNoTracking().ToListAsync();
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalSettings Get(string pageName)
|
public GlobalSettings Get(string pageName)
|
||||||
{
|
{
|
||||||
var entity = Db.Settings.FirstOrDefault(x => x.SettingsName == pageName);
|
var entity = Db.Settings.AsNoTracking().FirstOrDefault(x => x.SettingsName == pageName);
|
||||||
Db.Entry(entity).Reload();
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<GlobalSettings> GetAsync(string settingsName)
|
public async Task<GlobalSettings> GetAsync(string settingsName)
|
||||||
{
|
{
|
||||||
return await Db.Settings.FirstOrDefaultAsync(x => x.SettingsName == settingsName);
|
|
||||||
|
var obj = await Db.Settings.AsNoTracking().FirstOrDefaultAsync(x => x.SettingsName == settingsName);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteAsync(GlobalSettings entity)
|
public async Task DeleteAsync(GlobalSettings entity)
|
||||||
|
@ -67,6 +69,7 @@ namespace Ombi.Store.Repository
|
||||||
|
|
||||||
public async Task UpdateAsync(GlobalSettings entity)
|
public async Task UpdateAsync(GlobalSettings entity)
|
||||||
{
|
{
|
||||||
|
Db.Update(entity);
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
src/Ombi.sln
29
src/Ombi.sln
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26430.16
|
VisualStudioVersion = 15.0.26730.3
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -11,6 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||||
..\build.cake = ..\build.cake
|
..\build.cake = ..\build.cake
|
||||||
..\BuildTask.ps1 = ..\BuildTask.ps1
|
..\BuildTask.ps1 = ..\BuildTask.ps1
|
||||||
..\CHANGELOG.md = ..\CHANGELOG.md
|
..\CHANGELOG.md = ..\CHANGELOG.md
|
||||||
|
..\global.json = ..\global.json
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}"
|
||||||
|
@ -73,7 +74,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.FanartTv", "Ombi.A
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushbullet", "Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj", "{E237CDF6-D044-437D-B157-E9A3CC0BCF53}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushbullet", "Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj", "{E237CDF6-D044-437D-B157-E9A3CC0BCF53}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Slack", "Ombi.Api.Slack\Ombi.Api.Slack.csproj", "{71708256-9152-4E81-9FCA-E3181A185806}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Slack", "Ombi.Api.Slack\Ombi.Api.Slack.csproj", "{71708256-9152-4E81-9FCA-E3181A185806}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Mattermost", "Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj", "{737B2620-FE5A-4135-A017-79C269A7D36C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushover", "Ombi.Api.Pushover\Ombi.Api.Pushover.csproj", "{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Schedule.Tests", "Ombi.Schedule.Tests\Ombi.Schedule.Tests.csproj", "{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -185,6 +192,18 @@ Global
|
||||||
{71708256-9152-4E81-9FCA-E3181A185806}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{71708256-9152-4E81-9FCA-E3181A185806}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.Build.0 = Release|Any CPU
|
{71708256-9152-4E81-9FCA-E3181A185806}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{737B2620-FE5A-4135-A017-79C269A7D36C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{737B2620-FE5A-4135-A017-79C269A7D36C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{737B2620-FE5A-4135-A017-79C269A7D36C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{737B2620-FE5A-4135-A017-79C269A7D36C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -210,5 +229,11 @@ Global
|
||||||
{FD947E63-A0D2-4878-8378-2005D5E9AB8A} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{FD947E63-A0D2-4878-8378-2005D5E9AB8A} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
{E237CDF6-D044-437D-B157-E9A3CC0BCF53} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{E237CDF6-D044-437D-B157-E9A3CC0BCF53} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
{71708256-9152-4E81-9FCA-E3181A185806} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
{71708256-9152-4E81-9FCA-E3181A185806} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
|
{737B2620-FE5A-4135-A017-79C269A7D36C} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
|
{CA55DD4F-4EFF-4906-A848-35FCC7BD5654} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||||
|
{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -15,30 +15,24 @@ import { ICustomizationSettings } from './interfaces/ISettings';
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
constructor(public notificationService: NotificationService, public authService: AuthService, private router: Router, private settingsService: SettingsService)
|
constructor(public notificationService: NotificationService, public authService: AuthService, private router: Router, private settingsService: SettingsService) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
customizationSettings: ICustomizationSettings;
|
customizationSettings: ICustomizationSettings;
|
||||||
user: ILocalUser;
|
user: ILocalUser;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.user = this.authService.claims();
|
this.user = this.authService.claims();
|
||||||
|
|
||||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||||
|
|
||||||
this.router.events.subscribe(() => {
|
this.router.events.subscribe(() => {
|
||||||
|
|
||||||
this.user = this.authService.claims();
|
this.user = this.authService.claims();
|
||||||
this.showNav = this.authService.loggedIn();
|
this.showNav = this.authService.loggedIn();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hasRole(role: string): boolean {
|
hasRole(role: string): boolean {
|
||||||
return this.user.roles.some(r => r === role)
|
return this.user.roles.some(r => r === role);
|
||||||
}
|
}
|
||||||
|
|
||||||
logOut() {
|
logOut() {
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
|
||||||
|
import { Http, Headers } from '@angular/http';
|
||||||
|
|
||||||
import { ServiceHelpers } from '../services/service.helpers';
|
import { ServiceHelpers } from '../services/service.helpers';
|
||||||
|
|
||||||
import { IUserLogin, ILocalUser } from './IUserLogin';
|
import { IUserLogin, ILocalUser } from './IUserLogin';
|
||||||
|
|
||||||
import { tokenNotExpired, JwtHelper } from 'angular2-jwt';
|
|
||||||
|
|
||||||
import { Http, Headers } from '@angular/http';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService extends ServiceHelpers {
|
export class AuthService extends ServiceHelpers {
|
||||||
constructor(http: Http) {
|
constructor(http: Http) {
|
||||||
|
@ -23,7 +20,6 @@ export class AuthService extends ServiceHelpers {
|
||||||
|
|
||||||
return this.http.post(`${this.url}/`, JSON.stringify(login), { headers: this.headers })
|
return this.http.post(`${this.url}/`, JSON.stringify(login), { headers: this.headers })
|
||||||
.map(this.extractData);
|
.map(this.extractData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
|
@ -48,13 +44,16 @@ export class AuthService extends ServiceHelpers {
|
||||||
} else {
|
} else {
|
||||||
u.roles.push(roles);
|
u.roles.push(roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ILocalUser>u;
|
return <ILocalUser>u;
|
||||||
|
|
||||||
}
|
}
|
||||||
return <ILocalUser>{};
|
return <ILocalUser>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hasRole(role: string): boolean {
|
||||||
|
return this.claims().roles.some(r => r === role);
|
||||||
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
localStorage.removeItem('id_token');
|
localStorage.removeItem('id_token');
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,3 +65,17 @@ export interface IPushbulletNotificationSettings extends INotificationSettings {
|
||||||
notificationTemplates: INotificationTemplates[],
|
notificationTemplates: INotificationTemplates[],
|
||||||
channelTag: string;
|
channelTag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IPushoverNotificationSettings extends INotificationSettings {
|
||||||
|
accessToken: string,
|
||||||
|
notificationTemplates: INotificationTemplates[],
|
||||||
|
userToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMattermostNotifcationSettings extends INotificationSettings {
|
||||||
|
webhookUrl: string,
|
||||||
|
username: string,
|
||||||
|
channel: string,
|
||||||
|
iconUrl:string,
|
||||||
|
notificationTemplates: INotificationTemplates[],
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,8 @@ export interface IBaseRequest {
|
||||||
denied: boolean,
|
denied: boolean,
|
||||||
deniedReason: string,
|
deniedReason: string,
|
||||||
requestType: RequestType,
|
requestType: RequestType,
|
||||||
requestedUser: IUser
|
requestedUser: IUser,
|
||||||
|
canApprove:boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITvRequests {
|
export interface ITvRequests {
|
||||||
|
|
|
@ -20,5 +20,6 @@
|
||||||
approved: boolean,
|
approved: boolean,
|
||||||
requested: boolean,
|
requested: boolean,
|
||||||
available: boolean,
|
available: boolean,
|
||||||
plexUrl: string
|
plexUrl: string,
|
||||||
|
quality:string
|
||||||
}
|
}
|
|
@ -87,3 +87,15 @@ export interface ICustomizationSettings extends ISettings {
|
||||||
applicationName: string,
|
applicationName: string,
|
||||||
logo: string,
|
logo: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAuthenticationSettings extends ISettings {
|
||||||
|
|
||||||
|
allowExternalUsersToAuthenticate: boolean,
|
||||||
|
// Password
|
||||||
|
|
||||||
|
requiredDigit: boolean,
|
||||||
|
requiredLength: number,
|
||||||
|
requiredLowercase: boolean,
|
||||||
|
requireNonAlphanumeric: boolean,
|
||||||
|
requireUppercase:boolean,
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ export class TvRequestChildrenComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public deny(request: IChildRequests) {
|
public deny(request: IChildRequests) {
|
||||||
|
debugger;
|
||||||
request.approved = false;
|
request.approved = false;
|
||||||
request.denied = true;
|
request.denied = true;
|
||||||
this.requestService.updateChild(request)
|
this.requestService.updateChild(request)
|
||||||
|
@ -30,6 +31,7 @@ export class TvRequestChildrenComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public approve(request: IChildRequests) {
|
public approve(request: IChildRequests) {
|
||||||
|
debugger;
|
||||||
request.approved = true;
|
request.approved = true;
|
||||||
request.denied = false;
|
request.denied = false;
|
||||||
this.requestService.updateChild(request)
|
this.requestService.updateChild(request)
|
||||||
|
|
|
@ -46,7 +46,11 @@
|
||||||
|
|
||||||
<span *ngIf="result.releaseDate" class="label label-info" target="_blank">Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}}</span>
|
<span *ngIf="result.releaseDate" class="label label-info" target="_blank">Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}}</span>
|
||||||
|
|
||||||
|
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
|
||||||
|
|
||||||
|
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
|
||||||
<span *ngIf="result.available" class="label label-success">Available</span>
|
<span *ngIf="result.available" class="label label-success">Available</span>
|
||||||
|
<span *ngIf="result.quality" class="label label-success">{{result.quality}}p</span>
|
||||||
<span *ngIf="result.approved && !result.available" class="label label-info">Processing Request</span>
|
<span *ngIf="result.approved && !result.available" class="label label-info">Processing Request</span>
|
||||||
<div *ngIf="result.requested && !result.available; then requested else notRequested"></div>
|
<div *ngIf="result.requested && !result.available; then requested else notRequested"></div>
|
||||||
<ng-template #requested>
|
<ng-template #requested>
|
||||||
|
@ -58,11 +62,7 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
|
||||||
<span id="{{id}}netflixTab"></span>
|
|
||||||
|
|
||||||
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
|
|
||||||
|
|
||||||
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
|
|
||||||
|
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -132,11 +132,12 @@
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<div *ngIf="result.available">
|
<div *ngIf="result.available">
|
||||||
<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
|
||||||
|
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||||
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
|
<i class="fa fa-exclamation"></i> Report Issue
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
|
@ -146,7 +147,7 @@
|
||||||
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
||||||
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,20 +10,9 @@
|
||||||
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-film"></i> Movies</a>
|
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-film"></i> Movies</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!--<li role="presentation">
|
|
||||||
<a id="actorTabButton" href="#ActorsTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-users"></i> Actors</a>
|
|
||||||
|
|
||||||
</li>-->
|
|
||||||
|
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-television"></i> TV Shows</a>
|
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-television"></i> TV Shows</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
<li role="presentation">
|
|
||||||
<a href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab"><i class="fa fa-music"></i> Albums</a>
|
|
||||||
</li>-->
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
|
@ -33,28 +22,8 @@
|
||||||
<movie-search></movie-search>
|
<movie-search></movie-search>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
|
||||||
<div role="tabpanel" class="tab-pane" id="ActorsTab">
|
|
||||||
<div class="input-group">
|
|
||||||
<input id="actorSearchContent" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons">
|
|
||||||
<div class="input-group-addon">
|
|
||||||
<i id="actorSearchButton" class="fa fa-search"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox">
|
|
||||||
<input type="checkbox" id="actorsSearchNew" name="actorsSearchNew"><label for="actorsSearchNew">@UI.Search_NewOnly</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<div id="actorMovieList">
|
|
||||||
</div>
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
|
|
||||||
<div [hidden]="!showTv">
|
<div [hidden]="!showTv">
|
||||||
<tv-search></tv-search>
|
<tv-search></tv-search>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<a href="http://www.imdb.com/title/{{result.imdbId}}/" target="_blank">
|
<a href="http://www.imdb.com/title/{{result.imdbId}}/" target="_blank">
|
||||||
<h4>{{result.title}} ({{result.firstAired}})</h4>
|
<h4>{{result.title}} ({{result.firstAired | date: 'yyyy'}})</h4>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -85,16 +85,7 @@
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<input name="{{type}}Id" type="text" value="{{result.id}}" hidden="hidden"/>
|
<input name="{{type}}Id" type="text" value="{{result.id}}" hidden="hidden"/>
|
||||||
|
|
||||||
<div *ngIf="result.available">
|
|
||||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> Available</button>
|
|
||||||
|
|
||||||
<div *ngIf="result.url">
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{result.url}}" target="_blank"><i class="fa fa-eye"></i> View In Plex</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
|
<!--<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
|
||||||
<template #requestedBtn>
|
<template #requestedBtn>
|
||||||
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
|
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
|
||||||
|
@ -134,11 +125,13 @@
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<div *ngIf="result.available">
|
<div *ngIf="result.available">
|
||||||
<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
|
||||||
|
|
||||||
|
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
|
||||||
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
<i class="fa fa-exclamation"></i> @UI.Search_ReportIssue
|
<i class="fa fa-exclamation"></i> Report Issue
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
|
@ -148,7 +141,7 @@
|
||||||
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
|
||||||
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,7 +8,9 @@ import {
|
||||||
IDiscordNotifcationSettings,
|
IDiscordNotifcationSettings,
|
||||||
IEmailNotificationSettings,
|
IEmailNotificationSettings,
|
||||||
IPushbulletNotificationSettings,
|
IPushbulletNotificationSettings,
|
||||||
ISlackNotificationSettings
|
ISlackNotificationSettings,
|
||||||
|
IPushoverNotificationSettings,
|
||||||
|
IMattermostNotifcationSettings
|
||||||
} from '../../interfaces/INotifcationSettings'
|
} from '../../interfaces/INotifcationSettings'
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +27,13 @@ export class TesterService extends ServiceAuthHelpers {
|
||||||
pushbulletTest(settings: IPushbulletNotificationSettings): Observable<boolean> {
|
pushbulletTest(settings: IPushbulletNotificationSettings): Observable<boolean> {
|
||||||
return this.http.post(`${this.url}pushbullet`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
return this.http.post(`${this.url}pushbullet`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
||||||
}
|
}
|
||||||
|
pushoverTest(settings: IPushoverNotificationSettings): Observable<boolean> {
|
||||||
|
return this.http.post(`${this.url}pushover`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
||||||
|
}
|
||||||
|
|
||||||
|
mattermostTest(settings: IMattermostNotifcationSettings): Observable<boolean> {
|
||||||
|
return this.http.post(`${this.url}mattermost`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
||||||
|
}
|
||||||
|
|
||||||
slackTest(settings: ISlackNotificationSettings): Observable<boolean> {
|
slackTest(settings: ISlackNotificationSettings): Observable<boolean> {
|
||||||
return this.http.post(`${this.url}slack`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
return this.http.post(`${this.url}slack`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
|
||||||
|
|
|
@ -11,13 +11,16 @@ import {
|
||||||
ISonarrSettings,
|
ISonarrSettings,
|
||||||
ILandingPageSettings,
|
ILandingPageSettings,
|
||||||
ICustomizationSettings,
|
ICustomizationSettings,
|
||||||
IRadarrSettings
|
IRadarrSettings,
|
||||||
|
IAuthenticationSettings
|
||||||
} from '../interfaces/ISettings';
|
} from '../interfaces/ISettings';
|
||||||
import {
|
import {
|
||||||
IEmailNotificationSettings,
|
IEmailNotificationSettings,
|
||||||
IDiscordNotifcationSettings,
|
IDiscordNotifcationSettings,
|
||||||
IPushbulletNotificationSettings,
|
IPushbulletNotificationSettings,
|
||||||
ISlackNotificationSettings
|
ISlackNotificationSettings,
|
||||||
|
IPushoverNotificationSettings,
|
||||||
|
IMattermostNotifcationSettings
|
||||||
} from '../interfaces/INotifcationSettings';
|
} from '../interfaces/INotifcationSettings';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -31,23 +34,31 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveOmbi(settings: IOmbiSettings): Observable<boolean> {
|
saveOmbi(settings: IOmbiSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/Ombi/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/Ombi/`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetOmbiApi(): Observable<string> {
|
||||||
|
return this.httpAuth.post(`${this.url}/Ombi/resetApi`, { headers: this.headers }).map(this.extractData)
|
||||||
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getEmby(): Observable<IEmbySettings> {
|
getEmby(): Observable<IEmbySettings> {
|
||||||
return this.httpAuth.get(`${this.url}/Emby/`).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.get(`${this.url}/Emby/`).map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveEmby(settings: IEmbySettings): Observable<boolean> {
|
saveEmby(settings: IEmbySettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/Emby/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/Emby/`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlex(): Observable<IPlexSettings> {
|
getPlex(): Observable<IPlexSettings> {
|
||||||
return this.httpAuth.get(`${this.url}/Plex/`).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.get(`${this.url}/Plex/`).map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
savePlex(settings: IPlexSettings): Observable<boolean> {
|
savePlex(settings: IPlexSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/Plex/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/Plex/`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSonarr(): Observable<ISonarrSettings> {
|
getSonarr(): Observable<ISonarrSettings> {
|
||||||
|
@ -56,7 +67,8 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSonarr(settings: ISonarrSettings): Observable<boolean> {
|
saveSonarr(settings: ISonarrSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/Sonarr`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/Sonarr`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRadarr(): Observable<IRadarrSettings> {
|
getRadarr(): Observable<IRadarrSettings> {
|
||||||
|
@ -65,16 +77,29 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveRadarr(settings: IRadarrSettings): Observable<boolean> {
|
saveRadarr(settings: IRadarrSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/Radarr`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/Radarr`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getAuthentication(): Observable<IAuthenticationSettings> {
|
||||||
|
return this.httpAuth.get(`${this.url}/Authentication`).map(this.extractData)
|
||||||
|
.catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveAuthentication(settings: IAuthenticationSettings): Observable<boolean> {
|
||||||
|
return this.httpAuth.post(`${this.url}/Authentication`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using http since we need it not to be authenticated to get the landing page settings
|
// Using http since we need it not to be authenticated to get the landing page settings
|
||||||
getLandingPage(): Observable<ILandingPageSettings> {
|
getLandingPage(): Observable<ILandingPageSettings> {
|
||||||
return this.nonAuthHttp.get(`${this.url}/LandingPage`).map(this.extractData).catch(this.handleError)
|
return this.nonAuthHttp.get(`${this.url}/LandingPage`).map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveLandingPage(settings: ILandingPageSettings): Observable<boolean> {
|
saveLandingPage(settings: ILandingPageSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/LandingPage`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/LandingPage`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using http since we need it not to be authenticated to get the customization settings
|
// Using http since we need it not to be authenticated to get the customization settings
|
||||||
|
@ -83,7 +108,8 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveCustomization(settings: ICustomizationSettings): Observable<boolean> {
|
saveCustomization(settings: ICustomizationSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/customization`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.post(`${this.url}/customization`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getEmailNotificationSettings(): Observable<IEmailNotificationSettings> {
|
getEmailNotificationSettings(): Observable<IEmailNotificationSettings> {
|
||||||
|
@ -91,22 +117,46 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveEmailNotificationSettings(settings: IEmailNotificationSettings): Observable<boolean> {
|
saveEmailNotificationSettings(settings: IEmailNotificationSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/notifications/email`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/email`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDiscordNotificationSettings(): Observable<IDiscordNotifcationSettings> {
|
getDiscordNotificationSettings(): Observable<IDiscordNotifcationSettings> {
|
||||||
return this.httpAuth.get(`${this.url}/notifications/discord`).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.get(`${this.url}/notifications/discord`).map(this.extractData).catch(this.handleError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMattermostNotificationSettings(): Observable<IMattermostNotifcationSettings> {
|
||||||
|
return this.httpAuth.get(`${this.url}/notifications/mattermost`).map(this.extractData).catch(this.handleError)
|
||||||
|
}
|
||||||
|
|
||||||
saveDiscordNotificationSettings(settings: IDiscordNotifcationSettings): Observable<boolean> {
|
saveDiscordNotificationSettings(settings: IDiscordNotifcationSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/notifications/discord`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/discord`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveMattermostNotificationSettings(settings: IMattermostNotifcationSettings): Observable<boolean> {
|
||||||
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/mattermost`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
getPushbulletNotificationSettings(): Observable<IPushbulletNotificationSettings> {
|
getPushbulletNotificationSettings(): Observable<IPushbulletNotificationSettings> {
|
||||||
return this.httpAuth.get(`${this.url}/notifications/pushbullet`).map(this.extractData).catch(this.handleError)
|
return this.httpAuth.get(`${this.url}/notifications/pushbullet`).map(this.extractData).catch(this.handleError)
|
||||||
}
|
}
|
||||||
|
getPushoverNotificationSettings(): Observable<IPushoverNotificationSettings> {
|
||||||
|
return this.httpAuth.get(`${this.url}/notifications/pushover`).map(this.extractData).catch(this.handleError)
|
||||||
|
}
|
||||||
|
|
||||||
savePushbulletNotificationSettings(settings: IPushbulletNotificationSettings): Observable<boolean> {
|
savePushbulletNotificationSettings(settings: IPushbulletNotificationSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/notifications/pushbullet`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/pushbullet`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
|
}
|
||||||
|
savePushoverNotificationSettings(settings: IPushoverNotificationSettings): Observable<boolean> {
|
||||||
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/pushover`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSlackNotificationSettings(): Observable<ISlackNotificationSettings> {
|
getSlackNotificationSettings(): Observable<ISlackNotificationSettings> {
|
||||||
|
@ -114,6 +164,8 @@ export class SettingsService extends ServiceAuthHelpers {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSlackNotificationSettings(settings: ISlackNotificationSettings): Observable<boolean> {
|
saveSlackNotificationSettings(settings: ISlackNotificationSettings): Observable<boolean> {
|
||||||
return this.httpAuth.post(`${this.url}/notifications/slack`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData).catch(this.handleError)
|
return this.httpAuth
|
||||||
|
.post(`${this.url}/notifications/slack`, JSON.stringify(settings), { headers: this.headers })
|
||||||
|
.map(this.extractData).catch(this.handleError);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div class="col-md-12 col-md-push-10" style="float: right;">
|
<div class="col-md-2 " style="float: right;">
|
||||||
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
|
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
<settings-menu></settings-menu>
|
||||||
|
<div *ngIf="form">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Mattermost Notifications</legend>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" id="enable" formControlName="enabled">
|
||||||
|
<label for="enable">Enabled</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
||||||
|
<div *ngIf="form.get('webhookUrl').hasError('required')">The Incoming Webhook Url is required</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<small class="control-label"> Mattermost > Integrations > Incoming Webhook > Add Incoming Webhook. You will then have a Webhook</small>
|
||||||
|
<label for="webhookUrl" class="control-label">Incoming Webhook Url</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="webhookUrl" name="webhookUrl" formControlName="webhookUrl">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="channel" class="control-label">Channel Override</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="channel" name="channel" formControlName="channel" pTooltip="Optional, you can override the default channel">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="username" class="control-label">Username Override</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="username" name="username" formControlName="username" pTooltip="Optional, this will override the username you used for the Webhook">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="iconUrl" class="control-label">Icon Override</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="iconUrl" name="iconUrl" formControlName="iconUrl" pTooltip="Optional, this will override the icon you use for the Webhook">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="button" (click)="test(form)" class="btn btn-primary-outline">
|
||||||
|
Test
|
||||||
|
<div id="spinner"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<notification-templates [templates]="templates"></notification-templates>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { INotificationTemplates, IMattermostNotifcationSettings, NotificationType } from '../../interfaces/INotifcationSettings';
|
||||||
|
import { SettingsService } from '../../services/settings.service';
|
||||||
|
import { NotificationService } from "../../services/notification.service";
|
||||||
|
import { TesterService } from "../../services/applications/tester.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './mattermost.component.html'
|
||||||
|
})
|
||||||
|
export class MattermostComponent implements OnInit {
|
||||||
|
constructor(private settingsService: SettingsService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private testerService : TesterService) { }
|
||||||
|
|
||||||
|
NotificationType = NotificationType;
|
||||||
|
templates: INotificationTemplates[];
|
||||||
|
|
||||||
|
form: FormGroup;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.settingsService.getMattermostNotificationSettings().subscribe(x => {
|
||||||
|
this.templates = x.notificationTemplates;
|
||||||
|
|
||||||
|
this.form = this.fb.group({
|
||||||
|
enabled: [x.enabled],
|
||||||
|
username: [x.username],
|
||||||
|
webhookUrl: [x.webhookUrl, [Validators.required]],
|
||||||
|
channel: [x.channel],
|
||||||
|
iconUrl:[x.iconUrl]
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Validation", "Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var settings = <IMattermostNotifcationSettings>form.value;
|
||||||
|
settings.notificationTemplates = this.templates;
|
||||||
|
|
||||||
|
this.settingsService.saveMattermostNotificationSettings(settings).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Settings Saved", "Successfully saved the Mattermost settings");
|
||||||
|
} else {
|
||||||
|
this.notificationService.success("Settings Saved", "There was an error when saving the Mattermost settings");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
test(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Validation", "Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.testerService.mattermostTest(form.value).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Successful", "Successfully sent a Mattermost message, please check the discord channel");
|
||||||
|
} else {
|
||||||
|
this.notificationService.success("Error", "There was an error when sending the Mattermost message. Please check your settings");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
<settings-menu></settings-menu>
|
<settings-menu></settings-menu>
|
||||||
<div *ngIf="form">
|
<div *ngIf="form">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Pushbyllet Notifications</legend>
|
<legend>Pushbullet Notifications</legend>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
<settings-menu></settings-menu>
|
||||||
|
<div *ngIf="form">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Pushover Notifications</legend>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" id="enable" formControlName="enabled">
|
||||||
|
<label for="enable">Enabled</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
||||||
|
<div *ngIf="form.get('accessToken').hasError('required')">The Access Token is required</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="accessToken" class="control-label">Access Token</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="accessToken" name="accessToken" formControlName="accessToken" pTooltip="Enter your API Key from Pushover.">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="userToken" class="control-label">User Token</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control form-control-custom " id="userToken" name="userToken" formControlName="userToken" pTooltip="Your user or group key from Pushover.">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="button" (click)="test(form)" class="btn btn-primary-outline">
|
||||||
|
Test
|
||||||
|
<div id="spinner"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button [disabled]="form.invalid" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<notification-templates [templates]="templates"></notification-templates>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { INotificationTemplates, IPushoverNotificationSettings, NotificationType } from '../../interfaces/INotifcationSettings';
|
||||||
|
import { SettingsService } from '../../services/settings.service';
|
||||||
|
import { NotificationService } from "../../services/notification.service";
|
||||||
|
import { TesterService } from "../../services/applications/tester.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './pushover.component.html',
|
||||||
|
})
|
||||||
|
export class PushoverComponent implements OnInit {
|
||||||
|
constructor(private settingsService: SettingsService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private testerService : TesterService) { }
|
||||||
|
|
||||||
|
NotificationType = NotificationType;
|
||||||
|
templates: INotificationTemplates[];
|
||||||
|
|
||||||
|
form: FormGroup;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.settingsService.getPushoverNotificationSettings().subscribe(x => {
|
||||||
|
this.templates = x.notificationTemplates;
|
||||||
|
|
||||||
|
this.form = this.fb.group({
|
||||||
|
enabled: [x.enabled],
|
||||||
|
userToken: [x.userToken],
|
||||||
|
accessToken: [x.accessToken, [Validators.required]],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Validation", "Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var settings = <IPushoverNotificationSettings>form.value;
|
||||||
|
settings.notificationTemplates = this.templates;
|
||||||
|
|
||||||
|
this.settingsService.savePushoverNotificationSettings(settings).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Settings Saved", "Successfully saved the Pushover settings");
|
||||||
|
} else {
|
||||||
|
this.notificationService.success("Settings Saved", "There was an error when saving the Pushover settings");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
test(form: FormGroup) {
|
||||||
|
if (form.invalid) {
|
||||||
|
this.notificationService.error("Validation", "Please check your entered values");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.testerService.pushoverTest(form.value).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notificationService.success("Successful", "Successfully sent a Pushbullet message, please check the discord channel");
|
||||||
|
} else {
|
||||||
|
this.notificationService.success("Error", "There was an error when sending the Pushbullet message. Please check your settings");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
<!--<div *ngIf="form.invalid && form.dirty" class="alert alert-danger">
|
||||||
<div>The External URL is incorrect</div>
|
<div>The External URL is incorrect</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<div>
|
<div>
|
||||||
<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.">
|
<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>
|
</div>-->
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
@ -29,20 +29,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="ApiKey" class="control-label">Api Key</label>
|
<label for="ApiKey" class="control-label">Api Key</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control form-control-custom" id="ApiKey" name="ApiKey" formControlName="apiKey">
|
<input type="text" class="form-control form-control-custom" id="ApiKey" name="ApiKey" formControlName="apiKey">
|
||||||
|
|
||||||
<div class="input-group-addon">
|
<div class="input-group-addon">
|
||||||
<div (click)="refreshApiKey()" id="refreshKey" class="fa fa-refresh" title="Reset API Key"></div>
|
<div (click)="refreshApiKey()" id="refreshKey" class="fa fa-refresh" title="Reset API Key" pTooltip="This will invalidate the old API key"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group-addon">
|
<div class="input-group-addon">
|
||||||
<div class="fa fa-clipboard"></div>
|
<div class="fa fa-clipboard"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>-->
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
@ -29,13 +29,17 @@ export class OmbiComponent implements OnInit {
|
||||||
|
|
||||||
|
|
||||||
refreshApiKey() {
|
refreshApiKey() {
|
||||||
|
this.settingsService.resetOmbiApi().subscribe(x => {
|
||||||
|
this.form.patchValue({
|
||||||
|
apiKey: x
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(form: FormGroup) {
|
onSubmit(form: FormGroup) {
|
||||||
if (form.invalid) {
|
if (form.invalid) {
|
||||||
this.notificationService.error("Validation", "Please check your entered values");
|
this.notificationService.error("Validation", "Please check your entered values");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.settingsService.saveOmbi(form.value).subscribe(x => {
|
this.settingsService.saveOmbi(form.value).subscribe(x => {
|
||||||
if (x) {
|
if (x) {
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<ng-template ngbTabContent>
|
<ng-template ngbTabContent>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div class="col-md-12 col-md-push-10" style="float: right;">
|
<div class="col-md-2 " style="float: right;">
|
||||||
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
|
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -22,6 +22,9 @@ import { CustomizationComponent } from './customization/customization.component'
|
||||||
import { EmailNotificationComponent } from './notifications/emailnotification.component';
|
import { EmailNotificationComponent } from './notifications/emailnotification.component';
|
||||||
import { DiscordComponent } from './notifications/discord.component';
|
import { DiscordComponent } from './notifications/discord.component';
|
||||||
import { SlackComponent } from './notifications/slack.component';
|
import { SlackComponent } from './notifications/slack.component';
|
||||||
|
import { PushoverComponent } from './notifications/pushover.component';
|
||||||
|
import { PushbulletComponent } from './notifications/pushbullet.component';
|
||||||
|
import { MattermostComponent } from './notifications/mattermost.component';
|
||||||
import { NotificationTemplate } from './notifications/notificationtemplate.component';
|
import { NotificationTemplate } from './notifications/notificationtemplate.component';
|
||||||
|
|
||||||
import { SettingsMenuComponent } from './settingsmenu.component';
|
import { SettingsMenuComponent } from './settingsmenu.component';
|
||||||
|
@ -40,6 +43,9 @@ const routes: Routes = [
|
||||||
{ path: 'Settings/Email', component: EmailNotificationComponent, canActivate: [AuthGuard] },
|
{ path: 'Settings/Email', component: EmailNotificationComponent, canActivate: [AuthGuard] },
|
||||||
{ path: 'Settings/Discord', component: DiscordComponent, canActivate: [AuthGuard] },
|
{ path: 'Settings/Discord', component: DiscordComponent, canActivate: [AuthGuard] },
|
||||||
{ path: 'Settings/Slack', component: SlackComponent, canActivate: [AuthGuard] },
|
{ path: 'Settings/Slack', component: SlackComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'Settings/Pushover', component: PushoverComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'Settings/Pushbullet', component: PushbulletComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'Settings/Mattermost', component: MattermostComponent, canActivate: [AuthGuard] },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -72,6 +78,9 @@ const routes: Routes = [
|
||||||
EmailNotificationComponent,
|
EmailNotificationComponent,
|
||||||
HumanizePipe,
|
HumanizePipe,
|
||||||
NotificationTemplate,
|
NotificationTemplate,
|
||||||
|
PushoverComponent,
|
||||||
|
MattermostComponent,
|
||||||
|
PushbulletComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
RouterModule
|
RouterModule
|
||||||
|
|
|
@ -47,7 +47,8 @@
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Discord']">Discord</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Discord']">Discord</a></li>
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Slack']">Slack</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Slack']">Slack</a></li>
|
||||||
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushbullet']">Pushbullet</a></li>
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushbullet']">Pushbullet</a></li>
|
||||||
<!--<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushover']">Pushover</a></li>-->
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Pushover']">Pushover</a></li>
|
||||||
|
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Mattermost']">Mattermost</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace Ombi.Controllers.External
|
||||||
|
|
||||||
settings.Enable = true;
|
settings.Enable = true;
|
||||||
settings.Servers = new List<PlexServers> { new PlexServers{
|
settings.Servers = new List<PlexServers> { new PlexServers{
|
||||||
PlexAuthToken = result.user.authentication_token,
|
PlexAuthToken = result.user.authentication_token,
|
||||||
Id = new Random().Next(),
|
Id = new Random().Next(),
|
||||||
Ip = servers.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
|
Ip = servers.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
|
||||||
MachineIdentifier = servers.MachineIdentifier,
|
MachineIdentifier = servers.MachineIdentifier,
|
||||||
|
@ -87,7 +87,7 @@ PlexAuthToken = result.user.authentication_token,
|
||||||
/// <param name="settings">The settings.</param>
|
/// <param name="settings">The settings.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("Libraries")]
|
[HttpPost("Libraries")]
|
||||||
public async Task<PlexLibraries> GetPlexLibraries([FromBody] PlexServers settings)
|
public async Task<PlexContainer> GetPlexLibraries([FromBody] PlexServers settings)
|
||||||
{
|
{
|
||||||
var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
|
var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@ namespace Ombi.Controllers.External
|
||||||
/// <param name="pushbullet">The pushbullet.</param>
|
/// <param name="pushbullet">The pushbullet.</param>
|
||||||
/// <param name="slack">The slack.</param>
|
/// <param name="slack">The slack.</param>
|
||||||
public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN,
|
public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN,
|
||||||
IPushbulletNotification pushbullet, ISlackNotification slack)
|
IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm)
|
||||||
{
|
{
|
||||||
Service = service;
|
Service = service;
|
||||||
DiscordNotification = notification;
|
DiscordNotification = notification;
|
||||||
EmailNotification = emailN;
|
EmailNotification = emailN;
|
||||||
PushbulletNotification = pushbullet;
|
PushbulletNotification = pushbullet;
|
||||||
SlackNotification = slack;
|
SlackNotification = slack;
|
||||||
|
PushoverNotification = po;
|
||||||
|
MattermostNotification = mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private INotificationService Service { get; }
|
private INotificationService Service { get; }
|
||||||
|
@ -41,6 +43,8 @@ namespace Ombi.Controllers.External
|
||||||
private IEmailNotification EmailNotification { get; }
|
private IEmailNotification EmailNotification { get; }
|
||||||
private IPushbulletNotification PushbulletNotification { get; }
|
private IPushbulletNotification PushbulletNotification { get; }
|
||||||
private ISlackNotification SlackNotification { get; }
|
private ISlackNotification SlackNotification { get; }
|
||||||
|
private IPushoverNotification PushoverNotification { get; }
|
||||||
|
private IMattermostNotification MattermostNotification { get; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -73,6 +77,36 @@ namespace Ombi.Controllers.External
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a test message to Pushover using the provided settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("pushover")]
|
||||||
|
public bool Pushover([FromBody] PushoverSettings settings)
|
||||||
|
{
|
||||||
|
settings.Enabled = true;
|
||||||
|
PushoverNotification.NotifyAsync(
|
||||||
|
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a test message to mattermost using the provided settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("mattermost")]
|
||||||
|
public bool Mattermost([FromBody] MattermostNotificationSettings settings)
|
||||||
|
{
|
||||||
|
settings.Enabled = true;
|
||||||
|
MattermostNotification.NotifyAsync(
|
||||||
|
new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a test message to Slack using the provided settings
|
/// Sends a test message to Slack using the provided settings
|
||||||
|
|
|
@ -89,16 +89,32 @@ namespace Ombi.Controllers
|
||||||
var result = await UserManager.CreateAsync(userToCreate, user.Password);
|
var result = await UserManager.CreateAsync(userToCreate, user.Password);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
if (!await RoleManager.RoleExistsAsync(OmbiRoles.Admin))
|
await CreateRoles();
|
||||||
{
|
|
||||||
await RoleManager.CreateAsync(new IdentityRole(OmbiRoles.Admin));
|
|
||||||
}
|
|
||||||
await UserManager.AddToRoleAsync(userToCreate, OmbiRoles.Admin);
|
await UserManager.AddToRoleAsync(userToCreate, OmbiRoles.Admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CreateRoles()
|
||||||
|
{
|
||||||
|
await CreateRole(OmbiRoles.AutoApproveMovie);
|
||||||
|
await CreateRole(OmbiRoles.Admin);
|
||||||
|
await CreateRole(OmbiRoles.AutoApproveTv);
|
||||||
|
await CreateRole(OmbiRoles.PowerUser);
|
||||||
|
await CreateRole(OmbiRoles.RequestMovie);
|
||||||
|
await CreateRole(OmbiRoles.RequestTv);
|
||||||
|
await CreateRole(OmbiRoles.Disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateRole(string role)
|
||||||
|
{
|
||||||
|
if (!await RoleManager.RoleExistsAsync(role))
|
||||||
|
{
|
||||||
|
await RoleManager.CreateAsync(new IdentityRole(role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all users.
|
/// Gets all users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue