feat(plex-watchlist): Added Plex Watchlist Requests! 🎉

This commit is contained in:
Jamie 2022-04-07 13:29:32 +01:00 committed by GitHub
commit f3c0223a0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
132 changed files with 6429 additions and 221 deletions

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.Plex.Models; using Ombi.Api.Plex.Models;
using Ombi.Api.Plex.Models.Friends; using Ombi.Api.Plex.Models.Friends;
@ -16,9 +17,9 @@ namespace Ombi.Api.Plex
Task<PlexServer> GetServer(string authToken); Task<PlexServer> GetServer(string authToken);
Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost); Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost);
Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId); Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId);
Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, int ratingKey); Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, string ratingKey);
Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId); Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId);
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey); Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey);
Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount); Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount);
Task<PlexFriends> GetUsers(string authToken); Task<PlexFriends> GetUsers(string authToken);
Task<PlexAccount> GetAccount(string authToken); Task<PlexAccount> GetAccount(string authToken);
@ -26,5 +27,7 @@ namespace Ombi.Api.Plex
Task<OAuthContainer> GetPin(int pinId); Task<OAuthContainer> GetPin(int pinId);
Task<Uri> GetOAuthUrl(string code, string applicationUrl); Task<Uri> GetOAuthUrl(string code, string applicationUrl);
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs); Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken);
Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken);
} }
} }

View file

@ -4,7 +4,7 @@ namespace Ombi.Api.Plex.Models
{ {
public class Metadata public class Metadata
{ {
public int ratingKey { get; set; } public string 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; }
@ -22,8 +22,8 @@ namespace Ombi.Api.Plex.Models
public int childCount { get; set; } public int childCount { get; set; }
public Genre[] Genre { get; set; } public Genre[] Genre { get; set; }
public string primaryExtraKey { get; set; } public string primaryExtraKey { get; set; }
public int parentRatingKey { get; set; } public string parentRatingKey { get; set; }
public int grandparentRatingKey { get; set; } public string 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; }

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlist
{
public string librarySectionID { get; set; }
public string librarySectionTitle { get; set; }
public int offset { get; set; }
public int totalSize { get; set; }
public int size { get; set; }
public List<Metadata> Metadata { get; set; } = new List<Metadata>();
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlistContainer
{
public PlexWatchlist MediaContainer { get; set; }
}
}

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace Ombi.Api.Plex.Models
{
public class PlexWatchlistMetadataContainer
{
public PlexWatchlistMetadata MediaContainer { get; set; }
}
public class PlexWatchlistMetadata
{
public int offset { get; set; }
public int totalSize { get; set; }
public string identifier { get; set; }
public int size { get; set; }
public WatchlistMetadata[] Metadata { get; set; }
}
public class WatchlistMetadata
{
public string guid { get; set; }
public string key { get; set; }
public string primaryExtraKey { get; set; }
public string ratingKey { get; set; }
public string type { get; set; }
public string slug { get; set; }
public string title { get; set; }
public List<PlexGuids> Guid { get; set; } = new List<PlexGuids>();
}
}

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ombi.Api.Plex.Models; using Ombi.Api.Plex.Models;
@ -66,6 +67,7 @@ namespace Ombi.Api.Plex
private const string FriendsUri = "https://plex.tv/pms/friends/all"; private const string FriendsUri = "https://plex.tv/pms/friends/all";
private const string GetAccountUri = "https://plex.tv/users/account.json"; private const string GetAccountUri = "https://plex.tv/users/account.json";
private const string ServerUri = "https://plex.tv/pms/servers.xml"; private const string ServerUri = "https://plex.tv/pms/servers.xml";
private const string WatchlistUri = "https://metadata.provider.plex.tv/";
/// <summary> /// <summary>
/// Sign into the Plex API /// Sign into the Plex API
@ -145,21 +147,21 @@ namespace Ombi.Api.Plex
/// <param name="authToken"></param> /// <param name="authToken"></param>
/// <param name="plexFullHost"></param> /// <param name="plexFullHost"></param>
/// <param name="ratingKey"></param> /// <param name="ratingKey"></param>
public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, int ratingKey) public async Task<PlexMetadata> GetEpisodeMetaData(string authToken, string plexFullHost, string ratingKey)
{ {
var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get); var request = new Request($"/library/metadata/{ratingKey}", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
return await Api.Request<PlexMetadata>(request); return await Api.Request<PlexMetadata>(request);
} }
public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, int itemId) public async Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId)
{ {
var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get); var request = new Request($"library/metadata/{itemId}", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
return await Api.Request<PlexMetadata>(request); return await Api.Request<PlexMetadata>(request);
} }
public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey) public async Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey)
{ {
var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get); var request = new Request($"library/metadata/{ratingKey}/children", plexFullHost, HttpMethod.Get);
await AddHeaders(request, authToken); await AddHeaders(request, authToken);
@ -288,6 +290,26 @@ namespace Ombi.Api.Plex
} }
} }
public async Task<PlexWatchlistContainer> GetWatchlist(string plexToken, CancellationToken cancellationToken)
{
var request = new Request("library/sections/watchlist/all", WatchlistUri, HttpMethod.Get);
await AddHeaders(request, plexToken);
var result = await Api.Request<PlexWatchlistContainer>(request, cancellationToken);
return result;
}
public async Task<PlexWatchlistMetadataContainer> GetWatchlistMetadata(string ratingKey, string plexToken, CancellationToken cancellationToken)
{
var request = new Request($"library/metadata/{ratingKey}", WatchlistUri, HttpMethod.Get);
await AddHeaders(request, plexToken);
var result = await Api.Request<PlexWatchlistMetadataContainer>(request, cancellationToken);
return result;
}
/// <summary> /// <summary>
/// Adds the required headers and also the authorization header /// Adds the required headers and also the authorization header

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -8,7 +8,7 @@
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<AssemblyName>Ombi.Api.Service</AssemblyName> <AssemblyName>Ombi.Api.Service</AssemblyName>
<RootNamespace>Ombi.Api.Service</RootNamespace> <RootNamespace>Ombi.Api.Service</RootNamespace>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -10,6 +10,7 @@ using Ombi.Core.Authentication;
using Ombi.Core.Engine.V2; using Ombi.Core.Engine.V2;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Engine namespace Ombi.Core.Tests.Engine
{ {
@ -25,7 +26,7 @@ namespace Ombi.Core.Tests.Engine
{ {
MovieRepo = new Mock<IMovieRequestRepository>(); MovieRepo = new Mock<IMovieRequestRepository>();
TvRepo = new Mock<ITvRequestRepository>(); TvRepo = new Mock<ITvRequestRepository>();
var principle = new Mock<IPrincipal>(); var principle = new Mock<ICurrentUser>();
var identity = new Mock<IIdentity>(); var identity = new Mock<IIdentity>();
identity.Setup(x => x.Name).Returns("UnitTest"); identity.Setup(x => x.Name).Returns("UnitTest");
principle.Setup(x => x.Identity).Returns(identity.Object); principle.Setup(x => x.Identity).Returns(identity.Object);

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
@ -35,12 +36,17 @@ namespace Ombi.Core.Tests.Engine
var identity = new Mock<IIdentity>(); var identity = new Mock<IIdentity>();
identity.Setup(x => x.Name).Returns("Test"); identity.Setup(x => x.Name).Returns("Test");
principle.Setup(x => x.Identity).Returns(identity.Object); principle.Setup(x => x.Identity).Returns(identity.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identity.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { NormalizedUserName = "TEST", Id = "a" });
_repoMock = new Mock<IMovieRequestRepository>(); _repoMock = new Mock<IMovieRequestRepository>();
var requestServiceMock = new Mock<IRequestServiceMain>(); var requestServiceMock = new Mock<IRequestServiceMain>();
requestServiceMock.Setup(x => x.MovieRequestService).Returns(_repoMock.Object); requestServiceMock.Setup(x => x.MovieRequestService).Returns(_repoMock.Object);
_mocker.Use(principle.Object); _mocker.Use(principle.Object);
_mocker.Use(currentUser.Object);
_mocker.Use(userManager.Object); _mocker.Use(userManager.Object);
_mocker.Use(requestServiceMock); _mocker.Use(requestServiceMock);

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -36,6 +37,13 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(currentUser.Object);
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -36,7 +37,12 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_mocker.Use(currentUser.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();
} }

View file

@ -4,6 +4,7 @@ using Moq.AutoMock;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Helpers; using Ombi.Helpers;
@ -33,7 +34,12 @@ namespace Ombi.Core.Tests.Engine
var identityMock = new Mock<IIdentity>(); var identityMock = new Mock<IIdentity>();
identityMock.SetupGet(x => x.Name).Returns("Test"); identityMock.SetupGet(x => x.Name).Returns("Test");
principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object);
var currentUser = new Mock<ICurrentUser>();
currentUser.Setup(x => x.Identity).Returns(identityMock.Object);
currentUser.Setup(x => x.Username).Returns("Test");
currentUser.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "Test", NormalizedUserName = "TEST", Id = "a" });
_mocker.Use(principleMock.Object); _mocker.Use(principleMock.Object);
_mocker.Use(currentUser.Object);
_subject = _mocker.CreateInstance<RequestLimitService>(); _subject = _mocker.CreateInstance<RequestLimitService>();
} }

View file

@ -7,6 +7,7 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Services; using Ombi.Core.Services;
@ -33,7 +34,7 @@ namespace Ombi.Core.Tests.Engine.V2
var requestService = new Mock<IRequestServiceMain>(); var requestService = new Mock<IRequestServiceMain>();
_movieRequestRepository = new Mock<IMovieRequestRepository>(); _movieRequestRepository = new Mock<IMovieRequestRepository>();
requestService.Setup(x => x.MovieRequestService).Returns(_movieRequestRepository.Object); requestService.Setup(x => x.MovieRequestService).Returns(_movieRequestRepository.Object);
var user = new Mock<IPrincipal>(); var user = new Mock<ICurrentUser>();
var notificationHelper = new Mock<INotificationHelper>(); var notificationHelper = new Mock<INotificationHelper>();
var rules = new Mock<IRuleEvaluator>(); var rules = new Mock<IRuleEvaluator>();
var movieSender = new Mock<IMovieSender>(); var movieSender = new Mock<IMovieSender>();

View file

@ -23,6 +23,7 @@ using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.Test.Common; using Ombi.Test.Common;
using Artist = Hqub.MusicBrainz.API.Entities.Artist; using Artist = Hqub.MusicBrainz.API.Entities.Artist;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Engine.V2 namespace Ombi.Core.Tests.Engine.V2
{ {
@ -45,7 +46,7 @@ namespace Ombi.Core.Tests.Engine.V2
.ForEach(b => F.Behaviors.Remove(b)); .ForEach(b => F.Behaviors.Remove(b));
F.Behaviors.Add(new OmitOnRecursionBehavior()); F.Behaviors.Add(new OmitOnRecursionBehavior());
var principle = new Mock<IPrincipal>(); var principle = new Mock<ICurrentUser>();
var requestService = new Mock<IRequestServiceMain>(); var requestService = new Mock<IRequestServiceMain>();
var ruleEval = new Mock<IRuleEvaluator>(); var ruleEval = new Mock<IRuleEvaluator>();
var um = MockHelper.MockUserManager(new List<OmbiUser>()); var um = MockHelper.MockUserManager(new List<OmbiUser>());

View file

@ -9,6 +9,7 @@ using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Settings; using Ombi.Core.Settings;
@ -32,8 +33,9 @@ namespace Ombi.Core.Tests.Engine
TvRequestEngine = new Mock<ITvRequestEngine>(); TvRequestEngine = new Mock<ITvRequestEngine>();
MovieRequestEngine = new Mock<IMovieRequestEngine>(); MovieRequestEngine = new Mock<IMovieRequestEngine>();
MovieRequestEngine = new Mock<IMovieRequestEngine>(); MovieRequestEngine = new Mock<IMovieRequestEngine>();
User = new Mock<IPrincipal>(); User = new Mock<ICurrentUser>();
User.Setup(x => x.Identity.Name).Returns("abc"); User.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "abc" });
UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc", NormalizedUserName = "ABC" } }); UserManager = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserName = "abc", NormalizedUserName = "ABC" } });
Rule = new Mock<IRuleEvaluator>(); Rule = new Mock<IRuleEvaluator>();
Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object, Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object,
@ -48,7 +50,7 @@ namespace Ombi.Core.Tests.Engine
public Fixture F { get; set; } public Fixture F { get; set; }
public VoteEngine Engine { get; set; } public VoteEngine Engine { get; set; }
public Mock<IPrincipal> User { get; set; } public Mock<ICurrentUser> User { get; set; }
public Mock<OmbiUserManager> UserManager { get; set; } public Mock<OmbiUserManager> UserManager { get; set; }
public Mock<IRuleEvaluator> Rule { get; set; } public Mock<IRuleEvaluator> Rule { get; set; }
public Mock<IRepository<Votes>> VoteRepository { get; set; } public Mock<IRepository<Votes>> VoteRepository { get; set; }

View file

@ -11,6 +11,7 @@ using System.Collections.Generic;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using System; using System;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Core.Helpers;
namespace Ombi.Core.Tests.Rule.Request namespace Ombi.Core.Tests.Rule.Request
{ {
@ -27,17 +28,18 @@ namespace Ombi.Core.Tests.Rule.Request
public void Setup() public void Setup()
{ {
PrincipalMock = new Mock<IPrincipal>();
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc");
FeatureService = new Mock<IFeatureService>(); FeatureService = new Mock<IFeatureService>();
PrincipalMock = new Mock<ICurrentUser>();
PrincipalMock.Setup(x => x.Username).Returns("abc");
PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "a" });
UserManager = MockHelper.MockUserManager(_users); UserManager = MockHelper.MockUserManager(_users);
Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object, FeatureService.Object); Rule = new AutoApproveRule(PrincipalMock.Object, UserManager.Object, FeatureService.Object);
} }
private AutoApproveRule Rule { get; set; } private AutoApproveRule Rule { get; set; }
private Mock<IPrincipal> PrincipalMock { get; set; } private Mock<ICurrentUser> PrincipalMock { get; set; }
private Mock<OmbiUserManager> UserManager { get; set; } private Mock<OmbiUserManager> UserManager { get; set; }
private Mock<IFeatureService> FeatureService { get; set; } private Mock<IFeatureService> FeatureService { get; set; }
@ -99,7 +101,8 @@ namespace Ombi.Core.Tests.Rule.Request
[Test] [Test]
public async Task Should_ReturnSuccess_WhenSystemUserAndRequestTV() public async Task Should_ReturnSuccess_WhenSystemUserAndRequestTV()
{ {
PrincipalMock.Setup(x => x.Identity.Name).Returns("sys"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "sys", NormalizedUserName = "SYS", Id = "a" });
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(false); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.AutoApproveTv)).ReturnsAsync(false);
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);

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Rule.Rules; using Ombi.Core.Rule.Rules;
using Ombi.Core.Rule.Rules.Request; using Ombi.Core.Rule.Rules.Request;
using Ombi.Helpers; using Ombi.Helpers;
@ -26,8 +27,9 @@ namespace Ombi.Core.Tests.Rule.Request
public void Setup() public void Setup()
{ {
PrincipalMock = new Mock<IPrincipal>(); PrincipalMock = new Mock<ICurrentUser>();
PrincipalMock.Setup(x => x.Identity.Name).Returns("abc"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "abc", NormalizedUserName = "ABC", Id = "a" });
UserManager = MockHelper.MockUserManager(_users); UserManager = MockHelper.MockUserManager(_users);
Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object); Rule = new CanRequestRule(PrincipalMock.Object, UserManager.Object);
@ -35,7 +37,7 @@ namespace Ombi.Core.Tests.Rule.Request
private CanRequestRule Rule { get; set; } private CanRequestRule Rule { get; set; }
private Mock<IPrincipal> PrincipalMock { get; set; } private Mock<ICurrentUser> PrincipalMock { get; set; }
private Mock<OmbiUserManager> UserManager { get; set; } private Mock<OmbiUserManager> UserManager { get; set; }
[Test] [Test]
@ -107,7 +109,8 @@ namespace Ombi.Core.Tests.Rule.Request
[Test] [Test]
public async Task Should_ReturnSuccess_WhenRequestingMovieWithSystemRole() public async Task Should_ReturnSuccess_WhenRequestingMovieWithSystemRole()
{ {
PrincipalMock.Setup(x => x.Identity.Name).Returns("sys"); PrincipalMock.Setup(x => x.GetUser()).ReturnsAsync(new OmbiUser { UserName = "sys", NormalizedUserName = "SYS", Id = "a" });
UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(false); UserManager.Setup(x => x.IsInRoleAsync(It.IsAny<OmbiUser>(), OmbiRoles.Admin)).ReturnsAsync(false);
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);

View file

@ -116,16 +116,25 @@ namespace Ombi.Core.Authentication
public async Task<OmbiUser> GetOmbiUserFromPlexToken(string plexToken) public async Task<OmbiUser> GetOmbiUserFromPlexToken(string plexToken)
{ {
var plexAccount = await _plexApi.GetAccount(plexToken); var plexAccount = await _plexApi.GetAccount(plexToken);
// Check for a ombi user // Check for a ombi user
if (plexAccount?.user != null) if (plexAccount?.user == null)
{ {
var potentialOmbiUser = await Users.FirstOrDefaultAsync(x => return null;
x.ProviderUserId == plexAccount.user.id);
return potentialOmbiUser;
} }
return null; var potentialOmbiUser = await Users.FirstOrDefaultAsync(x =>
x.ProviderUserId == plexAccount.user.id);
// Update ombi user with the token
if (potentialOmbiUser != null)
{
potentialOmbiUser.MediaServerToken = plexAccount.user.authentication_token;
await UpdateAsync(potentialOmbiUser);
}
return potentialOmbiUser;
} }
@ -142,6 +151,10 @@ namespace Ombi.Core.Authentication
var result = await _plexApi.SignIn(new UserRequest { password = password, login = login }); var result = await _plexApi.SignIn(new UserRequest { password = password, login = login });
if (result.user?.authentication_token != null) if (result.user?.authentication_token != null)
{ {
// Update ombi user with the token
user.MediaServerToken = result.user?.authentication_token;
await UpdateAsync(user);
return true; return true;
} }
return false; return false;

View file

@ -26,7 +26,7 @@ namespace Ombi.Core.Engine
private Dictionary<int, MovieRequests> _dbMovies; private Dictionary<int, MovieRequests> _dbMovies;
private Dictionary<int, TvRequests> _dbTv; private Dictionary<int, TvRequests> _dbTv;
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService, protected BaseMediaEngine(ICurrentUser identity, IRequestServiceMain requestService,
IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub) : base(identity, um, rules) IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub) : base(identity, um, rules)
{ {
RequestService = requestService; RequestService = requestService;

View file

@ -11,6 +11,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Config; using Ombi.Config;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine.Demo
{ {
public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine public class DemoMovieSearchEngine : MovieSearchEngine, IDemoMovieSearchEngine
{ {
public DemoMovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public DemoMovieSearchEngine(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s,
IRepository<RequestSubscription> sub, IOptions<DemoLists> lists) IRepository<RequestSubscription> sub, IOptions<DemoLists> lists)
: base(identity, service, movApi, mapper, logger, r, um, mem, s, sub) : base(identity, service, movApi, mapper, logger, r, um, mem, s, sub)

View file

@ -4,6 +4,7 @@ using Ombi.Api.Trakt;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Config; using Ombi.Config;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine.Demo
public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine public class DemoTvSearchEngine : TvSearchEngine, IDemoTvSearchEngine
{ {
public DemoTvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public DemoTvSearchEngine(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache,
ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists, IImageService imageService, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IOptions<DemoLists> lists, IImageService imageService,
ISettingsService<CustomizationSettings> custom) ISettingsService<CustomizationSettings> custom)

View file

@ -1,42 +1,35 @@
using System; using System;
using Ombi.Core.Rule; using Ombi.Core.Rule;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Helpers; using Ombi.Core.Helpers;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
public abstract class BaseEngine public abstract class BaseEngine
{ {
protected BaseEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules) protected BaseEngine(ICurrentUser user, OmbiUserManager um, IRuleEvaluator rules)
{ {
UserPrinciple = user; CurrentUser = user;
Rules = rules; Rules = rules;
UserManager = um; UserManager = um;
} }
protected IPrincipal UserPrinciple { get; } protected ICurrentUser CurrentUser { get; }
protected IRuleEvaluator Rules { get; } protected IRuleEvaluator Rules { get; }
protected OmbiUserManager UserManager { get; } protected OmbiUserManager UserManager { get; }
protected string Username => UserPrinciple.Identity.Name; protected string Username => CurrentUser.Username;
protected Task<OmbiUser> GetUser() => CurrentUser.GetUser();
private OmbiUser _user; /// <summary>
protected async Task<OmbiUser> GetUser() /// Only used for background tasks
{ /// </summary>
if(!Username.HasValue()) public void SetUser(OmbiUser user) => CurrentUser.SetUser(user);
{
return null;
}
var username = Username.ToUpper();
return _user ??= await UserManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
}
protected async Task<string> UserAlias() protected async Task<string> UserAlias()
{ {
@ -52,7 +45,7 @@ namespace Ombi.Core.Engine.Interfaces
var user = await GetUser(); var user = await GetUser();
return await UserManager.IsInRoleAsync(user, roleName); return await UserManager.IsInRoleAsync(user, roleName);
} }
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model) public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
{ {
var ruleResults = await Rules.StartRequestRules(model); var ruleResults = await Rules.StartRequestRules(model);

View file

@ -25,5 +25,6 @@ namespace Ombi.Core.Engine.Interfaces
Task UnSubscribeRequest(int requestId, RequestType type); Task UnSubscribeRequest(int requestId, RequestType type);
Task SubscribeToRequest(int requestId, RequestType type); Task SubscribeToRequest(int requestId, RequestType type);
Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken); Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken);
void SetUser(OmbiUser user);
} }
} }

View file

@ -23,12 +23,13 @@ using Ombi.Store.Repository;
using Ombi.Core.Models; using Ombi.Core.Models;
using System.Threading; using System.Threading;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MovieRequestEngine : BaseMediaEngine, IMovieRequestEngine public class MovieRequestEngine : BaseMediaEngine, IMovieRequestEngine
{ {
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log, INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService,
@ -142,7 +143,8 @@ namespace Ombi.Core.Engine
RootPathOverride = model.RootFolderOverride.GetValueOrDefault(), RootPathOverride = model.RootFolderOverride.GetValueOrDefault(),
QualityOverride = model.QualityPathOverride.GetValueOrDefault(), QualityOverride = model.QualityPathOverride.GetValueOrDefault(),
RequestedDate4k = model.Is4kRequest ? DateTime.Now : DateTime.MinValue, RequestedDate4k = model.Is4kRequest ? DateTime.Now : DateTime.MinValue,
Is4kRequest = model.Is4kRequest Is4kRequest = model.Is4kRequest,
Source = model.Source
}; };
} }

View file

@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -22,7 +23,7 @@ namespace Ombi.Core.Engine
{ {
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
{ {
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public MovieSearchEngine(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub) ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)
{ {

View file

@ -24,12 +24,13 @@ using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using System.ComponentModel; using System.ComponentModel;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine
{ {
public MusicRequestEngine(IRequestServiceMain requestService, IPrincipal user, public MusicRequestEngine(IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log, INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,

View file

@ -27,7 +27,7 @@ namespace Ombi.Core.Engine
{ {
public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine public class MusicSearchEngine : BaseMediaEngine, IMusicSearchEngine
{ {
public MusicSearchEngine(IPrincipal identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper, public MusicSearchEngine(ICurrentUser identity, IRequestServiceMain service, ILidarrApi lidarrApi, IMapper mapper,
ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, ILogger<MusicSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
ISettingsService<LidarrSettings> lidarrSettings) ISettingsService<LidarrSettings> lidarrSettings)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)

View file

@ -32,7 +32,7 @@ namespace Ombi.Core.Engine
{ {
public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine
{ {
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user, public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, ILogger<TvRequestEngine> logger, INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, ILogger<TvRequestEngine> logger,
ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache, ITvSender sender, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) : base(user, requestService, rule, manager, cache, settings, sub) IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService) : base(user, requestService, rule, manager, cache, settings, sub)
@ -188,7 +188,7 @@ namespace Ombi.Core.Engine
(await tvBuilder (await tvBuilder
.GetShowInfo(tv.TheMovieDbId, tv.languageCode)) .GetShowInfo(tv.TheMovieDbId, tv.languageCode))
.CreateTvList(tv) .CreateTvList(tv)
.CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id); .CreateChild(tv, canRequestOnBehalf ? tv.RequestOnBehalf : user.Id, tv.Source);
await tvBuilder.BuildEpisodes(tv); await tvBuilder.BuildEpisodes(tv);

View file

@ -23,6 +23,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using System.Threading; using System.Threading;
using TraktSharp.Entities; using TraktSharp.Entities;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -32,7 +33,7 @@ namespace Ombi.Core.Engine
private readonly IImageService _imageService; private readonly IImageService _imageService;
private readonly IMovieDbApi _theMovieDbApi; private readonly IMovieDbApi _theMovieDbApi;
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public TvSearchEngine(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ISettingsService<CustomizationSettings> customizationSettings, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ISettingsService<CustomizationSettings> customizationSettings,
ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IImageService imageService, ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, IImageService imageService,
IMovieDbApi theMovieDbApi) IMovieDbApi theMovieDbApi)

View file

@ -5,6 +5,7 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -17,7 +18,7 @@ namespace Ombi.Core.Engine.V2
{ {
public DateTime DaysAgo => DateTime.Now.AddDays(-90); public DateTime DaysAgo => DateTime.Now.AddDays(-90);
public DateTime DaysAhead => DateTime.Now.AddDays(90); public DateTime DaysAhead => DateTime.Now.AddDays(90);
public CalendarEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo, public CalendarEngine(ICurrentUser user, OmbiUserManager um, IRuleEvaluator rules, IMovieRequestRepository movieRepo,
ITvRequestRepository tvRequestRepo) : base(user, um, rules) ITvRequestRepository tvRequestRepo) : base(user, um, rules)
{ {
_movieRepo = movieRepo; _movieRepo = movieRepo;

View file

@ -5,6 +5,7 @@ using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
@ -28,7 +29,7 @@ namespace Ombi.Core.Engine.V2
{ {
public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2 public class MovieSearchEngineV2 : BaseMediaEngine, IMovieEngineV2
{ {
public MovieSearchEngineV2(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public MovieSearchEngineV2(ICurrentUser identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngineV2> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub, ILogger<MovieSearchEngineV2> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub,
ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine, IHttpClientFactory httpClientFactory) ISettingsService<CustomizationSettings> customizationSettings, IMovieRequestEngine movieRequestEngine, IHttpClientFactory httpClientFactory)
: base(identity, service, r, um, mem, s, sub) : base(identity, service, r, um, mem, s, sub)

View file

@ -7,6 +7,7 @@ using Ombi.Api.MusicBrainz;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -25,7 +26,7 @@ namespace Ombi.Core.Engine.V2
{ {
public class MultiSearchEngine : BaseMediaEngine, IMultiSearchEngine public class MultiSearchEngine : BaseMediaEngine, IMultiSearchEngine
{ {
public MultiSearchEngine(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules, public MultiSearchEngine(ICurrentUser identity, IRequestServiceMain requestService, IRuleEvaluator rules,
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub,
IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, IMusicBrainzApi musicApi) IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, IMusicBrainzApi musicApi)
: base(identity, requestService, rules, um, cache, ombiSettings, sub) : base(identity, requestService, rules, um, cache, ombiSettings, sub)

View file

@ -11,6 +11,7 @@ using Ombi.Api.Lidarr.Models;
using Ombi.Api.MusicBrainz; using Ombi.Api.MusicBrainz;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search.V2.Music; using Ombi.Core.Models.Search.V2.Music;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -31,7 +32,7 @@ namespace Ombi.Core.Engine.V2
private readonly ISettingsService<LidarrSettings> _lidarrSettings; private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi; private readonly ILidarrApi _lidarrApi;
public MusicSearchEngineV2(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules, public MusicSearchEngineV2(ICurrentUser identity, IRequestServiceMain requestService, IRuleEvaluator rules,
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings,
IRepository<RequestSubscription> sub, IMusicBrainzApi musicBrainzApi, ISettingsService<LidarrSettings> lidarrSettings, IRepository<RequestSubscription> sub, IMusicBrainzApi musicBrainzApi, ISettingsService<LidarrSettings> lidarrSettings,
ILidarrApi lidarrApi) ILidarrApi lidarrApi)

View file

@ -25,6 +25,7 @@ using Ombi.Api.TheMovieDb.Models;
using System.Diagnostics; using System.Diagnostics;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine.V2 namespace Ombi.Core.Engine.V2
{ {
@ -37,7 +38,7 @@ namespace Ombi.Core.Engine.V2
private readonly ISettingsService<CustomizationSettings> _customization; private readonly ISettingsService<CustomizationSettings> _customization;
private readonly ITvRequestEngine _requestEngine; private readonly ITvRequestEngine _requestEngine;
public TvSearchEngineV2(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, public TvSearchEngineV2(ICurrentUser identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper,
ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ICacheService memCache, ISettingsService<OmbiSettings> s,
IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization, ITvRequestEngine requestEngine) IRepository<RequestSubscription> sub, IMovieDbApi movieApi, ISettingsService<CustomizationSettings> customization, ITvRequestEngine requestEngine)
: base(identity, service, r, um, memCache, s, sub) : base(identity, service, r, um, memCache, s, sub)

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
@ -20,7 +21,7 @@ namespace Ombi.Core.Engine
{ {
public class VoteEngine : BaseEngine, IVoteEngine public class VoteEngine : BaseEngine, IVoteEngine
{ {
public VoteEngine(IRepository<Votes> votes, IPrincipal user, OmbiUserManager um, IRuleEvaluator r, ISettingsService<VoteSettings> voteSettings, public VoteEngine(IRepository<Votes> votes, ICurrentUser user, OmbiUserManager um, IRuleEvaluator r, ISettingsService<VoteSettings> voteSettings,
IMusicRequestEngine musicRequestEngine, ITvRequestEngine tvRequestEngine, IMovieRequestEngine movieRequestEngine) : base(user, um, r) IMusicRequestEngine musicRequestEngine, ITvRequestEngine tvRequestEngine, IMovieRequestEngine movieRequestEngine) : base(user, um, r)
{ {
_voteRepository = votes; _voteRepository = votes;

View file

@ -0,0 +1,47 @@
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
using Ombi.Helpers;
using Ombi.Store.Entities;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Ombi.Core.Helpers
{
public class CurrentUser : ICurrentUser
{
private readonly IPrincipal _principle;
private readonly OmbiUserManager _userManager;
private OmbiUser _user;
public IIdentity Identity { get; set; }
public CurrentUser(IPrincipal principle, OmbiUserManager userManager)
{
_principle = principle;
_userManager = userManager;
Identity = _principle?.Identity ?? null;
}
public void SetUser(OmbiUser user)
{
_user = user;
}
public string Username => Identity?.Name ?? _user?.UserName;
public async Task<OmbiUser> GetUser()
{
if (!Username.HasValue() && _user == null)
{
return null;
}
if (_user != null)
{
return _user;
}
var username = Username.ToUpper();
return _user ??= await _userManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
}
}
}

View file

@ -0,0 +1,15 @@
using Ombi.Store.Entities;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Ombi.Core.Helpers
{
public interface ICurrentUser
{
string Username { get; }
Task<OmbiUser> GetUser();
void SetUser(OmbiUser user);
IIdentity Identity { get; set; }
}
}

View file

@ -53,7 +53,7 @@ namespace Ombi.Core.Helpers
return this; return this;
} }
public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId) public TvShowRequestBuilderV2 CreateChild(TvRequestViewModelV2 model, string userId, RequestSource source)
{ {
var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false; var animationGenre = TheMovieDbRecord.genres?.Any(s => s.name.Equals("Animation", StringComparison.InvariantCultureIgnoreCase)) ?? false;
var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false; var animeKeyword = TheMovieDbRecord.Keywords?.KeywordsValue?.Any(s => s.Name.Equals("Anime", StringComparison.InvariantCultureIgnoreCase)) ?? false;
@ -68,7 +68,8 @@ namespace Ombi.Core.Helpers
Title = TheMovieDbRecord.name, Title = TheMovieDbRecord.name,
ReleaseYear = FirstAir, ReleaseYear = FirstAir,
RequestedByAlias = model.RequestedByAlias, RequestedByAlias = model.RequestedByAlias,
SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard SeriesType = animationGenre && animeKeyword ? SeriesType.Anime : SeriesType.Standard,
Source = source
}; };
return this; return this;

View file

@ -1,31 +1,5 @@
#region Copyright using Newtonsoft.Json;
// /************************************************************************ using Ombi.Store.Entities.Requests;
// Copyright (c) 2018 Jamie Rees
// File: MovieRequestViewModel.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.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
@ -41,5 +15,11 @@ namespace Ombi.Core.Models.Requests
/// </summary> /// </summary>
[JsonIgnore] [JsonIgnore]
public string RequestedByAlias { get; set; } public string RequestedByAlias { get; set; }
/// <summary>
/// Only set via list imports
/// </summary>
[JsonIgnore]
public RequestSource Source { get; set; } = RequestSource.Ombi;
} }
} }

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
@ -7,5 +8,6 @@ namespace Ombi.Core.Models.Requests
{ {
public int TheMovieDbId { get; set; } public int TheMovieDbId { get; set; }
public string languageCode { get; set; } = "en"; public string languageCode { get; set; } = "en";
public RequestSource Source { get; set; } = RequestSource.Ombi;
} }
} }

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -3,6 +3,7 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Services; using Ombi.Core.Services;
@ -15,20 +16,21 @@ namespace Ombi.Core.Rule.Rules.Request
{ {
public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest> public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest>
{ {
public AutoApproveRule(IPrincipal principal, OmbiUserManager um, IFeatureService featureService) public AutoApproveRule(ICurrentUser principal, OmbiUserManager um, IFeatureService featureService)
{ {
User = principal; User = principal;
_manager = um; _manager = um;
_featureService = featureService; _featureService = featureService;
} }
private IPrincipal User { get; } private ICurrentUser User { get; }
private readonly OmbiUserManager _manager; private readonly OmbiUserManager _manager;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
public async Task<RuleResult> Execute(BaseRequest obj) public async Task<RuleResult> Execute(BaseRequest obj)
{ {
var username = User.Identity.Name.ToUpper(); var currentUser = await User.GetUser();
var username = currentUser.UserName.ToUpper();
var user = await _manager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username); var user = await _manager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin) || user.IsSystemUser) if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin) || user.IsSystemUser)
{ {

View file

@ -10,23 +10,25 @@ using Ombi.Core.Engine;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Core.Helpers;
namespace Ombi.Core.Rule.Rules.Request namespace Ombi.Core.Rule.Rules.Request
{ {
public class CanRequestRule : BaseRequestRule, IRules<BaseRequest> public class CanRequestRule : BaseRequestRule, IRules<BaseRequest>
{ {
public CanRequestRule(IPrincipal principal, OmbiUserManager manager) public CanRequestRule(ICurrentUser principal, OmbiUserManager manager)
{ {
User = principal; User = principal;
_manager = manager; _manager = manager;
} }
private IPrincipal User { get; } private ICurrentUser User { get; }
private readonly OmbiUserManager _manager; private readonly OmbiUserManager _manager;
public async Task<RuleResult> Execute(BaseRequest obj) public async Task<RuleResult> Execute(BaseRequest obj)
{ {
var username = User.Identity.Name.ToUpper(); var currentUser = await User.GetUser();
var username = currentUser.UserName.ToUpper();
var user = await _manager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username); var user = await _manager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin) || user.IsSystemUser) if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin) || user.IsSystemUser)
return Success(); return Success();

View file

@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Helpers;
using Ombi.Core.Models; using Ombi.Core.Models;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -20,11 +21,11 @@ namespace Ombi.Core.Services
} }
public class RequestLimitService : IRequestLimitService public class RequestLimitService : IRequestLimitService
{ {
private readonly IPrincipal _user; private readonly ICurrentUser _user;
private readonly OmbiUserManager _userManager; private readonly OmbiUserManager _userManager;
private readonly IRepository<RequestLog> _requestLog; private readonly IRepository<RequestLog> _requestLog;
public RequestLimitService(IPrincipal user, OmbiUserManager userManager, IRepository<RequestLog> rl) public RequestLimitService(ICurrentUser user, OmbiUserManager userManager, IRepository<RequestLog> rl)
{ {
_user = user; _user = user;
_userManager = userManager; _userManager = userManager;
@ -141,7 +142,8 @@ namespace Ombi.Core.Services
private async Task<OmbiUser> GetUser() private async Task<OmbiUser> GetUser()
{ {
var username = _user.Identity.Name.ToUpper(); var currentUser = await _user.GetUser();
var username = currentUser.UserName.ToUpper();
return await _userManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username); return await _userManager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
} }

View file

@ -70,6 +70,7 @@ using Ombi.Api.RottenTomatoes;
using System.Net.Http; using System.Net.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Core.Services; using Ombi.Core.Services;
using Ombi.Core.Helpers;
namespace Ombi.DependencyInjection namespace Ombi.DependencyInjection
{ {
@ -124,6 +125,8 @@ namespace Ombi.DependencyInjection
var runtimeVersion = AssemblyHelper.GetRuntimeVersion(); var runtimeVersion = AssemblyHelper.GetRuntimeVersion();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IPrincipal>(sp => sp.GetService<IHttpContextAccessor>().HttpContext.User); services.AddScoped<IPrincipal>(sp => sp.GetService<IHttpContextAccessor>().HttpContext.User);
// HttpContext User is null for background jobs
services.AddScoped<ICurrentUser, CurrentUser>(sp => new CurrentUser(sp.GetService<IHttpContextAccessor>()?.HttpContext?.User ?? null, sp.GetService<OmbiUserManager>()));
services.AddHttpClient("OmbiClient", client => services.AddHttpClient("OmbiClient", client =>
{ {
client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{runtimeVersion} (https://ombi.io/)"); client.DefaultRequestHeaders.Add("User-Agent", $"Ombi/{runtimeVersion} (https://ombi.io/)");
@ -233,6 +236,7 @@ namespace Ombi.DependencyInjection
services.AddSingleton<IJobFactory, IoCJobFactory>(); services.AddSingleton<IJobFactory, IoCJobFactory>();
services.AddTransient<IPlexContentSync, PlexContentSync>(); services.AddTransient<IPlexContentSync, PlexContentSync>();
services.AddTransient<IPlexWatchlistImport, PlexWatchlistImport>();
services.AddTransient<IEmbyContentSync, EmbyContentSync>(); services.AddTransient<IEmbyContentSync, EmbyContentSync>();
services.AddTransient<IEmbyEpisodeSync, EmbyEpisodeSync>(); services.AddTransient<IEmbyEpisodeSync, EmbyEpisodeSync>();
services.AddTransient<IEmbyAvaliabilityChecker, EmbyAvaliabilityChecker>(); services.AddTransient<IEmbyAvaliabilityChecker, EmbyAvaliabilityChecker>();

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -104,7 +104,7 @@ namespace Ombi.Helpers
return new ProviderId(); return new ProviderId();
} }
public static string GetPlexMediaUrl(string machineId, int mediaId, string plexHost) public static string GetPlexMediaUrl(string machineId, string mediaId, string plexHost)
{ {
var url = var url =
$"web/#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}"; $"web/#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}";

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -19,6 +19,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" /> <ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />
<ProjectReference Include="..\Ombi.Test.Common\Ombi.Test.Common.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -47,7 +47,7 @@ namespace Ombi.Schedule.Tests
} }
}; };
var contentToAdd = new HashSet<PlexServerContent>(); var contentToAdd = new HashSet<PlexServerContent>();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
_mocker.Setup<IPlexContentRepository>(x => _mocker.Setup<IPlexContentRepository>(x =>
x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>())) x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>()))
.Returns(Task.FromResult(new PlexServerContent())); .Returns(Task.FromResult(new PlexServerContent()));
@ -76,18 +76,18 @@ namespace Ombi.Schedule.Tests
Id = "imdb://tt0322259" Id = "imdb://tt0322259"
} }
}, },
ratingKey = 1 ratingKey = "1"
}, },
} }
}; };
var contentToAdd = new HashSet<PlexServerContent>(); var contentToAdd = new HashSet<PlexServerContent>();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
await _subject.MovieLoop(new PlexServers(), content, contentToAdd, contentProcessed); await _subject.MovieLoop(new PlexServers(), content, contentToAdd, contentProcessed);
var first = contentToAdd.First(); var first = contentToAdd.First();
Assert.That(first.ImdbId, Is.EqualTo("tt0322259")); Assert.That(first.ImdbId, Is.EqualTo("tt0322259"));
_mocker.Verify<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(),It.IsAny<int>()), Times.Never); _mocker.Verify<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(),It.IsAny<string>()), Times.Never);
} }
[Test] [Test]
@ -99,7 +99,7 @@ namespace Ombi.Schedule.Tests
{ {
new Metadata new Metadata
{ {
ratingKey = 11, ratingKey = "11",
title = "test1", title = "test1",
year = 2021, year = 2021,
type = "movie", type = "movie",
@ -107,8 +107,8 @@ namespace Ombi.Schedule.Tests
} }
}; };
var contentToAdd = new HashSet<PlexServerContent>(); var contentToAdd = new HashSet<PlexServerContent>();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
_mocker.Setup<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>())) _mocker.Setup<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(Task.FromResult(new PlexMetadata .Returns(Task.FromResult(new PlexMetadata
{ {
MediaContainer = new Mediacontainer MediaContainer = new Mediacontainer
@ -117,7 +117,7 @@ namespace Ombi.Schedule.Tests
{ {
new Metadata new Metadata
{ {
ratingKey = 11, ratingKey = "11",
title = "test1", title = "test1",
year = 2021, year = 2021,
type = "movie", type = "movie",
@ -138,7 +138,7 @@ namespace Ombi.Schedule.Tests
var first = contentToAdd.First(); var first = contentToAdd.First();
Assert.That(first.ImdbId, Is.EqualTo("tt0322259")); Assert.That(first.ImdbId, Is.EqualTo("tt0322259"));
_mocker.Verify<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Once); _mocker.Verify<IPlexApi>(x => x.GetMetadata(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once);
} }
[Test] [Test]
@ -150,7 +150,7 @@ namespace Ombi.Schedule.Tests
{ {
new Metadata new Metadata
{ {
ratingKey = 11, ratingKey = "11",
title = "test1", title = "test1",
year = 2021, year = 2021,
type = "movie", type = "movie",
@ -165,7 +165,7 @@ namespace Ombi.Schedule.Tests
} }
}; };
var contentToAdd = new HashSet<PlexServerContent>(); var contentToAdd = new HashSet<PlexServerContent>();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
_mocker.Setup<IPlexContentRepository>(x => _mocker.Setup<IPlexContentRepository>(x =>
x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>())) x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>()))
.Returns(Task.FromResult(new PlexServerContent .Returns(Task.FromResult(new PlexServerContent
@ -188,7 +188,7 @@ namespace Ombi.Schedule.Tests
{ {
new Metadata new Metadata
{ {
ratingKey = 11, ratingKey = "11",
title = "test1", title = "test1",
year = 2021, year = 2021,
type = "movie", type = "movie",
@ -203,7 +203,7 @@ namespace Ombi.Schedule.Tests
} }
}; };
var contentToAdd = new HashSet<PlexServerContent>(); var contentToAdd = new HashSet<PlexServerContent>();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
_mocker.Setup<IPlexContentRepository>(x => _mocker.Setup<IPlexContentRepository>(x =>
x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>())) x.GetFirstContentByCustom(It.IsAny<Expression<Func<PlexServerContent, bool>>>()))
.Returns(Task.FromResult(new PlexServerContent .Returns(Task.FromResult(new PlexServerContent

View file

@ -0,0 +1,375 @@
using Moq;
using Moq.AutoMock;
using NUnit.Framework;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Requests;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Schedule.Jobs.Plex;
using Ombi.Store.Entities;
using Ombi.Test.Common;
using Quartz;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Schedule.Tests
{
[TestFixture]
public class PlexWatchlistImportTests
{
private PlexWatchlistImport _subject;
private AutoMocker _mocker;
private Mock<IJobExecutionContext> _context;
[SetUp]
public void Setup()
{
_mocker = new AutoMocker();
var um = MockHelper.MockUserManager(new List<OmbiUser> { new OmbiUser { Id = "abc", UserType = UserType.PlexUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" } });
_mocker.Use(um);
_context = _mocker.GetMock<IJobExecutionContext>();
_context.Setup(x => x.CancellationToken).Returns(CancellationToken.None);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
}
[Test]
public async Task TerminatesWhenPlexIsNotEnabled()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = false, EnableWatchlistImport = true });
await _subject.Execute(null);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
}
[Test]
public async Task TerminatesWhenWatchlistIsNotEnabled()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = false });
await _subject.Execute(null);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
}
[Test]
public async Task EmptyWatchList()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer());
await _subject.Execute(_context.Object);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
}
[Test]
public async Task NoPlexUsersWithToken()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
var um = MockHelper.MockUserManager(new List<OmbiUser>
{
new OmbiUser { Id = "abc", UserType = UserType.EmbyUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" },
new OmbiUser { Id = "abc", UserType = UserType.LocalUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" },
new OmbiUser { Id = "abc", UserType = UserType.SystemUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" },
new OmbiUser { Id = "abc", UserType = UserType.JellyfinUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" },
new OmbiUser { Id = "abc", UserType = UserType.EmbyConnectUser, MediaServerToken = "abc", UserName = "abc", NormalizedUserName = "ABC" },
new OmbiUser { Id = "abc", UserType = UserType.PlexUser, UserName = "abc", NormalizedUserName = "ABC" },
});
_mocker.Use(um);
_subject = _mocker.CreateInstance<PlexWatchlistImport>();
await _subject.Execute(_context.Object);
_mocker.Verify<IPlexApi>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
}
[Test]
public async Task MovieRequestFromWatchList_NoGuid()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "movie",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "tmdb://123"
}
}
}
}
}
});
_mocker.Setup<IMovieRequestEngine, Task<RequestEngineResult>>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()))
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
await _subject.Execute(_context.Object);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.Is<MovieRequestViewModel>(x => x.TheMovieDbId == 123)), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
}
[Test]
public async Task TvRequestFromWatchList_NoGuid()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "show",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "tmdb://123"
}
}
}
}
}
});
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
await _subject.Execute(_context.Object);
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.Is<TvRequestViewModelV2>(x => x.TheMovieDbId == 123)), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
}
[Test]
public async Task MovieRequestFromWatchList_AlreadyRequested()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "movie",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "tmdb://123"
}
}
}
}
}
});
_mocker.Setup<IMovieRequestEngine, Task<RequestEngineResult>>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()))
.ReturnsAsync(new RequestEngineResult { ErrorCode = ErrorCode.AlreadyRequested, ErrorMessage = "Requested" });
await _subject.Execute(_context.Object);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.Is<MovieRequestViewModel>(x => x.TheMovieDbId == 123)), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
}
[Test]
public async Task TvRequestFromWatchList_AlreadyRequested()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "show",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "tmdb://123"
}
}
}
}
}
});
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
.ReturnsAsync(new RequestEngineResult { ErrorCode = ErrorCode.AlreadyRequested, ErrorMessage = "Requested" });
await _subject.Execute(_context.Object);
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.Is<TvRequestViewModelV2>(x => x.TheMovieDbId == 123)), Times.Once);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Once);
}
[Test]
public async Task MovieRequestFromWatchList_NoTmdbGuid()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "movie",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "imdb://123"
}
}
}
}
}
});
_mocker.Setup<IMovieRequestEngine, Task<RequestEngineResult>>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()))
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
await _subject.Execute(_context.Object);
_mocker.Verify<IMovieRequestEngine>(x => x.RequestMovie(It.IsAny<MovieRequestViewModel>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<IMovieRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Never);
}
[Test]
public async Task TvRequestFromWatchList_NoTmdbGuid()
{
_mocker.Setup<ISettingsService<PlexSettings>, Task<PlexSettings>>(x => x.GetSettingsAsync()).ReturnsAsync(new PlexSettings { Enable = true, EnableWatchlistImport = true });
_mocker.Setup<IPlexApi, Task<PlexWatchlistContainer>>(x => x.GetWatchlist(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(new PlexWatchlistContainer
{
MediaContainer = new PlexWatchlist
{
Metadata = new List<Metadata>
{
new Metadata
{
type = "movie",
ratingKey = "abc"
}
}
}
});
_mocker.Setup<IPlexApi, Task<PlexWatchlistMetadataContainer>>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new PlexWatchlistMetadataContainer
{
MediaContainer = new PlexWatchlistMetadata
{
Metadata = new WatchlistMetadata[]
{
new WatchlistMetadata
{
Guid = new List<PlexGuids>
{
new PlexGuids
{
Id = "imdb://123"
}
}
}
}
}
});
_mocker.Setup<ITvRequestEngine, Task<RequestEngineResult>>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()))
.ReturnsAsync(new RequestEngineResult { RequestId = 1 });
await _subject.Execute(_context.Object);
_mocker.Verify<ITvRequestEngine>(x => x.RequestTvShow(It.IsAny<TvRequestViewModelV2>()), Times.Never);
_mocker.Verify<IPlexApi>(x => x.GetWatchlistMetadata("abc", It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
_mocker.Verify<ITvRequestEngine>(x => x.SetUser(It.Is<OmbiUser>(x => x.Id == "abc")), Times.Never);
}
}
}

View file

@ -0,0 +1,6 @@
namespace Ombi.Schedule.Jobs.Plex
{
public interface IPlexWatchlistImport : IBaseJob
{
}
}

View file

@ -5,7 +5,7 @@ namespace Ombi.Schedule.Jobs.Plex.Models
{ {
public class ProcessedContent public class ProcessedContent
{ {
public IEnumerable<int> Content { get; set; } public IEnumerable<string> Content { get; set; }
public IEnumerable<int> Episodes { get; set; } public IEnumerable<int> Episodes { get; set; }
public bool HasProcessedContent => Content?.Any() ?? false; public bool HasProcessedContent => Content?.Any() ?? false;

View file

@ -167,7 +167,7 @@ namespace Ombi.Schedule.Jobs.Plex
private async Task<ProcessedContent> ProcessServer(PlexServers servers, bool recentlyAddedSearch) private async Task<ProcessedContent> ProcessServer(PlexServers servers, bool recentlyAddedSearch)
{ {
var retVal = new ProcessedContent(); var retVal = new ProcessedContent();
var contentProcessed = new Dictionary<int, int>(); var contentProcessed = new Dictionary<int, string>();
var episodesProcessed = new List<int>(); var episodesProcessed = new List<int>();
Logger.LogDebug("Getting all content from server {0}", servers.Name); Logger.LogDebug("Getting all content from server {0}", servers.Name);
var allContent = await GetAllContent(servers, recentlyAddedSearch); var allContent = await GetAllContent(servers, recentlyAddedSearch);
@ -290,7 +290,7 @@ namespace Ombi.Schedule.Jobs.Plex
} }
public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet<PlexServerContent> contentToAdd, public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet<PlexServerContent> contentToAdd,
Dictionary<int, int> contentProcessed) Dictionary<int, string> contentProcessed)
{ {
Logger.LogDebug("Processing Movies"); Logger.LogDebug("Processing Movies");
foreach (var movie in content?.Metadata ?? Array.Empty<Metadata>()) foreach (var movie in content?.Metadata ?? Array.Empty<Metadata>())
@ -437,7 +437,7 @@ namespace Ombi.Schedule.Jobs.Plex
} }
} }
private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet<PlexServerContent> contentToAdd, Dictionary<int, int> contentProcessed) private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet<PlexServerContent> contentToAdd, Dictionary<int, string> contentProcessed)
{ {
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri, var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
show.ratingKey); show.ratingKey);

View file

@ -0,0 +1,149 @@
using Microsoft.Extensions.Logging;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Core.Authentication;
using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Requests;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Quartz;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Schedule.Jobs.Plex
{
public class PlexWatchlistImport : IPlexWatchlistImport
{
private readonly IPlexApi _plexApi;
private readonly ISettingsService<PlexSettings> _settings;
private readonly OmbiUserManager _ombiUserManager;
private readonly IMovieRequestEngine _movieRequestEngine;
private readonly ITvRequestEngine _tvRequestEngine;
private readonly ILogger _logger;
public PlexWatchlistImport(IPlexApi plexApi, ISettingsService<PlexSettings> settings, OmbiUserManager ombiUserManager,
IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine,
ILogger<PlexWatchlistImport> logger)
{
_plexApi = plexApi;
_settings = settings;
_ombiUserManager = ombiUserManager;
_movieRequestEngine = movieRequestEngine;
_tvRequestEngine = tvRequestEngine;
_logger = logger;
}
public async Task Execute(IJobExecutionContext context)
{
var settings = await _settings.GetSettingsAsync();
if (!settings.Enable || !settings.EnableWatchlistImport)
{
return;
}
var plexUsersWithTokens = _ombiUserManager.Users.Where(x => x.UserType == UserType.PlexUser && x.MediaServerToken != null).ToList();
foreach (var user in plexUsersWithTokens)
{
var watchlist = await _plexApi.GetWatchlist(user.MediaServerToken, context?.CancellationToken ?? CancellationToken.None);
if (watchlist == null || !(watchlist.MediaContainer?.Metadata?.Any() ?? false))
{
return;
}
var items = watchlist.MediaContainer.Metadata;
foreach (var item in items)
{
var providerIds = await GetProviderIds(user.MediaServerToken, item, context?.CancellationToken ?? CancellationToken.None);
if (!providerIds.TheMovieDb.HasValue())
{
// We need a MovieDbId to support this;
return;
}
switch (item.type)
{
case "show":
await ProcessShow(int.Parse(providerIds.TheMovieDb), user, context?.CancellationToken ?? CancellationToken.None);
break;
case "movie":
await ProcessMovie(int.Parse(providerIds.TheMovieDb), user, context?.CancellationToken ?? CancellationToken.None);
break;
}
}
}
}
private async Task ProcessMovie(int theMovieDbId, OmbiUser user, CancellationToken cancellationToken)
{
_movieRequestEngine.SetUser(user);
var response = await _movieRequestEngine.RequestMovie(new() { TheMovieDbId = theMovieDbId, Source = RequestSource.PlexWatchlist});
if (response.IsError)
{
if (response.ErrorCode == ErrorCode.AlreadyRequested)
{
return;
}
_logger.LogInformation($"Error adding title from PlexWatchlist for user '{user.UserName}'. Message: '{response.ErrorMessage}'");
}
else
{
_logger.LogInformation($"Added title from PlexWatchlist for user '{user.UserName}'. {response.Message}");
}
}
private async Task ProcessShow(int theMovieDbId, OmbiUser user, CancellationToken cancellationToken)
{
_tvRequestEngine.SetUser(user);
var response = await _tvRequestEngine.RequestTvShow(new TvRequestViewModelV2 { RequestAll = true, TheMovieDbId = theMovieDbId, Source = RequestSource.PlexWatchlist });
if (response.IsError)
{
if (response.ErrorCode == ErrorCode.AlreadyRequested)
{
return;
}
_logger.LogInformation($"Error adding title from PlexWatchlist for user '{user.UserName}'. Message: '{response.ErrorMessage}'");
}
else
{
_logger.LogInformation($"Added title from PlexWatchlist for user '{user.UserName}'. {response.Message}");
}
}
private async Task<ProviderId> GetProviderIds(string authToken, Metadata movie, CancellationToken cancellationToken)
{
var guids = new List<string>();
if (!movie.Guid.Any())
{
var metaData = await _plexApi.GetWatchlistMetadata(movie.ratingKey, authToken, cancellationToken);
var meta = metaData.MediaContainer.Metadata.FirstOrDefault();
guids.Add(meta.guid);
if (meta.Guid != null)
{
foreach (var g in meta.Guid)
{
guids.Add(g.Id);
}
}
}
else
{
// Currently a Plex Pass feature only
foreach (var g in movie.Guid)
{
guids.Add(g.Id);
}
}
var providerIds = PlexHelper.GetProviderIdsFromMetadata(guids.ToArray());
return providerIds;
}
public void Dispose() { }
}
}

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -91,6 +91,7 @@ namespace Ombi.Schedule
await OmbiQuartz.Instance.AddJob<IPlexUserImporter>(nameof(IPlexUserImporter), "Plex", JobSettingsHelper.UserImporter(s)); await OmbiQuartz.Instance.AddJob<IPlexUserImporter>(nameof(IPlexUserImporter), "Plex", JobSettingsHelper.UserImporter(s));
await OmbiQuartz.Instance.AddJob<IPlexEpisodeSync>(nameof(IPlexEpisodeSync), "Plex", null); await OmbiQuartz.Instance.AddJob<IPlexEpisodeSync>(nameof(IPlexEpisodeSync), "Plex", null);
await OmbiQuartz.Instance.AddJob<IPlexAvailabilityChecker>(nameof(IPlexAvailabilityChecker), "Plex", null); await OmbiQuartz.Instance.AddJob<IPlexAvailabilityChecker>(nameof(IPlexAvailabilityChecker), "Plex", null);
await OmbiQuartz.Instance.AddJob<IPlexWatchlistImport>(nameof(IPlexWatchlistImport), "Plex", JobSettingsHelper.PlexWatchlistImport(s));
} }
private static async Task AddEmby(JobSettings s) private static async Task AddEmby(JobSettings s)

View file

@ -6,7 +6,7 @@
<FileVersion>3.0.0.0</FileVersion> <FileVersion>3.0.0.0</FileVersion>
<Version></Version> <Version></Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<LangVersion>8.0</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;NonUiBuild</Configurations> <Configurations>Debug;Release;NonUiBuild</Configurations>
</PropertyGroup> </PropertyGroup>

View file

@ -7,6 +7,7 @@ namespace Ombi.Core.Settings.Models.External
public sealed class PlexSettings : Ombi.Settings.Settings.Models.Settings public sealed class PlexSettings : Ombi.Settings.Settings.Models.Settings
{ {
public bool Enable { get; set; } public bool Enable { get; set; }
public bool EnableWatchlistImport { get; set; }
/// <summary> /// <summary>
/// This is the ClientId for OAuth /// This is the ClientId for OAuth
/// </summary> /// </summary>

View file

@ -19,5 +19,6 @@
public string RetryRequests { get; set; } public string RetryRequests { get; set; }
public string MediaDatabaseRefresh { get; set; } public string MediaDatabaseRefresh { get; set; }
public string AutoDeleteRequests { get; set; } public string AutoDeleteRequests { get; set; }
public string PlexWatchlistImport { get; set; }
} }
} }

View file

@ -54,6 +54,11 @@ namespace Ombi.Settings.Settings.Models
{ {
return ValidateCron(Get(s.UserImporter, Cron.Daily())); return ValidateCron(Get(s.UserImporter, Cron.Daily()));
} }
public static string PlexWatchlistImport(JobSettings s)
{
return ValidateCron(Get(s.PlexWatchlistImport, Cron.Daily()));
}
public static string Newsletter(JobSettings s) public static string Newsletter(JobSettings s)
{ {

View file

@ -36,6 +36,7 @@ namespace Ombi.Store.Entities
public RequestLimitType? MusicRequestLimitType { get; set; } public RequestLimitType? MusicRequestLimitType { get; set; }
public string UserAccessToken { get; set; } public string UserAccessToken { get; set; }
public string MediaServerToken { get; set; }
public List<NotificationUserId> NotificationUserIds { get; set; } public List<NotificationUserId> NotificationUserIds { get; set; }
public List<UserNotificationPreferences> UserNotificationPreferences { get; set; } public List<UserNotificationPreferences> UserNotificationPreferences { get; set; }

View file

@ -7,15 +7,15 @@ namespace Ombi.Store.Entities
[Table("PlexEpisode")] [Table("PlexEpisode")]
public class PlexEpisode : MediaServerEpisode public class PlexEpisode : MediaServerEpisode
{ {
public int Key { get; set; } // RatingKey public string Key { get; set; } // RatingKey
/// <value> /// <value>
/// The parent key. /// The parent key.
/// </value> /// </value>
public int ParentKey { get; set; } public string ParentKey { get; set; }
/// <value> /// <value>
/// The grandparent key. /// The grandparent key.
/// </value> /// </value>
public int GrandparentKey { get; set; } public string GrandparentKey { get; set; }
[NotMapped] [NotMapped]
public PlexServerContent PlexSeries public PlexServerContent PlexSeries
{ {

View file

@ -40,7 +40,7 @@ namespace Ombi.Store.Entities
/// <summary> /// <summary>
/// Plex's internal ID for this item /// Plex's internal ID for this item
/// </summary> /// </summary>
public int Key { get; set; } public string Key { get; set; }
public int? RequestId { get; set; } public int? RequestId { get; set; }
@ -50,9 +50,9 @@ namespace Ombi.Store.Entities
[Table("PlexSeasonsContent")] [Table("PlexSeasonsContent")]
public class PlexSeasonsContent : Entity public class PlexSeasonsContent : Entity
{ {
public int PlexContentId { get; set; } public string PlexContentId { get; set; }
public int SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public int SeasonKey { get; set; } public string SeasonKey { get; set; }
public int ParentKey { get; set; } public string ParentKey { get; set; }
} }
} }

View file

@ -22,6 +22,8 @@ namespace Ombi.Store.Entities.Requests
[ForeignKey(nameof(RequestedUserId))] [ForeignKey(nameof(RequestedUserId))]
public OmbiUser RequestedUser { get; set; } public OmbiUser RequestedUser { get; set; }
public RequestSource Source { get; set; } = RequestSource.Ombi;
[NotMapped] [NotMapped]
public virtual bool CanApprove => !Approved && !Available; public virtual bool CanApprove => !Approved && !Available;

View file

@ -0,0 +1,8 @@
namespace Ombi.Store.Entities.Requests
{
public enum RequestSource
{
Ombi = 0,
PlexWatchlist = 1
}
}

View file

@ -0,0 +1,535 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ombi.Store.Context.MySql;
#nullable disable
namespace Ombi.Store.Migrations.ExternalMySql
{
[DbContext(typeof(ExternalMySqlContext))]
[Migration("20220407114744_PlexIds")]
partial class PlexIds
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "6.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("EmbyId")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<string>("EmbyId")
.HasColumnType("longtext");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("ParentId")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("JellyfinId")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("JellyfinContent");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("JellyfinId")
.HasColumnType("longtext");
b.Property<string>("ParentId")
.HasColumnType("varchar(255)");
b.Property<string>("ProviderId")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("JellyfinEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrAlbumCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<int>("ArtistId")
.HasColumnType("int");
b.Property<string>("ForeignAlbumId")
.HasColumnType("longtext");
b.Property<bool>("Monitored")
.HasColumnType("tinyint(1)");
b.Property<decimal>("PercentOfTracks")
.HasColumnType("decimal(65,30)");
b.Property<DateTime>("ReleaseDate")
.HasColumnType("datetime(6)");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<int>("TrackCount")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("LidarrAlbumCache");
});
modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("ArtistId")
.HasColumnType("int");
b.Property<string>("ArtistName")
.HasColumnType("longtext");
b.Property<string>("ForeignArtistId")
.HasColumnType("longtext");
b.Property<bool>("Monitored")
.HasColumnType("tinyint(1)");
b.HasKey("Id");
b.ToTable("LidarrArtistCache");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<string>("GrandparentKey")
.HasColumnType("varchar(255)");
b.Property<string>("Key")
.HasColumnType("longtext");
b.Property<string>("ParentKey")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<string>("Title")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("ParentKey")
.HasColumnType("longtext");
b.Property<string>("PlexContentId")
.HasColumnType("longtext");
b.Property<int?>("PlexServerContentId")
.HasColumnType("int");
b.Property<string>("SeasonKey")
.HasColumnType("longtext");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("Quality")
.HasColumnType("longtext");
b.Property<string>("ReleaseYear")
.HasColumnType("longtext");
b.Property<int?>("RequestId")
.HasColumnType("int");
b.Property<string>("TheMovieDbId")
.HasColumnType("longtext");
b.Property<string>("Title")
.HasColumnType("longtext");
b.Property<string>("TvDbId")
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Url")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<bool>("Has4K")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasFile")
.HasColumnType("tinyint(1)");
b.Property<bool>("HasRegular")
.HasColumnType("tinyint(1)");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("TheMovieDbId")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("EpisodeNumber")
.HasColumnType("int");
b.Property<bool>("HasFile")
.HasColumnType("tinyint(1)");
b.Property<int>("MovieDbId")
.HasColumnType("int");
b.Property<int>("SeasonNumber")
.HasColumnType("int");
b.Property<int>("TvDbId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("EmbyId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.JellyfinContent", "Series")
.WithMany("Episodes")
.HasForeignKey("ParentId")
.HasPrincipalKey("JellyfinId");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes")
.HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key");
b.Navigation("Series");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.HasOne("Ombi.Store.Entities.PlexServerContent", null)
.WithMany("Seasons")
.HasForeignKey("PlexServerContentId");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.JellyfinContent", b =>
{
b.Navigation("Episodes");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Navigation("Episodes");
b.Navigation("Seasons");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,176 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.ExternalMySql
{
public partial class PlexIds : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PlexEpisode_PlexServerContent_GrandparentKey",
table: "PlexEpisode");
migrationBuilder.AlterColumn<string>(
name: "Key",
table: "PlexServerContent",
type: "varchar(255)",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "SeasonKey",
table: "PlexSeasonsContent",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "PlexContentId",
table: "PlexSeasonsContent",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "ParentKey",
table: "PlexSeasonsContent",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "ParentKey",
table: "PlexEpisode",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "Key",
table: "PlexEpisode",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
name: "GrandparentKey",
table: "PlexEpisode",
type: "varchar(255)",
nullable: true,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddForeignKey(
name: "FK_PlexEpisode_PlexServerContent_GrandparentKey",
table: "PlexEpisode",
column: "GrandparentKey",
principalTable: "PlexServerContent",
principalColumn: "Key");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PlexEpisode_PlexServerContent_GrandparentKey",
table: "PlexEpisode");
migrationBuilder.AlterColumn<int>(
name: "Key",
table: "PlexServerContent",
type: "int",
nullable: false,
oldClrType: typeof(string),
oldType: "varchar(255)")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "SeasonKey",
table: "PlexSeasonsContent",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "PlexContentId",
table: "PlexSeasonsContent",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "ParentKey",
table: "PlexSeasonsContent",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "ParentKey",
table: "PlexEpisode",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "Key",
table: "PlexEpisode",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
name: "GrandparentKey",
table: "PlexEpisode",
type: "int",
nullable: false,
defaultValue: 0,
oldClrType: typeof(string),
oldType: "varchar(255)",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddForeignKey(
name: "FK_PlexEpisode_PlexServerContent_GrandparentKey",
table: "PlexEpisode",
column: "GrandparentKey",
principalTable: "PlexServerContent",
principalColumn: "Key",
onDelete: ReferentialAction.Cascade);
}
}
}

View file

@ -276,14 +276,14 @@ namespace Ombi.Store.Migrations.ExternalMySql
b.Property<int>("EpisodeNumber") b.Property<int>("EpisodeNumber")
.HasColumnType("int"); .HasColumnType("int");
b.Property<int>("GrandparentKey") b.Property<string>("GrandparentKey")
.HasColumnType("int"); .HasColumnType("varchar(255)");
b.Property<int>("Key") b.Property<string>("Key")
.HasColumnType("int"); .HasColumnType("longtext");
b.Property<int>("ParentKey") b.Property<string>("ParentKey")
.HasColumnType("int"); .HasColumnType("longtext");
b.Property<int>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("int"); .HasColumnType("int");
@ -304,17 +304,17 @@ namespace Ombi.Store.Migrations.ExternalMySql
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("int"); .HasColumnType("int");
b.Property<int>("ParentKey") b.Property<string>("ParentKey")
.HasColumnType("int"); .HasColumnType("longtext");
b.Property<int>("PlexContentId") b.Property<string>("PlexContentId")
.HasColumnType("int"); .HasColumnType("longtext");
b.Property<int?>("PlexServerContentId") b.Property<int?>("PlexServerContentId")
.HasColumnType("int"); .HasColumnType("int");
b.Property<int>("SeasonKey") b.Property<string>("SeasonKey")
.HasColumnType("int"); .HasColumnType("longtext");
b.Property<int>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("int"); .HasColumnType("int");
@ -341,8 +341,9 @@ namespace Ombi.Store.Migrations.ExternalMySql
b.Property<string>("ImdbId") b.Property<string>("ImdbId")
.HasColumnType("longtext"); .HasColumnType("longtext");
b.Property<int>("Key") b.Property<string>("Key")
.HasColumnType("int"); .IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("Quality") b.Property<string>("Quality")
.HasColumnType("longtext"); .HasColumnType("longtext");
@ -498,9 +499,7 @@ namespace Ombi.Store.Migrations.ExternalMySql
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
.WithMany("Episodes") .WithMany("Episodes")
.HasForeignKey("GrandparentKey") .HasForeignKey("GrandparentKey")
.HasPrincipalKey("Key") .HasPrincipalKey("Key");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Series"); b.Navigation("Series");
}); });

Some files were not shown because too many files have changed in this diff Show more