#865 rework the backend data. Actually use real models rather than a JSON store.

pull/1488/head
Jamie.Rees 7 years ago
parent 08e389f590
commit 2bc916998c

@ -0,0 +1,46 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceRoot}/Ombi/bin/Debug/netcoreapp1.1/Ombi.dll",
"args": [],
"cwd": "${workspaceRoot}/Ombi",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart",
"launchBrowser": {
"enabled": true,
"args": "${auto-detect-url}",
"windows": {
"command": "cmd.exe",
"args": "/C start ${auto-detect-url}"
},
"osx": {
"command": "open"
},
"linux": {
"command": "xdg-open"
}
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceRoot}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

@ -0,0 +1,16 @@
{
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [
"${workspaceRoot}/Ombi/Ombi.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
}
]
}

@ -4,10 +4,7 @@ namespace Ombi.Api.TvMaze.Models
{ {
public class TvMazeShow public class TvMazeShow
{ {
public TvMazeShow()
{
Season = new List<TvMazeCustomSeason>();
}
public int id { get; set; } public int id { get; set; }
public string url { get; set; } public string url { get; set; }
public string name { get; set; } public string name { get; set; }
@ -27,7 +24,6 @@ namespace Ombi.Api.TvMaze.Models
public string summary { get; set; } public string summary { get; set; }
public int updated { get; set; } public int updated { get; set; }
public Links _links { get; set; } public Links _links { get; set; }
public List<TvMazeCustomSeason> Season { get; set; }
public Embedded _embedded { get; set; } public Embedded _embedded { get; set; }
} }

@ -57,31 +57,6 @@ namespace Ombi.Api.TvMaze
{ {
var obj = await Api.Request<TvMazeShow>(request); var obj = await Api.Request<TvMazeShow>(request);
var episodes = await EpisodeLookup(obj.id);
foreach (var e in episodes)
{
// Check if the season exists
var currentSeason = obj.Season.FirstOrDefault(x => x.SeasonNumber == e.season);
if (currentSeason == null)
{
// Create the season
obj.Season.Add(new TvMazeCustomSeason
{
SeasonNumber = e.season,
EpisodeNumber = new List<int> {e.number}
});
}
else
{
// Just add a new episode into that season
currentSeason.EpisodeNumber.Add(e.number);
}
}
return obj; return obj;
} }
catch (Exception e) catch (Exception e)

@ -1,131 +1,131 @@
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.Threading.Tasks; //using System.Threading.Tasks;
using Moq; //using Moq;
using Ombi.Core.Engine; //using Ombi.Core.Engine;
using Ombi.Core.Models.Requests; //using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie; //using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Requests.Models; //using Ombi.Core.Requests.Models;
using Xunit; //using Xunit;
namespace Ombi.Core.Tests.Engine //namespace Ombi.Core.Tests.Engine
{ //{
public class MovieRequestEngineTests // public class MovieRequestEngineTests
{ // {
public MovieRequestEngineTests() // public MovieRequestEngineTests()
{ // {
RequestService = new Mock<IRequestService<MovieRequestModel>>(); // RequestService = new Mock<IRequestService<MovieRequestModel>>();
var requestService = new RequestService(null, RequestService.Object); // var requestService = new RequestService(null, RequestService.Object);
Engine = new MovieRequestEngine(null, requestService, null, null, null, null, null); // Engine = new MovieRequestEngine(null, requestService, null, null, null, null, null);
} // }
private MovieRequestEngine Engine { get; } // private MovieRequestEngine Engine { get; }
private Mock<IRequestService<MovieRequestModel>> RequestService { get; } // private Mock<IRequestService<MovieRequestModel>> RequestService { get; }
[Fact] // [Fact]
public async Task GetNewRequests_Should_ReturnEmpty_WhenThereAreNoNewRequests() // public async Task GetNewRequests_Should_ReturnEmpty_WhenThereAreNoNewRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Available = true }, // new MovieRequestModel { Available = true },
new MovieRequestModel { Approved = true }, // new MovieRequestModel { Approved = true },
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetNewRequests(); // var result = await Engine.GetNewRequests();
Assert.False(result.Any()); // Assert.False(result.Any());
} // }
[Fact] // [Fact]
public async Task GetNewRequests_Should_ReturnOnlyNewRequests_WhenThereAreMultipleRequests() // public async Task GetNewRequests_Should_ReturnOnlyNewRequests_WhenThereAreMultipleRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Available = true }, // new MovieRequestModel { Available = true },
new MovieRequestModel { Approved = true }, // new MovieRequestModel { Approved = true },
new MovieRequestModel(), // new MovieRequestModel(),
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetNewRequests(); // var result = await Engine.GetNewRequests();
Assert.Equal(result.Count(), 1); // Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.All(result, x =>
{ // {
Assert.Equal(x.Available, false); // Assert.Equal(x.Available, false);
Assert.Equal(x.Approved, false); // Assert.Equal(x.Approved, false);
}); // });
} // }
[Fact] // [Fact]
public async Task GetApprovedRequests_Should_ReturnEmpty_WhenThereAreNoApprovedRequests() // public async Task GetApprovedRequests_Should_ReturnEmpty_WhenThereAreNoApprovedRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Available = true }, // new MovieRequestModel { Available = true },
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetApprovedRequests(); // var result = await Engine.GetApprovedRequests();
Assert.False(result.Any()); // Assert.False(result.Any());
} // }
[Fact] // [Fact]
public async Task GetApprovedRequests_Should_ReturnOnlyApprovedRequests_WhenThereAreMultipleRequests() // public async Task GetApprovedRequests_Should_ReturnOnlyApprovedRequests_WhenThereAreMultipleRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Available = true }, // new MovieRequestModel { Available = true },
new MovieRequestModel { Approved = true }, // new MovieRequestModel { Approved = true },
new MovieRequestModel(), // new MovieRequestModel(),
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetApprovedRequests(); // var result = await Engine.GetApprovedRequests();
Assert.Equal(result.Count(), 1); // Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.All(result, x =>
{ // {
Assert.Equal(x.Available, false); // Assert.Equal(x.Available, false);
Assert.Equal(x.Approved, true); // Assert.Equal(x.Approved, true);
}); // });
} // }
[Fact] // [Fact]
public async Task GetAvailableRequests_Should_ReturnEmpty_WhenThereAreNoAvailableRequests() // public async Task GetAvailableRequests_Should_ReturnEmpty_WhenThereAreNoAvailableRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Approved = true }, // new MovieRequestModel { Approved = true },
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetAvailableRequests(); // var result = await Engine.GetAvailableRequests();
Assert.False(result.Any()); // Assert.False(result.Any());
} // }
[Fact] // [Fact]
public async Task GetAvailableRequests_Should_ReturnOnlyAvailableRequests_WhenThereAreMultipleRequests() // public async Task GetAvailableRequests_Should_ReturnOnlyAvailableRequests_WhenThereAreMultipleRequests()
{ // {
var requests = new List<MovieRequestModel> // var requests = new List<MovieRequestModel>
{ // {
new MovieRequestModel { Available = true }, // new MovieRequestModel { Available = true },
new MovieRequestModel { Approved = true }, // new MovieRequestModel { Approved = true },
new MovieRequestModel(), // new MovieRequestModel(),
}; // };
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetAvailableRequests(); // var result = await Engine.GetAvailableRequests();
Assert.Equal(result.Count(), 1); // Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.All(result, x =>
{ // {
Assert.Equal(x.Available, true); // Assert.Equal(x.Available, true);
Assert.Equal(x.Approved, false); // Assert.Equal(x.Approved, false);
}); // });
} // }
} // }
} //}

@ -1,130 +1,131 @@
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.Threading.Tasks; //using System.Threading.Tasks;
using Moq; //using Moq;
using Ombi.Core.Engine; //using Ombi.Core.Engine;
using Ombi.Core.Models.Requests; //using Ombi.Core.Models.Requests;
using Ombi.Core.Requests.Models; //using Ombi.Core.Models.Requests.Tv;
using Xunit; //using Ombi.Core.Requests.Models;
//using Xunit;
namespace Ombi.Core.Tests.Engine
{ //namespace Ombi.Core.Tests.Engine
public class TvRequestEngineTests //{
{ // public class TvRequestEngineTests
public TvRequestEngineTests() // {
{ // public TvRequestEngineTests()
RequestService = new Mock<IRequestService<TvRequestModel>>(); // {
var requestService = new RequestService(RequestService.Object, null); // RequestService = new Mock<IRequestService<TvRequestModel>>();
Engine = new TvRequestEngine(null, requestService, null, null, null, null); // var requestService = new RequestService(RequestService.Object, null);
} // Engine = new TvRequestEngine(null, requestService, null, null, null, null);
// }
private TvRequestEngine Engine { get; }
private Mock<IRequestService<TvRequestModel>> RequestService { get; } // private TvRequestEngine Engine { get; }
// private Mock<IRequestService<TvRequestModel>> RequestService { get; }
[Fact]
public async Task GetNewRequests_Should_ReturnEmpty_WhenThereAreNoNewRequests() // [Fact]
{ // public async Task GetNewRequests_Should_ReturnEmpty_WhenThereAreNoNewRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Available = true }, // {
new TvRequestModel { Approved = true }, // new TvRequestModel { Available = true },
}; // new TvRequestModel { Approved = true },
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetNewRequests();
// var result = await Engine.GetNewRequests();
Assert.False(result.Any());
} // Assert.False(result.Any());
// }
[Fact]
public async Task GetNewRequests_Should_ReturnOnlyNewRequests_WhenThereAreMultipleRequests() // [Fact]
{ // public async Task GetNewRequests_Should_ReturnOnlyNewRequests_WhenThereAreMultipleRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Available = true }, // {
new TvRequestModel { Approved = true }, // new TvRequestModel { Available = true },
new TvRequestModel(), // new TvRequestModel { Approved = true },
}; // new TvRequestModel(),
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetNewRequests();
// var result = await Engine.GetNewRequests();
Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.Equal(result.Count(), 1);
{ // Assert.All(result, x =>
Assert.Equal(x.Available, false); // {
Assert.Equal(x.Approved, false); // Assert.Equal(x.Available, false);
}); // Assert.Equal(x.Approved, false);
} // });
// }
[Fact]
public async Task GetApprovedRequests_Should_ReturnEmpty_WhenThereAreNoApprovedRequests() // [Fact]
{ // public async Task GetApprovedRequests_Should_ReturnEmpty_WhenThereAreNoApprovedRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Available = true }, // {
}; // new TvRequestModel { Available = true },
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetApprovedRequests();
// var result = await Engine.GetApprovedRequests();
Assert.False(result.Any());
} // Assert.False(result.Any());
// }
[Fact]
public async Task GetApprovedRequests_Should_ReturnOnlyApprovedRequests_WhenThereAreMultipleRequests() // [Fact]
{ // public async Task GetApprovedRequests_Should_ReturnOnlyApprovedRequests_WhenThereAreMultipleRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Available = true }, // {
new TvRequestModel { Approved = true }, // new TvRequestModel { Available = true },
new TvRequestModel(), // new TvRequestModel { Approved = true },
}; // new TvRequestModel(),
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetApprovedRequests();
// var result = await Engine.GetApprovedRequests();
Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.Equal(result.Count(), 1);
{ // Assert.All(result, x =>
Assert.Equal(x.Available, false); // {
Assert.Equal(x.Approved, true); // Assert.Equal(x.Available, false);
}); // Assert.Equal(x.Approved, true);
} // });
// }
[Fact]
public async Task GetAvailableRequests_Should_ReturnEmpty_WhenThereAreNoAvailableRequests() // [Fact]
{ // public async Task GetAvailableRequests_Should_ReturnEmpty_WhenThereAreNoAvailableRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Approved = true }, // {
}; // new TvRequestModel { Approved = true },
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetAvailableRequests();
// var result = await Engine.GetAvailableRequests();
Assert.False(result.Any());
} // Assert.False(result.Any());
// }
[Fact]
public async Task GetAvailableRequests_Should_ReturnOnlyAvailableRequests_WhenThereAreMultipleRequests() // [Fact]
{ // public async Task GetAvailableRequests_Should_ReturnOnlyAvailableRequests_WhenThereAreMultipleRequests()
var requests = new List<TvRequestModel> // {
{ // var requests = new List<TvRequestModel>
new TvRequestModel { Available = true }, // {
new TvRequestModel { Approved = true }, // new TvRequestModel { Available = true },
new TvRequestModel(), // new TvRequestModel { Approved = true },
}; // new TvRequestModel(),
RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests); // };
// RequestService.Setup(x => x.GetAllAsync()).ReturnsAsync(requests);
var result = await Engine.GetAvailableRequests();
// var result = await Engine.GetAvailableRequests();
Assert.Equal(result.Count(), 1);
Assert.All(result, x => // Assert.Equal(result.Count(), 1);
{ // Assert.All(result, x =>
Assert.Equal(x.Available, true); // {
Assert.Equal(x.Approved, false); // Assert.Equal(x.Available, true);
}); // Assert.Equal(x.Approved, false);
} // });
} // }
} // }
//}

@ -1,89 +1,89 @@
using System.Security.Principal; //using System.Security.Principal;
using System.Threading.Tasks; //using System.Threading.Tasks;
using Moq; //using Moq;
using Ombi.Core.Claims; //using Ombi.Core.Claims;
using Ombi.Core.Models.Requests; //using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Rules; //using Ombi.Core.Rule.Rules;
using Ombi.Core.Rule.Rules.Request; //using Ombi.Core.Rule.Rules.Request;
using Xunit; //using Xunit;
namespace Ombi.Core.Tests.Rule //namespace Ombi.Core.Tests.Rule
{ //{
public class AutoApproveRuleTests // public class AutoApproveRuleTests
{ // {
public AutoApproveRuleTests() // public AutoApproveRuleTests()
{ // {
PrincipalMock = new Mock<IPrincipal>(); // PrincipalMock = new Mock<IPrincipal>();
Rule = new AutoApproveRule(PrincipalMock.Object); // Rule = new AutoApproveRule(PrincipalMock.Object);
} // }
private AutoApproveRule Rule { get; } // private AutoApproveRule Rule { get; }
private Mock<IPrincipal> PrincipalMock { get; } // private Mock<IPrincipal> PrincipalMock { get; }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie() // public async Task Should_ReturnSuccess_WhenAdminAndRequestMovie()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, true); // Assert.Equal(request.Approved, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenAdminAndRequestTV() // public async Task Should_ReturnSuccess_WhenAdminAndRequestTV()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, true); // Assert.Equal(request.Approved, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie() // public async Task Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveMovie)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveMovie)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, true); // Assert.Equal(request.Approved, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV() // public async Task Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveTv)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveTv)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, true); // Assert.Equal(request.Approved, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnFail_WhenNoClaimsAndRequestMovie() // public async Task Should_ReturnFail_WhenNoClaimsAndRequestMovie()
{ // {
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, false); // Assert.Equal(request.Approved, false);
} // }
[Fact] // [Fact]
public async Task Should_ReturnFail_WhenNoClaimsAndRequestTV() // public async Task Should_ReturnFail_WhenNoClaimsAndRequestTV()
{ // {
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
Assert.Equal(request.Approved, false); // Assert.Equal(request.Approved, false);
} // }
} // }
} //}

@ -1,84 +1,84 @@
using System.Security.Principal; //using System.Security.Principal;
using System.Threading.Tasks; //using System.Threading.Tasks;
using Moq; //using Moq;
using Ombi.Core.Claims; //using Ombi.Core.Claims;
using Ombi.Core.Models.Requests; //using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Rules; //using Ombi.Core.Rule.Rules;
using Xunit; //using Xunit;
namespace Ombi.Core.Tests.Rule //namespace Ombi.Core.Tests.Rule
{ //{
public class CanRequestRuleTests // public class CanRequestRuleTests
{ // {
public CanRequestRuleTests() // public CanRequestRuleTests()
{ // {
PrincipalMock = new Mock<IPrincipal>(); // PrincipalMock = new Mock<IPrincipal>();
Rule = new CanRequestRule(PrincipalMock.Object); // Rule = new CanRequestRule(PrincipalMock.Object);
} // }
private CanRequestRule Rule { get; } // private CanRequestRule Rule { get; }
private Mock<IPrincipal> PrincipalMock { get; } // private Mock<IPrincipal> PrincipalMock { get; }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole() // public async Task Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole() // public async Task Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(false); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(false);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, false); // Assert.Equal(result.Success, false);
Assert.Equal(string.IsNullOrEmpty(result.Message), false); // Assert.Equal(string.IsNullOrEmpty(result.Message), false);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenRequestingMovieWithAdminRole() // public async Task Should_ReturnSuccess_WhenRequestingMovieWithAdminRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenRequestingTVWithAdminRole() // public async Task Should_ReturnSuccess_WhenRequestingTVWithAdminRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnSuccess_WhenRequestingTVWithTVRole() // public async Task Should_ReturnSuccess_WhenRequestingTVWithTVRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(true); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(true);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, true); // Assert.Equal(result.Success, true);
} // }
[Fact] // [Fact]
public async Task Should_ReturnFail_WhenRequestingTVWithoutTVRole() // public async Task Should_ReturnFail_WhenRequestingTVWithoutTVRole()
{ // {
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(false); // PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(false);
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow }; // var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
var result = await Rule.Execute(request); // var result = await Rule.Execute(request);
Assert.Equal(result.Success, false); // Assert.Equal(result.Success, false);
Assert.Equal(string.IsNullOrEmpty(result.Message), false); // Assert.Equal(string.IsNullOrEmpty(result.Message), false);
} // }
} // }
} //}

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Moq; using Moq;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie; using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Models.Requests.Tv;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
using Ombi.Core.Rule.Rules.Search; using Ombi.Core.Rule.Rules.Search;

@ -1,7 +1,5 @@
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Requests.Models;
using Ombi.Core.Rules; using Ombi.Core.Rules;
using Ombi.Helpers; using Ombi.Helpers;
using System; using System;
@ -9,14 +7,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public abstract class BaseMediaEngine : BaseEngine public abstract class BaseMediaEngine : BaseEngine
{ {
private long _cacheTime; private long _cacheTime;
private Dictionary<int, MovieRequestModel> _dbMovies; private Dictionary<int, MovieRequests> _dbMovies;
private Dictionary<int, TvRequestModel> _dbTv; private Dictionary<int, TvRequests> _dbTv;
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService, protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
IRuleEvaluator rules) : base(identity, rules) IRuleEvaluator rules) : base(identity, rules)
@ -25,32 +27,32 @@ namespace Ombi.Core.Engine
} }
protected IRequestServiceMain RequestService { get; } protected IRequestServiceMain RequestService { get; }
protected IRequestService<MovieRequestModel> MovieRequestService => RequestService.MovieRequestService; protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
protected IRequestService<TvRequestModel> TvRequestService => RequestService.TvRequestService; protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
protected async Task<Dictionary<int, MovieRequestModel>> GetMovieRequests() protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests()
{ {
var now = DateTime.Now.Ticks; var now = DateTime.Now.Ticks;
if (_dbMovies == null || now - _cacheTime > 10000) if (_dbMovies == null || now - _cacheTime > 10000)
{ {
var allResults = await MovieRequestService.GetAllAsync(); var allResults = await MovieRepository.Get().ToListAsync();
var distinctResults = allResults.DistinctBy(x => x.ProviderId); var distinctResults = allResults.DistinctBy(x => x.TheMovieDbId);
_dbMovies = distinctResults.ToDictionary(x => x.ProviderId); _dbMovies = distinctResults.ToDictionary(x => x.TheMovieDbId);
_cacheTime = now; _cacheTime = now;
} }
return _dbMovies; return _dbMovies;
} }
protected async Task<Dictionary<int, TvRequestModel>> GetTvRequests() protected async Task<Dictionary<int, TvRequests>> GetTvRequests()
{ {
var now = DateTime.Now.Ticks; var now = DateTime.Now.Ticks;
if (_dbTv == null || now - _cacheTime > 10000) if (_dbTv == null || now - _cacheTime > 10000)
{ {
var allResults = await TvRequestService.GetAllAsync(); var allResults = await TvRepository.Get().ToListAsync();
var distinctResults = allResults.DistinctBy(x => x.ProviderId); var distinctResults = allResults.DistinctBy(x => x.TvDbId);
_dbTv = distinctResults.ToDictionary(x => x.ProviderId); _dbTv = distinctResults.ToDictionary(x => x.TvDbId);
_cacheTime = now; _cacheTime = now;
} }
return _dbTv; return _dbTv;
@ -58,16 +60,34 @@ namespace Ombi.Core.Engine
public RequestCountModel RequestCount() public RequestCountModel RequestCount()
{ {
var movieQuery = MovieRequestService.GetAllQueryable(); var movieQuery = MovieRepository.Get();
var tvQuery = MovieRequestService.GetAllQueryable(); var tvQuery = TvRepository.Get();
var pendingMovies = movieQuery.Count(x => !x.Approved && !x.Available); var pendingMovies = movieQuery.Count(x => !x.Approved && !x.Available);
var approvedMovies = movieQuery.Count(x => x.Approved && !x.Available); var approvedMovies = movieQuery.Count(x => x.Approved && !x.Available);
var availableMovies = movieQuery.Count(x => x.Available); var availableMovies = movieQuery.Count(x => x.Available);
var pendingTv = tvQuery.Count(x => !x.Approved && !x.Available); var pendingTv = 0;
var approvedTv = tvQuery.Count(x => x.Approved && !x.Available); var approvedTv = 0;
var availableTv = tvQuery.Count(x => x.Available); var availableTv = 0;
foreach (var tv in tvQuery)
{
foreach (var child in tv.ChildRequests)
{
if (!child.Approved && !child.Available)
{
pendingTv++;
}
if (child.Approved && !child.Available)
{
approvedTv++;
}
if (child.Available)
{
availableTv++;
}
}
}
return new RequestCountModel return new RequestCountModel
{ {

@ -14,6 +14,7 @@ using Ombi.Core.Models.Search;
using Ombi.Core.Notifications; using Ombi.Core.Notifications;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Notifications.Models; using Ombi.Notifications.Models;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
@ -65,7 +66,7 @@ namespace Ombi.Core.Engine.Interfaces
} }
} }
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequestModel model) public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
{ {
var ruleResults = await Rules.StartRequestRules(model); var ruleResults = await Rules.StartRequestRules(model);
return ruleResults; return ruleResults;

@ -1,23 +1,22 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
public interface IMovieRequestEngine : IRequestEngine<MovieRequestModel> public interface IMovieRequestEngine : IRequestEngine<MovieRequests>
{ {
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model); Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
bool ShouldAutoApprove(RequestType requestType); bool ShouldAutoApprove(RequestType requestType);
Task<IEnumerable<MovieRequestModel>> SearchMovieRequest(string search); Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
Task RemoveMovieRequest(int requestId); Task RemoveMovieRequest(int requestId);
Task<MovieRequestModel> UpdateMovieRequest(MovieRequestModel request); Task<MovieRequests> UpdateMovieRequest(MovieRequests request);
} }
} }

@ -1,19 +1,21 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Tv;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
public interface ITvRequestEngine : IRequestEngine<TvRequestModel> public interface ITvRequestEngine : IRequestEngine<TvRequests>
{ {
Task RemoveTvRequest(int requestId); Task RemoveTvRequest(int requestId);
Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv); Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv);
Task<IEnumerable<TvRequestModel>> SearchTvRequest(string search); Task<IEnumerable<TvRequests>> SearchTvRequest(string search);
Task<TvRequestModel> UpdateTvRequest(TvRequestModel request); Task<TvRequests> UpdateTvRequest(TvRequests request);
} }
} }

@ -12,27 +12,32 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.IdentityResolver;
using Ombi.Core.Rule; using Ombi.Core.Rule;
using Ombi.Store.Entities.Requests;
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, IPrincipal user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log) : base(user, requestService, r) INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log, IUserIdentityManager manager) : base(user, requestService, r)
{ {
MovieApi = movieApi; MovieApi = movieApi;
NotificationHelper = helper; NotificationHelper = helper;
Sender = sender; Sender = sender;
Logger = log; Logger = log;
UserManager = manager;
} }
private IMovieDbApi MovieApi { get; } private IMovieDbApi MovieApi { get; }
private INotificationHelper NotificationHelper { get; } private INotificationHelper NotificationHelper { get; }
private IMovieSender Sender { get; } private IMovieSender Sender { get; }
private ILogger<MovieRequestEngine> Logger { get; } private ILogger<MovieRequestEngine> Logger { get; }
private IUserIdentityManager UserManager { get; }
public async Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model) public async Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model)
{ {
@ -49,7 +54,7 @@ namespace Ombi.Core.Engine
var fullMovieName = var fullMovieName =
$"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}"; $"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}";
var existingRequest = await MovieRequestService.CheckRequestAsync(model.Id); var existingRequest = await MovieRepository.GetRequest(model.Id);
if (existingRequest != null) if (existingRequest != null)
{ {
return new RequestEngineResult return new RequestEngineResult
@ -85,11 +90,12 @@ namespace Ombi.Core.Engine
// }); // });
//} //}
var userDetails = await UserManager.GetUser(User.Identity.Name);
var requestModel = new MovieRequestModel var requestModel = new MovieRequests
{ {
ProviderId = movieInfo.Id, TheMovieDbId = movieInfo.Id,
Type = RequestType.Movie, RequestType = RequestType.Movie,
Overview = movieInfo.Overview, Overview = movieInfo.Overview,
ImdbId = movieInfo.ImdbId, ImdbId = movieInfo.ImdbId,
PosterPath = movieInfo.PosterPath, PosterPath = movieInfo.PosterPath,
@ -100,8 +106,7 @@ namespace Ombi.Core.Engine
Status = movieInfo.Status, Status = movieInfo.Status,
RequestedDate = DateTime.UtcNow, RequestedDate = DateTime.UtcNow,
Approved = false, Approved = false,
RequestedUser = Username, RequestedUserId = userDetails.Id,
Issues = IssueState.None
}; };
var ruleResults = await RunRequestRules(requestModel); var ruleResults = await RunRequestRules(requestModel);
@ -139,57 +144,56 @@ namespace Ombi.Core.Engine
$"{fullMovieName} has been successfully added!"); $"{fullMovieName} has been successfully added!");
} }
public async Task<IEnumerable<MovieRequestModel>> GetRequests(int count, int position) public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
{ {
var allRequests = await MovieRequestService.GetAllAsync(count, position); var allRequests = await MovieRepository.Get().Skip(position).Take(count).ToListAsync();
return allRequests; return allRequests;
} }
public async Task<IEnumerable<MovieRequestModel>> GetRequests() public async Task<IEnumerable<MovieRequests>> GetRequests()
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = await MovieRepository.Get().ToListAsync();
return allRequests; return allRequests;
} }
public async Task<IEnumerable<MovieRequestModel>> SearchMovieRequest(string search) public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = await MovieRepository.Get().ToListAsync();
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)); var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase));
return results; return results;
} }
public async Task<MovieRequestModel> UpdateMovieRequest(MovieRequestModel request) public async Task<MovieRequests> UpdateMovieRequest(MovieRequests request)
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = await MovieRepository.Get().ToListAsync();
var results = allRequests.FirstOrDefault(x => x.Id == request.Id); var results = allRequests.FirstOrDefault(x => x.Id == request.Id);
results.Approved = request.Approved; results.Approved = request.Approved;
results.Available = request.Available; results.Available = request.Available;
results.Denied = request.Denied; results.Denied = request.Denied;
results.DeniedReason = request.DeniedReason; results.DeniedReason = request.DeniedReason;
results.AdminNote = request.AdminNote;
results.ImdbId = request.ImdbId; results.ImdbId = request.ImdbId;
results.IssueId = request.IssueId; results.IssueId = request.IssueId;
results.Issues = request.Issues; results.Issues = request.Issues;
results.OtherMessage = request.OtherMessage;
results.Overview = request.Overview; results.Overview = request.Overview;
results.PosterPath = request.PosterPath; results.PosterPath = request.PosterPath;
results.RequestedUser = request.RequestedUser; results.RequestedUser = request.RequestedUser;
var model = MovieRequestService.UpdateRequest(results); await MovieRepository.Update(results);
return model; return results;
} }
public async Task RemoveMovieRequest(int requestId) public async Task RemoveMovieRequest(int requestId)
{ {
await MovieRequestService.DeleteRequestAsync(requestId); var request = await MovieRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
await MovieRepository.Delete(request);
} }
private async Task<RequestEngineResult> AddMovieRequest(MovieRequestModel model, string message) private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string message)
{ {
await MovieRequestService.AddRequestAsync(model); await MovieRepository.Add(model);
if (ShouldSendNotification(model.Type)) if (ShouldSendNotification(RequestType.Movie))
{ {
NotificationHelper.NewRequest(model); NotificationHelper.NewRequest(model);
} }
@ -215,22 +219,22 @@ namespace Ombi.Core.Engine
return new RequestEngineResult { RequestAdded = true, Message = message }; return new RequestEngineResult { RequestAdded = true, Message = message };
} }
public async Task<IEnumerable<MovieRequestModel>> GetApprovedRequests() public async Task<IEnumerable<MovieRequests>> GetApprovedRequests()
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = MovieRepository.Get();
return allRequests.Where(x => x.Approved && !x.Available); return await allRequests.Where(x => x.Approved && !x.Available).ToListAsync();
} }
public async Task<IEnumerable<MovieRequestModel>> GetNewRequests() public async Task<IEnumerable<MovieRequests>> GetNewRequests()
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = MovieRepository.Get();
return allRequests.Where(x => !x.Approved && !x.Available); return await allRequests.Where(x => !x.Approved && !x.Available).ToListAsync();
} }
public async Task<IEnumerable<MovieRequestModel>> GetAvailableRequests() public async Task<IEnumerable<MovieRequests>> GetAvailableRequests()
{ {
var allRequests = await MovieRequestService.GetAllAsync(); var allRequests = MovieRepository.Get();
return allRequests.Where(x => !x.Approved && x.Available); return await allRequests.Where(x => !x.Approved && x.Available).ToListAsync();
} }
} }
} }

@ -10,12 +10,18 @@ using Ombi.Notifications.Models;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.IdentityResolver;
using Ombi.Core.Models.Requests.Tv;
using Ombi.Core.Rule; using Ombi.Core.Rule;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -23,16 +29,18 @@ namespace Ombi.Core.Engine
{ {
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user, public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IMapper map, INotificationHelper helper, IMapper map,
IRuleEvaluator rule) : base(user, requestService, rule) IRuleEvaluator rule, IUserIdentityManager manager) : base(user, requestService, rule)
{ {
TvApi = tvApi; TvApi = tvApi;
NotificationHelper = helper; NotificationHelper = helper;
Mapper = map; Mapper = map;
UserManager = manager;
} }
private INotificationHelper NotificationHelper { get; } private INotificationHelper NotificationHelper { get; }
private ITvMazeApi TvApi { get; } private ITvMazeApi TvApi { get; }
private IMapper Mapper { get; } private IMapper Mapper { get; }
private IUserIdentityManager UserManager { get; }
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv) public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
{ {
@ -60,89 +68,66 @@ namespace Ombi.Core.Engine
} }
} }
var user = await UserManager.GetUser(User.Identity.Name);
var childRequest = new ChildTvRequest var childRequest = new ChildRequests
{ {
Id = tv.Id, Id = tv.Id,
Type = RequestType.TvShow, RequestType = RequestType.TvShow,
Overview = showInfo.summary.RemoveHtml(), //Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath, //PosterPath = posterPath,
Title = showInfo.name, //Title = showInfo.name,
ReleaseDate = firstAir, //ReleaseDate = firstAir,
Status = showInfo.status, //Status = showInfo.status,
RequestedDate = DateTime.UtcNow, RequestedDate = DateTime.UtcNow,
Approved = false, Approved = false,
RequestedUser = Username, RequestedUserId = user.Id,
Issues = IssueState.None,
ProviderId = tv.Id,
RequestAll = tv.RequestAll,
SeasonRequests = tvRequests
}; };
var model = new TvRequestModel
{
Id = tv.Id,
Type = RequestType.TvShow,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
Approved = false,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id.ToString(),
ProviderId = tv.Id
};
model.ChildRequests.Add(childRequest);
//if (childRequest.SeasonRequests.Any())
//{
// var episodes = await TvApi.EpisodeLookup(showInfo.id);
// foreach (var e in episodes)
// {
// var season = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
// season?.Episodes.Add(new EpisodesRequested
// {
// Url = e.url,
// Title = e.name,
// AirDate = DateTime.Parse(e.airstamp),
// EpisodeNumber = e.number
// });
// }
//}
if (tv.LatestSeason) if (tv.LatestSeason)
{ {
var latest = showInfo.Season.OrderBy(x => x.SeasonNumber).FirstOrDefault(); var episodes = await TvApi.EpisodeLookup(showInfo.id);
foreach (var modelSeasonRequest in childRequest.SeasonRequests) var latest = episodes.OrderBy(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{ {
if (modelSeasonRequest.SeasonNumber == latest.SeasonNumber) episodesRequests.Add(new EpisodeRequests
{ {
foreach (var episodesRequested in modelSeasonRequest.Episodes) EpisodeNumber = ep.number,
{ AirDate = DateTime.Parse(ep.airdate),
episodesRequested.Requested = true; Title = ep.name,
} Url = ep.url
} });
} }
childRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = latest.season,
});
} }
if (tv.FirstSeason) if (tv.FirstSeason)
{ {
var first = showInfo.Season.OrderByDescending(x => x.SeasonNumber).FirstOrDefault(); var episodes = await TvApi.EpisodeLookup(showInfo.id);
foreach (var modelSeasonRequest in childRequest.SeasonRequests) var first = episodes.OrderByDescending(x => x.season).FirstOrDefault();
var episodesRequests = new List<EpisodeRequests>();
foreach (var ep in episodes)
{ {
if (modelSeasonRequest.SeasonNumber == first.SeasonNumber) episodesRequests.Add(new EpisodeRequests
{ {
foreach (var episodesRequested in modelSeasonRequest.Episodes) EpisodeNumber = ep.number,
{ AirDate = DateTime.Parse(ep.airdate),
episodesRequested.Requested = true; Title = ep.name,
} Url = ep.url
} });
} }
childRequest.SeasonRequests.Add(new SeasonRequests
{
Episodes = episodesRequests,
SeasonNumber = first.season,
});
} }
var ruleResults = await RunRequestRules(model); var ruleResults = await RunRequestRules(childRequest);
var results = ruleResults as RuleResult[] ?? ruleResults.ToArray(); var results = ruleResults as RuleResult[] ?? ruleResults.ToArray();
if (results.Any(x => !x.Success)) if (results.Any(x => !x.Success))
{ {
@ -152,68 +137,72 @@ namespace Ombi.Core.Engine
}; };
} }
var existingRequest = await TvRequestService.CheckRequestAsync(model.Id); var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.Id);
if (existingRequest != null) if (existingRequest != null)
{ {
return await AddExistingRequest(model, existingRequest); return await AddExistingRequest(childRequest, existingRequest);
} }
// This is a new request // This is a new request
var model = new TvRequests
{
Id = tv.Id,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id,
ChildRequests = new List<ChildRequests>()
};
model.ChildRequests.Add(childRequest);
return await AddRequest(model); return await AddRequest(model);
} }
public async Task<IEnumerable<TvRequestModel>> GetRequests(int count, int position) public async Task<IEnumerable<TvRequests>> GetRequests(int count, int position)
{ {
var allRequests = await TvRequestService.GetAllAsync(count, position); var allRequests = await TvRepository.Get().Skip(position).Take(count).ToListAsync();
return allRequests; return allRequests;
} }
public async Task<IEnumerable<TvRequestModel>> GetRequests() public async Task<IEnumerable<TvRequests>> GetRequests()
{ {
var allRequests = await TvRequestService.GetAllAsync(); var allRequests = TvRepository.Get();
return allRequests; return await allRequests.ToListAsync();
} }
public async Task<IEnumerable<TvRequestModel>> SearchTvRequest(string search) public async Task<IEnumerable<TvRequests>> SearchTvRequest(string search)
{ {
var allRequests = await TvRequestService.GetAllAsync(); var allRequests = TvRepository.Get();
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)); var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase));
return results; return results;
} }
public async Task<TvRequestModel> UpdateTvRequest(TvRequestModel request) public async Task<TvRequests> UpdateTvRequest(TvRequests request)
{ {
var allRequests = await TvRequestService.GetAllAsync(); var allRequests = TvRepository.Get();
var results = allRequests.FirstOrDefault(x => x.Id == request.Id); var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id);
results = Mapper.Map<TvRequestModel>(request); results = Mapper.Map<TvRequests>(request);
// TODO need to check if we need to approve any child requests since they may have updated // TODO need to check if we need to approve any child requests since they may have updated
var model = TvRequestService.UpdateRequest(results); await TvRepository.Update(results);
return model; return results;
} }
public async Task RemoveTvRequest(int requestId) public async Task RemoveTvRequest(int requestId)
{ {
await TvRequestService.DeleteRequestAsync(requestId); var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
await TvRepository.Delete(request);
} }
private async Task<RequestEngineResult> AddExistingRequest(TvRequestModel newRequest, private async Task<RequestEngineResult> AddExistingRequest(ChildRequests newRequest, TvRequests existingRequest)
TvRequestModel existingRequest)
{ {
var child = newRequest.ChildRequests.FirstOrDefault(); // There will only be 1 // Add the child
var episodeDiff = new List<SeasonRequestModel>(); existingRequest.ChildRequests.Add(newRequest);
foreach (var existingChild in existingRequest.ChildRequests)
{
var difference = GetListDifferences(existingChild.SeasonRequests, child.SeasonRequests).ToList();
if (difference.Any())
episodeDiff = difference;
}
if (episodeDiff.Any()) await TvRepository.Update(existingRequest);
child.SeasonRequests = episodeDiff;
existingRequest.ChildRequests.AddRange(newRequest.ChildRequests);
TvRequestService.UpdateRequest(existingRequest);
if (newRequest.Approved) // The auto approve rule if (newRequest.Approved) // The auto approve rule
{ {
@ -263,18 +252,18 @@ namespace Ombi.Core.Engine
return request; return request;
} }
private async Task<RequestEngineResult> AddRequest(TvRequestModel model) private async Task<RequestEngineResult> AddRequest(TvRequests model)
{ {
await TvRequestService.AddRequestAsync(model); await TvRepository.Add(model);
// This is a new request so we should only have 1 child
return await AfterRequest(model); return await AfterRequest(model.ChildRequests.FirstOrDefault());
} }
private Task<RequestEngineResult> AfterRequest(TvRequestModel model) private Task<RequestEngineResult> AfterRequest(ChildRequests model)
{ {
if (ShouldSendNotification(model.Type)) if (ShouldSendNotification(RequestType.TvShow))
{ {
NotificationHelper.NewRequest(model); //NotificationHelper.NewRequest(model.ParentRequest);
} }
//var limit = await RequestLimitRepo.GetAllAsync(); //var limit = await RequestLimitRepo.GetAllAsync();
@ -298,22 +287,25 @@ namespace Ombi.Core.Engine
return Task.FromResult(new RequestEngineResult { RequestAdded = true }); return Task.FromResult(new RequestEngineResult { RequestAdded = true });
} }
public async Task<IEnumerable<TvRequestModel>> GetApprovedRequests() public async Task<IEnumerable<TvRequests>> GetApprovedRequests()
{ {
var allRequests = await TvRequestService.GetAllAsync(); //var allRequests = TvRepository.Get();
return allRequests.Where(x => x.Approved && !x.Available); //return await allRequests.Where(x => x.Approved && !x.Available).ToListAsync();
return null;
} }
public async Task<IEnumerable<TvRequestModel>> GetNewRequests() public async Task<IEnumerable<TvRequests>> GetNewRequests()
{ {
var allRequests = await TvRequestService.GetAllAsync(); //var allRequests = await TvRepository.GetAllAsync();
return allRequests.Where(x => !x.Approved && !x.Available); //return allRequests.Where(x => !x.Approved && !x.Available);
return null;
} }
public async Task<IEnumerable<TvRequestModel>> GetAvailableRequests() public async Task<IEnumerable<TvRequests>> GetAvailableRequests()
{ {
var allRequests = await TvRequestService.GetAllAsync(); //var allRequests = await TvRepository.GetAllAsync();
return allRequests.Where(x => x.Available); //return allRequests.Where(x => x.Available);
return null;
} }
} }
} }

@ -15,6 +15,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests.Tv;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -132,7 +134,7 @@ namespace Ombi.Core.Engine
return retVal; return retVal;
} }
private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item, Dictionary<int, TvRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) private async Task<SearchTvShowViewModel> ProcessResult(SearchTvShowViewModel item, Dictionary<int, TvRequests> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
if (embySettings.Enable) if (embySettings.Enable)
{ {
@ -162,7 +164,7 @@ namespace Ombi.Core.Engine
var existingRequest = existingRequests[tvdbid]; var existingRequest = existingRequests[tvdbid];
item.Requested = true; item.Requested = true;
item.Approved = existingRequest.Approved; item.Approved = existingRequest.ChildRequests.Any(x => x.Approved);
// Let's modify the seasonsrequested to reflect what we have requested... // Let's modify the seasonsrequested to reflect what we have requested...
foreach (var season in item.SeasonRequests) foreach (var season in item.SeasonRequests)
@ -178,9 +180,9 @@ namespace Ombi.Core.Engine
{ {
// Find the episode from what we are searching // Find the episode from what we are searching
var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber); var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber);
episodeSearching.Requested = ep.Requested; episodeSearching.Requested = true;
episodeSearching.Available = ep.Available; episodeSearching.Available = ep.Available;
episodeSearching.Approved = ep.Approved; episodeSearching.Approved = ep.Season.ChildRequest.Approved;
} }
} }
} }

@ -1,10 +1,11 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests.Movie; using Ombi.Core.Models.Requests.Movie;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core namespace Ombi.Core
{ {
public interface IMovieSender public interface IMovieSender
{ {
Task<MovieSenderResult> Send(MovieRequestModel model, string qualityId = ""); Task<MovieSenderResult> Send(MovieRequests model, string qualityId = "");
} }
} }

@ -1,9 +1,10 @@
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core namespace Ombi.Core
{ {
public interface INotificationHelper public interface INotificationHelper
{ {
void NewRequest(BaseRequestModel model); void NewRequest(FullBaseRequest model);
} }
} }

@ -5,6 +5,7 @@ using Ombi.Store.Repository;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests.Tv;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {

@ -1,17 +1,17 @@
using Ombi.Core.Models.Requests.Movie; using Ombi.Store.Repository;
using Ombi.Core.Requests.Models; using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
public class RequestService : IRequestServiceMain public class RequestService : IRequestServiceMain
{ {
public RequestService(IRequestService<TvRequestModel> tv, IRequestService<MovieRequestModel> movie) public RequestService(ITvRequestRepository tv, IMovieRequestRepository movie)
{ {
TvRequestService = tv; TvRequestService = tv;
MovieRequestService = movie; MovieRequestService = movie;
} }
public IRequestService<TvRequestModel> TvRequestService { get; } public ITvRequestRepository TvRequestService { get; }
public IRequestService<MovieRequestModel> MovieRequestService { get; } public IMovieRequestRepository MovieRequestService { get; }
} }
} }

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests.Tv
{ {
public class TvRequestModel : BaseRequestModel public class TvRequestModel : BaseRequestModel
{ {

@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
using Ombi.Api.Radarr; using Ombi.Api.Radarr;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core namespace Ombi.Core
{ {
@ -22,7 +23,7 @@ namespace Ombi.Core
private IRadarrApi RadarrApi { get; } private IRadarrApi RadarrApi { get; }
private ILogger<MovieSender> Log { get; } private ILogger<MovieSender> Log { get; }
public async Task<MovieSenderResult> Send(MovieRequestModel model, string qualityId = "") public async Task<MovieSenderResult> Send(MovieRequests model, string qualityId = "")
{ {
//var cpSettings = await CouchPotatoSettings.GetSettingsAsync(); //var cpSettings = await CouchPotatoSettings.GetSettingsAsync();
//var watcherSettings = await WatcherSettings.GetSettingsAsync(); //var watcherSettings = await WatcherSettings.GetSettingsAsync();
@ -50,7 +51,7 @@ namespace Ombi.Core
}; };
} }
private async Task<MovieSenderResult> SendToRadarr(BaseRequestModel model, RadarrSettings settings, string qualityId) private async Task<MovieSenderResult> SendToRadarr(MovieRequests model, RadarrSettings settings, string qualityId)
{ {
var qualityProfile = 0; var qualityProfile = 0;
if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality
@ -65,7 +66,7 @@ namespace Ombi.Core
//var rootFolderPath = model.RootFolderSelected <= 0 ? settings.FullRootPath : GetRootPath(model.RootFolderSelected, settings); //var rootFolderPath = model.RootFolderSelected <= 0 ? settings.FullRootPath : GetRootPath(model.RootFolderSelected, settings);
var rootFolderPath = settings.DefaultRootPath; // TODO Allow changing in the UI var rootFolderPath = settings.DefaultRootPath; // TODO Allow changing in the UI
var result = await RadarrApi.AddMovie(model.ProviderId, model.Title, model.ReleaseDate.Year, qualityProfile, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly, settings.MinimumAvailability); var result = await RadarrApi.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year, qualityProfile, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly, settings.MinimumAvailability);
if (!string.IsNullOrEmpty(result.Error?.message)) if (!string.IsNullOrEmpty(result.Error?.message))
{ {

@ -5,6 +5,7 @@ using Ombi.Core.Notifications;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Notifications.Models; using Ombi.Notifications.Models;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core namespace Ombi.Core
{ {
@ -16,16 +17,16 @@ namespace Ombi.Core
} }
private INotificationService NotificationService { get; } private INotificationService NotificationService { get; }
public void NewRequest(BaseRequestModel model) public void NewRequest(FullBaseRequest model)
{ {
var notificationModel = new NotificationOptions var notificationModel = new NotificationOptions
{ {
Title = model.Title, Title = model.Title,
RequestedUser = model.RequestedUser, RequestedUser = model.RequestedUser.Username,
DateTime = DateTime.Now, DateTime = DateTime.Now,
NotificationType = NotificationType.NewRequest, NotificationType = NotificationType.NewRequest,
RequestType = model.Type, RequestType = model.RequestType,
ImgSrc = model.Type == RequestType.Movie ImgSrc = model.RequestType == RequestType.Movie
? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}" ? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}"
: model.PosterPath : model.PosterPath
}; };

@ -1,11 +1,11 @@
using Ombi.Core.Models.Requests.Movie; using Ombi.Store.Repository;
using Ombi.Core.Requests.Models; using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
public interface IRequestServiceMain public interface IRequestServiceMain
{ {
IRequestService<MovieRequestModel> MovieRequestService { get; } IMovieRequestRepository MovieRequestService { get; }
IRequestService<TvRequestModel> TvRequestService { get; } ITvRequestRepository TvRequestService { get; }
} }
} }

@ -3,12 +3,13 @@ using Ombi.Core.Rule;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Rules namespace Ombi.Core.Rules
{ {
public interface IRuleEvaluator public interface IRuleEvaluator
{ {
Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequestModel obj); Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequest obj);
Task<IEnumerable<RuleResult>> StartSearchRules(SearchViewModel obj); Task<IEnumerable<RuleResult>> StartSearchRules(SearchViewModel obj);
} }
} }

@ -7,6 +7,7 @@ using System.Reflection;
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;
namespace Ombi.Core.Rule namespace Ombi.Core.Rule
{ {
@ -14,7 +15,7 @@ namespace Ombi.Core.Rule
{ {
public RuleEvaluator(IServiceProvider provider) public RuleEvaluator(IServiceProvider provider)
{ {
RequestRules = new List<IRequestRules<BaseRequestModel>>(); RequestRules = new List<IRequestRules<BaseRequest>>();
SearchRules = new List<IRequestRules<SearchViewModel>>(); SearchRules = new List<IRequestRules<SearchViewModel>>();
var baseSearchType = typeof(BaseRequestRule).FullName; var baseSearchType = typeof(BaseRequestRule).FullName;
var baseRequestType = typeof(BaseSearchRule).FullName; var baseRequestType = typeof(BaseSearchRule).FullName;
@ -36,7 +37,7 @@ namespace Ombi.Core.Rule
} }
var item = Activator.CreateInstance(type, services.ToArray()); var item = Activator.CreateInstance(type, services.ToArray());
RequestRules.Add((IRequestRules<BaseRequestModel>) item); RequestRules.Add((IRequestRules<BaseRequest>) item);
} }
} }
@ -60,10 +61,10 @@ namespace Ombi.Core.Rule
} }
} }
private List<IRequestRules<BaseRequestModel>> RequestRules { get; } private List<IRequestRules<BaseRequest>> RequestRules { get; }
private List<IRequestRules<SearchViewModel>> SearchRules { get; } private List<IRequestRules<SearchViewModel>> SearchRules { get; }
public async Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequestModel obj) public async Task<IEnumerable<RuleResult>> StartRequestRules(BaseRequest obj)
{ {
var results = new List<RuleResult>(); var results = new List<RuleResult>();
foreach (var rule in RequestRules) foreach (var rule in RequestRules)

@ -4,10 +4,11 @@ using Ombi.Core.Claims;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Rule.Rules.Request namespace Ombi.Core.Rule.Rules.Request
{ {
public class AutoApproveRule : BaseRequestRule, IRequestRules<BaseRequestModel> public class AutoApproveRule : BaseRequestRule, IRequestRules<BaseRequest>
{ {
public AutoApproveRule(IPrincipal principal) public AutoApproveRule(IPrincipal principal)
{ {
@ -16,7 +17,7 @@ namespace Ombi.Core.Rule.Rules.Request
private IPrincipal User { get; } private IPrincipal User { get; }
public Task<RuleResult> Execute(BaseRequestModel obj) public Task<RuleResult> Execute(BaseRequest obj)
{ {
if (User.IsInRole(OmbiClaims.Admin)) if (User.IsInRole(OmbiClaims.Admin))
{ {
@ -24,9 +25,9 @@ namespace Ombi.Core.Rule.Rules.Request
return Task.FromResult(Success()); return Task.FromResult(Success());
} }
if (obj.Type == RequestType.Movie && User.IsInRole(OmbiClaims.AutoApproveMovie)) if (obj.RequestType == RequestType.Movie && User.IsInRole(OmbiClaims.AutoApproveMovie))
obj.Approved = true; obj.Approved = true;
if (obj.Type == RequestType.TvShow && User.IsInRole(OmbiClaims.AutoApproveTv)) if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiClaims.AutoApproveTv))
obj.Approved = true; obj.Approved = true;
return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve
} }

@ -1,14 +1,13 @@
using Ombi.Core.Claims; using Ombi.Core.Claims;
using Ombi.Core.Models.Requests;
using Ombi.Core.Rules;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Rule.Rules namespace Ombi.Core.Rule.Rules
{ {
public class CanRequestRule : BaseRequestRule, IRequestRules<BaseRequestModel> public class CanRequestRule : BaseRequestRule, IRequestRules<BaseRequest>
{ {
public CanRequestRule(IPrincipal principal) public CanRequestRule(IPrincipal principal)
{ {
@ -17,12 +16,12 @@ namespace Ombi.Core.Rule.Rules
private IPrincipal User { get; } private IPrincipal User { get; }
public Task<RuleResult> Execute(BaseRequestModel obj) public Task<RuleResult> Execute(BaseRequest obj)
{ {
if (User.IsInRole(OmbiClaims.Admin)) if (User.IsInRole(OmbiClaims.Admin))
return Task.FromResult(Success()); return Task.FromResult(Success());
if (obj.Type == RequestType.Movie) if (obj.RequestType == RequestType.Movie)
{ {
if (User.IsInRole(OmbiClaims.RequestMovie)) if (User.IsInRole(OmbiClaims.RequestMovie))
return Task.FromResult(Success()); return Task.FromResult(Success());

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie; using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Models.Requests.Tv;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;

@ -30,6 +30,7 @@ using Ombi.Core.Rules;
using Ombi.Notifications.Agents; using Ombi.Notifications.Agents;
using Ombi.Schedule.Jobs.Radarr; using Ombi.Schedule.Jobs.Radarr;
using Ombi.Api; using Ombi.Api;
using Ombi.Store.Repository.Requests;
namespace Ombi.DependencyInjection namespace Ombi.DependencyInjection
{ {
@ -80,6 +81,9 @@ namespace Ombi.DependencyInjection
services.AddTransient<ISettingsResolver, SettingsResolver>(); services.AddTransient<ISettingsResolver, SettingsResolver>();
services.AddTransient<IPlexContentRepository, PlexContentRepository>(); services.AddTransient<IPlexContentRepository, PlexContentRepository>();
services.AddTransient<INotificationTemplatesRepository, NotificationTemplatesRepository>(); services.AddTransient<INotificationTemplatesRepository, NotificationTemplatesRepository>();
services.AddTransient<ITvRequestRepository, TvRequestRepository>();
services.AddTransient<IMovieRequestRepository, MovieRequestRepository>();
services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>)); services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>));
} }
public static void RegisterServices(this IServiceCollection services) public static void RegisterServices(this IServiceCollection services)

@ -30,7 +30,7 @@ namespace Ombi.Mapping.Profiles
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.show.name)) .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.show.name))
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http", "https") : string.Empty)) .ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http", "https") : string.Empty))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status)); .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status));
CreateMap<TvMazeShow, SearchTvShowViewModel>() CreateMap<TvMazeShow, SearchTvShowViewModel>()
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.externals.thetvdb)) .ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.externals.thetvdb))
.ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.premiered)) .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.premiered))
@ -39,12 +39,15 @@ namespace Ombi.Mapping.Profiles
.ForMember(dest => dest.NetworkId, opts => opts.MapFrom(src => src.network.id.ToString())) .ForMember(dest => dest.NetworkId, opts => opts.MapFrom(src => src.network.id.ToString()))
.ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.summary.RemoveHtml())) .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.summary.RemoveHtml()))
.ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.rating.ToString())) .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.rating.ToString()))
.ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.runtime.ToString(CultureInfo.CurrentUICulture))) .ForMember(dest => dest.Runtime,
opts => opts.MapFrom(src => src.runtime.ToString(CultureInfo.CurrentUICulture)))
.ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id)) .ForMember(dest => dest.SeriesId, opts => opts.MapFrom(src => src.id))
.ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.name)) .ForMember(dest => dest.Title, opts => opts.MapFrom(src => src.name))
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.image.medium) ? src.image.medium.Replace("http", "https") : string.Empty)) .ForMember(dest => dest.Banner,
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.status)) opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.image.medium)
.ForMember(dest => dest.SeasonRequests, opts => opts.MapFrom(src => src.Season)); ? src.image.medium.Replace("http", "https")
: string.Empty))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.status));

@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Context namespace Ombi.Store.Context
{ {
@ -22,5 +23,11 @@ namespace Ombi.Store.Context
EntityEntry<TEntity> Attach<TEntity>(TEntity entity) where TEntity : class; EntityEntry<TEntity> Attach<TEntity>(TEntity entity) where TEntity : class;
DbSet<TEntity> Set<TEntity>() where TEntity : class; DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet<NotificationTemplates> NotificationTemplates { get; set; } DbSet<NotificationTemplates> NotificationTemplates { get; set; }
DbSet<MovieRequests> MovieRequests { get; set; }
DbSet<TvRequests> TvRequests { get; set; }
DbSet<ChildRequests> ChildRequests { get; set; }
DbSet<MovieIssues> MovieIssues { get; set; }
DbSet<TvIssues> TvIssues { get; set; }
} }
} }

@ -4,6 +4,7 @@ using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Context namespace Ombi.Store.Context
{ {
@ -40,6 +41,13 @@ namespace Ombi.Store.Context
public DbSet<PlexContent> PlexContent { get; set; } public DbSet<PlexContent> PlexContent { get; set; }
public DbSet<RadarrCache> RadarrCache { get; set; } public DbSet<RadarrCache> RadarrCache { get; set; }
public DbSet<NotificationTemplates> NotificationTemplates { get; set; } public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
public DbSet<MovieRequests> MovieRequests { get; set; }
public DbSet<TvRequests> TvRequests { get; set; }
public DbSet<ChildRequests> ChildRequests { get; set; }
public DbSet<MovieIssues> MovieIssues { get; set; }
public DbSet<TvIssues> TvIssues { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities.Requests
{
public class BaseRequest : Entity
{
public bool Approved { get; set; }
public DateTime RequestedDate { get; set; }
public bool Available { get; set; }
public int RequestedUserId { get; set; }
public bool? Denied { get; set; }
public string DeniedReason { get; set; }
public RequestType RequestType { get; set; }
[ForeignKey(nameof(RequestedUserId))]
public User RequestedUser { get; set; }
[NotMapped]
public bool CanApprove => !Approved && !Available;
}
}

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Ombi.Store.Repository.Requests;
namespace Ombi.Store.Entities.Requests
{
[Table("ChildRequests")]
public class ChildRequests : BaseRequest
{
[ForeignKey(nameof(ParentRequestId))]
public TvRequests ParentRequest { get; set; }
public int ParentRequestId { get; set; }
public int? IssueId { get; set; }
[ForeignKey(nameof(IssueId))]
public List<TvIssues> Issues { get; set; }
public List<SeasonRequests> SeasonRequests { get; set; }
}
}

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities.Requests
{
public class FullBaseRequest : BaseRequest
{
public string ImdbId { get; set; }
public string Overview { get; set; }
public string Title { get; set; }
public string PosterPath { get; set; }
public DateTime ReleaseDate { get; set; }
public string Status { get; set; }
[NotMapped]
public bool Released => DateTime.UtcNow > ReleaseDate;
}
}

@ -0,0 +1,9 @@
namespace Ombi.Store.Entities.Requests
{
public class IssuesBase : Entity
{
public string Subect { get; set; }
public string Description { get; set; }
}
}

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities.Requests
{
[Table("MovieIssues")]
public class MovieIssues : IssuesBase
{
public int MovieId { get; set; }
[ForeignKey(nameof(MovieId))]
public MovieRequests Movie { get; set; }
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities.Requests
{
[Table("MovieRequests")]
public class MovieRequests : FullBaseRequest
{
public int TheMovieDbId { get; set; }
public int? IssueId { get; set; }
[ForeignKey(nameof(IssueId))]
public List<MovieIssues> Issues { get; set; }
}
}

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public class SeasonRequests : Entity
{
public int SeasonNumber { get; set; }
public List<EpisodeRequests> Episodes { get; set; }
public int ChildRequestId { get; set; }
[ForeignKey(nameof(ChildRequestId))]
public ChildRequests ChildRequest { get; set; }
}
public class EpisodeRequests : Entity
{
public int EpisodeNumber { get; set; }
public string Title { get; set; }
public DateTime AirDate { get; set; }
public string Url { get; set; }
public bool Available { get; set; }
public int SeasonId { get; set; }
[ForeignKey(nameof(SeasonId))]
public SeasonRequests Season { get; set; }
}
}

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities.Requests
{
[Table("TvIssues")]
public class TvIssues : IssuesBase
{
public int TvId { get; set; }
[ForeignKey(nameof(TvId))]
public ChildRequests Child { get; set; }
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace Ombi.Store.Entities.Requests
{
public class TvRequests : Entity
{
public int TvDbId { get; set; }
public string ImdbId { get; set; }
public int? RootFolder { get; set; }
public string Overview { get; set; }
public string Title { get; set; }
public string PosterPath { get; set; }
public DateTime ReleaseDate { get; set; }
public string Status { get; set; }
public List<ChildRequests> ChildRequests { get; set; }
}
}

@ -0,0 +1,15 @@
using System.Linq;
using System.Threading.Tasks;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository
{
public interface IMovieRequestRepository
{
Task<MovieRequests> Add(MovieRequests request);
Task Delete(MovieRequests request);
IQueryable<MovieRequests> Get();
Task<MovieRequests> GetRequest(int theMovieDbId);
Task Update(MovieRequests request);
}
}

@ -0,0 +1,19 @@
using System.Linq;
using System.Threading.Tasks;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public interface ITvRequestRepository
{
Task<TvRequests> Add(TvRequests request);
Task<ChildRequests> AddChild(ChildRequests request);
Task Delete(TvRequests request);
Task DeleteChild(ChildRequests request);
IQueryable<TvRequests> Get();
Task<TvRequests> GetRequest(int tvDbId);
Task Update(TvRequests request);
Task UpdateChild(ChildRequests request);
IQueryable<ChildRequests> GetChild();
}
}

@ -0,0 +1,50 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Store.Context;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public class MovieRequestRepository : IMovieRequestRepository
{
public MovieRequestRepository(IOmbiContext ctx)
{
Db = ctx;
}
private IOmbiContext Db { get; }
public async Task<MovieRequests> GetRequest(int theMovieDbId)
{
return await Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
.Include(x => x.RequestedUser)
.FirstOrDefaultAsync();
}
public IQueryable<MovieRequests> Get()
{
return Db.MovieRequests
.Include(x => x.RequestedUser)
.AsQueryable();
}
public async Task<MovieRequests> Add(MovieRequests request)
{
await Db.MovieRequests.AddAsync(request);
await Db.SaveChangesAsync();
return request;
}
public async Task Delete(MovieRequests request)
{
Db.MovieRequests.Remove(request);
await Db.SaveChangesAsync();
}
public async Task Update(MovieRequests request)
{
await Db.SaveChangesAsync();
}
}
}

@ -0,0 +1,82 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Store.Context;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public class TvRequestRepository : ITvRequestRepository
{
public TvRequestRepository(IOmbiContext ctx)
{
Db = ctx;
}
private IOmbiContext Db { get; }
public async Task<TvRequests> GetRequest(int tvDbId)
{
return await Db.TvRequests.Where(x => x.TvDbId == tvDbId)
.Include(x => x.ChildRequests)
.ThenInclude(x => x.Issues)
.Include(x => x.ChildRequests)
.ThenInclude(x => x.RequestedUser)
.FirstOrDefaultAsync();
}
public IQueryable<TvRequests> Get()
{
return Db.TvRequests
.Include(x => x.ChildRequests)
.ThenInclude(x => x.Issues)
.Include(x => x.ChildRequests)
.ThenInclude(x => x.RequestedUser)
.AsQueryable();
}
public IQueryable<ChildRequests> GetChild()
{
return Db.ChildRequests
.Include(x => x.Issues)
.Include(x => x.RequestedUser)
.AsQueryable();
}
public async Task<TvRequests> Add(TvRequests request)
{
await Db.TvRequests.AddAsync(request);
await Db.SaveChangesAsync();
return request;
}
public async Task<ChildRequests> AddChild(ChildRequests request)
{
await Db.ChildRequests.AddAsync(request);
await Db.SaveChangesAsync();
return request;
}
public async Task Delete(TvRequests request)
{
Db.TvRequests.Remove(request);
await Db.SaveChangesAsync();
}
public async Task DeleteChild(ChildRequests request)
{
Db.ChildRequests.Remove(request);
await Db.SaveChangesAsync();
}
public async Task Update(TvRequests request)
{
await Db.SaveChangesAsync();
}
public async Task UpdateChild(ChildRequests request)
{
await Db.SaveChangesAsync();
}
}
}

@ -75,4 +75,99 @@ CREATE TABLE IF NOT EXISTS NotificationTemplates
Message BLOB NULL, Message BLOB NULL,
Enabled INTEGER NOT NULL Enabled INTEGER NOT NULL
); );
CREATE TABLE IF NOT EXISTS MovieIssues
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Subject INTEGER NOT NULL,
Description INTEGER NOT NULL,
MovieId INTEGER NOT NULL,
FOREIGN KEY (MovieId) REFERENCES MovieRequests(Id)
);
CREATE TABLE IF NOT EXISTS TvIssues
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Subject INTEGER NOT NULL,
Description INTEGER NOT NULL,
ChildId INTEGER NOT NULL,
FOREIGN KEY (ChildId) REFERENCES TvChildRequests(ChildId)
);
CREATE TABLE IF NOT EXISTS MovieRequests (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ImdbId VARCHAR(20) NOT NULL,
TheMovieDbId INTEGER NOT NULL,
Overview VARCHAR(100) NOT NULL,
Title VARCHAR(50) NOT NULL,
PosterPath VARCHAR(100) NOT NULL,
ReleaseDate VARCHAR(100) NOT NULL,
Status VARCHAR(100) NOT NULL,
Approved INTEGER NOT NULL,
Available INTEGER NOT NULL,
RequestedDate VARCHAR(100) NOT NULL,
RequestedUserId INTEGER NOT NULL,
IssueId INTEGER NULL,
Denied INTEGER NULL,
DeniedReason VARCHAR(100) NULL,
RequestType INTEGER NOT NULL,
FOREIGN KEY (IssueId) REFERENCES MovieIssues(Id),
FOREIGN KEY (RequestedUserId) REFERENCES Users(Id)
);
CREATE TABLE IF NOT EXISTS TvRequests (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ImdbId VARCHAR(20) NOT NULL,
TvDbId INTEGER NOT NULL,
Overview VARCHAR(100) NOT NULL,
Title VARCHAR(50) NOT NULL,
PosterPath VARCHAR(100) NOT NULL,
ReleaseDate VARCHAR(100) NOT NULL,
Status VARCHAR(100) NULL,
RootFolder INTEGER NULL
);
CREATE TABLE IF NOT EXISTS ChildRequests (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Approved INTEGER NOT NULL,
Available INTEGER NOT NULL,
RequestedDate VARCHAR(100) NOT NULL,
RequestedUserId INTEGER NOT NULL,
IssueId INTEGER NULL,
Denied INTEGER NULL,
DeniedReason VARCHAR(100) NULL,
ParentRequestId INTEGER NOT NULL,
RequestType INTEGER NOT NULL,
FOREIGN KEY (IssueId) REFERENCES TvIssues(Id),
FOREIGN KEY (ParentRequestId) REFERENCES TvRequests(Id),
FOREIGN KEY (RequestedUserId) REFERENCES Users(Id)
);
CREATE TABLE IF NOT EXISTS SeasonRequests (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
SeasonNumber INTEGER NOT NULL,
ChildRequestId INTEGER NOT NULL,
FOREIGN KEY (ChildRequestId) REFERENCES ChildRequests(Id)
);
CREATE TABLE IF NOT EXISTS EpisodeRequests (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
EpisodeNumber INTEGER NOT NULL,
Title VARCHAR(100) NOT NULL,
AirDate VARCHAR(100) NOT NULL,
Url VARCHAR(100) NOT NULL,
SeasonId INTEGER NOT NULL,
Available INTEGER NOT NULL,
FOREIGN KEY (SeasonId) REFERENCES SeasonRequests(Id)
);

@ -1,4 +1,6 @@
export interface IMediaBase { import { IUser } from './IUser';
export interface IMediaBase {
imdbId: string, imdbId: string,
id: number, id: number,
providerId: number, providerId: number,
@ -73,5 +75,68 @@ export interface IRequestsPageScroll {
export interface IRequestGrid<T> { export interface IRequestGrid<T> {
available: T[], available: T[],
new: T[], new: T[],
approved:T[] approved: T[]
} }
// NEW WORLD
export interface IMovieRequests extends IFullBaseRequest {
theMovieDbId: number,
}
export interface IFullBaseRequest extends IBaseRequest {
imdbId: string,
overview: string,
title: string,
posterPath: string,
releaseDate: Date,
status: string,
released: boolean,
}
export interface IBaseRequest {
id: number,
approved: boolean,
requestedDate: Date,
available: boolean,
requestedUserId: number,
issueId: number,
denied: boolean,
deniedReason: string,
requestType: RequestType,
requestedUser: IUser
}
export interface ITvRequests {
id: number,
imdbId: string,
rootFolder: number,
overview: string,
title: string,
posterPath: string,
releaseDate: Date,
status: string,
childRequests: IChildRequests[]
}
export interface IChildRequests extends IBaseRequest {
seasonRequests: INewSeasonRequests[]
}
export interface INewSeasonRequests {
id: number,
seasonNumber: number,
episodes: IEpisodesRequests[]
}
export interface IEpisodesRequests {
id: number,
episodeNumber: number,
title: string,
airDate: Date,
url: string,
available: boolean,
}

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { DragulaService } from 'ng2-dragula/ng2-dragula'; import { DragulaService } from 'ng2-dragula/ng2-dragula';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
import { ITvRequestModel, IMovieRequestModel, IRequestGrid } from '../interfaces/IRequestModel'; import { ITvRequests, IMovieRequests, IRequestGrid } from '../interfaces/IRequestModel';
@Component({ @Component({
templateUrl: './request-grid.component.html' templateUrl: './request-grid.component.html'
@ -24,7 +24,7 @@ export class RequestGridComponent implements OnInit {
} }
movieRequests: IRequestGrid<IMovieRequestModel>; movieRequests: IRequestGrid<IMovieRequests>;
tvRequests: IRequestGrid<ITvRequestModel>; tvRequests: IRequestGrid<ITvRequests>;
} }

@ -13,7 +13,7 @@ import 'rxjs/add/operator/map';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
import { IdentityService } from '../services/identity.service'; import { IdentityService } from '../services/identity.service';
import { IMovieRequestModel } from '../interfaces/IRequestModel'; import { IMovieRequests } from '../interfaces/IRequestModel';
@Component({ @Component({
selector: 'movie-requests', selector: 'movie-requests',
@ -37,7 +37,7 @@ export class MovieRequestsComponent implements OnInit, OnDestroy {
}); });
} }
movieRequests: IMovieRequestModel[]; movieRequests: IMovieRequests[];
searchChanged: Subject<string> = new Subject<string>(); searchChanged: Subject<string> = new Subject<string>();
searchText: string; searchText: string;
@ -66,25 +66,25 @@ export class MovieRequestsComponent implements OnInit, OnDestroy {
this.searchChanged.next(text.target.value); this.searchChanged.next(text.target.value);
} }
removeRequest(request: IMovieRequestModel) { removeRequest(request: IMovieRequests) {
this.requestService.removeMovieRequest(request); this.requestService.removeMovieRequest(request);
this.removeRequestFromUi(request); this.removeRequestFromUi(request);
this.loadRequests(1, this.currentlyLoaded); this.loadRequests(1, this.currentlyLoaded);
} }
changeAvailability(request: IMovieRequestModel, available: boolean) { changeAvailability(request: IMovieRequests, available: boolean) {
request.available = available; request.available = available;
this.updateRequest(request); this.updateRequest(request);
} }
approve(request: IMovieRequestModel) { approve(request: IMovieRequests) {
request.approved = true; request.approved = true;
request.denied = false; request.denied = false;
this.updateRequest(request); this.updateRequest(request);
} }
deny(request: IMovieRequestModel) { deny(request: IMovieRequests) {
request.approved = false; request.approved = false;
request.denied = true; request.denied = true;
this.updateRequest(request); this.updateRequest(request);
@ -99,7 +99,7 @@ export class MovieRequestsComponent implements OnInit, OnDestroy {
}); });
} }
private updateRequest(request: IMovieRequestModel) { private updateRequest(request: IMovieRequests) {
this.requestService.updateMovieRequest(request) this.requestService.updateMovieRequest(request)
.takeUntil(this.subscriptions) .takeUntil(this.subscriptions)
.subscribe(x => request = x); .subscribe(x => request = x);
@ -117,7 +117,7 @@ export class MovieRequestsComponent implements OnInit, OnDestroy {
this.loadInit(); this.loadInit();
} }
private removeRequestFromUi(key: IMovieRequestModel) { private removeRequestFromUi(key: IMovieRequests) {
var index = this.movieRequests.indexOf(key, 0); var index = this.movieRequests.indexOf(key, 0);
if (index > -1) { if (index > -1) {
this.movieRequests.splice(index, 1); this.movieRequests.splice(index, 1);

@ -59,7 +59,7 @@
{{/if}} {{/if}}
{{/if_eq}}--> {{/if_eq}}-->
<div *ngIf="request.requestedUsers">Requested By: <span *ngFor="let user of request.requestedUsers">{{user}} </span></div>
<div>Requested Date: {{request.requestedDate | date}}</div> <div>Requested Date: {{request.requestedDate | date}}</div>
<!--{{#if admin}} <!--{{#if admin}}
@ -187,6 +187,7 @@
<div class="modal fade in" *ngIf="showChildDialogue" style="display: block;"> <div class="modal fade in" *ngIf="showChildDialogue" style="display: block;">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
@ -201,21 +202,21 @@
<div class="col-md-9"> <div class="col-md-9">
<span class="col-md-12">Requested By: <b>{{child.requestedUser}}</b></span> <span class="col-md-12">Requested By: <b>{{child.requestedUser}}</b></span>
<span class="col-md-12" *ngIf="child.requestAll">Requested All Seasons</span> <!--<span class="col-md-12" *ngIf="child.requestAll">Requested All Seasons</span>-->
<!--Seasons--> <!--Seasons-->
<span *ngIf="child.approved && !child.available" class="label label-info">Processing Request</span> <span *ngIf="child.approved && !child.available" class="label label-info">Processing Request</span>
<span *ngIf="child.denied" class="label label-danger">Request Denied</span> <span *ngIf="child.denied" class="label label-danger">Request Denied</span>
<span *ngIf="child.deniedReason" title="{{child.deniedReason}}"><i class="fa fa-info-circle"></i></span> <span *ngIf="child.deniedReason" title="{{child.deniedReason}}"><i class="fa fa-info-circle"></i></span>
<span *ngIf="!child.approved && !child.availble && !child.denied" class="label label-warning">Pending Approval</span> <span *ngIf="!child.approved && !child.availble && !child.denied" class="label label-warning">Pending Approval</span>
<div class="col-md-12" *ngFor="let seasons of child.seasonRequests"> <div class="col-md-12" *ngFor="let seasons of child.seasonRequests">
<span>Season: {{seasons.seasonNumber}}</span> <span>Season: {{seasons.seasonNumber}}</span>
<span>Episodes:</span> <span>Episodes:</span>
<div *ngFor="let episode of seasons.episodes"> <div *ngFor="let episode of seasons.episodes">
<!--Episodes--> <!--Episodes-->
<span># {{episode.episodeNumber}}</span> <span># {{episode.episodeNumber}} | {{episode.title}}</span>
<span *ngIf="episode.available" class="label label-success">Available</span> <span *ngIf="episode.available" class="label label-success">Available</span>
</div> </div>
</div> </div>

@ -12,7 +12,7 @@ import 'rxjs/add/operator/map';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
import { IdentityService } from '../services/identity.service'; import { IdentityService } from '../services/identity.service';
import { ITvRequestModel, IChildTvRequest } from '../interfaces/IRequestModel'; import { ITvRequests, IChildRequests } from '../interfaces/IRequestModel';
@Component({ @Component({
selector: 'tv-requests', selector: 'tv-requests',
@ -39,7 +39,7 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
private subscriptions = new Subject<void>(); private subscriptions = new Subject<void>();
tvRequests: ITvRequestModel[]; tvRequests: ITvRequests[];
searchChanged = new Subject<string>(); searchChanged = new Subject<string>();
searchText: string; searchText: string;
@ -50,7 +50,7 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
private amountToLoad: number; private amountToLoad: number;
public showChildDialogue = false; // This is for the child modal popup public showChildDialogue = false; // This is for the child modal popup
public selectedSeason : ITvRequestModel; public selectedSeason: ITvRequests;
ngOnInit() { ngOnInit() {
@ -74,53 +74,53 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
this.searchChanged.next(text.target.value); this.searchChanged.next(text.target.value);
} }
public removeRequest(request: ITvRequestModel) { public removeRequest(request: ITvRequests) {
this.requestService.removeTvRequest(request); this.requestService.removeTvRequest(request);
this.removeRequestFromUi(request); this.removeRequestFromUi(request);
} }
public changeAvailability(request: ITvRequestModel, available: boolean) { public changeAvailability(request: IChildRequests, available: boolean) {
request.available = available; request.available = available;
this.updateRequest(request); //this.updateRequest(request);
} }
public approve(request: ITvRequestModel) { public approve(request: IChildRequests) {
request.approved = true; request.approved = true;
request.denied = false; request.denied = false;
this.updateRequest(request); //this.updateRequest(request);
} }
public deny(request: ITvRequestModel) { public deny(request: IChildRequests) {
request.approved = false; request.approved = false;
request.denied = true; request.denied = true;
this.updateRequest(request); //this.updateRequest(request);
} }
public approveSeasonRequest(request: IChildTvRequest) { public approveSeasonRequest(request: IChildRequests) {
request.approved = true; request.approved = true;
request.denied = false; request.denied = false;
this.requestService.updateTvRequest(this.selectedSeason) this.requestService.updateTvRequest(this.selectedSeason)
.subscribe(); .subscribe();
} }
public denySeasonRequest(request: IChildTvRequest) { public denySeasonRequest(request: IChildRequests) {
request.approved = false; request.approved = false;
request.denied = true; request.denied = true;
this.requestService.updateTvRequest(this.selectedSeason) this.requestService.updateTvRequest(this.selectedSeason)
.subscribe(); .subscribe();
} }
public showChildren(request: ITvRequestModel) { public showChildren(request: ITvRequests) {
this.selectedSeason = request; this.selectedSeason = request;
this.showChildDialogue = true; this.showChildDialogue = true;
} }
private updateRequest(request: ITvRequestModel) { //private updateRequest(request: ITvRequests) {
this.requestService.updateTvRequest(request) // this.requestService.updateTvRequest(request)
.takeUntil(this.subscriptions) // .takeUntil(this.subscriptions)
.subscribe(x => request = x); // .subscribe(x => request = x);
} //}
private loadInit() { private loadInit() {
this.requestService.getTvRequests(this.amountToLoad, 0) this.requestService.getTvRequests(this.amountToLoad, 0)
@ -136,7 +136,7 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
this.loadInit(); this.loadInit();
} }
private removeRequestFromUi(key: ITvRequestModel) { private removeRequestFromUi(key: ITvRequests) {
var index = this.tvRequests.indexOf(key, 0); var index = this.tvRequests.indexOf(key, 0);
if (index > -1) { if (index > -1) {
this.tvRequests.splice(index, 1); this.tvRequests.splice(index, 1);

@ -7,7 +7,7 @@ import { ServiceAuthHelpers } from './service.helpers';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult'; import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult'; import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
import { ISearchTvResult } from '../interfaces/ISearchTvResult'; import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { IMovieRequestModel, ITvRequestModel, IRequestCountModel, IRequestGrid } from '../interfaces/IRequestModel'; import { IMovieRequests, ITvRequests, IRequestCountModel, IRequestGrid } from '../interfaces/IRequestModel';
@Injectable() @Injectable()
export class RequestService extends ServiceAuthHelpers { export class RequestService extends ServiceAuthHelpers {
@ -23,35 +23,35 @@ export class RequestService extends ServiceAuthHelpers {
return this.http.post(`${this.url}TV/`, JSON.stringify(tv), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}TV/`, JSON.stringify(tv), { headers: this.headers }).map(this.extractData);
} }
getMovieRequests(count: number, position: number): Observable<IMovieRequestModel[]> { getMovieRequests(count: number, position: number): Observable<IMovieRequests[]> {
return this.http.get(`${this.url}movie/${count}/${position}`).map(this.extractData); return this.http.get(`${this.url}movie/${count}/${position}`).map(this.extractData);
} }
searchMovieRequests(search: string): Observable<IMovieRequestModel[]> { searchMovieRequests(search: string): Observable<IMovieRequests[]> {
return this.http.get(`${this.url}movie/search/${search}`).map(this.extractData); return this.http.get(`${this.url}movie/search/${search}`).map(this.extractData);
} }
removeMovieRequest(request: IMovieRequestModel) { removeMovieRequest(request: IMovieRequests) {
this.http.delete(`${this.url}movie/${request.id}`).map(this.extractData).subscribe(); this.http.delete(`${this.url}movie/${request.id}`).map(this.extractData).subscribe();
} }
updateMovieRequest(request: IMovieRequestModel): Observable<IMovieRequestModel> { updateMovieRequest(request: IMovieRequests): Observable<IMovieRequests> {
return this.http.post(`${this.url}movie/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}movie/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData);
} }
getTvRequests(count: number, position: number): Observable<ITvRequestModel[]> { getTvRequests(count: number, position: number): Observable<ITvRequests[]> {
return this.http.get(`${this.url}tv/${count}/${position}`).map(this.extractData); return this.http.get(`${this.url}tv/${count}/${position}`).map(this.extractData);
} }
searchTvRequests(search: string): Observable<ITvRequestModel[]> { searchTvRequests(search: string): Observable<ITvRequests[]> {
return this.http.get(`${this.url}tv/search/${search}`).map(this.extractData); return this.http.get(`${this.url}tv/search/${search}`).map(this.extractData);
} }
removeTvRequest(request: ITvRequestModel) { removeTvRequest(request: ITvRequests) {
this.http.delete(`${this.url}tv/${request.id}`).map(this.extractData).subscribe(); this.http.delete(`${this.url}tv/${request.id}`).map(this.extractData).subscribe();
} }
updateTvRequest(request: ITvRequestModel): Observable<ITvRequestModel> { updateTvRequest(request: ITvRequests): Observable<ITvRequests> {
return this.http.put(`${this.url}tv/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData); return this.http.put(`${this.url}tv/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData);
} }
@ -59,11 +59,11 @@ export class RequestService extends ServiceAuthHelpers {
return this.basicHttp.get(`${this.url}count`).map(this.extractData); return this.basicHttp.get(`${this.url}count`).map(this.extractData);
} }
getMovieGrid(): Observable<IRequestGrid<IMovieRequestModel>> { getMovieGrid(): Observable<IRequestGrid<IMovieRequests>> {
return this.http.get(`${this.url}movie/grid`).map(this.extractData); return this.http.get(`${this.url}movie/grid`).map(this.extractData);
} }
getTvGrid(): Observable<IRequestGrid<ITvRequestModel>> { getTvGrid(): Observable<IRequestGrid<ITvRequests>> {
return this.http.get(`${this.url}tv/grid`).map(this.extractData); return this.http.get(`${this.url}tv/grid`).map(this.extractData);
} }
} }

@ -3,13 +3,10 @@ using Microsoft.AspNetCore.Mvc;
using Ombi.Core.Engine; using Ombi.Core.Engine;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Requests.Movie;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Models; using Ombi.Store.Entities.Requests;
using Ombi.Notifications.Models;
namespace Ombi.Controllers namespace Ombi.Controllers
{ {
@ -31,7 +28,7 @@ namespace Ombi.Controllers
/// <param name="count">The count of items you want to return.</param> /// <param name="count">The count of items you want to return.</param>
/// <param name="position">The position.</param> /// <param name="position">The position.</param>
[HttpGet("movie/{count:int}/{position:int}")] [HttpGet("movie/{count:int}/{position:int}")]
public async Task<IEnumerable<MovieRequestModel>> GetRequests(int count, int position) public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
{ {
return await MovieRequestEngine.GetRequests(count, position); return await MovieRequestEngine.GetRequests(count, position);
} }
@ -40,7 +37,7 @@ namespace Ombi.Controllers
/// Gets all movie requests. /// Gets all movie requests.
/// </summary> /// </summary>
[HttpGet("movie")] [HttpGet("movie")]
public async Task<IEnumerable<MovieRequestModel>> GetRequests() public async Task<IEnumerable<MovieRequests>> GetRequests()
{ {
return await MovieRequestEngine.GetRequests(); return await MovieRequestEngine.GetRequests();
} }
@ -62,7 +59,7 @@ namespace Ombi.Controllers
/// <param name="searchTerm">The search term.</param> /// <param name="searchTerm">The search term.</param>
/// <returns></returns> /// <returns></returns>
[HttpGet("movie/search/{searchTerm}")] [HttpGet("movie/search/{searchTerm}")]
public async Task<IEnumerable<MovieRequestModel>> Search(string searchTerm) public async Task<IEnumerable<MovieRequests>> Search(string searchTerm)
{ {
return await MovieRequestEngine.SearchMovieRequest(searchTerm); return await MovieRequestEngine.SearchMovieRequest(searchTerm);
} }
@ -84,7 +81,7 @@ namespace Ombi.Controllers
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[HttpPut("movie")] [HttpPut("movie")]
public async Task<MovieRequestModel> UpdateRequest([FromBody] MovieRequestModel model) public async Task<MovieRequests> UpdateRequest([FromBody] MovieRequests model)
{ {
return await MovieRequestEngine.UpdateMovieRequest(model); return await MovieRequestEngine.UpdateMovieRequest(model);
} }
@ -96,7 +93,7 @@ namespace Ombi.Controllers
/// <param name="position">The position.</param> /// <param name="position">The position.</param>
/// <returns></returns> /// <returns></returns>
[HttpGet("tv/{count:int}/{position:int}")] [HttpGet("tv/{count:int}/{position:int}")]
public async Task<IEnumerable<TvRequestModel>> GetTvRequests(int count, int position) public async Task<IEnumerable<TvRequests>> GetTvRequests(int count, int position)
{ {
return await TvRequestEngine.GetRequests(count, position); return await TvRequestEngine.GetRequests(count, position);
} }
@ -106,7 +103,7 @@ namespace Ombi.Controllers
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpGet("tv")] [HttpGet("tv")]
public async Task<IEnumerable<TvRequestModel>> GetTvRequests() public async Task<IEnumerable<TvRequests>> GetTvRequests()
{ {
return await TvRequestEngine.GetRequests(); return await TvRequestEngine.GetRequests();
} }
@ -128,7 +125,7 @@ namespace Ombi.Controllers
/// <param name="searchTerm">The search term.</param> /// <param name="searchTerm">The search term.</param>
/// <returns></returns> /// <returns></returns>
[HttpGet("tv/search/{searchTerm}")] [HttpGet("tv/search/{searchTerm}")]
public async Task<IEnumerable<TvRequestModel>> SearchTv(string searchTerm) public async Task<IEnumerable<TvRequests>> SearchTv(string searchTerm)
{ {
return await TvRequestEngine.SearchTvRequest(searchTerm); return await TvRequestEngine.SearchTvRequest(searchTerm);
} }
@ -150,7 +147,7 @@ namespace Ombi.Controllers
/// <param name="model">The model.</param> /// <param name="model">The model.</param>
/// <returns></returns> /// <returns></returns>
[HttpPut("tv")] [HttpPut("tv")]
public async Task<TvRequestModel> UpdateRequest([FromBody] TvRequestModel model) public async Task<TvRequests> UpdateRequest([FromBody] TvRequests model)
{ {
return await TvRequestEngine.UpdateTvRequest(model); return await TvRequestEngine.UpdateTvRequest(model);
} }
@ -167,39 +164,39 @@ namespace Ombi.Controllers
return TvRequestEngine.RequestCount(); return TvRequestEngine.RequestCount();
} }
/// <summary> ///// <summary>
/// Gets the specific grid model for the requests (for modelling the UI). ///// Gets the specific grid model for the requests (for modelling the UI).
/// </summary> ///// </summary>
/// <returns></returns> ///// <returns></returns>
[HttpGet("tv/grid")] //[HttpGet("tv/grid")]
[ApiExplorerSettings(IgnoreApi = true)] //[ApiExplorerSettings(IgnoreApi = true)]
public async Task<RequestGridModel<TvRequestModel>> GetTvRequestsGrid() //public async Task<RequestGridModel<TvRequests>> GetTvRequestsGrid()
{ //{
return await GetGrid(TvRequestEngine); // return await GetGrid(TvRequestEngine);
} //}
/// <summary> ///// <summary>
/// Gets the specific grid model for the requests (for modelling the UI). ///// Gets the specific grid model for the requests (for modelling the UI).
/// </summary> ///// </summary>
/// <returns></returns> ///// <returns></returns>
[HttpGet("movie/grid")] //[HttpGet("movie/grid")]
[ApiExplorerSettings(IgnoreApi = true)] //[ApiExplorerSettings(IgnoreApi = true)]
public async Task<RequestGridModel<MovieRequestModel>> GetMovieRequestsGrid() //public async Task<RequestGridModel<MovieRequests>> GetMovieRequestsGrid()
{ //{
return await GetGrid(MovieRequestEngine); // return await GetGrid(MovieRequestEngine);
} //}
private async Task<RequestGridModel<T>> GetGrid<T>(IRequestEngine<T> engine) where T : BaseRequestModel //private async Task<RequestGridModel<T>> GetGrid<T>(IRequestEngine<T> engine) where T : BaseRequestModel
{ //{
var allRequests = await engine.GetRequests(); // var allRequests = await engine.GetRequests();
var r = allRequests.ToList(); // var r = allRequests.ToList();
var model = new RequestGridModel<T> // var model = new RequestGridModel<T>
{ // {
Available = r.Where(x => x.Available && !x.Approved), // Available = r.Where(x => x.Available && !x.Approved),
Approved = r.Where(x => x.Approved && !x.Available), // Approved = r.Where(x => x.Approved && !x.Available),
New = r.Where(x => !x.Available && !x.Approved) // New = r.Where(x => !x.Available && !x.Approved)
}; // };
return model; // return model;
} //}
} }
} }

@ -13,7 +13,9 @@ namespace Ombi
{ {
public partial class Startup public partial class Startup
{ {
/// <summary>
/// A key...
/// </summary>
public SymmetricSecurityKey SigningKey; public SymmetricSecurityKey SigningKey;
private void ConfigureAuth(IApplicationBuilder app, IOptions<TokenAuthenticationOptions> options) private void ConfigureAuth(IApplicationBuilder app, IOptions<TokenAuthenticationOptions> options)
{ {

Loading…
Cancel
Save