mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 04:49:33 -07:00
Merge pull request #110 from Drewster727/dev
misc changes (sorting, ui, requesting, testing, other)
This commit is contained in:
commit
0b1a589a70
31 changed files with 895 additions and 231 deletions
|
@ -33,7 +33,7 @@ namespace PlexRequests.Core
|
||||||
public interface IRequestService
|
public interface IRequestService
|
||||||
{
|
{
|
||||||
long AddRequest(RequestedModel model);
|
long AddRequest(RequestedModel model);
|
||||||
bool CheckRequest(int providerId);
|
RequestedModel CheckRequest(int providerId);
|
||||||
void DeleteRequest(RequestedModel request);
|
void DeleteRequest(RequestedModel request);
|
||||||
bool UpdateRequest(RequestedModel model);
|
bool UpdateRequest(RequestedModel model);
|
||||||
RequestedModel Get(int id);
|
RequestedModel Get(int id);
|
||||||
|
|
|
@ -58,10 +58,11 @@ namespace PlexRequests.Core
|
||||||
return result ? id : -1;
|
return result ? id : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CheckRequest(int providerId)
|
public RequestedModel CheckRequest(int providerId)
|
||||||
{
|
{
|
||||||
var blobs = Repo.GetAll();
|
var blobs = Repo.GetAll();
|
||||||
return blobs.Any(x => x.ProviderId == providerId);
|
var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId);
|
||||||
|
return blob != null ? ByteConverterHelper.ReturnObject<RequestedModel>(blob.Content) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteRequest(RequestedModel request)
|
public void DeleteRequest(RequestedModel request)
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace PlexRequests.Core.SettingModels
|
namespace PlexRequests.Core.SettingModels
|
||||||
{
|
{
|
||||||
public class PlexRequestSettings : Settings
|
public class PlexRequestSettings : Settings
|
||||||
|
@ -36,6 +40,29 @@ namespace PlexRequests.Core.SettingModels
|
||||||
public bool RequireMovieApproval { get; set; }
|
public bool RequireMovieApproval { get; set; }
|
||||||
public bool RequireTvShowApproval { get; set; }
|
public bool RequireTvShowApproval { get; set; }
|
||||||
public bool RequireMusicApproval { get; set; }
|
public bool RequireMusicApproval { get; set; }
|
||||||
|
public bool UsersCanViewOnlyOwnRequests { get; set; }
|
||||||
public int WeeklyRequestLimit { get; set; }
|
public int WeeklyRequestLimit { get; set; }
|
||||||
|
public string NoApprovalUsers { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<string> NoApprovalUserList
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var users = new List<string>();
|
||||||
|
if (string.IsNullOrEmpty(NoApprovalUsers))
|
||||||
|
{
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitUsers = NoApprovalUsers.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var user in splitUsers)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(user))
|
||||||
|
users.Add(user.Trim());
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using PlexRequests.Services.Notification;
|
using PlexRequests.Services.Notification;
|
||||||
|
using PlexRequests.Core.SettingModels;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Interfaces
|
namespace PlexRequests.Services.Interfaces
|
||||||
{
|
{
|
||||||
|
@ -35,5 +36,7 @@ namespace PlexRequests.Services.Interfaces
|
||||||
string NotificationName { get; }
|
string NotificationName { get; }
|
||||||
|
|
||||||
Task NotifyAsync(NotificationModel model);
|
Task NotifyAsync(NotificationModel model);
|
||||||
|
|
||||||
|
Task NotifyAsync(NotificationModel model, Settings settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,12 +27,14 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using PlexRequests.Services.Notification;
|
using PlexRequests.Services.Notification;
|
||||||
|
using PlexRequests.Core.SettingModels;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Interfaces
|
namespace PlexRequests.Services.Interfaces
|
||||||
{
|
{
|
||||||
public interface INotificationService
|
public interface INotificationService
|
||||||
{
|
{
|
||||||
Task Publish(NotificationModel model);
|
Task Publish(NotificationModel model);
|
||||||
|
Task Publish(NotificationModel model, Settings settings);
|
||||||
void Subscribe(INotification notification);
|
void Subscribe(INotification notification);
|
||||||
void UnSubscribe(INotification notification);
|
void UnSubscribe(INotification notification);
|
||||||
|
|
||||||
|
|
|
@ -46,24 +46,29 @@ namespace PlexRequests.Services.Notification
|
||||||
|
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private ISettingsService<EmailNotificationSettings> EmailNotificationSettings { get; }
|
private ISettingsService<EmailNotificationSettings> EmailNotificationSettings { get; }
|
||||||
private EmailNotificationSettings Settings => GetConfiguration();
|
|
||||||
public string NotificationName => "EmailMessageNotification";
|
public string NotificationName => "EmailMessageNotification";
|
||||||
|
|
||||||
public async Task NotifyAsync(NotificationModel model)
|
public async Task NotifyAsync(NotificationModel model)
|
||||||
{
|
{
|
||||||
var configuration = GetConfiguration();
|
var configuration = GetConfiguration();
|
||||||
if (!ValidateConfiguration(configuration))
|
await NotifyAsync(model, configuration);
|
||||||
{
|
}
|
||||||
return;
|
|
||||||
}
|
public async Task NotifyAsync(NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
|
var emailSettings = (EmailNotificationSettings)settings;
|
||||||
|
|
||||||
|
if (!ValidateConfiguration(emailSettings)) return;
|
||||||
|
|
||||||
switch (model.NotificationType)
|
switch (model.NotificationType)
|
||||||
{
|
{
|
||||||
case NotificationType.NewRequest:
|
case NotificationType.NewRequest:
|
||||||
await EmailNewRequest(model);
|
await EmailNewRequest(model, emailSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.Issue:
|
case NotificationType.Issue:
|
||||||
await EmailIssue(model);
|
await EmailIssue(model, emailSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.RequestAvailable:
|
case NotificationType.RequestAvailable:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -74,6 +79,10 @@ namespace PlexRequests.Services.Notification
|
||||||
case NotificationType.AdminNote:
|
case NotificationType.AdminNote:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
case NotificationType.Test:
|
||||||
|
await EmailTest(model, emailSettings);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -100,23 +109,23 @@ namespace PlexRequests.Services.Notification
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EmailNewRequest(NotificationModel model)
|
private async Task EmailNewRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = new MailMessage
|
var message = new MailMessage
|
||||||
{
|
{
|
||||||
IsBodyHtml = true,
|
IsBodyHtml = true,
|
||||||
To = { new MailAddress(Settings.RecipientEmail) },
|
To = { new MailAddress(settings.RecipientEmail) },
|
||||||
Body = $"Hello! The user '{model.User}' has requested {model.Title}! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}",
|
Body = $"Hello! The user '{model.User}' has requested {model.Title}! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}",
|
||||||
From = new MailAddress(Settings.EmailSender),
|
From = new MailAddress(settings.EmailSender),
|
||||||
Subject = $"Plex Requests: New request for {model.Title}!"
|
Subject = $"Plex Requests: New request for {model.Title}!"
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var smtp = new SmtpClient(Settings.EmailHost, Settings.EmailPort))
|
using (var smtp = new SmtpClient(settings.EmailHost, settings.EmailPort))
|
||||||
{
|
{
|
||||||
smtp.Credentials = new NetworkCredential(Settings.EmailUsername, Settings.EmailPassword);
|
smtp.Credentials = new NetworkCredential(settings.EmailUsername, settings.EmailPassword);
|
||||||
smtp.EnableSsl = Settings.Ssl;
|
smtp.EnableSsl = settings.Ssl;
|
||||||
await smtp.SendMailAsync(message).ConfigureAwait(false);
|
await smtp.SendMailAsync(message).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,23 +139,53 @@ namespace PlexRequests.Services.Notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EmailIssue(NotificationModel model)
|
private async Task EmailIssue(NotificationModel model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = new MailMessage
|
var message = new MailMessage
|
||||||
{
|
{
|
||||||
IsBodyHtml = true,
|
IsBodyHtml = true,
|
||||||
To = { new MailAddress(Settings.RecipientEmail) },
|
To = { new MailAddress(settings.RecipientEmail) },
|
||||||
Body = $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
Body = $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
||||||
From = new MailAddress(Settings.RecipientEmail),
|
From = new MailAddress(settings.RecipientEmail),
|
||||||
Subject = $"Plex Requests: New issue for {model.Title}!"
|
Subject = $"Plex Requests: New issue for {model.Title}!"
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var smtp = new SmtpClient(Settings.EmailHost, Settings.EmailPort))
|
using (var smtp = new SmtpClient(settings.EmailHost, settings.EmailPort))
|
||||||
{
|
{
|
||||||
smtp.Credentials = new NetworkCredential(Settings.EmailUsername, Settings.EmailPassword);
|
smtp.Credentials = new NetworkCredential(settings.EmailUsername, settings.EmailPassword);
|
||||||
smtp.EnableSsl = Settings.Ssl;
|
smtp.EnableSsl = settings.Ssl;
|
||||||
|
await smtp.SendMailAsync(message).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SmtpException smtp)
|
||||||
|
{
|
||||||
|
Log.Error(smtp);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EmailTest(NotificationModel model, EmailNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = new MailMessage
|
||||||
|
{
|
||||||
|
IsBodyHtml = true,
|
||||||
|
To = { new MailAddress(settings.RecipientEmail) },
|
||||||
|
Body = "This is just a test! Success!",
|
||||||
|
From = new MailAddress(settings.RecipientEmail),
|
||||||
|
Subject = "Plex Requests: Test Message!"
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var smtp = new SmtpClient(settings.EmailHost, settings.EmailPort))
|
||||||
|
{
|
||||||
|
smtp.Credentials = new NetworkCredential(settings.EmailUsername, settings.EmailPassword);
|
||||||
|
smtp.EnableSsl = settings.Ssl;
|
||||||
await smtp.SendMailAsync(message).ConfigureAwait(false);
|
await smtp.SendMailAsync(message).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
using PlexRequests.Services.Interfaces;
|
using PlexRequests.Services.Interfaces;
|
||||||
|
using PlexRequests.Core.SettingModels;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Notification
|
namespace PlexRequests.Services.Notification
|
||||||
{
|
{
|
||||||
|
@ -47,6 +48,13 @@ namespace PlexRequests.Services.Notification
|
||||||
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Publish(NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
var notificationTasks = Observers.Values.Select(notification => NotifyAsync(notification, model, settings));
|
||||||
|
|
||||||
|
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
public void Subscribe(INotification notification)
|
public void Subscribe(INotification notification)
|
||||||
{
|
{
|
||||||
Observers.TryAdd(notification.NotificationName, notification);
|
Observers.TryAdd(notification.NotificationName, notification);
|
||||||
|
@ -67,6 +75,19 @@ namespace PlexRequests.Services.Notification
|
||||||
{
|
{
|
||||||
Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception");
|
Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task NotifyAsync(INotification notification, NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await notification.NotifyAsync(model, settings).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,5 +33,6 @@ namespace PlexRequests.Services.Notification
|
||||||
RequestAvailable,
|
RequestAvailable,
|
||||||
RequestApproved,
|
RequestApproved,
|
||||||
AdminNote,
|
AdminNote,
|
||||||
|
Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,18 +51,25 @@ namespace PlexRequests.Services.Notification
|
||||||
public string NotificationName => "PushbulletNotification";
|
public string NotificationName => "PushbulletNotification";
|
||||||
public async Task NotifyAsync(NotificationModel model)
|
public async Task NotifyAsync(NotificationModel model)
|
||||||
{
|
{
|
||||||
if (!ValidateConfiguration())
|
var configuration = GetSettings();
|
||||||
{
|
await NotifyAsync(model, configuration);
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
public async Task NotifyAsync(NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
|
var pushSettings = (PushbulletNotificationSettings)settings;
|
||||||
|
|
||||||
|
if (!ValidateConfiguration(pushSettings)) return;
|
||||||
|
|
||||||
switch (model.NotificationType)
|
switch (model.NotificationType)
|
||||||
{
|
{
|
||||||
case NotificationType.NewRequest:
|
case NotificationType.NewRequest:
|
||||||
await PushNewRequestAsync(model);
|
await PushNewRequestAsync(model, pushSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.Issue:
|
case NotificationType.Issue:
|
||||||
await PushIssueAsync(model);
|
await PushIssueAsync(model, pushSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.RequestAvailable:
|
case NotificationType.RequestAvailable:
|
||||||
break;
|
break;
|
||||||
|
@ -70,18 +77,21 @@ namespace PlexRequests.Services.Notification
|
||||||
break;
|
break;
|
||||||
case NotificationType.AdminNote:
|
case NotificationType.AdminNote:
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.Test:
|
||||||
|
await PushTestAsync(model, pushSettings);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateConfiguration()
|
private bool ValidateConfiguration(PushbulletNotificationSettings settings)
|
||||||
{
|
{
|
||||||
if (!Settings.Enabled)
|
if (!settings.Enabled)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(Settings.AccessToken))
|
if (string.IsNullOrEmpty(settings.AccessToken))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,13 +103,13 @@ namespace PlexRequests.Services.Notification
|
||||||
return SettingsService.GetSettings();
|
return SettingsService.GetSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushNewRequestAsync(NotificationModel model)
|
private async Task PushNewRequestAsync(NotificationModel model, PushbulletNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = $"{model.Title} has been requested by user: {model.User}";
|
var message = $"{model.Title} has been requested by user: {model.User}";
|
||||||
var pushTitle = $"Plex Requests: {model.Title} has been requested!";
|
var pushTitle = $"Plex Requests: {model.Title} has been requested!";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await PushbulletApi.PushAsync(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier);
|
var result = await PushbulletApi.PushAsync(settings.AccessToken, pushTitle, message, settings.DeviceIdentifier);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
||||||
|
@ -111,13 +121,31 @@ namespace PlexRequests.Services.Notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushIssueAsync(NotificationModel model)
|
private async Task PushIssueAsync(NotificationModel model, PushbulletNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||||
var pushTitle = $"Plex Requests: A new issue has been reported for {model.Title}";
|
var pushTitle = $"Plex Requests: A new issue has been reported for {model.Title}";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await PushbulletApi.PushAsync(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier);
|
var result = await PushbulletApi.PushAsync(settings.AccessToken, pushTitle, message, settings.DeviceIdentifier);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushTestAsync(NotificationModel model, PushbulletNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = "This is just a test! Success!";
|
||||||
|
var pushTitle = "Plex Requests: Test Message!";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await PushbulletApi.PushAsync(settings.AccessToken, pushTitle, message, settings.DeviceIdentifier);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
Log.Error("Pushbullet api returned a null value, the notification did not get pushed");
|
||||||
|
|
|
@ -51,18 +51,25 @@ namespace PlexRequests.Services.Notification
|
||||||
public string NotificationName => "PushoverNotification";
|
public string NotificationName => "PushoverNotification";
|
||||||
public async Task NotifyAsync(NotificationModel model)
|
public async Task NotifyAsync(NotificationModel model)
|
||||||
{
|
{
|
||||||
if (!ValidateConfiguration())
|
var configuration = GetSettings();
|
||||||
{
|
await NotifyAsync(model, configuration);
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
public async Task NotifyAsync(NotificationModel model, Settings settings)
|
||||||
|
{
|
||||||
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
|
var pushSettings = (PushoverNotificationSettings)settings;
|
||||||
|
|
||||||
|
if (!ValidateConfiguration(pushSettings)) return;
|
||||||
|
|
||||||
switch (model.NotificationType)
|
switch (model.NotificationType)
|
||||||
{
|
{
|
||||||
case NotificationType.NewRequest:
|
case NotificationType.NewRequest:
|
||||||
await PushNewRequestAsync(model);
|
await PushNewRequestAsync(model, pushSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.Issue:
|
case NotificationType.Issue:
|
||||||
await PushIssueAsync(model);
|
await PushIssueAsync(model, pushSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.RequestAvailable:
|
case NotificationType.RequestAvailable:
|
||||||
break;
|
break;
|
||||||
|
@ -70,18 +77,21 @@ namespace PlexRequests.Services.Notification
|
||||||
break;
|
break;
|
||||||
case NotificationType.AdminNote:
|
case NotificationType.AdminNote:
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.Test:
|
||||||
|
await PushTestAsync(model, pushSettings);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateConfiguration()
|
private bool ValidateConfiguration(PushoverNotificationSettings settings)
|
||||||
{
|
{
|
||||||
if (!Settings.Enabled)
|
if (!settings.Enabled)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(Settings.AccessToken) || string.IsNullOrEmpty(Settings.UserToken))
|
if (string.IsNullOrEmpty(settings.AccessToken) || string.IsNullOrEmpty(settings.UserToken))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -93,12 +103,12 @@ namespace PlexRequests.Services.Notification
|
||||||
return SettingsService.GetSettings();
|
return SettingsService.GetSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushNewRequestAsync(NotificationModel model)
|
private async Task PushNewRequestAsync(NotificationModel model, PushoverNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = $"Plex Requests: {model.Title} has been requested by user: {model.User}";
|
var message = $"Plex Requests: {model.Title} has been requested by user: {model.User}";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await PushoverApi.PushAsync(Settings.AccessToken, message, Settings.UserToken);
|
var result = await PushoverApi.PushAsync(settings.AccessToken, message, settings.UserToken);
|
||||||
if (result?.status != 1)
|
if (result?.status != 1)
|
||||||
{
|
{
|
||||||
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
||||||
|
@ -110,12 +120,29 @@ namespace PlexRequests.Services.Notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PushIssueAsync(NotificationModel model)
|
private async Task PushIssueAsync(NotificationModel model, PushoverNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = $"Plex Requests: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
var message = $"Plex Requests: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await PushoverApi.PushAsync(Settings.AccessToken, message, Settings.UserToken);
|
var result = await PushoverApi.PushAsync(settings.AccessToken, message, settings.UserToken);
|
||||||
|
if (result?.status != 1)
|
||||||
|
{
|
||||||
|
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PushTestAsync(NotificationModel model, PushoverNotificationSettings settings)
|
||||||
|
{
|
||||||
|
var message = $"Plex Requests: Test Message!";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await PushoverApi.PushAsync(settings.AccessToken, message, settings.UserToken);
|
||||||
if (result?.status != 1)
|
if (result?.status != 1)
|
||||||
{
|
{
|
||||||
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed");
|
||||||
|
|
|
@ -2,12 +2,20 @@
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
using Dapper.Contrib.Extensions;
|
using Dapper.Contrib.Extensions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PlexRequests.Store
|
namespace PlexRequests.Store
|
||||||
{
|
{
|
||||||
[Table("Requested")]
|
[Table("Requested")]
|
||||||
public class RequestedModel : Entity
|
public class RequestedModel : Entity
|
||||||
{
|
{
|
||||||
|
public RequestedModel()
|
||||||
|
{
|
||||||
|
RequestedUsers = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once IdentifierTypo
|
// ReSharper disable once IdentifierTypo
|
||||||
public int ProviderId { get; set; }
|
public int ProviderId { get; set; }
|
||||||
public string ImdbId { get; set; }
|
public string ImdbId { get; set; }
|
||||||
|
@ -18,7 +26,10 @@ namespace PlexRequests.Store
|
||||||
public RequestType Type { get; set; }
|
public RequestType Type { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
|
|
||||||
|
[Obsolete("Use RequestedUsers")]
|
||||||
public string RequestedBy { get; set; }
|
public string RequestedBy { get; set; }
|
||||||
|
|
||||||
public DateTime RequestedDate { get; set; }
|
public DateTime RequestedDate { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
public IssueState Issues { get; set; }
|
public IssueState Issues { get; set; }
|
||||||
|
@ -27,6 +38,40 @@ namespace PlexRequests.Store
|
||||||
public int[] SeasonList { get; set; }
|
public int[] SeasonList { get; set; }
|
||||||
public int SeasonCount { get; set; }
|
public int SeasonCount { get; set; }
|
||||||
public string SeasonsRequested { get; set; }
|
public string SeasonsRequested { get; set; }
|
||||||
|
public List<string> RequestedUsers { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<string> AllUsers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var u = new List<string>();
|
||||||
|
if (!string.IsNullOrEmpty(RequestedBy))
|
||||||
|
{
|
||||||
|
u.Add(RequestedBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RequestedUsers.Any())
|
||||||
|
{
|
||||||
|
u.AddRange(RequestedUsers.Where(requestedUser => requestedUser != RequestedBy));
|
||||||
|
}
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool CanApprove
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !Approved && !Available;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UserHasRequested(string username)
|
||||||
|
{
|
||||||
|
return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RequestType
|
public enum RequestType
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
|
|
||||||
.form-control-custom {
|
.form-control-custom {
|
||||||
background-color: #4e5d6c !important;
|
background-color: #4e5d6c !important;
|
||||||
color: white !important; }
|
color: white !important;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: 0 0 0 !important; }
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 3.5rem !important;
|
font-size: 3.5rem !important;
|
||||||
|
@ -40,6 +42,18 @@ label {
|
||||||
margin-bottom: 0.5rem !important;
|
margin-bottom: 0.5rem !important;
|
||||||
font-size: 16px !important; }
|
font-size: 16px !important; }
|
||||||
|
|
||||||
|
.nav-tabs > li.active > a,
|
||||||
|
.nav-tabs > li.active > a:hover,
|
||||||
|
.nav-tabs > li.active > a:focus {
|
||||||
|
background: #4e5d6c; }
|
||||||
|
|
||||||
|
.navbar .nav a .fa {
|
||||||
|
font-size: 130%;
|
||||||
|
top: 1px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px; }
|
||||||
|
|
||||||
.btn-danger-outline {
|
.btn-danger-outline {
|
||||||
color: #d9534f !important;
|
color: #d9534f !important;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -162,3 +176,14 @@ label {
|
||||||
.scroll-top-wrapper i.fa {
|
.scroll-top-wrapper i.fa {
|
||||||
line-height: inherit; }
|
line-height: inherit; }
|
||||||
|
|
||||||
|
.no-search-results {
|
||||||
|
text-align: center; }
|
||||||
|
|
||||||
|
.no-search-results .no-search-results-icon {
|
||||||
|
font-size: 10em;
|
||||||
|
color: #4e5d6c; }
|
||||||
|
|
||||||
|
.no-search-results .no-search-results-text {
|
||||||
|
margin: 20px 0;
|
||||||
|
color: #ccc; }
|
||||||
|
|
||||||
|
|
2
PlexRequests.UI/Content/custom.min.css
vendored
2
PlexRequests.UI/Content/custom.min.css
vendored
|
@ -1 +1 @@
|
||||||
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}
|
@media(min-width:768px){.row{position:relative;}.bottom-align-text{position:absolute;bottom:0;right:0;}}@media(max-width:48em){.home{padding-top:1rem;}}@media(min-width:48em){.home{padding-top:4rem;}}.btn{border-radius:.25rem !important;}.multiSelect{background-color:#4e5d6c;}.form-control-custom{background-color:#4e5d6c !important;color:#fff !important;border-radius:0;box-shadow:0 0 0 !important;}h1{font-size:3.5rem !important;font-weight:600 !important;}.request-title{margin-top:0 !important;font-size:1.9rem !important;}p{font-size:1.1rem !important;}label{display:inline-block !important;margin-bottom:.5rem !important;font-size:16px !important;}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{background:#4e5d6c;}.navbar .nav a .fa{font-size:130%;top:1px;position:relative;display:inline-block;margin-right:5px;}.btn-danger-outline{color:#d9534f !important;background-color:transparent;background-image:none;border-color:#d9534f !important;}.btn-danger-outline:focus,.btn-danger-outline.focus,.btn-danger-outline:active,.btn-danger-outline.active,.btn-danger-outline:hover,.open>.btn-danger-outline.dropdown-toggle{color:#fff !important;background-color:#d9534f !important;border-color:#d9534f !important;}.btn-primary-outline{color:#ff761b !important;background-color:transparent;background-image:none;border-color:#ff761b !important;}.btn-primary-outline:focus,.btn-primary-outline.focus,.btn-primary-outline:active,.btn-primary-outline.active,.btn-primary-outline:hover,.open>.btn-primary-outline.dropdown-toggle{color:#fff !important;background-color:#df691a !important;border-color:#df691a !important;}.btn-info-outline{color:#5bc0de !important;background-color:transparent;background-image:none;border-color:#5bc0de !important;}.btn-info-outline:focus,.btn-info-outline.focus,.btn-info-outline:active,.btn-info-outline.active,.btn-info-outline:hover,.open>.btn-info-outline.dropdown-toggle{color:#fff !important;background-color:#5bc0de !important;border-color:#5bc0de !important;}.btn-warning-outline{color:#f0ad4e !important;background-color:transparent;background-image:none;border-color:#f0ad4e !important;}.btn-warning-outline:focus,.btn-warning-outline.focus,.btn-warning-outline:active,.btn-warning-outline.active,.btn-warning-outline:hover,.open>.btn-warning-outline.dropdown-toggle{color:#fff !important;background-color:#f0ad4e !important;border-color:#f0ad4e !important;}.btn-success-outline{color:#5cb85c !important;background-color:transparent;background-image:none;border-color:#5cb85c !important;}.btn-success-outline:focus,.btn-success-outline.focus,.btn-success-outline:active,.btn-success-outline.active,.btn-success-outline:hover,.open>.btn-success-outline.dropdown-toggle{color:#fff !important;background-color:#5cb85c !important;border-color:#5cb85c !important;}#movieList .mix{display:none;}#tvList .mix{display:none;}.scroll-top-wrapper{position:fixed;opacity:0;visibility:hidden;overflow:hidden;text-align:center;z-index:99999999;background-color:#4e5d6c;color:#eee;width:50px;height:48px;line-height:48px;right:30px;bottom:30px;padding-top:2px;border-top-left-radius:10px;border-top-right-radius:10px;border-bottom-right-radius:10px;border-bottom-left-radius:10px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;}.scroll-top-wrapper:hover{background-color:#637689;}.scroll-top-wrapper.show{visibility:visible;cursor:pointer;opacity:1;}.scroll-top-wrapper i.fa{line-height:inherit;}.no-search-results{text-align:center;}.no-search-results .no-search-results-icon{font-size:10em;color:#4e5d6c;}.no-search-results .no-search-results-text{margin:20px 0;color:#ccc;}
|
|
@ -6,7 +6,9 @@ $info-colour: #5bc0de;
|
||||||
$warning-colour: #f0ad4e;
|
$warning-colour: #f0ad4e;
|
||||||
$danger-colour: #d9534f;
|
$danger-colour: #d9534f;
|
||||||
$success-colour: #5cb85c;
|
$success-colour: #5cb85c;
|
||||||
$i:!important;
|
$i:
|
||||||
|
!important
|
||||||
|
;
|
||||||
|
|
||||||
@media (min-width: 768px ) {
|
@media (min-width: 768px ) {
|
||||||
.row {
|
.row {
|
||||||
|
@ -43,6 +45,8 @@ $i:!important;
|
||||||
.form-control-custom {
|
.form-control-custom {
|
||||||
background-color: $form-color $i;
|
background-color: $form-color $i;
|
||||||
color: white $i;
|
color: white $i;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: 0 0 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,6 +70,20 @@ label {
|
||||||
font-size: 16px $i;
|
font-size: 16px $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-tabs > li.active > a,
|
||||||
|
.nav-tabs > li.active > a:hover,
|
||||||
|
.nav-tabs > li.active > a:focus {
|
||||||
|
background: #4e5d6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar .nav a .fa {
|
||||||
|
font-size: 130%;
|
||||||
|
top: 1px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-danger-outline {
|
.btn-danger-outline {
|
||||||
color: $danger-colour $i;
|
color: $danger-colour $i;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -157,10 +175,11 @@ label {
|
||||||
border-color: $success-colour $i;
|
border-color: $success-colour $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#movieList .mix{
|
#movieList .mix {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#tvList .mix{
|
|
||||||
|
#tvList .mix {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,4 +221,18 @@ $border-radius: 10px;
|
||||||
.scroll-top-wrapper i.fa {
|
.scroll-top-wrapper i.fa {
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.no-search-results {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-search-results .no-search-results-icon {
|
||||||
|
font-size: 10em;
|
||||||
|
color: $form-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-search-results .no-search-results-text {
|
||||||
|
margin: 20px 0;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
|
@ -9,68 +9,122 @@ var searchSource = $("#search-template").html();
|
||||||
var searchTemplate = Handlebars.compile(searchSource);
|
var searchTemplate = Handlebars.compile(searchSource);
|
||||||
var movieTimer = 0;
|
var movieTimer = 0;
|
||||||
var tvimer = 0;
|
var tvimer = 0;
|
||||||
|
var mixItUpDefault = {
|
||||||
|
animation: { enable: true },
|
||||||
|
load: {
|
||||||
|
filter: 'all',
|
||||||
|
sort: 'requestorder:desc'
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
display: 'block'
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
onMixStart: function (state, futureState) {
|
||||||
|
$('.mix', this).removeAttr('data-bound').removeData('bound'); // fix for animation issues in other tabs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
movieLoad();
|
initLoad();
|
||||||
tvLoad();
|
|
||||||
|
|
||||||
|
|
||||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||||
var target = $(e.target).attr('href');
|
var target = $(e.target).attr('href');
|
||||||
var activeState = "";
|
var activeState = "";
|
||||||
if (target === "#TvShowTab") {
|
|
||||||
if ($('#movieList').mixItUp('isLoaded')) {
|
|
||||||
activeState = $('#movieList').mixItUp('getState');
|
|
||||||
$('#movieList').mixItUp('destroy');
|
|
||||||
}
|
|
||||||
if (!$('#tvList').mixItUp('isLoaded')) {
|
|
||||||
$('#tvList').mixItUp({
|
|
||||||
load: {
|
|
||||||
filter: activeState.activeFilter || 'all',
|
|
||||||
sort: activeState.activeSort || 'default:asc'
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
display: 'block'
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
var $ml = $('#movieList');
|
||||||
|
var $tvl = $('#tvList');
|
||||||
|
|
||||||
|
$('.approve-category').hide();
|
||||||
|
if (target === "#TvShowTab") {
|
||||||
|
$('#approveTVShows').show();
|
||||||
|
if ($ml.mixItUp('isLoaded')) {
|
||||||
|
activeState = $ml.mixItUp('getState');
|
||||||
|
$ml.mixItUp('destroy');
|
||||||
}
|
}
|
||||||
|
if ($tvl.mixItUp('isLoaded')) $tvl.mixItUp('destroy');
|
||||||
|
$tvl.mixItUp(mixItUpConfig(activeState)); // init or reinit
|
||||||
}
|
}
|
||||||
if (target === "#MoviesTab") {
|
if (target === "#MoviesTab") {
|
||||||
if ($('#tvList').mixItUp('isLoaded')) {
|
$('#approveMovies').show();
|
||||||
activeState = $('#tvList').mixItUp('getState');
|
if ($tvl.mixItUp('isLoaded')) {
|
||||||
$('#tvList').mixItUp('destroy');
|
activeState = $tvl.mixItUp('getState');
|
||||||
}
|
$tvl.mixItUp('destroy');
|
||||||
if (!$('#movieList').mixItUp('isLoaded')) {
|
|
||||||
$('#movieList').mixItUp({
|
|
||||||
load: {
|
|
||||||
filter: activeState.activeFilter || 'all',
|
|
||||||
sort: activeState.activeSort || 'default:asc'
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
display: 'block'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if ($ml.mixItUp('isLoaded')) $ml.mixItUp('destroy');
|
||||||
|
$ml.mixItUp(mixItUpConfig(activeState)); // init or reinit
|
||||||
}
|
}
|
||||||
|
//$('.mix[data-bound]').removeAttr('data-bound');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Approve all
|
// Approve all
|
||||||
$('#approveAll').click(function () {
|
$('#approveMovies').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var buttonId = e.target.id;
|
||||||
|
var origHtml = $(this).html();
|
||||||
|
|
||||||
|
if ($('#' + buttonId).text() === " Loading...") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingButton(buttonId, "success");
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'post',
|
type: 'post',
|
||||||
url: '/approval/approveall',
|
url: '/approval/approveallmovies',
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (checkJsonResponse(response)) {
|
if (checkJsonResponse(response)) {
|
||||||
generateNotify("Success! All requests approved!", "success");
|
generateNotify("Success! All Movie requests approved!", "success");
|
||||||
|
movieLoad();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
generateNotify("Something went wrong!", "danger");
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
},
|
||||||
|
complete: function (e) {
|
||||||
|
finishLoading(buttonId, "success", origHtml)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
$('#approveTVShows').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var buttonId = e.target.id;
|
||||||
|
var origHtml = $(this).html();
|
||||||
|
|
||||||
|
if ($('#' + buttonId).text() === " Loading...") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingButton(buttonId, "success");
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: 'post',
|
||||||
|
url: '/approval/approvealltvshows',
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (checkJsonResponse(response)) {
|
||||||
|
generateNotify("Success! All TV Show requests approved!", "success");
|
||||||
|
tvLoad();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
},
|
||||||
|
complete: function (e) {
|
||||||
|
finishLoading(buttonId, "success", origHtml)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// filtering/sorting
|
||||||
|
$('.filter,.sort', '.dropdown-menu').click(function (e) {
|
||||||
|
var $this = $(this);
|
||||||
|
$('.fa-square', $this.parents('.dropdown-menu:first')).removeClass('fa-square').addClass('fa-square-o');
|
||||||
|
$this.children('.fa').first().removeClass('fa-square-o').addClass('fa-square');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Report Issue
|
// Report Issue
|
||||||
|
@ -315,36 +369,54 @@ $(document).on("click", ".change", function (e) {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function mixItUpConfig(activeState) {
|
||||||
|
var conf = mixItUpDefault;
|
||||||
|
|
||||||
|
if (activeState) {
|
||||||
|
if (activeState.activeFilter) conf['load']['filter'] = activeState.activeFilter;
|
||||||
|
if (activeState.activeSort) conf['load']['sort'] = activeState.activeSort;
|
||||||
|
}
|
||||||
|
return conf;
|
||||||
|
};
|
||||||
|
|
||||||
|
function initLoad() {
|
||||||
|
movieLoad();
|
||||||
|
tvLoad();
|
||||||
|
}
|
||||||
|
|
||||||
function movieLoad() {
|
function movieLoad() {
|
||||||
$("#movieList").html("");
|
var $ml = $('#movieList');
|
||||||
|
if ($ml.mixItUp('isLoaded')) {
|
||||||
|
activeState = $ml.mixItUp('getState');
|
||||||
|
$ml.mixItUp('destroy');
|
||||||
|
}
|
||||||
|
$ml.html("");
|
||||||
|
|
||||||
$.ajax("/requests/movies/").success(function (results) {
|
$.ajax("/requests/movies/").success(function (results) {
|
||||||
results.forEach(function (result) {
|
results.forEach(function (result) {
|
||||||
var context = buildRequestContext(result, "movie");
|
var context = buildRequestContext(result, "movie");
|
||||||
|
|
||||||
var html = searchTemplate(context);
|
var html = searchTemplate(context);
|
||||||
$("#movieList").append(html);
|
$ml.append(html);
|
||||||
});
|
|
||||||
$('#movieList').mixItUp({
|
|
||||||
layout: {
|
|
||||||
display: 'block'
|
|
||||||
},
|
|
||||||
load: {
|
|
||||||
filter: 'all'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
$ml.mixItUp(mixItUpConfig());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function tvLoad() {
|
function tvLoad() {
|
||||||
$("#tvList").html("");
|
var $tvl = $('#tvList');
|
||||||
|
if ($tvl.mixItUp('isLoaded')) {
|
||||||
|
activeState = $tvl.mixItUp('getState');
|
||||||
|
$tvl.mixItUp('destroy');
|
||||||
|
}
|
||||||
|
$tvl.html("");
|
||||||
|
|
||||||
$.ajax("/requests/tvshows/").success(function (results) {
|
$.ajax("/requests/tvshows/").success(function (results) {
|
||||||
results.forEach(function (result) {
|
results.forEach(function (result) {
|
||||||
var context = buildRequestContext(result, "tv");
|
var context = buildRequestContext(result, "tv");
|
||||||
var html = searchTemplate(context);
|
var html = searchTemplate(context);
|
||||||
$("#tvList").append(html);
|
$tvl.append(html);
|
||||||
});
|
});
|
||||||
|
$tvl.mixItUp(mixItUpConfig());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -359,9 +431,11 @@ function buildRequestContext(result, type) {
|
||||||
type: type,
|
type: type,
|
||||||
status: result.status,
|
status: result.status,
|
||||||
releaseDate: result.releaseDate,
|
releaseDate: result.releaseDate,
|
||||||
|
releaseDateTicks: result.releaseDateTicks,
|
||||||
approved: result.approved,
|
approved: result.approved,
|
||||||
requestedBy: result.requestedBy,
|
requestedUsers: result.requestedUsers ? result.requestedUsers.join(', ') : '',
|
||||||
requestedDate: result.requestedDate,
|
requestedDate: result.requestedDate,
|
||||||
|
requestedDateTicks: result.requestedDateTicks,
|
||||||
available: result.available,
|
available: result.available,
|
||||||
admin: result.admin,
|
admin: result.admin,
|
||||||
issues: result.issues,
|
issues: result.issues,
|
||||||
|
@ -373,16 +447,4 @@ function buildRequestContext(result, type) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
|
||||||
|
|
||||||
function startFilter(elementId) {
|
|
||||||
$('#'+element).mixItUp({
|
|
||||||
load: {
|
|
||||||
filter: activeState.activeFilter || 'all',
|
|
||||||
sort: activeState.activeSort || 'default:asc'
|
|
||||||
},
|
|
||||||
layout: {
|
|
||||||
display: 'block'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
var searchSource = $("#search-template").html();
|
var searchSource = $("#search-template").html();
|
||||||
var searchTemplate = Handlebars.compile(searchSource);
|
var searchTemplate = Handlebars.compile(searchSource);
|
||||||
|
var noResultsHtml = "<div class='no-search-results'>" +
|
||||||
|
"<i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text'>Sorry, we didn't find any results!</div></div>";
|
||||||
var movieTimer = 0;
|
var movieTimer = 0;
|
||||||
var tvimer = 0;
|
var tvimer = 0;
|
||||||
|
|
||||||
|
@ -124,6 +126,9 @@ function movieSearch() {
|
||||||
$("#movieList").append(html);
|
$("#movieList").append(html);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$("#movieList").html(noResultsHtml);
|
||||||
|
}
|
||||||
$('#movieSearchButton').attr("class","fa fa-search");
|
$('#movieSearchButton').attr("class","fa fa-search");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -140,6 +145,9 @@ function tvSearch() {
|
||||||
$("#tvList").append(html);
|
$("#tvList").append(html);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$("#tvList").html(noResultsHtml);
|
||||||
|
}
|
||||||
$('#tvSearchButton').attr("class", "fa fa-search");
|
$('#tvSearchButton').attr("class", "fa fa-search");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,11 +37,13 @@ namespace PlexRequests.UI.Models
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string PosterPath { get; set; }
|
public string PosterPath { get; set; }
|
||||||
public string ReleaseDate { get; set; }
|
public string ReleaseDate { get; set; }
|
||||||
|
public long ReleaseDateTicks { get; set; }
|
||||||
public RequestType Type { get; set; }
|
public RequestType Type { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
public bool Approved { get; set; }
|
public bool Approved { get; set; }
|
||||||
public string RequestedBy { get; set; }
|
public string[] RequestedUsers { get; set; }
|
||||||
public string RequestedDate { get; set; }
|
public string RequestedDate { get; set; }
|
||||||
|
public long RequestedDateTicks { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
public bool Admin { get; set; }
|
public bool Admin { get; set; }
|
||||||
|
|
|
@ -53,6 +53,7 @@ using PlexRequests.Store.Models;
|
||||||
using PlexRequests.Store.Repository;
|
using PlexRequests.Store.Repository;
|
||||||
using PlexRequests.UI.Helpers;
|
using PlexRequests.UI.Helpers;
|
||||||
using PlexRequests.UI.Models;
|
using PlexRequests.UI.Models;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace PlexRequests.UI.Modules
|
namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
|
@ -144,13 +145,16 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
Get["/emailnotification"] = _ => EmailNotifications();
|
Get["/emailnotification"] = _ => EmailNotifications();
|
||||||
Post["/emailnotification"] = _ => SaveEmailNotifications();
|
Post["/emailnotification"] = _ => SaveEmailNotifications();
|
||||||
|
Post["/testemailnotification"] = _ => TestEmailNotifications();
|
||||||
Get["/status"] = _ => Status();
|
Get["/status"] = _ => Status();
|
||||||
|
|
||||||
Get["/pushbulletnotification"] = _ => PushbulletNotifications();
|
Get["/pushbulletnotification"] = _ => PushbulletNotifications();
|
||||||
Post["/pushbulletnotification"] = _ => SavePushbulletNotifications();
|
Post["/pushbulletnotification"] = _ => SavePushbulletNotifications();
|
||||||
|
Post["/testpushbulletnotification"] = _ => TestPushbulletNotifications();
|
||||||
|
|
||||||
Get["/pushovernotification"] = _ => PushoverNotifications();
|
Get["/pushovernotification"] = _ => PushoverNotifications();
|
||||||
Post["/pushovernotification"] = _ => SavePushoverNotifications();
|
Post["/pushovernotification"] = _ => SavePushoverNotifications();
|
||||||
|
Post["/testpushovernotification"] = _ => TestPushoverNotifications();
|
||||||
|
|
||||||
Get["/logs"] = _ => Logs();
|
Get["/logs"] = _ => Logs();
|
||||||
Get["/loglevel"] = _ => GetLogLevels();
|
Get["/loglevel"] = _ => GetLogLevels();
|
||||||
|
@ -380,6 +384,37 @@ namespace PlexRequests.UI.Modules
|
||||||
return View["EmailNotifications", settings];
|
return View["EmailNotifications", settings];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response TestEmailNotifications()
|
||||||
|
{
|
||||||
|
var settings = this.Bind<EmailNotificationSettings>();
|
||||||
|
var valid = this.Validate(settings);
|
||||||
|
if (!valid.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(valid.SendJsonError());
|
||||||
|
}
|
||||||
|
var notificationModel = new NotificationModel
|
||||||
|
{
|
||||||
|
NotificationType = NotificationType.Test,
|
||||||
|
DateTime = DateTime.Now
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NotificationService.Subscribe(new EmailMessageNotification(EmailService));
|
||||||
|
settings.Enabled = true;
|
||||||
|
NotificationService.Publish(notificationModel, settings);
|
||||||
|
Log.Info("Sent email notification test");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to subscribe and publish test Email Notification");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
NotificationService.UnSubscribe(new EmailMessageNotification(EmailService));
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Email Notification!" });
|
||||||
|
}
|
||||||
|
|
||||||
private Response SaveEmailNotifications()
|
private Response SaveEmailNotifications()
|
||||||
{
|
{
|
||||||
var settings = this.Bind<EmailNotificationSettings>();
|
var settings = this.Bind<EmailNotificationSettings>();
|
||||||
|
@ -448,6 +483,37 @@ namespace PlexRequests.UI.Modules
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response TestPushbulletNotifications()
|
||||||
|
{
|
||||||
|
var settings = this.Bind<PushbulletNotificationSettings>();
|
||||||
|
var valid = this.Validate(settings);
|
||||||
|
if (!valid.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(valid.SendJsonError());
|
||||||
|
}
|
||||||
|
var notificationModel = new NotificationModel
|
||||||
|
{
|
||||||
|
NotificationType = NotificationType.Test,
|
||||||
|
DateTime = DateTime.Now
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NotificationService.Subscribe(new PushbulletNotification(PushbulletApi, PushbulletService));
|
||||||
|
settings.Enabled = true;
|
||||||
|
NotificationService.Publish(notificationModel, settings);
|
||||||
|
Log.Info("Sent pushbullet notification test");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to subscribe and publish test Pushbullet Notification");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
NotificationService.UnSubscribe(new PushbulletNotification(PushbulletApi, PushbulletService));
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Pushbullet Notification!" });
|
||||||
|
}
|
||||||
|
|
||||||
private Negotiator PushoverNotifications()
|
private Negotiator PushoverNotifications()
|
||||||
{
|
{
|
||||||
var settings = PushoverService.GetSettings();
|
var settings = PushoverService.GetSettings();
|
||||||
|
@ -480,6 +546,37 @@ namespace PlexRequests.UI.Modules
|
||||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response TestPushoverNotifications()
|
||||||
|
{
|
||||||
|
var settings = this.Bind<PushoverNotificationSettings>();
|
||||||
|
var valid = this.Validate(settings);
|
||||||
|
if (!valid.IsValid)
|
||||||
|
{
|
||||||
|
return Response.AsJson(valid.SendJsonError());
|
||||||
|
}
|
||||||
|
var notificationModel = new NotificationModel
|
||||||
|
{
|
||||||
|
NotificationType = NotificationType.Test,
|
||||||
|
DateTime = DateTime.Now
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NotificationService.Subscribe(new PushoverNotification(PushoverApi, PushoverService));
|
||||||
|
settings.Enabled = true;
|
||||||
|
NotificationService.Publish(notificationModel, settings);
|
||||||
|
Log.Info("Sent pushover notification test");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to subscribe and publish test Pushover Notification");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
NotificationService.UnSubscribe(new PushoverNotification(PushoverApi, PushoverService));
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Pushover Notification!" });
|
||||||
|
}
|
||||||
|
|
||||||
private Response GetCpProfiles()
|
private Response GetCpProfiles()
|
||||||
{
|
{
|
||||||
var settings = this.Bind<CouchPotatoSettings>();
|
var settings = this.Bind<CouchPotatoSettings>();
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
Post["/approve"] = parameters => Approve((int)Request.Form.requestid);
|
Post["/approve"] = parameters => Approve((int)Request.Form.requestid);
|
||||||
Post["/approveall"] = x => ApproveAll();
|
Post["/approveall"] = x => ApproveAll();
|
||||||
|
Post["/approveallmovies"] = x => ApproveAllMovies();
|
||||||
|
Post["/approvealltvshows"] = x => ApproveAllTVShows();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IRequestService Service { get; }
|
private IRequestService Service { get; }
|
||||||
|
@ -216,6 +218,56 @@ namespace PlexRequests.UI.Modules
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response ApproveAllMovies()
|
||||||
|
{
|
||||||
|
if (!Context.CurrentUser.IsAuthenticated())
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
|
||||||
|
}
|
||||||
|
|
||||||
|
var requests = Service.GetAll().Where(x => x.CanApprove && x.Type == RequestType.Movie);
|
||||||
|
var requestedModels = requests as RequestedModel[] ?? requests.ToArray();
|
||||||
|
if (!requestedModels.Any())
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no movie requests to approve. Please refresh." });
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return UpdateRequests(requestedModels);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response ApproveAllTVShows()
|
||||||
|
{
|
||||||
|
if (!Context.CurrentUser.IsAuthenticated())
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
|
||||||
|
}
|
||||||
|
|
||||||
|
var requests = Service.GetAll().Where(x => x.CanApprove && x.Type == RequestType.TvShow);
|
||||||
|
var requestedModels = requests as RequestedModel[] ?? requests.ToArray();
|
||||||
|
if (!requestedModels.Any())
|
||||||
|
{
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no tv show requests to approve. Please refresh." });
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return UpdateRequests(requestedModels);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Approves all.
|
/// Approves all.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -227,23 +279,35 @@ namespace PlexRequests.UI.Modules
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "You are not an Admin, so you cannot approve any requests." });
|
||||||
}
|
}
|
||||||
|
|
||||||
var requests = Service.GetAll().Where(x => x.Approved == false);
|
var requests = Service.GetAll().Where(x => x.CanApprove);
|
||||||
var requestedModels = requests as RequestedModel[] ?? requests.ToArray();
|
var requestedModels = requests as RequestedModel[] ?? requests.ToArray();
|
||||||
if (!requestedModels.Any())
|
if (!requestedModels.Any())
|
||||||
{
|
{
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no requests to approve. Please refresh." });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "There are no requests to approve. Please refresh." });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return UpdateRequests(requestedModels);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e);
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response UpdateRequests(RequestedModel[] requestedModels)
|
||||||
|
{
|
||||||
var cpSettings = CpService.GetSettings();
|
var cpSettings = CpService.GetSettings();
|
||||||
|
|
||||||
|
|
||||||
var updatedRequests = new List<RequestedModel>();
|
var updatedRequests = new List<RequestedModel>();
|
||||||
foreach (var r in requestedModels)
|
foreach (var r in requestedModels)
|
||||||
{
|
{
|
||||||
if (r.Type == RequestType.Movie)
|
if (r.Type == RequestType.Movie)
|
||||||
{
|
{
|
||||||
var result = SendMovie(cpSettings, r, CpApi);
|
var res = SendMovie(cpSettings, r, CpApi);
|
||||||
if (result)
|
if (res)
|
||||||
{
|
{
|
||||||
r.Approved = true;
|
r.Approved = true;
|
||||||
updatedRequests.Add(r);
|
updatedRequests.Add(r);
|
||||||
|
@ -260,8 +324,8 @@ namespace PlexRequests.UI.Modules
|
||||||
var sonarr = SonarrSettings.GetSettings();
|
var sonarr = SonarrSettings.GetSettings();
|
||||||
if (sr.Enabled)
|
if (sr.Enabled)
|
||||||
{
|
{
|
||||||
var result = sender.SendToSickRage(sr, r);
|
var res = sender.SendToSickRage(sr, r);
|
||||||
if (result?.result == "success")
|
if (res?.result == "success")
|
||||||
{
|
{
|
||||||
r.Approved = true;
|
r.Approved = true;
|
||||||
updatedRequests.Add(r);
|
updatedRequests.Add(r);
|
||||||
|
@ -269,14 +333,14 @@ namespace PlexRequests.UI.Modules
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Error("Could not approve and send the TV {0} to SickRage!", r.Title);
|
Log.Error("Could not approve and send the TV {0} to SickRage!", r.Title);
|
||||||
Log.Error("SickRage Message: {0}", result?.message);
|
Log.Error("SickRage Message: {0}", res?.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sonarr.Enabled)
|
if (sonarr.Enabled)
|
||||||
{
|
{
|
||||||
var result = sender.SendToSonarr(sonarr, r);
|
var res = sender.SendToSonarr(sonarr, r);
|
||||||
if (!string.IsNullOrEmpty(result?.title))
|
if (!string.IsNullOrEmpty(res?.title))
|
||||||
{
|
{
|
||||||
r.Approved = true;
|
r.Approved = true;
|
||||||
updatedRequests.Add(r);
|
updatedRequests.Add(r);
|
||||||
|
@ -284,7 +348,7 @@ namespace PlexRequests.UI.Modules
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Error("Could not approve and send the TV {0} to Sonarr!", r.Title);
|
Log.Error("Could not approve and send the TV {0} to Sonarr!", r.Title);
|
||||||
Log.Error("Error message: {0}", result?.ErrorMessage);
|
Log.Error("Error message: {0}", res?.ErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,17 +356,16 @@ namespace PlexRequests.UI.Modules
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = Service.BatchUpdate(updatedRequests); return Response.AsJson(result
|
var result = Service.BatchUpdate(updatedRequests);
|
||||||
|
return Response.AsJson(result
|
||||||
? new JsonResponseModel { Result = true }
|
? new JsonResponseModel { Result = true }
|
||||||
: new JsonResponseModel { Result = false, Message = "We could not approve all of the requests. Please try again or check the logs." });
|
: new JsonResponseModel { Result = false, Message = "We could not approve all of the requests. Please try again or check the logs." });
|
||||||
|
}
|
||||||
}
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Fatal(e);
|
Log.Fatal(e);
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Something bad happened, please check the logs!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SendMovie(CouchPotatoSettings settings, RequestedModel r, ICouchPotatoApi cp)
|
private bool SendMovie(CouchPotatoSettings settings, RequestedModel r, ICouchPotatoApi cp)
|
||||||
|
|
|
@ -33,16 +33,30 @@ namespace PlexRequests.UI.Modules
|
||||||
{
|
{
|
||||||
public class BaseModule : NancyModule
|
public class BaseModule : NancyModule
|
||||||
{
|
{
|
||||||
|
private string _username;
|
||||||
|
|
||||||
|
protected string Username
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_username))
|
||||||
|
{
|
||||||
|
_username = Session[SessionKeys.UsernameKey].ToString();
|
||||||
|
}
|
||||||
|
return _username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BaseModule()
|
public BaseModule()
|
||||||
{
|
{
|
||||||
Before += (ctx)=> CheckAuth();
|
Before += (ctx) => CheckAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseModule(string modulePath) : base(modulePath)
|
public BaseModule(string modulePath) : base(modulePath)
|
||||||
{
|
{
|
||||||
Before += (ctx) => CheckAuth();
|
Before += (ctx) => CheckAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Response CheckAuth()
|
private Response CheckAuth()
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,28 +79,38 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
private Response GetMovies()
|
private Response GetMovies()
|
||||||
{
|
{
|
||||||
|
var settings = PrSettings.GetSettings();
|
||||||
var isAdmin = Context.CurrentUser.IsAuthenticated();
|
var isAdmin = Context.CurrentUser.IsAuthenticated();
|
||||||
var dbMovies = Service.GetAll().Where(x => x.Type == RequestType.Movie);
|
var dbMovies = Service.GetAll().Where(x => x.Type == RequestType.Movie);
|
||||||
var viewModel = dbMovies.Select(movie => new RequestViewModel
|
if (settings.UsersCanViewOnlyOwnRequests && !isAdmin)
|
||||||
{
|
{
|
||||||
ProviderId = movie.ProviderId,
|
dbMovies = dbMovies.Where(x => x.UserHasRequested(Username));
|
||||||
Type = movie.Type,
|
}
|
||||||
Status = movie.Status,
|
|
||||||
ImdbId = movie.ImdbId,
|
var viewModel = dbMovies.Select(movie => {
|
||||||
Id = movie.Id,
|
return new RequestViewModel
|
||||||
PosterPath = movie.PosterPath,
|
{
|
||||||
ReleaseDate = movie.ReleaseDate.Humanize(),
|
ProviderId = movie.ProviderId,
|
||||||
RequestedDate = movie.RequestedDate.Humanize(),
|
Type = movie.Type,
|
||||||
Approved = movie.Approved,
|
Status = movie.Status,
|
||||||
Title = movie.Title,
|
ImdbId = movie.ImdbId,
|
||||||
Overview = movie.Overview,
|
Id = movie.Id,
|
||||||
RequestedBy = movie.RequestedBy,
|
PosterPath = movie.PosterPath,
|
||||||
ReleaseYear = movie.ReleaseDate.Year.ToString(),
|
ReleaseDate = movie.ReleaseDate.Humanize(),
|
||||||
Available = movie.Available,
|
ReleaseDateTicks = movie.ReleaseDate.Ticks,
|
||||||
Admin = isAdmin,
|
RequestedDate = movie.RequestedDate.Humanize(),
|
||||||
Issues = movie.Issues.Humanize(LetterCasing.Title),
|
RequestedDateTicks = movie.RequestedDate.Ticks,
|
||||||
OtherMessage = movie.OtherMessage,
|
Approved = movie.Available || movie.Approved,
|
||||||
AdminNotes = movie.AdminNote
|
Title = movie.Title,
|
||||||
|
Overview = movie.Overview,
|
||||||
|
RequestedUsers = isAdmin ? movie.AllUsers.ToArray() : new string[] { },
|
||||||
|
ReleaseYear = movie.ReleaseDate.Year.ToString(),
|
||||||
|
Available = movie.Available,
|
||||||
|
Admin = isAdmin,
|
||||||
|
Issues = movie.Issues.Humanize(LetterCasing.Title),
|
||||||
|
OtherMessage = movie.OtherMessage,
|
||||||
|
AdminNotes = movie.AdminNote
|
||||||
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Response.AsJson(viewModel);
|
return Response.AsJson(viewModel);
|
||||||
|
@ -108,29 +118,39 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
private Response GetTvShows()
|
private Response GetTvShows()
|
||||||
{
|
{
|
||||||
|
var settings = PrSettings.GetSettings();
|
||||||
var isAdmin = Context.CurrentUser.IsAuthenticated();
|
var isAdmin = Context.CurrentUser.IsAuthenticated();
|
||||||
var dbTv = Service.GetAll().Where(x => x.Type == RequestType.TvShow);
|
var dbTv = Service.GetAll().Where(x => x.Type == RequestType.TvShow);
|
||||||
var viewModel = dbTv.Select(tv => new RequestViewModel
|
if (settings.UsersCanViewOnlyOwnRequests && !isAdmin)
|
||||||
{
|
{
|
||||||
ProviderId = tv.ProviderId,
|
dbTv = dbTv.Where(x => x.UserHasRequested(Username));
|
||||||
Type = tv.Type,
|
}
|
||||||
Status = tv.Status,
|
|
||||||
ImdbId = tv.ImdbId,
|
var viewModel = dbTv.Select(tv => {
|
||||||
Id = tv.Id,
|
return new RequestViewModel
|
||||||
PosterPath = tv.PosterPath,
|
{
|
||||||
ReleaseDate = tv.ReleaseDate.Humanize(),
|
ProviderId = tv.ProviderId,
|
||||||
RequestedDate = tv.RequestedDate.Humanize(),
|
Type = tv.Type,
|
||||||
Approved = tv.Approved,
|
Status = tv.Status,
|
||||||
Title = tv.Title,
|
ImdbId = tv.ImdbId,
|
||||||
Overview = tv.Overview,
|
Id = tv.Id,
|
||||||
RequestedBy = tv.RequestedBy,
|
PosterPath = tv.PosterPath,
|
||||||
ReleaseYear = tv.ReleaseDate.Year.ToString(),
|
ReleaseDate = tv.ReleaseDate.Humanize(),
|
||||||
Available = tv.Available,
|
ReleaseDateTicks = tv.ReleaseDate.Ticks,
|
||||||
Admin = isAdmin,
|
RequestedDate = tv.RequestedDate.Humanize(),
|
||||||
Issues = tv.Issues.Humanize(LetterCasing.Title),
|
RequestedDateTicks = tv.RequestedDate.Ticks,
|
||||||
OtherMessage = tv.OtherMessage,
|
Approved = tv.Available || tv.Approved,
|
||||||
AdminNotes = tv.AdminNote,
|
Title = tv.Title,
|
||||||
TvSeriesRequestType = tv.SeasonsRequested
|
Overview = tv.Overview,
|
||||||
|
RequestedUsers = isAdmin ? tv.AllUsers.ToArray() : new string[] { },
|
||||||
|
ReleaseYear = tv.ReleaseDate.Year.ToString(),
|
||||||
|
Available = tv.Available,
|
||||||
|
Admin = isAdmin,
|
||||||
|
Issues = tv.Issues.Humanize(LetterCasing.Title),
|
||||||
|
OtherMessage = tv.OtherMessage,
|
||||||
|
AdminNotes = tv.AdminNote,
|
||||||
|
TvSeriesRequestType = tv.SeasonsRequested
|
||||||
|
};
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Response.AsJson(viewModel);
|
return Response.AsJson(viewModel);
|
||||||
|
@ -165,7 +185,7 @@ namespace PlexRequests.UI.Modules
|
||||||
}
|
}
|
||||||
originalRequest.Issues = issue;
|
originalRequest.Issues = issue;
|
||||||
originalRequest.OtherMessage = !string.IsNullOrEmpty(comment)
|
originalRequest.OtherMessage = !string.IsNullOrEmpty(comment)
|
||||||
? $"{Session[SessionKeys.UsernameKey]} - {comment}"
|
? $"{Username} - {comment}"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,7 +193,7 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
var model = new NotificationModel
|
var model = new NotificationModel
|
||||||
{
|
{
|
||||||
User = Session[SessionKeys.UsernameKey].ToString(),
|
User = Username,
|
||||||
NotificationType = NotificationType.Issue,
|
NotificationType = NotificationType.Issue,
|
||||||
Title = originalRequest.Title,
|
Title = originalRequest.Title,
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
|
|
|
@ -179,11 +179,20 @@ namespace PlexRequests.UI.Modules
|
||||||
Log.Trace(movieInfo.DumpJson);
|
Log.Trace(movieInfo.DumpJson);
|
||||||
//#if !DEBUG
|
//#if !DEBUG
|
||||||
|
|
||||||
|
var settings = PrService.GetSettings();
|
||||||
|
|
||||||
|
// check if the movie has already been requested
|
||||||
Log.Info("Requesting movie with id {0}", movieId);
|
Log.Info("Requesting movie with id {0}", movieId);
|
||||||
if (RequestService.CheckRequest(movieId))
|
var existingRequest = RequestService.CheckRequest(movieId);
|
||||||
|
if (existingRequest != null)
|
||||||
{
|
{
|
||||||
Log.Trace("movie with id {0} exists", movieId);
|
// check if the current user is already marked as a requester for this movie, if not, add them
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullMovieName} has already been requested!" });
|
if (!existingRequest.UserHasRequested(Username))
|
||||||
|
{
|
||||||
|
existingRequest.RequestedUsers.Add(Username);
|
||||||
|
RequestService.UpdateRequest(existingRequest);
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = settings.UsersCanViewOnlyOwnRequests ? $"{fullMovieName} was successfully added!" : $"{fullMovieName} has already been requested!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Debug("movie with id {0} doesnt exists", movieId);
|
Log.Debug("movie with id {0} doesnt exists", movieId);
|
||||||
|
@ -213,14 +222,12 @@ namespace PlexRequests.UI.Modules
|
||||||
Status = movieInfo.Status,
|
Status = movieInfo.Status,
|
||||||
RequestedDate = DateTime.Now,
|
RequestedDate = DateTime.Now,
|
||||||
Approved = false,
|
Approved = false,
|
||||||
RequestedBy = Session[SessionKeys.UsernameKey].ToString(),
|
RequestedUsers = new List<string>() { Username },
|
||||||
Issues = IssueState.None,
|
Issues = IssueState.None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var settings = PrService.GetSettings();
|
|
||||||
Log.Trace(settings.DumpJson());
|
Log.Trace(settings.DumpJson());
|
||||||
if (!settings.RequireMovieApproval)
|
if (!settings.RequireMovieApproval || settings.NoApprovalUserList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
var cpSettings = CpService.GetSettings();
|
var cpSettings = CpService.GetSettings();
|
||||||
|
|
||||||
|
@ -247,7 +254,7 @@ namespace PlexRequests.UI.Modules
|
||||||
};
|
};
|
||||||
NotificationService.Publish(notificationModel);
|
NotificationService.Publish(notificationModel);
|
||||||
|
|
||||||
return Response.AsJson(new JsonResponseModel {Result = true});
|
return Response.AsJson(new JsonResponseModel {Result = true, Message = $"{fullMovieName} was successfully added!" });
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
Response.AsJson(new JsonResponseModel
|
Response.AsJson(new JsonResponseModel
|
||||||
|
@ -272,7 +279,7 @@ namespace PlexRequests.UI.Modules
|
||||||
};
|
};
|
||||||
NotificationService.Publish(notificationModel);
|
NotificationService.Publish(notificationModel);
|
||||||
|
|
||||||
return Response.AsJson(new JsonResponseModel { Result = true });
|
return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullMovieName} was successfully added!" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,9 +317,20 @@ namespace PlexRequests.UI.Modules
|
||||||
string fullShowName = $"{showInfo.name} ({firstAir.Year})";
|
string fullShowName = $"{showInfo.name} ({firstAir.Year})";
|
||||||
//#if !DEBUG
|
//#if !DEBUG
|
||||||
|
|
||||||
if (RequestService.CheckRequest(showId))
|
var settings = PrService.GetSettings();
|
||||||
|
|
||||||
|
// check if the show has already been requested
|
||||||
|
Log.Info("Requesting tv show with id {0}", showId);
|
||||||
|
var existingRequest = RequestService.CheckRequest(showId);
|
||||||
|
if (existingRequest != null)
|
||||||
{
|
{
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullShowName} has already been requested!" });
|
// check if the current user is already marked as a requester for this show, if not, add them
|
||||||
|
if (!existingRequest.UserHasRequested(Username))
|
||||||
|
{
|
||||||
|
existingRequest.RequestedUsers.Add(Username);
|
||||||
|
RequestService.UpdateRequest(existingRequest);
|
||||||
|
}
|
||||||
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = settings.UsersCanViewOnlyOwnRequests ? $"{fullShowName} was successfully added!" : $"{fullShowName} has already been requested!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -340,7 +358,7 @@ namespace PlexRequests.UI.Modules
|
||||||
Status = showInfo.status,
|
Status = showInfo.status,
|
||||||
RequestedDate = DateTime.Now,
|
RequestedDate = DateTime.Now,
|
||||||
Approved = false,
|
Approved = false,
|
||||||
RequestedBy = Session[SessionKeys.UsernameKey].ToString(),
|
RequestedUsers = new List<string>() { Username },
|
||||||
Issues = IssueState.None,
|
Issues = IssueState.None,
|
||||||
ImdbId = showInfo.externals?.imdb ?? string.Empty,
|
ImdbId = showInfo.externals?.imdb ?? string.Empty,
|
||||||
SeasonCount = showInfo.seasonCount
|
SeasonCount = showInfo.seasonCount
|
||||||
|
@ -363,8 +381,7 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
model.SeasonList = seasonsList.ToArray();
|
model.SeasonList = seasonsList.ToArray();
|
||||||
|
|
||||||
var settings = PrService.GetSettings();
|
if (!settings.RequireTvShowApproval || settings.NoApprovalUserList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase)))
|
||||||
if (!settings.RequireTvShowApproval)
|
|
||||||
{
|
{
|
||||||
var sonarrSettings = SonarrService.GetSettings();
|
var sonarrSettings = SonarrService.GetSettings();
|
||||||
var sender = new TvSender(SonarrApi, SickrageApi);
|
var sender = new TvSender(SonarrApi, SickrageApi);
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace PlexRequests.UI
|
||||||
if (port == -1)
|
if (port == -1)
|
||||||
port = GetStartupPort();
|
port = GetStartupPort();
|
||||||
|
|
||||||
var options = new StartOptions( $"http://+:{port}")
|
var options = new StartOptions(Debugger.IsAttached ? $"http://localhost:{port}" : $"http://+:{port}")
|
||||||
{
|
{
|
||||||
ServerFactory = "Microsoft.Owin.Host.HttpListener"
|
ServerFactory = "Microsoft.Owin.Host.HttpListener"
|
||||||
};
|
};
|
||||||
|
|
|
@ -88,6 +88,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button id="testEmail" type="submit" class="btn btn-primary-outline">Test</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
|
@ -128,7 +133,32 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#testEmail').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var port = $('#EmailPort').val();
|
||||||
|
if (isNaN(port)) {
|
||||||
|
generateNotify("You must specify a valid Port.", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var $form = $("#mainForm");
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop("method"),
|
||||||
|
data: $form.serialize(),
|
||||||
|
url: '/admin/testemailnotification',
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (response.result === true) {
|
||||||
|
generateNotify(response.message, "success");
|
||||||
|
} else {
|
||||||
|
generateNotify(response.message, "warning");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,6 +36,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button id="testPushbullet" type="submit" class="btn btn-primary-outline">Test</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
|
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
|
||||||
|
@ -70,5 +76,28 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#testPushbullet').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $form = $("#mainForm");
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop("method"),
|
||||||
|
data: $form.serialize(),
|
||||||
|
url: '/admin/testpushbulletnotification',
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (response.result === true) {
|
||||||
|
generateNotify(response.message, "success");
|
||||||
|
} else {
|
||||||
|
generateNotify(response.message, "warning");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
|
@ -36,6 +36,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div>
|
||||||
|
<button id="testPushover" type="submit" class="btn btn-primary-outline">Test</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
|
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
|
||||||
|
@ -70,5 +76,28 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#testPushover').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $form = $("#mainForm");
|
||||||
|
$.ajax({
|
||||||
|
type: $form.prop("method"),
|
||||||
|
data: $form.serialize(),
|
||||||
|
url: '/admin/testpushovernotification',
|
||||||
|
dataType: "json",
|
||||||
|
success: function (response) {
|
||||||
|
if (response.result === true) {
|
||||||
|
generateNotify(response.message, "success");
|
||||||
|
} else {
|
||||||
|
generateNotify(response.message, "warning");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
console.log(e);
|
||||||
|
generateNotify("Something went wrong!", "danger");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
|
@ -111,7 +111,31 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p class="form-group">A comma separated list of users whose requests do not require approval.</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="noApprovalUsers" class="control-label">Users</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" class="form-control-custom form-control " id="NoApprovalUsers" name="NoApprovalUsers" placeholder="e.g. John, Bobby" value="@Model.NoApprovalUsers">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
@if (Model.UsersCanViewOnlyOwnRequests)
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="UsersCanViewOnlyOwnRequests" name="UsersCanViewOnlyOwnRequests" checked="checked"><text>Users can view their own requests only</text>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="UsersCanViewOnlyOwnRequests" name="UsersCanViewOnlyOwnRequests"><text>Users can view their own requests only</text>
|
||||||
|
}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@*<div class="form-group">
|
@*<div class="form-group">
|
||||||
<label for="WeeklyRequestLimit" class="control-label">Weekly Request Limit</label>
|
<label for="WeeklyRequestLimit" class="control-label">Weekly Request Limit</label>
|
||||||
<div>
|
<div>
|
||||||
|
@ -131,4 +155,3 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
Password <input class="form-control form-control-custom" name="Password" type="password"/>
|
Password <input class="form-control form-control-custom" name="Password" type="password"/>
|
||||||
<br/>
|
<br/>
|
||||||
Remember Me <input name="RememberMe" type="checkbox" value="True"/>
|
Remember Me <input name="RememberMe" type="checkbox" value="True"/>
|
||||||
<br/>
|
<br/><br/>
|
||||||
<input class="btn btn-success-outline" type="submit" value="Login"/>
|
<input class="btn btn-success-outline" type="submit" value="Login"/>
|
||||||
</form>
|
</form>
|
||||||
@if (!Model.AdminExists)
|
@if (!Model.AdminExists)
|
||||||
|
|
|
@ -2,12 +2,8 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Requests</h1>
|
<h1>Requests</h1>
|
||||||
<h4>Below you can see yours and all other requests, as well as their download and approval status.</h4>
|
<h4>Below you can see yours and all other requests, as well as their download and approval status.</h4>
|
||||||
@if (Context.CurrentUser.IsAuthenticated())
|
<br />
|
||||||
{
|
|
||||||
<button id="approveAll" class="btn btn-success-outline" type="submit"><i class="fa fa-plus"></i> Approve All</button>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
}
|
|
||||||
<!-- Nav tabs -->
|
<!-- Nav tabs -->
|
||||||
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
||||||
@if (Model.SearchForMovies)
|
@if (Model.SearchForMovies)
|
||||||
|
@ -20,40 +16,62 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<br />
|
||||||
|
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content contentList">
|
<div class="tab-content contentList">
|
||||||
<div class="btn-group col-sm-push-10">
|
<div class="row">
|
||||||
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
<div class="col-sm-12">
|
||||||
Filter
|
<div class="pull-right">
|
||||||
<i class="fa fa-filter"></i>
|
<div class="btn-group">
|
||||||
</a>
|
@if (Context.CurrentUser.IsAuthenticated())
|
||||||
<ul class="dropdown-menu">
|
{
|
||||||
<li><a href="#" class="filter" data-filter="all">All</a></li>
|
@if (Model.SearchForMovies)
|
||||||
<li><a href="#" class="filter" data-filter=".approved-true">Approved</a></li>
|
{
|
||||||
<li><a href="#" class="filter" data-filter=".approved-false">Not Approved</a></li>
|
<button id="approveMovies" class="btn btn-success-outline approve-category" type="submit"><i class="fa fa-plus"></i> Approve Movies</button>
|
||||||
<li><a href="#" class="filter" data-filter=".available-true">Available</a></li>
|
}
|
||||||
<li><a href="#" class="filter" data-filter=".available-false">Not Available</a></li>
|
@if (Model.SearchForTvShows)
|
||||||
</ul>
|
{
|
||||||
</div>
|
<button id="approveTVShows" class="btn btn-success-outline approve-category" type="submit" style="display: none;"><i class="fa fa-plus"></i> Approve TV Shows</button>
|
||||||
<div class="btn-group col-sm-push-10">
|
}
|
||||||
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
}
|
||||||
Order
|
</div>
|
||||||
<i class="fa fa-sort"></i>
|
<div class="btn-group">
|
||||||
</a>
|
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||||
<ul class="dropdown-menu">
|
Filter
|
||||||
<li><a href="#" class="sort" data-sort="default">Default</a></li>
|
<i class="fa fa-filter"></i>
|
||||||
<li><a href="#" class="sort" data-sort="requestorder:asc">Requested Date</a></li>
|
</a>
|
||||||
</ul>
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#" class="filter" data-filter="all"><i class="fa fa-square"></i> All</a></li>
|
||||||
|
<li><a href="#" class="filter" data-filter=".approved-true"><i class="fa fa-square-o"></i> Approved</a></li>
|
||||||
|
<li><a href="#" class="filter" data-filter=".approved-false"><i class="fa fa-square-o"></i> Not Approved</a></li>
|
||||||
|
<li><a href="#" class="filter" data-filter=".available-true"><i class="fa fa-square-o"></i> Available</a></li>
|
||||||
|
<li><a href="#" class="filter" data-filter=".available-false"><i class="fa fa-square-o"></i> Not Available</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="#" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||||
|
Order
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#" class="sort" data-sort="requestorder:desc"><i class="fa fa-square"></i> Recent Requests</a></li>
|
||||||
|
<li><a href="#" class="sort" data-sort="requestorder:asc"><i class="fa fa-square-o"></i> Older Requests</a></li>
|
||||||
|
<li><a href="#" class="sort" data-sort="releaseorder:desc"><i class="fa fa-square-o"></i> Recent Releases</a></li>
|
||||||
|
<li><a href="#" class="sort" data-sort="releaseorder:asc"><i class="fa fa-square-o"></i> Older Releases</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (Model.SearchForMovies)
|
@if (Model.SearchForMovies)
|
||||||
{
|
{
|
||||||
|
|
||||||
<!-- Movie tab -->
|
<!-- Movie tab -->
|
||||||
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
|
||||||
|
|
||||||
<br/>
|
<br />
|
||||||
<br/>
|
<br />
|
||||||
<!-- Movie content -->
|
<!-- Movie content -->
|
||||||
<div id="movieList">
|
<div id="movieList">
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,12 +79,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Model.SearchForTvShows)
|
@if (Model.SearchForTvShows)
|
||||||
{
|
{
|
||||||
<!-- TV tab -->
|
<!-- TV tab -->
|
||||||
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
<div role="tabpanel" class="tab-pane" id="TvShowTab">
|
||||||
|
|
||||||
<br/>
|
<br />
|
||||||
<br/>
|
<br />
|
||||||
<!-- TV content -->
|
<!-- TV content -->
|
||||||
<div id="tvList">
|
<div id="tvList">
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,7 +96,7 @@
|
||||||
|
|
||||||
|
|
||||||
<script id="search-template" type="text/x-handlebars-template">
|
<script id="search-template" type="text/x-handlebars-template">
|
||||||
<div id="{{requestId}}Template" class="mix available-{{available}} approved-{{approved}}">
|
<div id="{{requestId}}Template" class="mix available-{{available}} approved-{{approved}}" data-requestorder="{{requestedDateTicks}}" data-releaseorder="{{releaseDateTicks}}">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
{{#if_eq type "movie"}}
|
{{#if_eq type "movie"}}
|
||||||
|
@ -122,7 +140,7 @@
|
||||||
{{#if_eq type "tv"}}
|
{{#if_eq type "tv"}}
|
||||||
<div>Series Requested: {{seriesRequested}}</div>
|
<div>Series Requested: {{seriesRequested}}</div>
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
<div>Requested By: {{requestedBy}}</div>
|
<div>Requested By: {{requestedUsers}}</div>
|
||||||
<div>Requested Date: {{requestedDate}}</div>
|
<div>Requested Date: {{requestedDate}}</div>
|
||||||
<div id="issueArea{{requestId}}">
|
<div id="issueArea{{requestId}}">
|
||||||
{{#if otherMessage}}
|
{{#if otherMessage}}
|
||||||
|
@ -181,7 +199,7 @@
|
||||||
<li><a id="{{requestId}}" issue-select="4" class="dropdownIssue" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#myModal">Other</a></li>
|
<li><a id="{{requestId}}" issue-select="4" class="dropdownIssue" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#myModal">Other</a></li>
|
||||||
|
|
||||||
{{#if_eq admin true}}
|
{{#if_eq admin true}}
|
||||||
<li><a id="{{requestId}}" issue-select="4" class="note" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#noteModal">Add Note</a></li>
|
<li><a id="{{requestId}}" issue-select="4" class="note" data-identifier="{{requestId}}" href="#" data-toggle="modal" data-target="#noteModal">Add Note</a></li>
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Search</h1>
|
<h1>Search</h1>
|
||||||
<h4>Want to watch something that is not currently on Plex?! No problem! Just search for it below and request it!</h4>
|
<h4>Want to watch something that is not currently on Plex?! No problem! Just search for it below and request it!</h4>
|
||||||
|
<br />
|
||||||
<!-- Nav tabs -->
|
<!-- Nav tabs -->
|
||||||
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
|
||||||
@if (Model.SearchForMovies)
|
@if (Model.SearchForMovies)
|
||||||
|
@ -57,7 +58,6 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script id="search-template" type="text/x-handlebars-template">
|
<script id="search-template" type="text/x-handlebars-template">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<title>Plex Requests</title>
|
<title>Plex Requests</title>
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="~/Content/custom.min.css" type="text/css"/>
|
|
||||||
<link rel="stylesheet" href="~/Content/bootstrap.css" type="text/css"/>
|
<link rel="stylesheet" href="~/Content/bootstrap.css" type="text/css"/>
|
||||||
|
<link rel="stylesheet" href="~/Content/custom.min.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="~/Content/font-awesome.css" type="text/css"/>
|
<link rel="stylesheet" href="~/Content/font-awesome.css" type="text/css"/>
|
||||||
<link rel="stylesheet" href="~/Content/pace.min.css" type="text/css"/>
|
<link rel="stylesheet" href="~/Content/pace.min.css" type="text/css"/>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue