diff --git a/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs
new file mode 100644
index 000000000..a7b17d61c
--- /dev/null
+++ b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs
@@ -0,0 +1,37 @@
+#region Copyright
+// /************************************************************************
+// Copyright (c) 2016 Jamie Rees
+// File: ICouchPotatoApi.cs
+// Created By: Jamie Rees
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// ************************************************************************/
+#endregion
+
+using System;
+
+namespace PlexRequests.Api.Interfaces
+{
+ public interface ICouchPotatoApi
+ {
+ bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl);
+
+ }
+}
\ No newline at end of file
diff --git a/PlexRequests.Api.Interfaces/IPlexApi.cs b/PlexRequests.Api.Interfaces/IPlexApi.cs
index 3ce0ee7d0..59fffb5d5 100644
--- a/PlexRequests.Api.Interfaces/IPlexApi.cs
+++ b/PlexRequests.Api.Interfaces/IPlexApi.cs
@@ -27,6 +27,7 @@
using System;
using PlexRequests.Api.Models;
+using PlexRequests.Api.Models.Plex;
namespace PlexRequests.Api.Interfaces
{
diff --git a/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj b/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj
index 005a42c47..45ff3157f 100644
--- a/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj
+++ b/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj
@@ -46,6 +46,7 @@
+
diff --git a/PlexRequests.Api.Models/Plex/PlexAuthentication.cs b/PlexRequests.Api.Models/Plex/PlexAuthentication.cs
index 36f65c1b8..7d4a1a0be 100644
--- a/PlexRequests.Api.Models/Plex/PlexAuthentication.cs
+++ b/PlexRequests.Api.Models/Plex/PlexAuthentication.cs
@@ -24,9 +24,10 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
+
using System.Collections.Generic;
-namespace PlexRequests.Api.Models
+namespace PlexRequests.Api.Models.Plex
{
public class PlexAuthentication
{
diff --git a/PlexRequests.Api.Models/Plex/PlexError.cs b/PlexRequests.Api.Models/Plex/PlexError.cs
index 7dc696fc9..f62a0a7f0 100644
--- a/PlexRequests.Api.Models/Plex/PlexError.cs
+++ b/PlexRequests.Api.Models/Plex/PlexError.cs
@@ -24,9 +24,10 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
+
using System.Xml.Serialization;
-namespace PlexRequests.Api.Models
+namespace PlexRequests.Api.Models.Plex
{
[XmlRoot(ElementName = "errors")]
public class PlexError
diff --git a/PlexRequests.Api.Models/Plex/PlexFriends.cs b/PlexRequests.Api.Models/Plex/PlexFriends.cs
index db3523057..886b12dbf 100644
--- a/PlexRequests.Api.Models/Plex/PlexFriends.cs
+++ b/PlexRequests.Api.Models/Plex/PlexFriends.cs
@@ -24,10 +24,10 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
-using System.Collections.Generic;
+
using System.Xml.Serialization;
-namespace PlexRequests.Api.Models
+namespace PlexRequests.Api.Models.Plex
{
[XmlRoot(ElementName = "Server")]
public class Server
diff --git a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj
index 6025b2705..21d6ccefc 100644
--- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj
+++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj
@@ -9,8 +9,9 @@
Properties
PlexRequests.Api.Models
PlexRequests.Api.Models
- v4.5.2
+ v4.6
512
+
true
diff --git a/PlexRequests.Api/ApiRequest.cs b/PlexRequests.Api/ApiRequest.cs
index 205089a34..f90aec7cf 100644
--- a/PlexRequests.Api/ApiRequest.cs
+++ b/PlexRequests.Api/ApiRequest.cs
@@ -36,7 +36,6 @@ using Newtonsoft.Json.Linq;
using NLog;
using PlexRequests.Api.Interfaces;
-using PlexRequests.Api.Models;
using RestSharp;
diff --git a/PlexRequests.Api/CouchPotatoApi.cs b/PlexRequests.Api/CouchPotatoApi.cs
index cf9fd7d04..0f8e91fcd 100644
--- a/PlexRequests.Api/CouchPotatoApi.cs
+++ b/PlexRequests.Api/CouchPotatoApi.cs
@@ -29,12 +29,12 @@ using System;
using Newtonsoft.Json.Linq;
using NLog;
-
+using PlexRequests.Api.Interfaces;
using RestSharp;
namespace PlexRequests.Api
{
- public class CouchPotatoApi
+ public class CouchPotatoApi : ICouchPotatoApi
{
public CouchPotatoApi()
{
diff --git a/PlexRequests.Api/PlexApi.cs b/PlexRequests.Api/PlexApi.cs
index 9fc190e6b..cf31ce53e 100644
--- a/PlexRequests.Api/PlexApi.cs
+++ b/PlexRequests.Api/PlexApi.cs
@@ -28,6 +28,7 @@ using System;
using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models;
+using PlexRequests.Api.Models.Plex;
using PlexRequests.Helpers;
using RestSharp;
diff --git a/PlexRequests.UI.Tests/UserLoginModuleTests.cs b/PlexRequests.UI.Tests/UserLoginModuleTests.cs
index 444f679be..6b4e0b4d3 100644
--- a/PlexRequests.UI.Tests/UserLoginModuleTests.cs
+++ b/PlexRequests.UI.Tests/UserLoginModuleTests.cs
@@ -37,6 +37,7 @@ using NUnit.Framework;
using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models;
+using PlexRequests.Api.Models.Plex;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.UI.Models;
@@ -91,6 +92,39 @@ namespace PlexRequests.UI.Tests
PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never);
}
+ [Test]
+ public void LoginWithoutAuthenticationWithEmptyUsername()
+ {
+ var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
+ AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
+
+ var bootstrapper = new ConfigurableBootstrapper(with =>
+ {
+ with.Module();
+ with.Dependency(AuthMock.Object);
+ with.Dependency(PlexMock.Object);
+ with.RootPathProvider();
+ });
+
+ bootstrapper.WithSession(new Dictionary());
+
+ var browser = new Browser(bootstrapper);
+ var result = browser.Post("/userlogin", with =>
+ {
+ with.HttpRequest();
+ with.Header("Accept", "application/json");
+ with.FormValue("Username", string.Empty);
+ });
+
+ Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
+
+ var body = JsonConvert.DeserializeObject(result.Body.AsString());
+ Assert.That(body.Result, Is.EqualTo(false));
+ AuthMock.Verify(x => x.GetSettings(), Times.Never);
+ PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never);
+ PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never);
+ }
+
[Test]
public void LoginWithUsernameSuccessfully()
{
diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs
index f27f9a0ac..7d9a09bc3 100644
--- a/PlexRequests.UI/Bootstrapper.cs
+++ b/PlexRequests.UI/Bootstrapper.cs
@@ -76,6 +76,10 @@ namespace PlexRequests.UI
container.Register();
container.Register();
+ container.Register();
+
+
+
container.Register();
base.ConfigureRequestContainer(container, context);
diff --git a/PlexRequests.UI/Content/requests.js b/PlexRequests.UI/Content/requests.js
index e216b0ee5..f3651efac 100644
--- a/PlexRequests.UI/Content/requests.js
+++ b/PlexRequests.UI/Content/requests.js
@@ -13,6 +13,7 @@ var tvimer = 0;
movieLoad();
tvLoad();
+// Approve all
$('#approveAll').click(function () {
$.ajax({
type: 'post',
@@ -127,6 +128,34 @@ $(document).on("click", ".delete", function (e) {
});
+// Approve single request
+$(document).on("click", ".approve", function (e) {
+ e.preventDefault();
+ var buttonId = e.target.id;
+ var $form = $('#approve' + buttonId);
+
+ $.ajax({
+ type: $form.prop('method'),
+ url: $form.prop('action'),
+ data: $form.serialize(),
+ dataType: "json",
+ success: function (response) {
+
+ if (checkJsonResponse(response)) {
+ generateNotify("Success! Request Approved.", "success");
+
+ $("button[custom-button='" + buttonId + "']").remove();
+ $("#" + buttonId + "notapproved").prop("class", "fa fa-check");
+ }
+ },
+ error: function (e) {
+ console.log(e);
+ generateNotify("Something went wrong!", "danger");
+ }
+ });
+
+});
+
// Clear issues
$(document).on("click", ".clear", function (e) {
e.preventDefault();
diff --git a/PlexRequests.UI/Content/site.js b/PlexRequests.UI/Content/site.js
index 4f8efeac6..d16a70def 100644
--- a/PlexRequests.UI/Content/site.js
+++ b/PlexRequests.UI/Content/site.js
@@ -5,7 +5,13 @@
message: message
}, {
// settings
- type: type
+ type: type,
+ animate: {
+ enter: 'animated bounceInDown',
+ exit: 'animated bounceOutUp'
+ },
+ newest_on_top: true
+
});
}
diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs
index 4128fdab9..2c11b46b5 100644
--- a/PlexRequests.UI/Modules/ApprovalModule.cs
+++ b/PlexRequests.UI/Modules/ApprovalModule.cs
@@ -32,7 +32,10 @@ using Nancy;
using Nancy.Security;
using NLog;
-
+using PlexRequests.Api;
+using PlexRequests.Api.Interfaces;
+using PlexRequests.Core;
+using PlexRequests.Core.SettingModels;
using PlexRequests.Store;
using PlexRequests.UI.Models;
@@ -41,11 +44,13 @@ namespace PlexRequests.UI.Modules
public class ApprovalModule : BaseModule
{
- public ApprovalModule(IRepository service) : base("approval")
+ public ApprovalModule(IRepository service, ISettingsService cpService, ICouchPotatoApi cpApi) : base("approval")
{
this.RequiresAuthentication();
Service = service;
+ CpService = cpService;
+ CpApi = cpApi;
Post["/approve"] = parameters => Approve((int)Request.Form.requestid);
Post["/approveall"] = x => ApproveAll();
@@ -54,6 +59,8 @@ namespace PlexRequests.UI.Modules
private IRepository Service { get; set; }
private static Logger Log = LogManager.GetCurrentClassLogger();
+ private ISettingsService CpService { get; }
+ private ICouchPotatoApi CpApi { get; }
///
/// Approves the specified request identifier.
@@ -62,6 +69,10 @@ namespace PlexRequests.UI.Modules
///
private Response Approve(int requestId)
{
+ if (!Context.CurrentUser.IsAuthenticated())
+ {
+ return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
+ }
// Get the request from the DB
var request = Service.Get(requestId);
@@ -71,15 +82,59 @@ namespace PlexRequests.UI.Modules
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no requests to approve. Please refresh." });
}
- // Approve it
- request.Approved = true;
+ switch (request.Type)
+ {
+ case RequestType.Movie:
+ return RequestMovieAndUpdateStatus(request);
+ case RequestType.TvShow:
+ return RequestTvAndUpdateStatus(request);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(request));
+ }
+ }
- // Update the record
- var result = Service.Update(request);
+ private Response RequestTvAndUpdateStatus(RequestedModel request)
+ {
+ // TODO
+ return Response.AsJson(new JsonResponseModel());
+ }
- return Response.AsJson(result
- ? new JsonResponseModel { Result = true }
- : new JsonResponseModel { Result = false, Message = "We could not approve this request. Please try again or check the logs." });
+ private Response RequestMovieAndUpdateStatus(RequestedModel request)
+ {
+ if (!Context.CurrentUser.IsAuthenticated())
+ {
+ return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
+ }
+
+ var cpSettings = CpService.GetSettings();
+ var cp = new CouchPotatoApi();
+ Log.Info("Adding movie to CP : {0}", request.Title);
+ var result = cp.AddMovie(request.ImdbId, cpSettings.ApiKey, request.Title, cpSettings.FullUri);
+ Log.Trace("Adding movie to CP result {0}", result);
+ if (result)
+ {
+ // Approve it
+ request.Approved = true;
+
+ // Update the record
+ var inserted = Service.Update(request);
+
+ return Response.AsJson(inserted
+ ? new JsonResponseModel {Result = true}
+ : new JsonResponseModel
+ {
+ Result = false,
+ Message = "We could not approve this request. Please try again or check the logs."
+ });
+ }
+ return
+ Response.AsJson(
+ new
+ {
+ Result = false,
+ Message =
+ "Something went wrong adding the movie to CouchPotato! Please check your settings."
+ });
}
///
@@ -88,18 +143,36 @@ namespace PlexRequests.UI.Modules
///
private Response ApproveAll()
{
- var requests = Service.GetAll();
+ var requests = Service.GetAll().Where(x => x.Approved == false);
var requestedModels = requests as RequestedModel[] ?? requests.ToArray();
if (!requestedModels.Any())
{
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no requests to approve. Please refresh." });
}
+ var cpSettings = CpService.GetSettings();
+
+
var updatedRequests = new List();
foreach (var r in requestedModels)
{
- r.Approved = true;
- updatedRequests.Add(r);
+ if (r.Type == RequestType.Movie)
+ {
+ var result = SendMovie(cpSettings, r, CpApi);
+ if (result)
+ {
+ r.Approved = true;
+ updatedRequests.Add(r);
+ }
+ else
+ {
+ Log.Error("Could not approve send the movie {0} to couch potato!", r.Title);
+ }
+ }
+ if (r.Type == RequestType.TvShow)
+ {
+ // TODO
+ }
}
try
{
@@ -116,5 +189,14 @@ namespace PlexRequests.UI.Modules
}
}
+
+
+ private bool SendMovie(CouchPotatoSettings settings, RequestedModel r, ICouchPotatoApi cp)
+ {
+ Log.Info("Adding movie to CP : {0}", r.Title);
+ var result = cp.AddMovie(r.ImdbId, settings.ApiKey, r.Title, settings.FullUri);
+ Log.Trace("Adding movie to CP result {0}", result);
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/PlexRequests.UI/Modules/UserLoginModule.cs b/PlexRequests.UI/Modules/UserLoginModule.cs
index fba37f859..e8f6d214e 100644
--- a/PlexRequests.UI/Modules/UserLoginModule.cs
+++ b/PlexRequests.UI/Modules/UserLoginModule.cs
@@ -32,6 +32,7 @@ using Nancy.Responses.Negotiation;
using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models;
+using PlexRequests.Api.Models.Plex;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.UI.Models;
@@ -61,10 +62,17 @@ namespace PlexRequests.UI.Modules
private Response LoginUser()
{
+ var username = Request.Form.username.Value;
+
+ if (string.IsNullOrWhiteSpace(username))
+ {
+ return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" });
+ }
+
var authenticated = false;
var settings = AuthService.GetSettings();
- var username = Request.Form.username.Value;
+
if (IsUserInDeniedList(username, settings))
{
diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml
index f2bce55b3..586ce2406 100644
--- a/PlexRequests.UI/Views/Requests/Index.cshtml
+++ b/PlexRequests.UI/Views/Requests/Index.cshtml
@@ -4,7 +4,9 @@
Below you can see yours and all other requests, as well as their download and approval status.
@if (Context.CurrentUser.IsAuthenticated())
{
-
+
+
+
}