mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 05:13:18 -07:00
Merge branch 'dev' into master
This commit is contained in:
commit
a056ba17e5
206 changed files with 8047 additions and 2824 deletions
3
.gitattributes
vendored
3
.gitattributes
vendored
|
@ -66,6 +66,3 @@
|
|||
PlexRequests.UI/Content/* linguist-vendored
|
||||
PlexRequests.UI/Content/* linguist-vendored
|
||||
base.scss linguist-vendored=false
|
||||
requests-1.7.js linguist-vendored=false
|
||||
search-1.7.js linguist-vendored=false
|
||||
site-1.7.js linguist-vendored=false
|
||||
|
|
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
|
@ -3,6 +3,8 @@ If this is a bug report please make sure you have filled the following in:
|
|||
|
||||
#### Plex Requests.Net Version:
|
||||
|
||||
#### update Branch:
|
||||
|
||||
|
||||
#### Operating System:
|
||||
|
||||
|
@ -19,4 +21,4 @@ Logs go here (Please make sure you remove any personal information from the logs
|
|||
|
||||
#### Reproduction Steps:
|
||||
|
||||
Please include any steps to reproduce the issue, this the request that is causing the problem etc.
|
||||
Please include any steps to reproduce the issue, this the request that is causing the problem etc.
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace PlexRequests.Api.Interfaces
|
|||
PlexSearch GetAllEpisodes(string authToken, Uri host, string section, int startPage, int returnCount);
|
||||
PlexServer GetServer(string authToken);
|
||||
PlexSeasonMetadata GetSeasons(string authToken, Uri plexFullHost, string ratingKey);
|
||||
RecentlyAddedModel RecentlyAdded(string authToken, Uri plexFullHost, string sectionId);
|
||||
RecentlyAddedModelOld RecentlyAddedOld(string authToken, Uri plexFullHost, string sectionId);
|
||||
PlexRecentlyAddedModel RecentlyAdded(string authToken, Uri plexFullHost, string sectionId);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RecentlyAddedModel.cs
|
||||
// File: RecentlyAddedModelOld.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -110,7 +110,7 @@ namespace PlexRequests.Api.Models.Plex
|
|||
public string tag { get; set; }
|
||||
}
|
||||
|
||||
public class RecentlyAddedModel
|
||||
public class RecentlyAddedModelOld
|
||||
{
|
||||
public string _elementType { get; set; }
|
||||
public string allowSync { get; set; }
|
||||
|
@ -130,4 +130,112 @@ namespace PlexRequests.Api.Models.Plex
|
|||
public string viewMode { get; set; }
|
||||
public List<RecentlyAddedChild> _children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
// 1.3 and forward!
|
||||
public class PartRecentlyAdded
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string key { get; set; }
|
||||
public int duration { get; set; }
|
||||
public string file { get; set; }
|
||||
public double size { get; set; }
|
||||
public string audioProfile { get; set; }
|
||||
public string container { get; set; }
|
||||
public string videoProfile { get; set; }
|
||||
public string deepAnalysisVersion { get; set; }
|
||||
public string requiredBandwidths { get; set; }
|
||||
}
|
||||
|
||||
public class Medium
|
||||
{
|
||||
public string videoResolution { get; set; }
|
||||
public int id { get; set; }
|
||||
public int duration { get; set; }
|
||||
public int bitrate { get; set; }
|
||||
public int width { get; set; }
|
||||
public int height { get; set; }
|
||||
public double aspectRatio { get; set; }
|
||||
public int audioChannels { get; set; }
|
||||
public string audioCodec { get; set; }
|
||||
public string videoCodec { get; set; }
|
||||
public string container { get; set; }
|
||||
public string videoFrameRate { get; set; }
|
||||
public string audioProfile { get; set; }
|
||||
public string videoProfile { get; set; }
|
||||
public List<PartRecentlyAdded> Part { get; set; }
|
||||
}
|
||||
|
||||
public class DirectorRecentlyAdded
|
||||
{
|
||||
public string tag { get; set; }
|
||||
}
|
||||
|
||||
public class WriterRecentlyAdded
|
||||
{
|
||||
public string tag { get; set; }
|
||||
}
|
||||
|
||||
public class Metadata
|
||||
{
|
||||
public string ratingKey { get; set; }
|
||||
public string key { get; set; }
|
||||
public string parentRatingKey { get; set; }
|
||||
public string grandparentRatingKey { get; set; }
|
||||
public string type { get; set; }
|
||||
public string title { get; set; }
|
||||
public string titleSort { get; set; }
|
||||
public string grandparentKey { get; set; }
|
||||
public string parentKey { get; set; }
|
||||
public string grandparentTitle { get; set; }
|
||||
public string contentRating { get; set; }
|
||||
public string summary { get; set; }
|
||||
public int index { get; set; }
|
||||
public int parentIndex { get; set; }
|
||||
public int year { get; set; }
|
||||
public string thumb { get; set; }
|
||||
public string art { get; set; }
|
||||
public string parentThumb { get; set; }
|
||||
public string grandparentThumb { get; set; }
|
||||
public string grandparentArt { get; set; }
|
||||
public string grandparentTheme { get; set; }
|
||||
public int duration { get; set; }
|
||||
public string originallyAvailableAt { get; set; }
|
||||
public int addedAt { get; set; }
|
||||
public int updatedAt { get; set; }
|
||||
public List<Medium> Media { get; set; }
|
||||
public List<DirectorRecentlyAdded> Director { get; set; }
|
||||
public List<WriterRecentlyAdded> Writer { get; set; }
|
||||
public int? viewCount { get; set; }
|
||||
public int? lastViewedAt { get; set; }
|
||||
public double? rating { get; set; }
|
||||
}
|
||||
|
||||
public class MediaContainer
|
||||
{
|
||||
public double size { get; set; }
|
||||
public double totalSize { get; set; }
|
||||
public bool allowSync { get; set; }
|
||||
public string art { get; set; }
|
||||
public string identifier { get; set; }
|
||||
public int librarySectionID { get; set; }
|
||||
public string librarySectionTitle { get; set; }
|
||||
public string librarySectionUUID { get; set; }
|
||||
public string mediaTagPrefix { get; set; }
|
||||
public int mediaTagVersion { get; set; }
|
||||
public bool mixedParents { get; set; }
|
||||
public bool nocache { get; set; }
|
||||
public int offset { get; set; }
|
||||
public string thumb { get; set; }
|
||||
public string title1 { get; set; }
|
||||
public string title2 { get; set; }
|
||||
public string viewGroup { get; set; }
|
||||
public int viewMode { get; set; }
|
||||
public List<Metadata> Metadata { get; set; }
|
||||
}
|
||||
|
||||
public class PlexRecentlyAddedModel
|
||||
{
|
||||
public MediaContainer MediaContainer { get; set; }
|
||||
}
|
||||
}
|
|
@ -73,7 +73,7 @@
|
|||
<Compile Include="Plex\PlexStatus.cs" />
|
||||
<Compile Include="Plex\PlexMediaType.cs" />
|
||||
<Compile Include="Plex\PlexUserRequest.cs" />
|
||||
<Compile Include="Plex\RecentlyAddedModel.cs" />
|
||||
<Compile Include="Plex\RecentlyAddedModelOld.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SickRage\SickRageBase.cs" />
|
||||
<Compile Include="SickRage\SickrageShows.cs" />
|
||||
|
|
|
@ -104,8 +104,7 @@ namespace PlexRequests.Api
|
|||
}
|
||||
|
||||
var result = DeserializeXml<T>(response.Content);
|
||||
return result;
|
||||
}
|
||||
return result;}
|
||||
|
||||
public T ExecuteJson<T>(IRestRequest request, Uri baseUri) where T : new()
|
||||
{
|
||||
|
|
|
@ -65,9 +65,7 @@ namespace PlexRequests.Api
|
|||
|
||||
var obj = RetryHandler.Execute(() => Api.ExecuteJson<JObject>(request, baseUrl),
|
||||
(exception, timespan) => Log.Error(exception, "Exception when calling AddMovie for CP, Retrying {0}", timespan), new[] {
|
||||
TimeSpan.FromSeconds (2),
|
||||
TimeSpan.FromSeconds(5),
|
||||
TimeSpan.FromSeconds(10)});
|
||||
TimeSpan.FromSeconds (2)});
|
||||
|
||||
|
||||
if (obj.Count > 0)
|
||||
|
|
|
@ -346,7 +346,7 @@ namespace PlexRequests.Api
|
|||
return servers;
|
||||
}
|
||||
|
||||
public RecentlyAddedModel RecentlyAdded(string authToken, Uri plexFullHost, string sectionId)
|
||||
public RecentlyAddedModelOld RecentlyAddedOld(string authToken, Uri plexFullHost, string sectionId)
|
||||
{
|
||||
var request = new RestRequest
|
||||
{
|
||||
|
@ -360,7 +360,7 @@ namespace PlexRequests.Api
|
|||
|
||||
try
|
||||
{
|
||||
var lib = RetryHandler.Execute(() => Api.ExecuteJson<RecentlyAddedModel>(request, plexFullHost),
|
||||
var lib = RetryHandler.Execute(() => Api.ExecuteJson<RecentlyAddedModelOld>(request, plexFullHost),
|
||||
(exception, timespan) => Log.Error(exception, "Exception when calling RecentlyAddedModel for Plex, Retrying {0}", timespan), new[] {
|
||||
TimeSpan.FromSeconds (5),
|
||||
TimeSpan.FromSeconds(10),
|
||||
|
@ -372,7 +372,37 @@ namespace PlexRequests.Api
|
|||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "There has been a API Exception when attempting to get the Plex RecentlyAddedModel");
|
||||
return new RecentlyAddedModel();
|
||||
return new RecentlyAddedModelOld();
|
||||
}
|
||||
}
|
||||
|
||||
public PlexRecentlyAddedModel RecentlyAdded(string authToken, Uri plexFullHost, string sectionId)
|
||||
{
|
||||
var request = new RestRequest
|
||||
{
|
||||
Method = Method.GET,
|
||||
Resource = "library/sections/{sectionId}/recentlyAdded"
|
||||
};
|
||||
|
||||
request.AddUrlSegment("sectionId", sectionId);
|
||||
AddHeaders(ref request, authToken, true);
|
||||
AddLimitHeaders(ref request, 0, 25);
|
||||
|
||||
try
|
||||
{
|
||||
var lib = RetryHandler.Execute(() => Api.ExecuteJson<PlexRecentlyAddedModel>(request, plexFullHost),
|
||||
(exception, timespan) => Log.Error(exception, "Exception when calling PlexRecentlyAddedModel for Plex, Retrying {0}", timespan), new[] {
|
||||
TimeSpan.FromSeconds (5),
|
||||
TimeSpan.FromSeconds(10),
|
||||
TimeSpan.FromSeconds(30)
|
||||
});
|
||||
|
||||
return lib;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "There has been a API Exception when attempting to get the Plex RecentlyAddedModel");
|
||||
return new PlexRecentlyAddedModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace PlexRequests.Api
|
|||
{
|
||||
public static class RetryHandler
|
||||
{
|
||||
private static readonly TimeSpan[] DefaultRetryTime = { TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) };
|
||||
private static readonly TimeSpan[] DefaultRetryTime = { TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5) };
|
||||
|
||||
public static T Execute<T>(Func<T> action, TimeSpan[] timeSpan = null)
|
||||
{
|
||||
|
|
|
@ -117,8 +117,7 @@ namespace PlexRequests.Api
|
|||
try
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||
TimeSpan.FromSeconds (1),
|
||||
TimeSpan.FromSeconds(2),
|
||||
TimeSpan.FromSeconds (2)
|
||||
});
|
||||
|
||||
result = policy.Execute(() => Api.ExecuteJson<SonarrAddSeries>(request, baseUrl));
|
||||
|
@ -186,8 +185,7 @@ namespace PlexRequests.Api
|
|||
try
|
||||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||
TimeSpan.FromSeconds (1),
|
||||
TimeSpan.FromSeconds(2),
|
||||
TimeSpan.FromSeconds (2)
|
||||
});
|
||||
|
||||
result = policy.Execute(() => Api.ExecuteJson<SonarrAddSeries>(request, baseUrl));
|
||||
|
@ -228,8 +226,8 @@ namespace PlexRequests.Api
|
|||
{
|
||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
||||
TimeSpan.FromSeconds (5),
|
||||
TimeSpan.FromSeconds(10),
|
||||
TimeSpan.FromSeconds(30)
|
||||
TimeSpan.FromSeconds(5),
|
||||
TimeSpan.FromSeconds(5)
|
||||
});
|
||||
|
||||
return policy.Execute(() => Api.ExecuteJson<List<Series>>(request, baseUrl));
|
||||
|
|
|
@ -47,25 +47,18 @@ namespace PlexRequests.Api
|
|||
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
|
||||
{
|
||||
var results = await Client.SearchMovie(searchTerm);
|
||||
return results.Results;
|
||||
}
|
||||
|
||||
[Obsolete("Should use TvMaze for TV")]
|
||||
public async Task<List<SearchTv>> SearchTv(string searchTerm)
|
||||
{
|
||||
var results = await Client.SearchTvShow(searchTerm);
|
||||
return results.Results;
|
||||
return results?.Results ?? new List<SearchMovie>();
|
||||
}
|
||||
|
||||
public async Task<List<MovieResult>> GetCurrentPlayingMovies()
|
||||
{
|
||||
var movies = await Client.GetMovieList(MovieListType.NowPlaying);
|
||||
return movies.Results;
|
||||
return movies?.Results ?? new List<MovieResult>();
|
||||
}
|
||||
public async Task<List<MovieResult>> GetUpcomingMovies()
|
||||
{
|
||||
var movies = await Client.GetMovieList(MovieListType.Upcoming);
|
||||
return movies.Results;
|
||||
return movies?.Results ?? new List<MovieResult>();
|
||||
}
|
||||
|
||||
public async Task<Movie> GetMovieInformation(int tmdbId)
|
||||
|
@ -77,14 +70,7 @@ namespace PlexRequests.Api
|
|||
public async Task<Movie> GetMovieInformation(string imdbId)
|
||||
{
|
||||
var movies = await Client.GetMovie(imdbId);
|
||||
return movies;
|
||||
}
|
||||
|
||||
[Obsolete("Should use TvMaze for TV")]
|
||||
public async Task<TvShow> GetTvShowInformation(int tmdbId)
|
||||
{
|
||||
var show = await Client.GetTvShow(tmdbId);
|
||||
return show;
|
||||
return movies ?? new Movie();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,42 +22,31 @@ namespace PlexRequests.Core.Migration
|
|||
public void MigrateToLatest()
|
||||
{
|
||||
var con = Db.DbConnection();
|
||||
var versions = GetMigrations().OrderBy(x => x.Key);
|
||||
|
||||
var dbVersion = con.GetVersionInfo().OrderByDescending(x => x.Version).FirstOrDefault();
|
||||
if (dbVersion == null)
|
||||
{
|
||||
dbVersion = new TableCreation.VersionInfo { Version = 0 };
|
||||
}
|
||||
var versions = GetMigrations();
|
||||
|
||||
var dbVersion = con.GetVersionInfo().OrderByDescending(x => x.Version).FirstOrDefault() ??
|
||||
new TableCreation.VersionInfo { Version = 0 };
|
||||
foreach (var v in versions)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (v.Value.Version > dbVersion.Version)
|
||||
{
|
||||
// Assuming only one constructor
|
||||
var ctor = v.Key.GetConstructors().FirstOrDefault();
|
||||
var dependencies = new List<object>();
|
||||
#endif
|
||||
// Assuming only one constructor
|
||||
var ctor = v.Key.GetConstructors().FirstOrDefault();
|
||||
var dependencies = ctor.GetParameters().Select(param => Kernel.Get(param.ParameterType)).ToList();
|
||||
|
||||
foreach (var param in ctor.GetParameters())
|
||||
{
|
||||
Console.WriteLine(string.Format(
|
||||
"Param {0} is named {1} and is of type {2}",
|
||||
param.Position, param.Name, param.ParameterType));
|
||||
var method = v.Key.GetMethod("Start");
|
||||
if (method != null)
|
||||
{
|
||||
var classInstance = Activator.CreateInstance(v.Key, dependencies.Any() ? dependencies.ToArray() : null);
|
||||
var parametersArray = new object[] { Db.DbConnection() };
|
||||
|
||||
var dep = Kernel.Get(param.ParameterType);
|
||||
dependencies.Add(dep);
|
||||
}
|
||||
|
||||
var method = v.Key.GetMethod("Start");
|
||||
if (method != null)
|
||||
{
|
||||
object result = null;
|
||||
var classInstance = Activator.CreateInstance(v.Key, dependencies.Any() ? dependencies.ToArray() : null);
|
||||
|
||||
var parametersArray = new object[] { Db.DbConnection() };
|
||||
|
||||
method.Invoke(classInstance, parametersArray);
|
||||
}
|
||||
method.Invoke(classInstance, parametersArray);
|
||||
}
|
||||
#if !DEBUG
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
278
PlexRequests.Core.Migration/Migrations/Version1100.cs
Normal file
278
PlexRequests.Core.Migration/Migrations/Version1100.cs
Normal file
|
@ -0,0 +1,278 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: Version1100.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using NLog;
|
||||
using System.Linq;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Core.Users;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
namespace PlexRequests.Core.Migration.Migrations
|
||||
{
|
||||
[Migration(11000, "v1.10.0.0")]
|
||||
public class Version1100 : BaseMigration, IMigration
|
||||
{
|
||||
public Version1100(IUserRepository userRepo, IRequestService requestService, ISettingsService<LogSettings> log, IPlexApi plexApi, ISettingsService<PlexSettings> plexService,
|
||||
IPlexUserRepository plexusers, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
|
||||
ISettingsService<ScheduledJobsSettings> sjs, IRepository<UsersToNotify> usersToNotify)
|
||||
{
|
||||
UserRepo = userRepo;
|
||||
RequestService = requestService;
|
||||
Log = log;
|
||||
PlexApi = plexApi;
|
||||
PlexSettings = plexService;
|
||||
PlexUsers = plexusers;
|
||||
PlexRequestSettings = prSettings;
|
||||
UserManagementSettings = umSettings;
|
||||
ScheduledJobSettings = sjs;
|
||||
UserNotifyRepo = usersToNotify;
|
||||
}
|
||||
public int Version => 11000;
|
||||
private IUserRepository UserRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private ISettingsService<LogSettings> Log { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private IPlexUserRepository PlexUsers { get; }
|
||||
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
|
||||
private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
|
||||
private ISettingsService<ScheduledJobsSettings> ScheduledJobSettings { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
|
||||
public void Start(IDbConnection con)
|
||||
{
|
||||
UpdateDb(con);
|
||||
|
||||
// Update the current admin permissions set
|
||||
|
||||
PopulateDefaultUserManagementSettings();
|
||||
UpdateAdmin();
|
||||
ResetLogLevel();
|
||||
UpdatePlexUsers();
|
||||
UpdateScheduledJobs();
|
||||
MigrateUserNotifications();
|
||||
|
||||
UpdateSchema(con, Version);
|
||||
}
|
||||
|
||||
private void MigrateUserNotifications()
|
||||
{
|
||||
var usersToNotify = UserNotifyRepo.GetAll();
|
||||
var plexUsers = PlexUsers.GetAll().ToList();
|
||||
var users = UserRepo.GetAll().ToList();
|
||||
|
||||
if (usersToNotify == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var u in usersToNotify)
|
||||
{
|
||||
var selectedPlexUser = plexUsers.FirstOrDefault(x => x.Username.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (selectedPlexUser != null)
|
||||
{
|
||||
selectedPlexUser.Features += (int)Features.RequestAddedNotification;
|
||||
PlexUsers.Update(selectedPlexUser);
|
||||
}
|
||||
|
||||
var selectedLocalUser =
|
||||
users.FirstOrDefault(x => x.UserName.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (selectedLocalUser != null)
|
||||
{
|
||||
selectedLocalUser.Features += (int)Features.RequestAddedNotification;
|
||||
UserRepo.Update(selectedLocalUser);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScheduledJobs()
|
||||
{
|
||||
var settings = ScheduledJobSettings.GetSettings();
|
||||
|
||||
settings.PlexUserChecker = 24;
|
||||
settings.PlexContentCacher = 60;
|
||||
|
||||
ScheduledJobSettings.SaveSettings(settings);
|
||||
}
|
||||
|
||||
private void PopulateDefaultUserManagementSettings()
|
||||
{
|
||||
var plexRequestSettings = PlexRequestSettings.GetSettings();
|
||||
|
||||
UserManagementSettings.SaveSettings(new UserManagementSettings
|
||||
{
|
||||
AutoApproveMovies = !plexRequestSettings.RequireMovieApproval,
|
||||
RequestTvShows = plexRequestSettings.SearchForTvShows,
|
||||
RequestMusic = plexRequestSettings.SearchForMusic,
|
||||
RequestMovies = plexRequestSettings.SearchForMovies,
|
||||
AutoApproveMusic = !plexRequestSettings.RequireMusicApproval,
|
||||
AutoApproveTvShows = !plexRequestSettings.RequireTvShowApproval
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdatePlexUsers()
|
||||
{
|
||||
var settings = PlexSettings.GetSettings();
|
||||
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var plexUsers = PlexApi.GetUsers(settings.PlexAuthToken);
|
||||
|
||||
if (plexUsers?.User == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var prSettings = PlexRequestSettings.GetSettings();
|
||||
|
||||
var dbUsers = PlexUsers.GetAll().ToList();
|
||||
foreach (var user in plexUsers.User)
|
||||
{
|
||||
if (dbUsers.FirstOrDefault(x => x.PlexUserId == user.Id) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int permissions = 0;
|
||||
if (prSettings.SearchForMovies)
|
||||
{
|
||||
permissions = (int)Permissions.RequestMovie;
|
||||
}
|
||||
if (prSettings.SearchForTvShows)
|
||||
{
|
||||
permissions += (int)Permissions.RequestTvShow;
|
||||
}
|
||||
if (prSettings.SearchForMusic)
|
||||
{
|
||||
permissions += (int)Permissions.RequestMusic;
|
||||
}
|
||||
if (!prSettings.RequireMovieApproval)
|
||||
{
|
||||
permissions += (int)Permissions.AutoApproveMovie;
|
||||
}
|
||||
if (!prSettings.RequireTvShowApproval)
|
||||
{
|
||||
permissions += (int)Permissions.AutoApproveTv;
|
||||
}
|
||||
if (!prSettings.RequireMusicApproval)
|
||||
{
|
||||
permissions += (int)Permissions.AutoApproveAlbum;
|
||||
}
|
||||
|
||||
// Add report Issues
|
||||
|
||||
permissions += (int)Permissions.ReportIssue;
|
||||
|
||||
var m = new PlexUsers
|
||||
{
|
||||
PlexUserId = user.Id,
|
||||
Permissions = permissions,
|
||||
Features = 0,
|
||||
UserAlias = string.Empty,
|
||||
EmailAddress = user.Email,
|
||||
Username = user.Username,
|
||||
LoginId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
PlexUsers.Insert(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ResetLogLevel()
|
||||
{
|
||||
var logSettings = Log.GetSettings();
|
||||
logSettings.Level = LogLevel.Error.Ordinal;
|
||||
Log.SaveSettings(logSettings);
|
||||
|
||||
LoggingHelper.ReconfigureLogLevel(LogLevel.FromOrdinal(logSettings.Level));
|
||||
}
|
||||
|
||||
private void UpdateDb(IDbConnection con)
|
||||
{
|
||||
// Create the two new columns
|
||||
con.AlterTable("Users", "ADD", "Permissions", true, "INTEGER");
|
||||
con.AlterTable("Users", "ADD", "Features", true, "INTEGER");
|
||||
|
||||
con.AlterTable("PlexUsers", "ADD", "Permissions", true, "INTEGER");
|
||||
con.AlterTable("PlexUsers", "ADD", "Features", true, "INTEGER");
|
||||
con.AlterTable("PlexUsers", "ADD", "Username", true, "VARCHAR(100)");
|
||||
con.AlterTable("PlexUsers", "ADD", "EmailAddress", true, "VARCHAR(100)");
|
||||
con.AlterTable("PlexUsers", "ADD", "LoginId", true, "VARCHAR(100)");
|
||||
|
||||
//https://image.tmdb.org/t/p/w150/https://image.tmdb.org/t/p/w150//aqhAqttDq7zgsTaBHtCD8wmTk6k.jpg
|
||||
|
||||
// UI = https://image.tmdb.org/t/p/w150/{{posterPath}}
|
||||
// Update old invalid posters
|
||||
var allRequests = RequestService.GetAll();
|
||||
if (allRequests == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var requestedModels = allRequests as RequestedModel[] ?? allRequests.ToArray();
|
||||
foreach (var req in requestedModels)
|
||||
{
|
||||
if (req.PosterPath.Contains("https://image.tmdb.org/t/p/w150/"))
|
||||
{
|
||||
var newImg = req.PosterPath.Replace("https://image.tmdb.org/t/p/w150/", string.Empty);
|
||||
req.PosterPath = newImg;
|
||||
}
|
||||
}
|
||||
RequestService.BatchUpdate(requestedModels);
|
||||
}
|
||||
|
||||
private void UpdateAdmin()
|
||||
{
|
||||
var users = UserRepo.GetAll().ToList();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
user.Permissions = (int)
|
||||
(Permissions.Administrator
|
||||
| Permissions.ReportIssue
|
||||
| Permissions.RequestMusic
|
||||
| Permissions.RequestTvShow
|
||||
| Permissions.RequestMovie
|
||||
| Permissions.AutoApproveAlbum
|
||||
| Permissions.AutoApproveMovie
|
||||
| Permissions.AutoApproveTv);
|
||||
}
|
||||
|
||||
UserRepo.UpdateAll(users);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,10 @@
|
|||
<Reference Include="Ninject">
|
||||
<HintPath>..\packages\Ninject.3.2.0.0\lib\net45-full\Ninject.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.3.11\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Quartz, Version=2.3.3.0, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -65,14 +69,27 @@
|
|||
<Compile Include="MigrationAttribute.cs" />
|
||||
<Compile Include="MigrationRunner.cs" />
|
||||
<Compile Include="Migrations\BaseMigration.cs" />
|
||||
<Compile Include="Migrations\Version1100.cs" />
|
||||
<Compile Include="Migrations\Version195.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PlexRequests.Api.Interfaces\PlexRequests.Api.Interfaces.csproj">
|
||||
<Project>{95834072-A675-415D-AA8F-877C91623810}</Project>
|
||||
<Name>PlexRequests.Api.Interfaces</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PlexRequests.Api.Models\PlexRequests.Api.Models.csproj">
|
||||
<Project>{CB37A5F8-6DFC-4554-99D3-A42B502E4591}</Project>
|
||||
<Name>PlexRequests.Api.Models</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PlexRequests.Core\PlexRequests.Core.csproj">
|
||||
<Project>{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}</Project>
|
||||
<Name>PlexRequests.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PlexRequests.Helpers\PlexRequests.Helpers.csproj">
|
||||
<Project>{1252336D-42A3-482A-804C-836E60173DFA}</Project>
|
||||
<Name>PlexRequests.Helpers</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\PlexRequests.Store\PlexRequests.Store.csproj">
|
||||
<Project>{92433867-2B7B-477B-A566-96C382427525}</Project>
|
||||
<Name>PlexRequests.Store</Name>
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<packages>
|
||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Common.Logging.Core" version="3.0.0" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.11" targetFramework="net45" />
|
||||
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||
</packages>
|
|
@ -60,7 +60,6 @@
|
|||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="AuthenticationSettingsTests.cs" />
|
||||
<Compile Include="StatusCheckerTests.cs" />
|
||||
<Compile Include="NotificationMessageResolverTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace PlexRequests.Core
|
|||
{
|
||||
public struct TimeFrameMinutes
|
||||
{
|
||||
public const int SchedulerCaching = 60;
|
||||
public const int SchedulerCaching = 120;
|
||||
}
|
||||
|
||||
public const string PlexLibaries = nameof(PlexLibaries);
|
||||
|
|
|
@ -24,18 +24,16 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using NLog;
|
||||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Store;
|
||||
|
||||
namespace PlexRequests.UI.Helpers
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public class HeadphonesSender
|
||||
{
|
34
PlexRequests.Core/ISecurityExtensions.cs
Normal file
34
PlexRequests.Core/ISecurityExtensions.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using Nancy;
|
||||
using Nancy.Security;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public interface ISecurityExtensions
|
||||
{
|
||||
Response AdminLoginRedirect(Permissions perm, NancyContext context);
|
||||
Response AdminLoginRedirect(NancyContext context, params Permissions[] perm);
|
||||
bool DoesNotHavePermissions(Permissions perm, IUserIdentity currentUser);
|
||||
|
||||
Response HasAnyPermissionsRedirect(NancyContext context, string routeName, HttpStatusCode code,
|
||||
params Permissions[] perm);
|
||||
bool DoesNotHavePermissions(int perm, IUserIdentity currentUser);
|
||||
Func<NancyContext, Response> ForbiddenIfNot(Func<NancyContext, bool> test);
|
||||
bool HasAnyPermissions(IUserIdentity user, params Permissions[] perm);
|
||||
bool HasPermissions(IUserIdentity user, Permissions perm);
|
||||
Response HasPermissionsRedirect(Permissions perm, NancyContext context, string routeName, HttpStatusCode code);
|
||||
Func<NancyContext, Response> HttpStatusCodeIfNot(HttpStatusCode statusCode, Func<NancyContext, bool> test);
|
||||
bool IsLoggedIn(NancyContext context);
|
||||
bool IsNormalUser(IUserIdentity user);
|
||||
bool IsPlexUser(IUserIdentity user);
|
||||
bool HasPermissions(string userName, Permissions perm);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the username this could be the alias! We should always use this method when getting the username
|
||||
/// </summary>
|
||||
/// <param name="username">The username.</param>
|
||||
/// <returns><c>null</c> if we cannot find a user</returns>
|
||||
string GetUsername(string username);
|
||||
}
|
||||
}
|
11
PlexRequests.Core/IStatusChecker.cs
Normal file
11
PlexRequests.Core/IStatusChecker.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
using Octokit;
|
||||
using PlexRequests.Core.Models;
|
||||
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public interface IStatusChecker
|
||||
{
|
||||
Task<StatusModel> GetStatus();
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ namespace PlexRequests.Core.Models
|
|||
RequestApproved,
|
||||
AdminNote,
|
||||
Test,
|
||||
|
||||
RequestDeclined,
|
||||
ItemAddedToFaultQueue
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ namespace PlexRequests.Core.Models
|
|||
{
|
||||
public class StatusModel
|
||||
{
|
||||
public string Version { get; set; }
|
||||
public string CurrentVersion { get; set; }
|
||||
public string NewVersion { get; set; }
|
||||
public bool UpdateAvailable { get; set; }
|
||||
public string UpdateUri { get; set; }
|
||||
public string DownloadUri { get; set; }
|
||||
|
|
|
@ -39,9 +39,17 @@
|
|||
<HintPath>..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Dapper, Version=1.50.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Dapper.1.50.0-beta8\lib\net45\Dapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Data.Sqlite">
|
||||
<HintPath>..\Assemblies\Mono.Data.Sqlite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Nancy.Linker, Version=0.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Nancy.Linker.0.3.1\lib\net40-Client\Nancy.Linker.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -54,7 +62,12 @@
|
|||
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
@ -81,7 +94,10 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CacheKeys.cs" />
|
||||
<Compile Include="HeadphonesSender.cs" />
|
||||
<Compile Include="IPlexReadOnlyDatabase.cs" />
|
||||
<Compile Include="ISecurityExtensions.cs" />
|
||||
<Compile Include="IStatusChecker.cs" />
|
||||
<Compile Include="Notification\NotificationMessage.cs" />
|
||||
<Compile Include="Notification\NotificationMessageContent.cs" />
|
||||
<Compile Include="Notification\NotificationMessageCurlys.cs" />
|
||||
|
@ -99,6 +115,9 @@
|
|||
<Compile Include="Notification\Templates\IEmailBasicTemplate.cs" />
|
||||
<Compile Include="Notification\TransportType.cs" />
|
||||
<Compile Include="PlexReadOnlyDatabase.cs" />
|
||||
<Compile Include="Queue\ITransientFaultQueue.cs" />
|
||||
<Compile Include="Queue\TransientFaultQueue.cs" />
|
||||
<Compile Include="SecurityExtensions.cs" />
|
||||
<Compile Include="SettingModels\AuthenticationSettings.cs" />
|
||||
<Compile Include="SettingModels\ExternalSettings.cs" />
|
||||
<Compile Include="SettingModels\HeadphonesSettings.cs" />
|
||||
|
@ -119,12 +138,22 @@
|
|||
<Compile Include="SettingModels\CouchPotatoSettings.cs" />
|
||||
<Compile Include="SettingModels\PlexRequestSettings.cs" />
|
||||
<Compile Include="SettingModels\Settings.cs" />
|
||||
<Compile Include="SettingModels\SystemSettings.cs" />
|
||||
<Compile Include="SettingModels\UserManagementSettings.cs" />
|
||||
<Compile Include="SettingsServiceV2.cs" />
|
||||
<Compile Include="Setup.cs" />
|
||||
<Compile Include="StatusChecker.cs" />
|
||||
<Compile Include="StatusChecker\AppveyorArtifactResult.cs" />
|
||||
<Compile Include="StatusChecker\StatusChecker.cs" />
|
||||
<Compile Include="StatusChecker\AppveyorBranchResult.cs" />
|
||||
<Compile Include="TvSender.cs" />
|
||||
<Compile Include="TvSenderOld.cs" />
|
||||
<Compile Include="Users\IUserHelper.cs" />
|
||||
<Compile Include="Users\UserHelper.cs" />
|
||||
<Compile Include="UserIdentity.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UserMapper.cs" />
|
||||
<Compile Include="Users\UserHelperModel.cs" />
|
||||
<Compile Include="Users\UserManagementHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
|
|
17
PlexRequests.Core/Queue/ITransientFaultQueue.cs
Normal file
17
PlexRequests.Core/Queue/ITransientFaultQueue.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
|
||||
namespace PlexRequests.Core.Queue
|
||||
{
|
||||
public interface ITransientFaultQueue
|
||||
{
|
||||
void Dequeue();
|
||||
Task DequeueAsync();
|
||||
IEnumerable<RequestQueue> GetQueue();
|
||||
Task<IEnumerable<RequestQueue>> GetQueueAsync();
|
||||
void QueueItem(RequestedModel request, string id, RequestType type, FaultType faultType);
|
||||
Task QueueItemAsync(RequestedModel request, string id, RequestType type, FaultType faultType, string message = null);
|
||||
}
|
||||
}
|
130
PlexRequests.Core/Queue/TransientFaultQueue.cs
Normal file
130
PlexRequests.Core/Queue/TransientFaultQueue.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: TransientFaultQueue.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
namespace PlexRequests.Core.Queue
|
||||
{
|
||||
public class TransientFaultQueue : ITransientFaultQueue
|
||||
{
|
||||
public TransientFaultQueue(IRepository<RequestQueue> queue)
|
||||
{
|
||||
RequestQueue = queue;
|
||||
}
|
||||
|
||||
private IRepository<RequestQueue> RequestQueue { get; }
|
||||
|
||||
|
||||
public void QueueItem(RequestedModel request, string id, RequestType type, FaultType faultType)
|
||||
{
|
||||
//Ensure there is not a duplicate queued item
|
||||
var existingItem = RequestQueue.Custom(
|
||||
connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = connection.Query<RequestQueue>("select * from RequestQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = id });
|
||||
|
||||
return result;
|
||||
}).FirstOrDefault();
|
||||
|
||||
if (existingItem != null)
|
||||
{
|
||||
// It's already in the queue
|
||||
return;
|
||||
}
|
||||
|
||||
var queue = new RequestQueue
|
||||
{
|
||||
Type = type,
|
||||
Content = ByteConverterHelper.ReturnBytes(request),
|
||||
PrimaryIdentifier = id,
|
||||
FaultType = faultType
|
||||
};
|
||||
RequestQueue.Insert(queue);
|
||||
}
|
||||
|
||||
public async Task QueueItemAsync(RequestedModel request, string id, RequestType type, FaultType faultType, string description = null)
|
||||
{
|
||||
//Ensure there is not a duplicate queued item
|
||||
var existingItem = await RequestQueue.CustomAsync(async connection =>
|
||||
{
|
||||
connection.Open();
|
||||
var result = await connection.QueryAsync<RequestQueue>("select * from RequestFaultQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = id });
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
if (existingItem.FirstOrDefault() != null)
|
||||
{
|
||||
// It's already in the queue
|
||||
return;
|
||||
}
|
||||
|
||||
var queue = new RequestQueue
|
||||
{
|
||||
Type = type,
|
||||
Content = ByteConverterHelper.ReturnBytes(request),
|
||||
PrimaryIdentifier = id,
|
||||
FaultType = faultType,
|
||||
Message = description ?? string.Empty
|
||||
};
|
||||
await RequestQueue.InsertAsync(queue);
|
||||
}
|
||||
|
||||
public IEnumerable<RequestQueue> GetQueue()
|
||||
{
|
||||
var items = RequestQueue.GetAll();
|
||||
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RequestQueue>> GetQueueAsync()
|
||||
{
|
||||
var items = RequestQueue.GetAllAsync();
|
||||
|
||||
return await items;
|
||||
}
|
||||
|
||||
public void Dequeue()
|
||||
{
|
||||
RequestQueue.DeleteAll("RequestQueue");
|
||||
}
|
||||
|
||||
public async Task DequeueAsync()
|
||||
{
|
||||
await RequestQueue.DeleteAllAsync("RequestQueue");
|
||||
}
|
||||
}
|
||||
}
|
302
PlexRequests.Core/SecurityExtensions.cs
Normal file
302
PlexRequests.Core/SecurityExtensions.cs
Normal file
|
@ -0,0 +1,302 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SecurityExtensions.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Nancy;
|
||||
using Nancy.Linker;
|
||||
using Nancy.Responses;
|
||||
using Nancy.Security;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Store.Repository;
|
||||
using ISecurityExtensions = PlexRequests.Core.ISecurityExtensions;
|
||||
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public class SecurityExtensions : ISecurityExtensions
|
||||
{
|
||||
public SecurityExtensions(IUserRepository userRepository, IResourceLinker linker, IPlexUserRepository plexUsers)
|
||||
{
|
||||
UserRepository = userRepository;
|
||||
Linker = linker;
|
||||
PlexUsers = plexUsers;
|
||||
}
|
||||
|
||||
private IUserRepository UserRepository { get; }
|
||||
private IResourceLinker Linker { get; }
|
||||
private IPlexUserRepository PlexUsers { get; }
|
||||
|
||||
public bool IsLoggedIn(NancyContext context)
|
||||
{
|
||||
var userName = context.Request.Session[SessionKeys.UsernameKey];
|
||||
var realUser = false;
|
||||
var plexUser = userName != null;
|
||||
|
||||
if (context.CurrentUser?.IsAuthenticated() ?? false)
|
||||
{
|
||||
realUser = true;
|
||||
}
|
||||
|
||||
return realUser || plexUser;
|
||||
}
|
||||
|
||||
public bool IsPlexUser(IUserIdentity user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var plexUser = PlexUsers.GetUserByUsername(user.UserName);
|
||||
return plexUser != null;
|
||||
}
|
||||
|
||||
public bool IsNormalUser(IUserIdentity user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var dbUser = UserRepository.GetUserByUsername(user.UserName);
|
||||
|
||||
return dbUser != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the username this could be the alias! We should always use this method when getting the username
|
||||
/// </summary>
|
||||
/// <param name="username">The username.</param>
|
||||
/// <returns><c>null</c> if we cannot find a user</returns>
|
||||
public string GetUsername(string username)
|
||||
{
|
||||
var plexUser = PlexUsers.GetUserByUsername(username);
|
||||
if (plexUser != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(plexUser.UserAlias))
|
||||
{
|
||||
return plexUser.UserAlias;
|
||||
}
|
||||
else
|
||||
{
|
||||
return plexUser.Username;
|
||||
}
|
||||
}
|
||||
|
||||
var dbUser = UserRepository.GetUserByUsername(username);
|
||||
if (dbUser != null)
|
||||
{
|
||||
var userProps = ByteConverterHelper.ReturnObject<UserProperties>(dbUser.UserProperties);
|
||||
if (!string.IsNullOrEmpty(userProps.UserAlias))
|
||||
{
|
||||
return userProps.UserAlias;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dbUser.UserName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hook to be used in a pipeline before a route handler to ensure
|
||||
/// that the request was made by an authenticated user does not have the claims.
|
||||
/// </summary>
|
||||
/// <param name="perm">Claims the authenticated user needs to have</param>
|
||||
/// <returns>Hook that returns an Unauthorized response if the user is not
|
||||
/// authenticated or does have the claims, null otherwise</returns>
|
||||
private Func<NancyContext, Response> DoesNotHavePermissions(int perm)
|
||||
{
|
||||
return ForbiddenIfNot(ctx =>
|
||||
{
|
||||
var permissions = GetPermissions(ctx.CurrentUser);
|
||||
var result = permissions.HasFlag((Permissions)perm);
|
||||
return !result;
|
||||
});
|
||||
}
|
||||
|
||||
public bool DoesNotHavePermissions(int perm, IUserIdentity currentUser)
|
||||
{
|
||||
return DoesNotHavePermissions((Permissions)perm, currentUser);
|
||||
}
|
||||
|
||||
public bool DoesNotHavePermissions(Permissions perm, IUserIdentity currentUser)
|
||||
{
|
||||
var permissions = GetPermissions(currentUser);
|
||||
var result = permissions.HasFlag(perm);
|
||||
return !result;
|
||||
}
|
||||
|
||||
public bool HasPermissions(IUserIdentity user, Permissions perm)
|
||||
{
|
||||
var permissions = GetPermissions(user);
|
||||
return permissions.HasFlag(perm);
|
||||
}
|
||||
public bool HasPermissions(string userName, Permissions perm)
|
||||
{
|
||||
var permissions = GetPermissions(userName);
|
||||
return permissions.HasFlag(perm);
|
||||
}
|
||||
|
||||
public bool HasAnyPermissions(IUserIdentity user, params Permissions[] perm)
|
||||
{
|
||||
var permissions = GetPermissions(user);
|
||||
|
||||
foreach (var p in perm)
|
||||
{
|
||||
var result = permissions.HasFlag(p);
|
||||
if (result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Response HasPermissionsRedirect(Permissions perm, NancyContext context, string routeName, HttpStatusCode code)
|
||||
{
|
||||
var url = Linker.BuildRelativeUri(context, routeName);
|
||||
|
||||
var response = ForbiddenIfNot(ctx =>
|
||||
{
|
||||
var permissions = GetPermissions(ctx.CurrentUser);
|
||||
var result = permissions.HasFlag(perm);
|
||||
return result;
|
||||
});
|
||||
|
||||
var r = response(context);
|
||||
return r.StatusCode == code
|
||||
? new RedirectResponse($"{url.ToString()}?redirect={context.Request.Path}")
|
||||
: null;
|
||||
}
|
||||
public Response HasAnyPermissionsRedirect(NancyContext context, string routeName, HttpStatusCode code, params Permissions[] perm)
|
||||
{
|
||||
var url = Linker.BuildRelativeUri(context, routeName);
|
||||
|
||||
var response = ForbiddenIfNot(ctx =>
|
||||
{
|
||||
var permissions = GetPermissions(ctx.CurrentUser);
|
||||
var hasPermission = false;
|
||||
foreach (var p in perm)
|
||||
{
|
||||
var result = permissions.HasFlag(p);
|
||||
if (result)
|
||||
{
|
||||
hasPermission = true;
|
||||
}
|
||||
}
|
||||
return hasPermission;
|
||||
});
|
||||
|
||||
var r = response(context);
|
||||
return r.StatusCode == code
|
||||
? new RedirectResponse(url.ToString())
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
public Response AdminLoginRedirect(Permissions perm, NancyContext context)
|
||||
{
|
||||
// This will redirect us to the Login Page if we don't have the correct permission passed in (e.g. Admin with Http 403 status code).
|
||||
return HasPermissionsRedirect(perm, context, "LocalLogin", HttpStatusCode.Forbidden);
|
||||
}
|
||||
|
||||
public Response AdminLoginRedirect(NancyContext context, params Permissions[] perm)
|
||||
{
|
||||
// This will redirect us to the Login Page if we don't have the correct permission passed in (e.g. Admin with Http 403 status code).
|
||||
return HasAnyPermissionsRedirect(context, "LocalLogin", HttpStatusCode.Forbidden, perm);
|
||||
}
|
||||
|
||||
// BELOW IS A COPY FROM THE SecurityHooks CLASS!
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hook to be used in a pipeline before a route handler to ensure that
|
||||
/// the request satisfies a specific test.
|
||||
/// </summary>
|
||||
/// <param name="test">Test that must return true for the request to continue</param>
|
||||
/// <returns>Hook that returns an Forbidden response if the test fails, null otherwise</returns>
|
||||
public Func<NancyContext, Response> ForbiddenIfNot(Func<NancyContext, bool> test)
|
||||
{
|
||||
return HttpStatusCodeIfNot(HttpStatusCode.Forbidden, test);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hook to be used in a pipeline before a route handler to ensure that
|
||||
/// the request satisfies a specific test.
|
||||
/// </summary>
|
||||
/// <param name="statusCode">HttpStatusCode to use for the response</param>
|
||||
/// <param name="test">Test that must return true for the request to continue</param>
|
||||
/// <returns>Hook that returns a response with a specific HttpStatusCode if the test fails, null otherwise</returns>
|
||||
public Func<NancyContext, Response> HttpStatusCodeIfNot(HttpStatusCode statusCode, Func<NancyContext, bool> test)
|
||||
{
|
||||
return ctx =>
|
||||
{
|
||||
Response response = new Response
|
||||
{
|
||||
StatusCode = HttpStatusCode.OK
|
||||
};
|
||||
if (!test(ctx))
|
||||
{
|
||||
response = new Response
|
||||
{
|
||||
StatusCode = statusCode
|
||||
};
|
||||
}
|
||||
return response;
|
||||
};
|
||||
}
|
||||
|
||||
private Permissions GetPermissions(IUserIdentity user)
|
||||
{
|
||||
return GetPermissions(user?.UserName);
|
||||
}
|
||||
|
||||
private Permissions GetPermissions(string userName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userName)) return 0;
|
||||
|
||||
var dbUser = UserRepository.GetUserByUsername(userName);
|
||||
|
||||
if (dbUser != null)
|
||||
{
|
||||
var permissions = (Permissions)dbUser.Permissions;
|
||||
return permissions;
|
||||
}
|
||||
|
||||
var plexUser = PlexUsers.GetUserByUsername(userName);
|
||||
if (plexUser != null)
|
||||
{
|
||||
var permissions = (Permissions)plexUser.Permissions;
|
||||
return permissions;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,15 +44,20 @@ namespace PlexRequests.Core.SettingModels
|
|||
public bool SearchForMovies { get; set; }
|
||||
public bool SearchForTvShows { get; set; }
|
||||
public bool SearchForMusic { get; set; }
|
||||
[Obsolete("Use the user management settings")]
|
||||
public bool RequireMovieApproval { get; set; }
|
||||
[Obsolete("Use the user management settings")]
|
||||
public bool RequireTvShowApproval { get; set; }
|
||||
[Obsolete("Use the user management settings")]
|
||||
public bool RequireMusicApproval { get; set; }
|
||||
|
||||
[Obsolete("Use the user management settings")]
|
||||
public bool UsersCanViewOnlyOwnRequests { get; set; }
|
||||
[Obsolete("Use the user management settings")]
|
||||
public bool UsersCanViewOnlyOwnIssues { get; set; }
|
||||
public int MovieWeeklyRequestLimit { get; set; }
|
||||
public int TvWeeklyRequestLimit { get; set; }
|
||||
public int AlbumWeeklyRequestLimit { get; set; }
|
||||
public string NoApprovalUsers { get; set; }
|
||||
public bool CollectAnalyticData { get; set; }
|
||||
public bool IgnoreNotifyForAutoApprovedRequests { get; set; }
|
||||
public bool Wizard { get; set; }
|
||||
|
@ -69,26 +74,5 @@ namespace PlexRequests.Core.SettingModels
|
|||
public string ThemeName { get; set; }
|
||||
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<string> ApprovalWhiteList
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,5 +42,8 @@ namespace PlexRequests.Core.SettingModels
|
|||
[Obsolete("We use the CRON job now")]
|
||||
public int RecentlyAdded { get; set; }
|
||||
public string RecentlyAddedCron { get; set; }
|
||||
public int FaultQueueHandler { get; set; }
|
||||
public int PlexContentCacher { get; set; }
|
||||
public int PlexUserChecker { get; set; }
|
||||
}
|
||||
}
|
63
PlexRequests.Core/SettingModels/SystemSettings.cs
Normal file
63
PlexRequests.Core/SettingModels/SystemSettings.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SystemSettings.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Newtonsoft.Json;
|
||||
using PlexRequests.Core.Models;
|
||||
|
||||
namespace PlexRequests.Core.SettingModels
|
||||
{
|
||||
public class SystemSettings : Settings
|
||||
{
|
||||
public Branches Branch { get; set; }
|
||||
public string Version { get; set; }
|
||||
public StatusModel Status { get; set; }
|
||||
[JsonIgnore]
|
||||
public List<BranchDropdown> BranchDropdown { get; set; }
|
||||
}
|
||||
|
||||
public class BranchDropdown
|
||||
{
|
||||
public bool Selected { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Branches Value { get; set; }
|
||||
}
|
||||
|
||||
public enum Branches
|
||||
{
|
||||
[Display(Name = "Stable")]
|
||||
Stable,
|
||||
|
||||
[Display(Name = "Early Access Preview")]
|
||||
EarlyAccessPreview,
|
||||
|
||||
[Display(Name = "Development")]
|
||||
Dev,
|
||||
}
|
||||
}
|
45
PlexRequests.Core/SettingModels/UserManagementSettings.cs
Normal file
45
PlexRequests.Core/SettingModels/UserManagementSettings.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserManagementSettings.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
namespace PlexRequests.Core.SettingModels
|
||||
{
|
||||
public class UserManagementSettings : Settings
|
||||
{
|
||||
public bool RequestMovies { get; set; }
|
||||
public bool RequestTvShows { get; set; }
|
||||
public bool RequestMusic { get; set; }
|
||||
public bool AutoApproveMovies { get; set; }
|
||||
public bool AutoApproveTvShows { get; set; }
|
||||
public bool AutoApproveMusic { get; set; }
|
||||
public bool ReportIssues { get; set; }
|
||||
public bool UsersCanViewOnlyOwnRequests { get; set; }
|
||||
public bool UsersCanViewOnlyOwnIssues { get; set; }
|
||||
|
||||
// Features
|
||||
public bool RecentlyAddedNotification { get; set; }
|
||||
public bool RecentlyAddedNewsletter { get; set; }
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace PlexRequests.Core
|
|||
Db = new DbConfiguration(new SqliteFactory());
|
||||
var created = Db.CheckDb();
|
||||
TableCreation.CreateTables(Db.DbConnection());
|
||||
|
||||
|
||||
if (created)
|
||||
{
|
||||
CreateDefaultSettingsPage(urlBase);
|
||||
|
@ -61,65 +61,35 @@ namespace PlexRequests.Core
|
|||
TableCreation.Vacuum(Db.DbConnection());
|
||||
}
|
||||
|
||||
|
||||
// The below code is obsolete, we should use PlexRequests.Core.Migrations.MigrationRunner
|
||||
var version = CheckSchema();
|
||||
if (version > 0)
|
||||
{
|
||||
if (version > 1899 && version <= 1900)
|
||||
{
|
||||
MigrateToVersion1900();
|
||||
}
|
||||
|
||||
if(version > 1899 && version <= 1910)
|
||||
{
|
||||
MigrateToVersion1910();
|
||||
}
|
||||
}
|
||||
// Add the new 'running' item into the scheduled jobs so we can check if the cachers are running
|
||||
Db.DbConnection().AlterTable("ScheduledJobs", "ADD", "Running", true, "INTEGER");
|
||||
|
||||
return Db.DbConnection().ConnectionString;
|
||||
}
|
||||
|
||||
public static string ConnectionString => Db.DbConnection().ConnectionString;
|
||||
|
||||
|
||||
private int CheckSchema()
|
||||
{
|
||||
var productVersion = AssemblyHelper.GetProductVersion();
|
||||
var trimStatus = new Regex("[^0-9]", RegexOptions.Compiled).Replace(productVersion, string.Empty).PadRight(4, '0');
|
||||
var version = int.Parse(trimStatus);
|
||||
|
||||
var connection = Db.DbConnection();
|
||||
var schema = connection.GetSchemaVersion();
|
||||
if (schema == null)
|
||||
{
|
||||
connection.CreateSchema(version); // Set the default.
|
||||
schema = connection.GetSchemaVersion();
|
||||
}
|
||||
if (version > schema.SchemaVersion)
|
||||
{
|
||||
Db.DbConnection().UpdateSchemaVersion(version);
|
||||
schema = connection.GetSchemaVersion();
|
||||
}
|
||||
version = schema.SchemaVersion;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
private void CreateDefaultSettingsPage(string baseUrl)
|
||||
{
|
||||
var defaultUserSettings = new UserManagementSettings
|
||||
{
|
||||
RequestMovies = true,
|
||||
RequestTvShows = true,
|
||||
ReportIssues = true,
|
||||
|
||||
};
|
||||
var defaultSettings = new PlexRequestSettings
|
||||
{
|
||||
RequireTvShowApproval = true,
|
||||
RequireMovieApproval = true,
|
||||
SearchForMovies = true,
|
||||
SearchForTvShows = true,
|
||||
BaseUrl = baseUrl ?? string.Empty,
|
||||
CollectAnalyticData = true,
|
||||
};
|
||||
var s = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
||||
var ctor = new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider());
|
||||
var s = new SettingsServiceV2<PlexRequestSettings>(ctor);
|
||||
s.SaveSettings(defaultSettings);
|
||||
|
||||
var userSettings = new SettingsServiceV2<UserManagementSettings>(ctor);
|
||||
userSettings.SaveSettings(defaultUserSettings);
|
||||
|
||||
|
||||
var cron = (Quartz.Impl.Triggers.CronTriggerImpl)CronScheduleBuilder.WeeklyOnDayAndHourAndMinute(DayOfWeek.Friday, 7, 0).Build();
|
||||
var scheduled = new ScheduledJobsSettings
|
||||
|
@ -148,7 +118,6 @@ namespace PlexRequests.Core
|
|||
Task.Run(() => { CacheSonarrQualityProfiles(mc); });
|
||||
Task.Run(() => { CacheCouchPotatoQualityProfiles(mc); });
|
||||
// we don't need to cache sickrage profiles, those are static
|
||||
// TODO: cache headphones profiles?
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -156,12 +125,12 @@ namespace PlexRequests.Core
|
|||
}
|
||||
}
|
||||
|
||||
private void CacheSonarrQualityProfiles(MemoryCacheProvider cacheProvider)
|
||||
private void CacheSonarrQualityProfiles(ICacheProvider cacheProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Info("Executing GetSettings call to Sonarr for quality profiles");
|
||||
var sonarrSettingsService = new SettingsServiceV2<SonarrSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
||||
var sonarrSettingsService = new SettingsServiceV2<SonarrSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), cacheProvider));
|
||||
var sonarrSettings = sonarrSettingsService.GetSettings();
|
||||
if (sonarrSettings.Enabled)
|
||||
{
|
||||
|
@ -178,12 +147,12 @@ namespace PlexRequests.Core
|
|||
}
|
||||
}
|
||||
|
||||
private void CacheCouchPotatoQualityProfiles(MemoryCacheProvider cacheProvider)
|
||||
private void CacheCouchPotatoQualityProfiles(ICacheProvider cacheProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Info("Executing GetSettings call to CouchPotato for quality profiles");
|
||||
var cpSettingsService = new SettingsServiceV2<CouchPotatoSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
||||
var cpSettingsService = new SettingsServiceV2<CouchPotatoSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), cacheProvider));
|
||||
var cpSettings = cpSettingsService.GetSettings();
|
||||
if (cpSettings.Enabled)
|
||||
{
|
||||
|
@ -199,102 +168,5 @@ namespace PlexRequests.Core
|
|||
Log.Error(ex, "Failed to cache CouchPotato quality profiles!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Migrates to version 1.9.
|
||||
/// Move the Plex auth token to the new field.
|
||||
/// Reconfigure the log level
|
||||
/// Set the wizard flag to true if we already have settings
|
||||
/// </summary>
|
||||
public void MigrateToVersion1900()
|
||||
{
|
||||
// Need to change the Plex Token location
|
||||
var authSettings = new SettingsServiceV2<AuthenticationSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var auth = authSettings.GetSettings();
|
||||
var plexSettings = new SettingsServiceV2<PlexSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
|
||||
if (auth != null)
|
||||
{
|
||||
//If we have an authToken we do not need to go through the setup
|
||||
if (!string.IsNullOrEmpty(auth.OldPlexAuthToken))
|
||||
{
|
||||
var prServuce = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var settings = prServuce.GetSettings();
|
||||
settings.Wizard = true;
|
||||
prServuce.SaveSettings(settings);
|
||||
}
|
||||
|
||||
// Clear out the old token and save it to the new field
|
||||
var currentSettings = plexSettings.GetSettings();
|
||||
if (!string.IsNullOrEmpty(auth.OldPlexAuthToken))
|
||||
{
|
||||
currentSettings.PlexAuthToken = auth.OldPlexAuthToken;
|
||||
plexSettings.SaveSettings(currentSettings);
|
||||
|
||||
// Clear out the old value
|
||||
auth.OldPlexAuthToken = string.Empty;
|
||||
authSettings.SaveSettings(auth);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Set the log level
|
||||
try
|
||||
{
|
||||
var settingsService = new SettingsServiceV2<LogSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var logSettings = settingsService.GetSettings();
|
||||
logSettings.Level = LogLevel.Error.Ordinal;
|
||||
settingsService.SaveSettings(logSettings);
|
||||
|
||||
LoggingHelper.ReconfigureLogLevel(LogLevel.FromOrdinal(logSettings.Level));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
|
||||
|
||||
// Enable analytics;
|
||||
try
|
||||
{
|
||||
|
||||
var prSettings = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var settings = prSettings.GetSettings();
|
||||
settings.CollectAnalyticData = true;
|
||||
var updated = prSettings.SaveSettings(settings);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrates to version1910.
|
||||
/// </summary>
|
||||
public void MigrateToVersion1910()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the new machine Identifier
|
||||
var settings = new SettingsServiceV2<PlexSettings>(new SettingsJsonRepository(Db, new MemoryCacheProvider()));
|
||||
var plex = settings.GetSettings();
|
||||
if (!string.IsNullOrEmpty(plex.PlexAuthToken))
|
||||
{
|
||||
var api = new PlexApi(new ApiRequest());
|
||||
var server = api.GetServer(plex.PlexAuthToken); // Get the server info
|
||||
plex.MachineIdentifier = server.Server.FirstOrDefault(x => x.AccessToken == plex.PlexAuthToken)?.MachineIdentifier;
|
||||
|
||||
settings.SaveSettings(plex); // Save the new settings
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StatusChecker.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Octokit;
|
||||
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Helpers;
|
||||
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public class StatusChecker
|
||||
{
|
||||
public StatusChecker()
|
||||
{
|
||||
Git = new GitHubClient(new ProductHeaderValue("PlexRequests-StatusChecker"));
|
||||
}
|
||||
private IGitHubClient Git { get; }
|
||||
private const string Owner = "tidusjar";
|
||||
private const string RepoName = "PlexRequests.Net";
|
||||
|
||||
public async Task<Release> GetLatestRelease()
|
||||
{
|
||||
var releases = await Git.Repository.Release.GetAll(Owner, RepoName);
|
||||
return releases.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<StatusModel> GetStatus()
|
||||
{
|
||||
var assemblyVersion = AssemblyHelper.GetProductVersion();
|
||||
var model = new StatusModel
|
||||
{
|
||||
Version = assemblyVersion,
|
||||
};
|
||||
|
||||
var latestRelease = await GetLatestRelease();
|
||||
if (latestRelease == null)
|
||||
{
|
||||
return new StatusModel { Version = "Unknown" };
|
||||
}
|
||||
var latestVersionArray = latestRelease.Name.Split(new[] { 'v' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var latestVersion = latestVersionArray.Length > 1 ? latestVersionArray[1] : string.Empty;
|
||||
|
||||
if (!latestVersion.Equals(assemblyVersion, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
model.UpdateAvailable = true;
|
||||
model.UpdateUri = latestRelease.HtmlUrl;
|
||||
}
|
||||
|
||||
model.ReleaseNotes = latestRelease.Body;
|
||||
model.DownloadUri = latestRelease.Assets[0].BrowserDownloadUrl;
|
||||
model.ReleaseTitle = latestRelease.Name;
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
35
PlexRequests.Core/StatusChecker/AppveyorArtifactResult.cs
Normal file
35
PlexRequests.Core/StatusChecker/AppveyorArtifactResult.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: AppveyorArtifactResult.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
namespace PlexRequests.Core.StatusChecker
|
||||
{
|
||||
public class AppveyorArtifactResult
|
||||
{
|
||||
public string fileName { get; set; }
|
||||
public string type { get; set; }
|
||||
public int size { get; set; }
|
||||
}
|
||||
}
|
138
PlexRequests.Core/StatusChecker/AppveyorBranchResult.cs
Normal file
138
PlexRequests.Core/StatusChecker/AppveyorBranchResult.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: AppveyorBranchResult.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PlexRequests.Core.StatusChecker
|
||||
{
|
||||
public class NuGetFeed
|
||||
{
|
||||
public string id { get; set; }
|
||||
public string name { get; set; }
|
||||
public bool publishingEnabled { get; set; }
|
||||
public string created { get; set; }
|
||||
}
|
||||
|
||||
public class AccessRightDefinition
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string description { get; set; }
|
||||
}
|
||||
|
||||
public class AccessRight
|
||||
{
|
||||
public string name { get; set; }
|
||||
public bool allowed { get; set; }
|
||||
}
|
||||
|
||||
public class RoleAce
|
||||
{
|
||||
public int roleId { get; set; }
|
||||
public string name { get; set; }
|
||||
public bool isAdmin { get; set; }
|
||||
public List<AccessRight> accessRights { get; set; }
|
||||
}
|
||||
|
||||
public class SecurityDescriptor
|
||||
{
|
||||
public List<AccessRightDefinition> accessRightDefinitions { get; set; }
|
||||
public List<RoleAce> roleAces { get; set; }
|
||||
}
|
||||
|
||||
public class Project
|
||||
{
|
||||
public int projectId { get; set; }
|
||||
public int accountId { get; set; }
|
||||
public string accountName { get; set; }
|
||||
public List<object> builds { get; set; }
|
||||
public string name { get; set; }
|
||||
public string slug { get; set; }
|
||||
public string repositoryType { get; set; }
|
||||
public string repositoryScm { get; set; }
|
||||
public string repositoryName { get; set; }
|
||||
public string repositoryBranch { get; set; }
|
||||
public bool isPrivate { get; set; }
|
||||
public bool skipBranchesWithoutAppveyorYml { get; set; }
|
||||
public bool enableSecureVariablesInPullRequests { get; set; }
|
||||
public bool enableSecureVariablesInPullRequestsFromSameRepo { get; set; }
|
||||
public bool enableDeploymentInPullRequests { get; set; }
|
||||
public bool rollingBuilds { get; set; }
|
||||
public bool alwaysBuildClosedPullRequests { get; set; }
|
||||
public string tags { get; set; }
|
||||
public NuGetFeed nuGetFeed { get; set; }
|
||||
public SecurityDescriptor securityDescriptor { get; set; }
|
||||
public string created { get; set; }
|
||||
public string updated { get; set; }
|
||||
}
|
||||
|
||||
public class Job
|
||||
{
|
||||
public string jobId { get; set; }
|
||||
public string name { get; set; }
|
||||
public bool allowFailure { get; set; }
|
||||
public int messagesCount { get; set; }
|
||||
public int compilationMessagesCount { get; set; }
|
||||
public int compilationErrorsCount { get; set; }
|
||||
public int compilationWarningsCount { get; set; }
|
||||
public int testsCount { get; set; }
|
||||
public int passedTestsCount { get; set; }
|
||||
public int failedTestsCount { get; set; }
|
||||
public int artifactsCount { get; set; }
|
||||
public string status { get; set; }
|
||||
public string started { get; set; }
|
||||
public string finished { get; set; }
|
||||
public string created { get; set; }
|
||||
public string updated { get; set; }
|
||||
}
|
||||
|
||||
public class Build
|
||||
{
|
||||
public int buildId { get; set; }
|
||||
public List<Job> jobs { get; set; }
|
||||
public int buildNumber { get; set; }
|
||||
public string version { get; set; }
|
||||
public string message { get; set; }
|
||||
public string branch { get; set; }
|
||||
public bool isTag { get; set; }
|
||||
public string commitId { get; set; }
|
||||
public string authorName { get; set; }
|
||||
public string committerName { get; set; }
|
||||
public string committed { get; set; }
|
||||
public List<object> messages { get; set; }
|
||||
public string status { get; set; }
|
||||
public string started { get; set; }
|
||||
public string finished { get; set; }
|
||||
public string created { get; set; }
|
||||
public string updated { get; set; }
|
||||
}
|
||||
|
||||
public class AppveyorBranchResult
|
||||
{
|
||||
public Project project { get; set; }
|
||||
public Build build { get; set; }
|
||||
}
|
||||
}
|
183
PlexRequests.Core/StatusChecker/StatusChecker.cs
Normal file
183
PlexRequests.Core/StatusChecker/StatusChecker.cs
Normal file
|
@ -0,0 +1,183 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StatusChecker.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Octokit;
|
||||
using PlexRequests.Api;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using RestSharp;
|
||||
|
||||
namespace PlexRequests.Core.StatusChecker
|
||||
{
|
||||
public class StatusChecker : IStatusChecker
|
||||
{
|
||||
public StatusChecker(ISettingsService<SystemSettings> ss)
|
||||
{
|
||||
SystemSettings = ss;
|
||||
Git = new GitHubClient(new ProductHeaderValue("PlexRequests-StatusChecker"));
|
||||
}
|
||||
|
||||
private ISettingsService<SystemSettings> SystemSettings { get; }
|
||||
|
||||
private IGitHubClient Git { get; }
|
||||
private const string Owner = "tidusjar";
|
||||
private const string RepoName = "PlexRequests.Net";
|
||||
private const string AppveyorApiUrl = "https://ci.appveyor.com/api";
|
||||
|
||||
private const string Api =
|
||||
"48Ku58C0794nBrXra8IxWav+dc6NqgkRw+PZB3/bQwbt/D0IrnJQkgtjzo0bd6nkooLMKsC8M+Ab7jyBO+ROjY14VRuxffpDopX9r0iG/fjBl6mZVvqkm+VTDNstDtzp";
|
||||
|
||||
public async Task<StatusModel> GetStatus()
|
||||
{
|
||||
var settings = await SystemSettings.GetSettingsAsync();
|
||||
var stable = settings.Branch == Branches.Stable;
|
||||
|
||||
if (!stable)
|
||||
{
|
||||
// Early Access Preview Releases
|
||||
return GetAppveyorRelease(settings.Branch);
|
||||
}
|
||||
|
||||
// Stable releases
|
||||
return await GetLatestGithubRelease();
|
||||
}
|
||||
|
||||
private async Task<StatusModel> GetLatestGithubRelease()
|
||||
{
|
||||
var assemblyVersion = AssemblyHelper.GetProductVersion();
|
||||
var model = new StatusModel
|
||||
{
|
||||
CurrentVersion = assemblyVersion,
|
||||
};
|
||||
|
||||
var releases = await Git.Repository.Release.GetAll(Owner, RepoName);
|
||||
var latestRelease = releases.FirstOrDefault();
|
||||
|
||||
if (latestRelease == null)
|
||||
{
|
||||
return new StatusModel { NewVersion = "Unknown" };
|
||||
}
|
||||
var latestVersionArray = latestRelease.Name.Split(new[] { 'v' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var latestVersion = latestVersionArray.Length > 1 ? latestVersionArray[1] : string.Empty;
|
||||
|
||||
if (!latestVersion.Equals(assemblyVersion, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
model.UpdateAvailable = true;
|
||||
model.UpdateUri = latestRelease.HtmlUrl;
|
||||
model.NewVersion = latestVersion;
|
||||
}
|
||||
|
||||
model.ReleaseNotes = latestRelease.Body;
|
||||
model.DownloadUri = latestRelease.Assets[0].BrowserDownloadUrl;
|
||||
model.ReleaseTitle = latestRelease.Name;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private StatusModel GetAppveyorRelease(Branches branch)
|
||||
{
|
||||
var request = new ApiRequest();
|
||||
|
||||
// Get latest EAP Build
|
||||
var eapBranchRequest = new RestRequest
|
||||
{
|
||||
Method = Method.GET
|
||||
};
|
||||
|
||||
|
||||
switch (branch)
|
||||
{
|
||||
case Branches.Dev:
|
||||
eapBranchRequest.Resource = "/projects/tidusjar/requestplex/branch/dev";
|
||||
break;
|
||||
case Branches.EarlyAccessPreview:
|
||||
eapBranchRequest.Resource = "/projects/tidusjar/requestplex/branch/EAP";
|
||||
break;
|
||||
}
|
||||
|
||||
var api = StringCipher.Decrypt(Api,"Appveyor");
|
||||
eapBranchRequest.AddHeader("Authorization", $"Bearer {api}");
|
||||
eapBranchRequest.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var branchResult = request.ExecuteJson<AppveyorBranchResult>(eapBranchRequest, new Uri(AppveyorApiUrl));
|
||||
|
||||
var jobId = branchResult.build.jobs.FirstOrDefault()?.jobId ?? string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(jobId))
|
||||
{
|
||||
return new StatusModel {UpdateAvailable = false};
|
||||
}
|
||||
|
||||
// Get artifacts from the EAP Build
|
||||
var eapAtrifactRequest = new RestRequest
|
||||
{
|
||||
Resource = $"/buildjobs/{jobId}/artifacts",
|
||||
Method = Method.GET
|
||||
};
|
||||
eapAtrifactRequest.AddHeader("Authorization", $"Bearer {api}");
|
||||
eapAtrifactRequest.AddHeader("Content-Type", "application/json");
|
||||
|
||||
var artifactResults = request.ExecuteJson<List<AppveyorArtifactResult>>(eapAtrifactRequest, new Uri(AppveyorApiUrl));
|
||||
|
||||
var artifactResult = artifactResults.FirstOrDefault();
|
||||
|
||||
if (artifactResult == null)
|
||||
{
|
||||
return new StatusModel
|
||||
{
|
||||
UpdateAvailable = false
|
||||
};
|
||||
}
|
||||
var downloadLink = $"{AppveyorApiUrl}/buildjobs/{jobId}/artifacts/{artifactResult.fileName}";
|
||||
|
||||
var branchDisplay = EnumHelper<Branches>.GetDisplayValue(branch);
|
||||
var fileversion = AssemblyHelper.GetFileVersion();
|
||||
|
||||
var model = new StatusModel
|
||||
{
|
||||
DownloadUri = downloadLink,
|
||||
ReleaseNotes = $"{branchDisplay} (See recent commits for details)",
|
||||
ReleaseTitle = $"Plex Requests {branchDisplay}",
|
||||
NewVersion = branchResult.build.version,
|
||||
UpdateUri = downloadLink,
|
||||
CurrentVersion = fileversion
|
||||
};
|
||||
|
||||
if (!fileversion.Equals(branchResult.build.version, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
model.UpdateAvailable = true;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,18 +24,19 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.SickRage;
|
||||
using PlexRequests.Api.Models.Sonarr;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Store;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PlexRequests.UI.Helpers
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public class TvSender
|
||||
{
|
|
@ -36,7 +36,7 @@ using PlexRequests.Api.Models.Sonarr;
|
|||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Store;
|
||||
|
||||
namespace PlexRequests.UI.Helpers
|
||||
namespace PlexRequests.Core
|
||||
{
|
||||
public class TvSenderOld
|
||||
{
|
|
@ -36,6 +36,7 @@ using Nancy.Security;
|
|||
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
|
@ -60,7 +61,6 @@ namespace PlexRequests.Core
|
|||
return new UserIdentity
|
||||
{
|
||||
UserName = user.UserName,
|
||||
Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace PlexRequests.Core
|
|||
return users.Any();
|
||||
}
|
||||
|
||||
public Guid? CreateUser(string username, string password, string[] claims = default(string[]), UserProperties properties = null)
|
||||
public Guid? CreateUser(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
var salt = PasswordHasher.GenerateSalt();
|
||||
|
||||
|
@ -109,7 +109,7 @@ namespace PlexRequests.Core
|
|||
UserGuid = Guid.NewGuid().ToString(),
|
||||
Salt = salt,
|
||||
Hash = PasswordHasher.ComputeHash(password, salt),
|
||||
Claims = ByteConverterHelper.ReturnBytes(claims),
|
||||
Claims = new byte[] {0},
|
||||
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties()),
|
||||
};
|
||||
Repo.Insert(userModel);
|
||||
|
@ -118,32 +118,33 @@ namespace PlexRequests.Core
|
|||
return new Guid(userRecord.UserGuid);
|
||||
}
|
||||
|
||||
public Guid? CreateUser(string username, string password, int permissions, int features, UserProperties properties = null)
|
||||
{
|
||||
var salt = PasswordHasher.GenerateSalt();
|
||||
|
||||
var userModel = new UsersModel
|
||||
{
|
||||
UserName = username,
|
||||
UserGuid = Guid.NewGuid().ToString(),
|
||||
Salt = salt,
|
||||
Hash = PasswordHasher.ComputeHash(password, salt),
|
||||
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties()),
|
||||
Permissions = permissions,
|
||||
Features = features,
|
||||
Claims = new byte[] {0}
|
||||
};
|
||||
Repo.Insert(userModel);
|
||||
var userRecord = Repo.Get(userModel.UserGuid);
|
||||
|
||||
return new Guid(userRecord.UserGuid);
|
||||
}
|
||||
|
||||
public void DeleteUser(string userId)
|
||||
{
|
||||
var user = Repo.Get(userId);
|
||||
Repo.Delete(user);
|
||||
}
|
||||
|
||||
public Guid? CreateAdmin(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.RegularUser, UserClaims.PowerUser, UserClaims.Admin }, properties);
|
||||
}
|
||||
|
||||
public Guid? CreatePowerUser(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.RegularUser, UserClaims.PowerUser }, properties);
|
||||
}
|
||||
|
||||
public Guid? CreateRegularUser(string username, string password, UserProperties properties = null)
|
||||
{
|
||||
return CreateUser(username, password, new[] { UserClaims.RegularUser }, properties);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllClaims()
|
||||
{
|
||||
var properties = typeof(UserClaims).GetConstantsValues<string>();
|
||||
return properties;
|
||||
}
|
||||
|
||||
public bool UpdatePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
|
@ -186,8 +187,8 @@ namespace PlexRequests.Core
|
|||
|
||||
public interface ICustomUserMapper
|
||||
{
|
||||
Guid? CreateUser(string username, string password, string[] claims, UserProperties props);
|
||||
IEnumerable<string> GetAllClaims();
|
||||
Guid? CreateUser(string username, string password, int permissions, int features,
|
||||
UserProperties properties = null);
|
||||
IEnumerable<UsersModel> GetUsers();
|
||||
Task<IEnumerable<UsersModel>> GetUsersAsync();
|
||||
UsersModel GetUser(Guid userId);
|
||||
|
@ -195,9 +196,6 @@ namespace PlexRequests.Core
|
|||
bool DoUsersExist();
|
||||
Guid? ValidateUser(string username, string password);
|
||||
bool UpdatePassword(string username, string oldPassword, string newPassword);
|
||||
Guid? CreateAdmin(string username, string password, UserProperties properties = null);
|
||||
Guid? CreatePowerUser(string username, string password, UserProperties properties = null);
|
||||
Guid? CreateRegularUser(string username, string password, UserProperties properties = null);
|
||||
void DeleteUser(string userId);
|
||||
}
|
||||
}
|
||||
|
|
12
PlexRequests.Core/Users/IUserHelper.cs
Normal file
12
PlexRequests.Core/Users/IUserHelper.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
|
||||
namespace PlexRequests.Core.Users
|
||||
{
|
||||
public interface IUserHelper
|
||||
{
|
||||
IEnumerable<UserHelperModel> GetUsers();
|
||||
IEnumerable<UserHelperModel> GetUsersWithPermission(Permissions permission);
|
||||
IEnumerable<UserHelperModel> GetUsersWithFeature(Features feature);
|
||||
}
|
||||
}
|
159
PlexRequests.Core/Users/UserHelper.cs
Normal file
159
PlexRequests.Core/Users/UserHelper.cs
Normal file
|
@ -0,0 +1,159 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserHelper.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
namespace PlexRequests.Core.Users
|
||||
{
|
||||
public class UserHelper : IUserHelper
|
||||
{
|
||||
public UserHelper(IUserRepository userRepository, IPlexUserRepository plexUsers, ISecurityExtensions security)
|
||||
{
|
||||
LocalUserRepository = userRepository;
|
||||
PlexUserRepository = plexUsers;
|
||||
Security = security;
|
||||
}
|
||||
|
||||
private IUserRepository LocalUserRepository { get; }
|
||||
private IPlexUserRepository PlexUserRepository { get; }
|
||||
private ISecurityExtensions Security { get; }
|
||||
|
||||
|
||||
public IEnumerable<UserHelperModel> GetUsers()
|
||||
{
|
||||
var model = new List<UserHelperModel>();
|
||||
|
||||
var localUsers = LocalUserRepository.GetAll();
|
||||
var plexUsers = PlexUserRepository.GetAll();
|
||||
|
||||
foreach (var user in localUsers)
|
||||
{
|
||||
var props = ByteConverterHelper.ReturnObject<UserProperties>(user.UserProperties);
|
||||
model.Add(new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.UserName,
|
||||
UserAlias = props.UserAlias,
|
||||
EmailAddress = props.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions
|
||||
});
|
||||
}
|
||||
|
||||
model.AddRange(plexUsers.Select(user => new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.Username,
|
||||
UserAlias = user.UserAlias,
|
||||
EmailAddress = user.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions
|
||||
}));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public IEnumerable<UserHelperModel> GetUsersWithPermission(Permissions permission)
|
||||
{
|
||||
var model = new List<UserHelperModel>();
|
||||
|
||||
var localUsers = LocalUserRepository.GetAll().ToList();
|
||||
var plexUsers = PlexUserRepository.GetAll().ToList();
|
||||
|
||||
var filteredLocal = localUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission));
|
||||
var filteredPlex = plexUsers.Where(x => ((Permissions)x.Permissions).HasFlag(permission));
|
||||
|
||||
|
||||
foreach (var user in filteredLocal)
|
||||
{
|
||||
var props = ByteConverterHelper.ReturnObject<UserProperties>(user.UserProperties);
|
||||
model.Add(new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.UserName,
|
||||
UserAlias = props.UserAlias,
|
||||
EmailAddress = props.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions,
|
||||
Features = (Features)user.Features
|
||||
});
|
||||
}
|
||||
|
||||
model.AddRange(filteredPlex.Select(user => new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.Username,
|
||||
UserAlias = user.UserAlias,
|
||||
EmailAddress = user.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions,
|
||||
Features = (Features)user.Features
|
||||
}));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public IEnumerable<UserHelperModel> GetUsersWithFeature(Features features)
|
||||
{
|
||||
var model = new List<UserHelperModel>();
|
||||
|
||||
var localUsers = LocalUserRepository.GetAll().ToList();
|
||||
var plexUsers = PlexUserRepository.GetAll().ToList();
|
||||
|
||||
var filteredLocal = localUsers.Where(x => ((Features)x.Features).HasFlag(features));
|
||||
var filteredPlex = plexUsers.Where(x => ((Features)x.Features).HasFlag(features));
|
||||
|
||||
|
||||
foreach (var user in filteredLocal)
|
||||
{
|
||||
var props = ByteConverterHelper.ReturnObject<UserProperties>(user.UserProperties);
|
||||
model.Add(new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.UserName,
|
||||
UserAlias = props.UserAlias,
|
||||
EmailAddress = props.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions,
|
||||
Features = (Features)user.Features
|
||||
});
|
||||
}
|
||||
|
||||
model.AddRange(filteredPlex.Select(user => new UserHelperModel
|
||||
{
|
||||
Type = UserType.LocalUser,
|
||||
Username = user.Username,
|
||||
UserAlias = user.UserAlias,
|
||||
EmailAddress = user.EmailAddress,
|
||||
Permissions = (Permissions)user.Permissions,
|
||||
Features = (Features)user.Features
|
||||
}));
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
42
PlexRequests.Core/Users/UserHelperModel.cs
Normal file
42
PlexRequests.Core/Users/UserHelperModel.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserHelperModel.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
|
||||
namespace PlexRequests.Core.Users
|
||||
{
|
||||
public class UserHelperModel
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string UserAlias { get; set; }
|
||||
public Permissions Permissions { get; set; }
|
||||
public Features Features { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public UserType Type { get; set; }
|
||||
}
|
||||
}
|
70
PlexRequests.Core/Users/UserManagementHelper.cs
Normal file
70
PlexRequests.Core/Users/UserManagementHelper.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
|
||||
namespace PlexRequests.Core.Users
|
||||
{
|
||||
public static class UserManagementHelper
|
||||
{
|
||||
|
||||
public static int GetPermissions(UserManagementSettings settings)
|
||||
{
|
||||
var permission = 0;
|
||||
|
||||
if (settings.AutoApproveMovies)
|
||||
{
|
||||
permission += (int)Permissions.AutoApproveMovie;
|
||||
}
|
||||
if (settings.AutoApproveMusic)
|
||||
{
|
||||
permission += (int)Permissions.AutoApproveAlbum;
|
||||
}
|
||||
if (settings.AutoApproveTvShows)
|
||||
{
|
||||
permission += (int)Permissions.AutoApproveTv;
|
||||
}
|
||||
if (settings.RequestMovies)
|
||||
{
|
||||
permission += (int)Permissions.RequestMovie;
|
||||
}
|
||||
if (settings.RequestMusic)
|
||||
{
|
||||
permission += (int)Permissions.RequestMusic;
|
||||
}
|
||||
if (settings.RequestTvShows)
|
||||
{
|
||||
permission += (int)Permissions.RequestTvShow;
|
||||
}
|
||||
if (settings.ReportIssues)
|
||||
{
|
||||
permission += (int)Permissions.ReportIssue;
|
||||
}
|
||||
if (settings.UsersCanViewOnlyOwnRequests)
|
||||
{
|
||||
permission += (int)Permissions.UsersCanViewOnlyOwnRequests;
|
||||
}
|
||||
if (settings.UsersCanViewOnlyOwnIssues)
|
||||
{
|
||||
permission += (int)Permissions.UsersCanViewOnlyOwnIssues;
|
||||
}
|
||||
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static int GetFeatures(UserManagementSettings settings)
|
||||
{
|
||||
var features = 0;
|
||||
|
||||
if (settings.RecentlyAddedNewsletter)
|
||||
{
|
||||
features += (int)Features.Newsletter;
|
||||
}
|
||||
if (settings.RecentlyAddedNotification)
|
||||
{
|
||||
features += (int)Features.RequestAddedNotification;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,14 @@
|
|||
<packages>
|
||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Common.Logging.Core" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net45" />
|
||||
<package id="Nancy.Linker" version="0.3.1" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||
<package id="Octokit" version="0.19.0" targetFramework="net45" />
|
||||
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||
<package id="valueinjecter" version="3.1.1.2" targetFramework="net45" />
|
||||
</packages>
|
|
@ -54,7 +54,7 @@ namespace PlexRequests.Helpers.Analytics
|
|||
Track(HitType.@event, username, cat, act, label, clientId, value);
|
||||
}
|
||||
|
||||
public async Task TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null)
|
||||
public async void TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null)
|
||||
{
|
||||
var cat = category.ToString();
|
||||
var act = action.ToString();
|
||||
|
@ -146,7 +146,7 @@ namespace PlexRequests.Helpers.Analytics
|
|||
request.Method = RequestMethod;
|
||||
// set the Content-Length header to the correct value
|
||||
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
||||
|
||||
#if !DEBUG
|
||||
// write the request body to the request
|
||||
using (var writer = new StreamWriter(request.GetRequestStream()))
|
||||
{
|
||||
|
@ -165,7 +165,10 @@ namespace PlexRequests.Helpers.Analytics
|
|||
{
|
||||
Log.Error(ex, "Analytics tracking failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
private async Task SendRequestAsync(string postDataString)
|
||||
{
|
||||
var request = (HttpWebRequest)WebRequest.Create(AnalyticsUri);
|
||||
|
@ -173,6 +176,7 @@ namespace PlexRequests.Helpers.Analytics
|
|||
// set the Content-Length header to the correct value
|
||||
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
||||
|
||||
#if !DEBUG
|
||||
// write the request body to the request
|
||||
using (var writer = new StreamWriter(await request.GetRequestStreamAsync()))
|
||||
{
|
||||
|
@ -191,7 +195,9 @@ namespace PlexRequests.Helpers.Analytics
|
|||
{
|
||||
Log.Error(ex, "Analytics tracking failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
private Dictionary<string, string> BuildRequestData(HitType type, string username, string category, string action, string clientId, string label, int? value, string exceptionDescription, int? fatal)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace PlexRequests.Helpers.Analytics
|
|||
Issues,
|
||||
UserLogin,
|
||||
Services,
|
||||
Navbar
|
||||
Navbar,
|
||||
UserManagement
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ namespace PlexRequests.Helpers.Analytics
|
|||
/// <param name="clientId">The client identifier.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns></returns>
|
||||
Task TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null);
|
||||
void TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null);
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the page view.
|
||||
|
|
|
@ -45,5 +45,13 @@ namespace PlexRequests.Helpers
|
|||
var retVersion = fvi.ProductVersion;
|
||||
return retVersion;
|
||||
}
|
||||
|
||||
public static string GetFileVersion()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
var retVersion = fvi.FileVersion;
|
||||
return retVersion;
|
||||
}
|
||||
}
|
||||
}
|
54
PlexRequests.Helpers/EnumExtensions.cs
Normal file
54
PlexRequests.Helpers/EnumExtensions.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: EnumExtensions.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlexRequests.Helpers
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static IEnumerable<Enum> GetUniqueFlags(this Enum flags)
|
||||
{
|
||||
ulong flag = 1;
|
||||
foreach (var value in Enum.GetValues(flags.GetType()).Cast<Enum>())
|
||||
{
|
||||
var bits = Convert.ToUInt64(value);
|
||||
while (flag < bits)
|
||||
{
|
||||
flag <<= 1;
|
||||
}
|
||||
|
||||
if (flag == bits && flags.HasFlag(value))
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
PlexRequests.Helpers/EnumHelper.cs
Normal file
117
PlexRequests.Helpers/EnumHelper.cs
Normal file
|
@ -0,0 +1,117 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: EnumHelper.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace PlexRequests.Helpers
|
||||
{
|
||||
public static class EnumHelper<T>
|
||||
{
|
||||
public static IList<T> GetValues(Enum value)
|
||||
{
|
||||
return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => (T) Enum.Parse(value.GetType(), fi.Name, false)).ToList();
|
||||
}
|
||||
|
||||
public static T Parse(string value)
|
||||
{
|
||||
return (T)Enum.Parse(typeof(T), value, true);
|
||||
}
|
||||
|
||||
public static IList<string> GetNames(Enum value)
|
||||
{
|
||||
return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
|
||||
}
|
||||
|
||||
public static IList<string> GetDisplayValues(Enum value)
|
||||
{
|
||||
return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
|
||||
}
|
||||
|
||||
private static string LookupResource(Type resourceManagerProvider, string resourceKey)
|
||||
{
|
||||
foreach (var staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
|
||||
{
|
||||
System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
|
||||
return resourceManager.GetString(resourceKey);
|
||||
}
|
||||
}
|
||||
|
||||
return resourceKey; // Fallback with the key name
|
||||
}
|
||||
|
||||
public static string GetDisplayValue(T value)
|
||||
{
|
||||
var fieldInfo = value.GetType().GetField(value.ToString());
|
||||
|
||||
var descriptionAttributes = fieldInfo.GetCustomAttributes(
|
||||
typeof(DisplayAttribute), false) as DisplayAttribute[];
|
||||
|
||||
if (descriptionAttributes[0].ResourceType != null)
|
||||
return LookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);
|
||||
|
||||
if (descriptionAttributes == null) return string.Empty;
|
||||
return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
|
||||
}
|
||||
|
||||
public static T GetValueFromName(string name)
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (!type.IsEnum) throw new InvalidOperationException();
|
||||
|
||||
foreach (var field in type.GetFields())
|
||||
{
|
||||
var attribute = Attribute.GetCustomAttribute(field,
|
||||
typeof(DisplayAttribute)) as DisplayAttribute;
|
||||
if (attribute != null)
|
||||
{
|
||||
if (attribute.Name == name)
|
||||
{
|
||||
return (T)field.GetValue(null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (field.Name == name)
|
||||
return (T)field.GetValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(name));
|
||||
}
|
||||
|
||||
public static int All()
|
||||
{
|
||||
return Enum.GetValues(typeof(T)).Cast<int>().Sum();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: AuthenticationSettingsTests.cs
|
||||
// File: Features.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -26,21 +26,17 @@
|
|||
#endregion
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PlexRequests.Core.Tests
|
||||
namespace PlexRequests.Helpers.Permissions
|
||||
{
|
||||
[TestFixture]
|
||||
public class StatusCheckerTests
|
||||
[Flags]
|
||||
public enum Features
|
||||
{
|
||||
[Test]
|
||||
[Ignore("API Limit")]
|
||||
public void CheckStatusTest()
|
||||
{
|
||||
var checker = new StatusChecker();
|
||||
var status = checker.GetStatus();
|
||||
[Display(Name = "Newsletter")]
|
||||
Newsletter = 1,
|
||||
[Display(Name = "Request Added Notification")]
|
||||
RequestAddedNotification = 2,
|
||||
|
||||
Assert.That(status, Is.Not.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
PlexRequests.Helpers/Permissions/Permissions.cs
Normal file
78
PlexRequests.Helpers/Permissions/Permissions.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: Permissions.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace PlexRequests.Helpers.Permissions
|
||||
{
|
||||
[Flags]
|
||||
////
|
||||
//// NOTE if any are added, make sure we change the UserManagementHelper
|
||||
////
|
||||
public enum Permissions
|
||||
{
|
||||
[Display(Name = "Access Administration Settings")]
|
||||
Administrator = 1,
|
||||
|
||||
[Display(Name = "Request Movie")]
|
||||
RequestMovie = 2,
|
||||
|
||||
[Display(Name = "Request TV Show")]
|
||||
RequestTvShow = 4,
|
||||
|
||||
[Display(Name = "Request Music")]
|
||||
RequestMusic = 8,
|
||||
|
||||
[Display(Name = "Report Issue")]
|
||||
ReportIssue = 16,
|
||||
|
||||
[Display(Name = "Read Only User")]
|
||||
ReadOnlyUser = 32,
|
||||
|
||||
[Display(Name = "Auto Approve Movie Requests")]
|
||||
AutoApproveMovie = 64,
|
||||
|
||||
[Display(Name = "Auto Approve TV Show Requests")]
|
||||
AutoApproveTv = 128,
|
||||
|
||||
[Display(Name = "Auto Approve Album Requests")]
|
||||
AutoApproveAlbum = 256,
|
||||
|
||||
[Display(Name = "Manage Requests")]
|
||||
ManageRequests = 512,
|
||||
|
||||
[Display(Name = "Users can only view their own requests")]
|
||||
UsersCanViewOnlyOwnRequests = 1024,
|
||||
|
||||
[Display(Name = "Users can only view their own issues")]
|
||||
UsersCanViewOnlyOwnIssues = 2048,
|
||||
|
||||
[Display(Name = "Bypass the request limit")]
|
||||
BypassRequestLimit = 4096
|
||||
}
|
||||
}
|
|
@ -39,6 +39,10 @@
|
|||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Ninject, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Ninject.3.2.0.0\lib\net45-full\Ninject.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -48,6 +52,7 @@
|
|||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Caching" />
|
||||
<Reference Include="System.Web" />
|
||||
|
@ -69,6 +74,7 @@
|
|||
<Compile Include="ByteConverterHelper.cs" />
|
||||
<Compile Include="CookieHelper.cs" />
|
||||
<Compile Include="DateTimeHelper.cs" />
|
||||
<Compile Include="EnumHelper.cs" />
|
||||
<Compile Include="Exceptions\ApiRequestException.cs" />
|
||||
<Compile Include="Exceptions\ApplicationSettingsException.cs" />
|
||||
<Compile Include="HtmlRemover.cs" />
|
||||
|
@ -78,9 +84,13 @@
|
|||
<Compile Include="MemoryCacheProvider.cs" />
|
||||
<Compile Include="ObjectCopier.cs" />
|
||||
<Compile Include="PasswordHasher.cs" />
|
||||
<Compile Include="EnumExtensions.cs" />
|
||||
<Compile Include="Permissions\Features.cs" />
|
||||
<Compile Include="Permissions\Permissions.cs" />
|
||||
<Compile Include="PlexHelper.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SerializerSettings.cs" />
|
||||
<Compile Include="SessionKeys.cs" />
|
||||
<Compile Include="StringCipher.cs" />
|
||||
<Compile Include="StringHasher.cs" />
|
||||
<Compile Include="StringHelper.cs" />
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
namespace PlexRequests.UI.Models
|
||||
namespace PlexRequests.Helpers
|
||||
{
|
||||
public class SessionKeys
|
||||
{
|
|
@ -2,6 +2,7 @@
|
|||
<packages>
|
||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||
<package id="Ninject" version="3.2.0.0" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,284 +1,284 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityCheckerTests.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
//#region Copyright
|
||||
//// /************************************************************************
|
||||
//// Copyright (c) 2016 Jamie Rees
|
||||
//// File: PlexAvailabilityCheckerTests.cs
|
||||
//// Created By: Jamie Rees
|
||||
////
|
||||
//// Permission is hereby granted, free of charge, to any person obtaining
|
||||
//// a copy of this software and associated documentation files (the
|
||||
//// "Software"), to deal in the Software without restriction, including
|
||||
//// without limitation the rights to use, copy, modify, merge, publish,
|
||||
//// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
//// permit persons to whom the Software is furnished to do so, subject to
|
||||
//// the following conditions:
|
||||
////
|
||||
//// The above copyright notice and this permission notice shall be
|
||||
//// included in all copies or substantial portions of the Software.
|
||||
////
|
||||
//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
//// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
//// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
//// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
//// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
//// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
//// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//// ************************************************************************/
|
||||
//#endregion
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Data;
|
||||
//using System.Linq;
|
||||
//using System.Threading.Tasks;
|
||||
|
||||
using Moq;
|
||||
//using Moq;
|
||||
|
||||
using NUnit.Framework;
|
||||
//using NUnit.Framework;
|
||||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Services.Jobs;
|
||||
using PlexRequests.Services.Models;
|
||||
using PlexRequests.Services.Notification;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
//using PlexRequests.Api.Interfaces;
|
||||
//using PlexRequests.Api.Models.Plex;
|
||||
//using PlexRequests.Core;
|
||||
//using PlexRequests.Core.SettingModels;
|
||||
//using PlexRequests.Services.Interfaces;
|
||||
//using PlexRequests.Helpers;
|
||||
//using PlexRequests.Services.Jobs;
|
||||
//using PlexRequests.Services.Models;
|
||||
//using PlexRequests.Services.Notification;
|
||||
//using PlexRequests.Store.Models;
|
||||
//using PlexRequests.Store.Repository;
|
||||
|
||||
using Ploeh.AutoFixture;
|
||||
//using Ploeh.AutoFixture;
|
||||
|
||||
namespace PlexRequests.Services.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class PlexAvailabilityCheckerTests
|
||||
{
|
||||
public IAvailabilityChecker Checker { get; set; }
|
||||
private Fixture F { get; set; } = new Fixture();
|
||||
private Mock<ISettingsService<PlexSettings>> SettingsMock { get; set; }
|
||||
private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
|
||||
private Mock<IRequestService> RequestMock { get; set; }
|
||||
private Mock<IPlexApi> PlexMock { get; set; }
|
||||
private Mock<ICacheProvider> CacheMock { get; set; }
|
||||
private Mock<INotificationService> NotificationMock { get; set; }
|
||||
private Mock<IJobRecord> JobRec { get; set; }
|
||||
private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
||||
private Mock<IRepository<PlexEpisodes>> PlexEpisodes { get; set; }
|
||||
private Mock<INotificationEngine> Engine
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
//namespace PlexRequests.Services.Tests
|
||||
//{
|
||||
// [TestFixture]
|
||||
// public class PlexAvailabilityCheckerTests
|
||||
// {
|
||||
// public IAvailabilityChecker Checker { get; set; }
|
||||
// private Fixture F { get; set; } = new Fixture();
|
||||
// private Mock<ISettingsService<PlexSettings>> SettingsMock { get; set; }
|
||||
// private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
|
||||
// private Mock<IRequestService> RequestMock { get; set; }
|
||||
// private Mock<IPlexApi> PlexMock { get; set; }
|
||||
// private Mock<ICacheProvider> CacheMock { get; set; }
|
||||
// private Mock<INotificationService> NotificationMock { get; set; }
|
||||
// private Mock<IJobRecord> JobRec { get; set; }
|
||||
// private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
||||
// private Mock<IRepository<PlexEpisodes>> PlexEpisodes { get; set; }
|
||||
// private Mock<INotificationEngine> Engine
|
||||
// {
|
||||
// get;
|
||||
// set;
|
||||
// }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
SettingsMock = new Mock<ISettingsService<PlexSettings>>();
|
||||
AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
|
||||
RequestMock = new Mock<IRequestService>();
|
||||
PlexMock = new Mock<IPlexApi>();
|
||||
NotificationMock = new Mock<INotificationService>();
|
||||
CacheMock = new Mock<ICacheProvider>();
|
||||
NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
||||
PlexEpisodes = new Mock<IRepository<PlexEpisodes>>();
|
||||
JobRec = new Mock<IJobRecord>();
|
||||
Engine = new Mock<INotificationEngine>();
|
||||
Checker = new PlexAvailabilityChecker(SettingsMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object, PlexEpisodes.Object, Engine.Object);
|
||||
// [SetUp]
|
||||
// public void Setup()
|
||||
// {
|
||||
// SettingsMock = new Mock<ISettingsService<PlexSettings>>();
|
||||
// AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
|
||||
// RequestMock = new Mock<IRequestService>();
|
||||
// PlexMock = new Mock<IPlexApi>();
|
||||
// NotificationMock = new Mock<INotificationService>();
|
||||
// CacheMock = new Mock<ICacheProvider>();
|
||||
// NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
||||
// PlexEpisodes = new Mock<IRepository<PlexEpisodes>>();
|
||||
// JobRec = new Mock<IJobRecord>();
|
||||
// Engine = new Mock<INotificationEngine>();
|
||||
// Checker = new PlexAvailabilityChecker(SettingsMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object, PlexEpisodes.Object, Engine.Object);
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void InvalidSettings()
|
||||
{
|
||||
Checker.CheckAndUpdateAll();
|
||||
PlexMock.Verify(x => x.GetLibrary(It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()), Times.Never);
|
||||
PlexMock.Verify(x => x.GetAccount(It.IsAny<string>()), Times.Never);
|
||||
PlexMock.Verify(x => x.GetLibrarySections(It.IsAny<string>(), It.IsAny<Uri>()), Times.Never);
|
||||
PlexMock.Verify(x => x.GetStatus(It.IsAny<string>(), It.IsAny<Uri>()), Times.Never);
|
||||
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
|
||||
}
|
||||
// [Test]
|
||||
// public void InvalidSettings()
|
||||
// {
|
||||
// Checker.CheckAndUpdateAll();
|
||||
// PlexMock.Verify(x => x.GetLibrary(It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()), Times.Never);
|
||||
// PlexMock.Verify(x => x.GetAccount(It.IsAny<string>()), Times.Never);
|
||||
// PlexMock.Verify(x => x.GetLibrarySections(It.IsAny<string>(), It.IsAny<Uri>()), Times.Never);
|
||||
// PlexMock.Verify(x => x.GetStatus(It.IsAny<string>(), It.IsAny<Uri>()), Times.Never);
|
||||
// PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(IsMovieAvailableTestData))]
|
||||
public bool IsMovieAvailableTest(string title, string year)
|
||||
{
|
||||
var movies = new List<PlexMovie>
|
||||
{
|
||||
new PlexMovie {Title = title, ProviderId = null, ReleaseYear = year}
|
||||
};
|
||||
var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011");
|
||||
// [TestCaseSource(nameof(IsMovieAvailableTestData))]
|
||||
// public bool IsMovieAvailableTest(string title, string year)
|
||||
// {
|
||||
// var movies = new List<PlexMovie>
|
||||
// {
|
||||
// new PlexMovie {Title = title, ProviderId = null, ReleaseYear = year}
|
||||
// };
|
||||
// var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011");
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsMovieAvailableTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("title", "2011").Returns(true).SetName("IsMovieAvailable True");
|
||||
yield return new TestCaseData("title2", "2011").Returns(false).SetName("IsMovieAvailable False different title");
|
||||
yield return new TestCaseData("title", "2001").Returns(false).SetName("IsMovieAvailable False different year");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsMovieAvailableTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("title", "2011").Returns(true).SetName("IsMovieAvailable True");
|
||||
// yield return new TestCaseData("title2", "2011").Returns(false).SetName("IsMovieAvailable False different title");
|
||||
// yield return new TestCaseData("title", "2001").Returns(false).SetName("IsMovieAvailable False different year");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
[TestCaseSource(nameof(IsMovieAvailableAdvancedTestData))]
|
||||
public bool IsMovieAvailableAdvancedTest(string title, string year, string providerId)
|
||||
{
|
||||
var movies = new List<PlexMovie>
|
||||
{
|
||||
new PlexMovie {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||
};
|
||||
var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||
// [TestCaseSource(nameof(IsMovieAvailableAdvancedTestData))]
|
||||
// public bool IsMovieAvailableAdvancedTest(string title, string year, string providerId)
|
||||
// {
|
||||
// var movies = new List<PlexMovie>
|
||||
// {
|
||||
// new PlexMovie {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||
// };
|
||||
// var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsMovieAvailableAdvancedTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsMovieAvailable True");
|
||||
yield return new TestCaseData("title2", "2011", "99929").Returns(false).SetName("Advanced IsMovieAvailable False different title");
|
||||
yield return new TestCaseData("title", "2001", "99939").Returns(false).SetName("Advanced IsMovieAvailable False different year");
|
||||
yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsMovieAvailable False different providerID");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsMovieAvailableAdvancedTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsMovieAvailable True");
|
||||
// yield return new TestCaseData("title2", "2011", "99929").Returns(false).SetName("Advanced IsMovieAvailable False different title");
|
||||
// yield return new TestCaseData("title", "2001", "99939").Returns(false).SetName("Advanced IsMovieAvailable False different year");
|
||||
// yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsMovieAvailable False different providerID");
|
||||
// }
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(IsTvAvailableTestData))]
|
||||
public bool IsTvAvailableTest(string title, string year)
|
||||
{
|
||||
var tv = new List<PlexTvShow>
|
||||
{
|
||||
new PlexTvShow {Title = title, ProviderId = null, ReleaseYear = year}
|
||||
};
|
||||
var result = Checker.IsTvShowAvailable(tv.ToArray(), "title", "2011");
|
||||
// [TestCaseSource(nameof(IsTvAvailableTestData))]
|
||||
// public bool IsTvAvailableTest(string title, string year)
|
||||
// {
|
||||
// var tv = new List<PlexTvShow>
|
||||
// {
|
||||
// new PlexTvShow {Title = title, ProviderId = null, ReleaseYear = year}
|
||||
// };
|
||||
// var result = Checker.IsTvShowAvailable(tv.ToArray(), "title", "2011");
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsTvAvailableTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("title", "2011").Returns(true).SetName("IsTvAvailable True");
|
||||
yield return new TestCaseData("title2", "2011").Returns(false).SetName("IsTvAvailable False different title");
|
||||
yield return new TestCaseData("title", "2001").Returns(false).SetName("IsTvAvailable False different year");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsTvAvailableTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("title", "2011").Returns(true).SetName("IsTvAvailable True");
|
||||
// yield return new TestCaseData("title2", "2011").Returns(false).SetName("IsTvAvailable False different title");
|
||||
// yield return new TestCaseData("title", "2001").Returns(false).SetName("IsTvAvailable False different year");
|
||||
// }
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(IsTvAvailableAdvancedTestData))]
|
||||
public bool IsTvAvailableAdvancedTest(string title, string year, string providerId)
|
||||
{
|
||||
var movies = new List<PlexTvShow>
|
||||
{
|
||||
new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||
};
|
||||
var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||
// [TestCaseSource(nameof(IsTvAvailableAdvancedTestData))]
|
||||
// public bool IsTvAvailableAdvancedTest(string title, string year, string providerId)
|
||||
// {
|
||||
// var movies = new List<PlexTvShow>
|
||||
// {
|
||||
// new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||
// };
|
||||
// var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsTvAvailableAdvancedTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsTvAvailable True");
|
||||
yield return new TestCaseData("title2", "2011", "99929").Returns(false).SetName("Advanced IsTvAvailable False different title");
|
||||
yield return new TestCaseData("title", "2001", "99939").Returns(false).SetName("Advanced IsTvAvailable False different year");
|
||||
yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsTvAvailable False different providerID");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsTvAvailableAdvancedTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsTvAvailable True");
|
||||
// yield return new TestCaseData("title2", "2011", "99929").Returns(false).SetName("Advanced IsTvAvailable False different title");
|
||||
// yield return new TestCaseData("title", "2001", "99939").Returns(false).SetName("Advanced IsTvAvailable False different year");
|
||||
// yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsTvAvailable False different providerID");
|
||||
// }
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(IsTvAvailableAdvancedSeasonsTestData))]
|
||||
public bool IsTvAvailableAdvancedSeasonsTest(string title, string year, string providerId, int[] seasons)
|
||||
{
|
||||
var movies = new List<PlexTvShow>
|
||||
{
|
||||
new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year , Seasons = seasons}
|
||||
};
|
||||
var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString(), new[] { 1, 2, 3 });
|
||||
// [TestCaseSource(nameof(IsTvAvailableAdvancedSeasonsTestData))]
|
||||
// public bool IsTvAvailableAdvancedSeasonsTest(string title, string year, string providerId, int[] seasons)
|
||||
// {
|
||||
// var movies = new List<PlexTvShow>
|
||||
// {
|
||||
// new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year , Seasons = seasons}
|
||||
// };
|
||||
// var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString(), new[] { 1, 2, 3 });
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsTvAvailableAdvancedSeasonsTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("title", "2011", "9999", new[] { 1, 2, 3 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable True");
|
||||
yield return new TestCaseData("title2", "2011", "99929", new[] { 5, 6 }).Returns(false).SetName("Advanced IsTvSeasonsAvailable False no seasons");
|
||||
yield return new TestCaseData("title2", "2011", "9999", new[] { 1, 6 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable true one season");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsTvAvailableAdvancedSeasonsTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("title", "2011", "9999", new[] { 1, 2, 3 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable True");
|
||||
// yield return new TestCaseData("title2", "2011", "99929", new[] { 5, 6 }).Returns(false).SetName("Advanced IsTvSeasonsAvailable False no seasons");
|
||||
// yield return new TestCaseData("title2", "2011", "9999", new[] { 1, 6 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable true one season");
|
||||
// }
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(IsEpisodeAvailableTestData))]
|
||||
public bool IsEpisodeAvailableTest(string providerId, int season, int episode)
|
||||
{
|
||||
var expected = new List<PlexEpisodes>
|
||||
{
|
||||
new PlexEpisodes {EpisodeNumber = 1, ShowTitle = "The Flash",ProviderId = 23.ToString(), SeasonNumber = 1, EpisodeTitle = "Pilot"}
|
||||
};
|
||||
PlexEpisodes.Setup(x => x.Custom(It.IsAny<Func<IDbConnection, IEnumerable<PlexEpisodes>>>())).Returns(expected);
|
||||
// [TestCaseSource(nameof(IsEpisodeAvailableTestData))]
|
||||
// public bool IsEpisodeAvailableTest(string providerId, int season, int episode)
|
||||
// {
|
||||
// var expected = new List<PlexEpisodes>
|
||||
// {
|
||||
// new PlexEpisodes {EpisodeNumber = 1, ShowTitle = "The Flash",ProviderId = 23.ToString(), SeasonNumber = 1, EpisodeTitle = "Pilot"}
|
||||
// };
|
||||
// PlexEpisodes.Setup(x => x.Custom(It.IsAny<Func<IDbConnection, IEnumerable<PlexEpisodes>>>())).Returns(expected);
|
||||
|
||||
var result = Checker.IsEpisodeAvailable(providerId, season, episode);
|
||||
// var result = Checker.IsEpisodeAvailable(providerId, season, episode);
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> IsEpisodeAvailableTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("23", 1, 1).Returns(true).SetName("IsEpisodeAvailable True S01E01");
|
||||
yield return new TestCaseData("23", 1, 2).Returns(false).SetName("IsEpisodeAvailable False S01E02");
|
||||
yield return new TestCaseData("23", 99, 99).Returns(false).SetName("IsEpisodeAvailable False S99E99");
|
||||
yield return new TestCaseData("230", 99, 99).Returns(false).SetName("IsEpisodeAvailable False Incorrect ProviderId");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> IsEpisodeAvailableTestData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData("23", 1, 1).Returns(true).SetName("IsEpisodeAvailable True S01E01");
|
||||
// yield return new TestCaseData("23", 1, 2).Returns(false).SetName("IsEpisodeAvailable False S01E02");
|
||||
// yield return new TestCaseData("23", 99, 99).Returns(false).SetName("IsEpisodeAvailable False S99E99");
|
||||
// yield return new TestCaseData("230", 99, 99).Returns(false).SetName("IsEpisodeAvailable False Incorrect ProviderId");
|
||||
// }
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void GetPlexMoviesTests()
|
||||
{
|
||||
var cachedMovies = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||
cachedMovies.Add(new PlexSearch
|
||||
{
|
||||
Video = new List<Video>
|
||||
{
|
||||
new Video {Type = "movie", Title = "title1", Year = "2016", ProviderId = "1212"}
|
||||
}
|
||||
});
|
||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
||||
SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||
var movies = Checker.GetPlexMovies();
|
||||
// [Test]
|
||||
// public void GetPlexMoviesTests()
|
||||
// {
|
||||
// var cachedMovies = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||
// cachedMovies.Add(new PlexSearch
|
||||
// {
|
||||
// Video = new List<Video>
|
||||
// {
|
||||
// new Video {Type = "movie", Title = "title1", Year = "2016", ProviderId = "1212"}
|
||||
// }
|
||||
// });
|
||||
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
||||
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||
// var movies = Checker.GetPlexMovies();
|
||||
|
||||
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||
}
|
||||
// Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void GetPlexTvShowsTests()
|
||||
{
|
||||
var cachedTv = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||
cachedTv.Add(new PlexSearch
|
||||
{
|
||||
Directory = new List<Directory1>
|
||||
{
|
||||
new Directory1 {Type = "show", Title = "title1", Year = "2016", ProviderId = "1212", Seasons = new List<Directory1>()}
|
||||
}
|
||||
});
|
||||
SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
||||
var movies = Checker.GetPlexTvShows();
|
||||
// [Test]
|
||||
// public void GetPlexTvShowsTests()
|
||||
// {
|
||||
// var cachedTv = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||
// cachedTv.Add(new PlexSearch
|
||||
// {
|
||||
// Directory = new List<Directory1>
|
||||
// {
|
||||
// new Directory1 {Type = "show", Title = "title1", Year = "2016", ProviderId = "1212", Seasons = new List<Directory1>()}
|
||||
// }
|
||||
// });
|
||||
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
||||
// var movies = Checker.GetPlexTvShows();
|
||||
|
||||
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||
}
|
||||
// Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public async Task GetAllPlexEpisodes()
|
||||
{
|
||||
PlexEpisodes.Setup(x => x.GetAllAsync()).ReturnsAsync(F.CreateMany<PlexEpisodes>().ToList());
|
||||
var episodes = await Checker.GetEpisodes();
|
||||
// [Test]
|
||||
// public async Task GetAllPlexEpisodes()
|
||||
// {
|
||||
// PlexEpisodes.Setup(x => x.GetAllAsync()).ReturnsAsync(F.CreateMany<PlexEpisodes>().ToList());
|
||||
// var episodes = await Checker.GetEpisodes();
|
||||
|
||||
Assert.That(episodes.Count(), Is.GreaterThan(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Assert.That(episodes.Count(), Is.GreaterThan(0));
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -29,22 +29,23 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Models.Plex;
|
||||
|
||||
namespace PlexRequests.Services.Interfaces
|
||||
{
|
||||
public interface IAvailabilityChecker
|
||||
{
|
||||
void CheckAndUpdateAll();
|
||||
List<PlexMovie> GetPlexMovies();
|
||||
bool IsMovieAvailable(PlexMovie[] plexMovies, string title, string year, string providerId = null);
|
||||
List<PlexTvShow> GetPlexTvShows();
|
||||
bool IsTvShowAvailable(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
List<PlexAlbum> GetPlexAlbums();
|
||||
bool IsAlbumAvailable(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
||||
IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content);
|
||||
bool IsMovieAvailable(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
||||
IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content);
|
||||
bool IsTvShowAvailable(PlexContent[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content);
|
||||
bool IsAlbumAvailable(PlexContent[] plexAlbums, string title, string year, string artist);
|
||||
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
||||
PlexAlbum GetAlbum(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
||||
PlexMovie GetMovie(PlexMovie[] plexMovies, string title, string year, string providerId = null);
|
||||
PlexTvShow GetTvShow(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
PlexContent GetAlbum(PlexContent[] plexAlbums, string title, string year, string artist);
|
||||
PlexContent GetMovie(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
||||
PlexContent GetTvShow(PlexContent[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||
/// <summary>
|
||||
/// Gets the episode's stored in the cache.
|
||||
/// </summary>
|
||||
|
|
|
@ -36,5 +36,6 @@ namespace PlexRequests.Services.Interfaces
|
|||
void Record(string jobName);
|
||||
Task<IEnumerable<ScheduledJobs>> GetJobsAsync();
|
||||
IEnumerable<ScheduledJobs> GetJobs();
|
||||
void SetRunning(bool running, string jobName);
|
||||
}
|
||||
}
|
|
@ -27,13 +27,14 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Store;
|
||||
|
||||
namespace PlexRequests.Services.Interfaces
|
||||
{
|
||||
public interface INotificationEngine
|
||||
{
|
||||
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey);
|
||||
Task NotifyUsers(RequestedModel modelChanged, string apiKey);
|
||||
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey, NotificationType type);
|
||||
Task NotifyUsers(RequestedModel modelChanged, string apiKey, NotificationType type);
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
|||
var settings = CpSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
Job.SetRunning(true, JobNames.CpCacher);
|
||||
Log.Trace("Getting all movies from CouchPotato");
|
||||
try
|
||||
{
|
||||
|
@ -81,6 +82,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
Job.Record(JobNames.CpCacher);
|
||||
Job.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
327
PlexRequests.Services/Jobs/FaultQueueHandler.cs
Normal file
327
PlexRequests.Services/Jobs/FaultQueueHandler.cs
Normal file
|
@ -0,0 +1,327 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserRequestLimitResetter.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using NLog;
|
||||
using PlexRequests.Api;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
using Quartz;
|
||||
|
||||
namespace PlexRequests.Services.Jobs
|
||||
{
|
||||
public class FaultQueueHandler : IJob
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public FaultQueueHandler(IJobRecord record, IRepository<RequestQueue> repo, ISonarrApi sonarrApi,
|
||||
ISickRageApi srApi, ISettingsService<SonarrSettings> sonarrSettings, ISettingsService<SickRageSettings> srSettings,
|
||||
ICouchPotatoApi cpApi, ISettingsService<CouchPotatoSettings> cpsettings, IRequestService requestService,
|
||||
ISettingsService<HeadphonesSettings> hpSettings, IHeadphonesApi headphonesApi, ISettingsService<PlexRequestSettings> prSettings,
|
||||
ISecurityExtensions security)
|
||||
{
|
||||
Record = record;
|
||||
Repo = repo;
|
||||
SonarrApi = sonarrApi;
|
||||
SrApi = srApi;
|
||||
CpApi = cpApi;
|
||||
HpApi = headphonesApi;
|
||||
|
||||
RequestService = requestService;
|
||||
|
||||
SickrageSettings = srSettings;
|
||||
SonarrSettings = sonarrSettings;
|
||||
CpSettings = cpsettings;
|
||||
HeadphoneSettings = hpSettings;
|
||||
Security = security;
|
||||
PrSettings = prSettings.GetSettings();
|
||||
}
|
||||
|
||||
private IRepository<RequestQueue> Repo { get; }
|
||||
private IJobRecord Record { get; }
|
||||
private ISonarrApi SonarrApi { get; }
|
||||
private ISickRageApi SrApi { get; }
|
||||
private ICouchPotatoApi CpApi { get; }
|
||||
private IHeadphonesApi HpApi { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private PlexRequestSettings PrSettings { get; }
|
||||
private ISettingsService<SonarrSettings> SonarrSettings { get; }
|
||||
private ISettingsService<SickRageSettings> SickrageSettings { get; }
|
||||
private ISettingsService<CouchPotatoSettings> CpSettings { get; }
|
||||
private ISettingsService<HeadphonesSettings> HeadphoneSettings { get; }
|
||||
private ISecurityExtensions Security { get; }
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Record.SetRunning(true, JobNames.CpCacher);
|
||||
try
|
||||
{
|
||||
var faultedRequests = Repo.GetAll().ToList();
|
||||
|
||||
var missingInfo = faultedRequests.Where(x => x.FaultType == FaultType.MissingInformation).ToList();
|
||||
ProcessMissingInformation(missingInfo);
|
||||
|
||||
var transientErrors = faultedRequests.Where(x => x.FaultType == FaultType.RequestFault).ToList();
|
||||
ProcessTransientErrors(transientErrors);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Record.Record(JobNames.FaultQueueHandler);
|
||||
Record.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ProcessMissingInformation(List<RequestQueue> requests)
|
||||
{
|
||||
if (!requests.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
var sickrageSettings = SickrageSettings.GetSettings();
|
||||
|
||||
var tv = requests.Where(x => x.Type == RequestType.TvShow);
|
||||
|
||||
// TV
|
||||
var tvApi = new TvMazeApi();
|
||||
foreach (var t in tv)
|
||||
{
|
||||
var providerId = int.Parse(t.PrimaryIdentifier);
|
||||
var showInfo = tvApi.ShowLookup(providerId);
|
||||
|
||||
if (showInfo.externals?.thetvdb != null)
|
||||
{
|
||||
// We now have the info
|
||||
var tvModel = ByteConverterHelper.ReturnObject<RequestedModel>(t.Content);
|
||||
tvModel.ProviderId = showInfo.externals.thetvdb.Value;
|
||||
var result = ProcessTvShow(tvModel, sonarrSettings, sickrageSettings);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// we now have the info but couldn't add it, so add it back into the queue but with a different fault
|
||||
t.Content = ByteConverterHelper.ReturnBytes(tvModel);
|
||||
t.FaultType = FaultType.RequestFault;
|
||||
t.LastRetry = DateTime.UtcNow;
|
||||
Repo.Update(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Successful, remove from the fault queue
|
||||
Repo.Delete(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessTvShow(RequestedModel tvModel, SonarrSettings sonarr, SickRageSettings sickrage)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var sender = new TvSenderOld(SonarrApi, SrApi);
|
||||
if (sonarr.Enabled)
|
||||
{
|
||||
var task = sender.SendToSonarr(sonarr, tvModel, sonarr.QualityProfile);
|
||||
var a = task.Result;
|
||||
if (string.IsNullOrEmpty(a?.title))
|
||||
{
|
||||
// Couldn't send it
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sickrage.Enabled)
|
||||
{
|
||||
var result = sender.SendToSickRage(sickrage, tvModel);
|
||||
if (result?.result != "success")
|
||||
{
|
||||
// Couldn't send it
|
||||
return false;
|
||||
}
|
||||
|
||||
// Approve it
|
||||
tvModel.Approved = true;
|
||||
RequestService.UpdateRequest(tvModel);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessMovies(RequestedModel model, CouchPotatoSettings cp)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cp.Enabled)
|
||||
{
|
||||
var result = CpApi.AddMovie(model.ImdbId, cp.ApiKey, model.Title,
|
||||
cp.FullUri, cp.ProfileId);
|
||||
|
||||
if (result)
|
||||
{
|
||||
// Approve it now
|
||||
model.Approved = true;
|
||||
RequestService.UpdateRequest(model);
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessAlbums(RequestedModel model, HeadphonesSettings hp)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hp.Enabled)
|
||||
{
|
||||
var sender = new HeadphonesSender(HpApi, hp, RequestService);
|
||||
var result = sender.AddAlbum(model).Result;
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
||||
if (ShouldAutoApprove(model.Type, PrSettings, model.RequestedUsers))
|
||||
// Approve it now
|
||||
model.Approved = true;
|
||||
RequestService.UpdateRequest(model);
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return false; // It fails so it will get added back into the queue
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessTransientErrors(List<RequestQueue> requests)
|
||||
{
|
||||
var sonarrSettings = SonarrSettings.GetSettings();
|
||||
var sickrageSettings = SickrageSettings.GetSettings();
|
||||
var cpSettings = CpSettings.GetSettings();
|
||||
var hpSettings = HeadphoneSettings.GetSettings();
|
||||
|
||||
if (!requests.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var request in requests)
|
||||
{
|
||||
var model = ByteConverterHelper.ReturnObject<RequestedModel>(request.Content);
|
||||
bool result;
|
||||
switch (request.Type)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
result = ProcessMovies(model, cpSettings);
|
||||
break;
|
||||
case RequestType.TvShow:
|
||||
result = ProcessTvShow(model, sonarrSettings, sickrageSettings);
|
||||
break;
|
||||
case RequestType.Album:
|
||||
result = ProcessAlbums(model, hpSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// we now have the info but couldn't add it, so do nothing now.
|
||||
request.LastRetry = DateTime.UtcNow;
|
||||
Repo.Update(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Successful, remove from the fault queue
|
||||
Repo.Delete(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSettings, List<string> username)
|
||||
{
|
||||
foreach (var user in username)
|
||||
{
|
||||
var admin = Security.HasPermissions(user, Permissions.Administrator);
|
||||
// if the user is an admin or they are whitelisted, they go ahead and allow auto-approval
|
||||
if (admin) return true;
|
||||
|
||||
// check by request type if the category requires approval or not
|
||||
switch (requestType)
|
||||
{
|
||||
case RequestType.Movie:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveMovie);
|
||||
case RequestType.TvShow:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveTv);
|
||||
case RequestType.Album:
|
||||
return Security.HasPermissions(user, Permissions.AutoApproveAlbum);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
10
PlexRequests.Services/Jobs/IPlexContentCacher.cs
Normal file
10
PlexRequests.Services/Jobs/IPlexContentCacher.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Quartz;
|
||||
|
||||
namespace PlexRequests.Services.Jobs
|
||||
{
|
||||
public interface IPlexContentCacher
|
||||
{
|
||||
void CacheContent();
|
||||
void Execute(IJobExecutionContext context);
|
||||
}
|
||||
}
|
|
@ -33,9 +33,13 @@ namespace PlexRequests.Services.Jobs
|
|||
public const string SonarrCacher = "Sonarr Cacher";
|
||||
public const string SrCacher = "SickRage Cacher";
|
||||
public const string PlexChecker = "Plex Availability Cacher";
|
||||
public const string PlexCacher = "Plex Cacher";
|
||||
public const string StoreCleanup = "Database Cleanup";
|
||||
public const string RequestLimitReset = "Request Limit Reset";
|
||||
public const string EpisodeCacher = "Plex Episode Cacher";
|
||||
public const string RecentlyAddedEmail = "Recently Added Email Notification";
|
||||
public const string FaultQueueHandler = "Request Fault Queue Handler";
|
||||
public const string PlexUserChecker = "Plex User Checker";
|
||||
|
||||
}
|
||||
}
|
|
@ -60,6 +60,23 @@ namespace PlexRequests.Services.Jobs
|
|||
}
|
||||
}
|
||||
|
||||
public void SetRunning(bool running, string jobName)
|
||||
{
|
||||
var allJobs = Repo.GetAll();
|
||||
var storeJob = allJobs.FirstOrDefault(x => x.Name == jobName);
|
||||
if (storeJob != null)
|
||||
{
|
||||
storeJob.Running = running;
|
||||
Repo.Update(storeJob);
|
||||
}
|
||||
else
|
||||
{
|
||||
var job = new ScheduledJobs { Running = running, Name = jobName };
|
||||
Repo.Insert(job);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<IEnumerable<ScheduledJobs>> GetJobsAsync()
|
||||
{
|
||||
return await Repo.GetAllAsync();
|
||||
|
|
|
@ -30,7 +30,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
|
||||
using Dapper;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
|
@ -44,6 +44,7 @@ using PlexRequests.Services.Models;
|
|||
using PlexRequests.Services.Notification;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Models.Plex;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
using Quartz;
|
||||
|
@ -53,7 +54,7 @@ namespace PlexRequests.Services.Jobs
|
|||
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
||||
{
|
||||
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e)
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e, IRepository<PlexContent> content)
|
||||
{
|
||||
Plex = plexSettings;
|
||||
RequestService = request;
|
||||
|
@ -64,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
|||
UserNotifyRepo = users;
|
||||
EpisodeRepo = repo;
|
||||
NotificationEngine = e;
|
||||
PlexContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<PlexSettings> Plex { get; }
|
||||
|
@ -76,7 +78,7 @@ namespace PlexRequests.Services.Jobs
|
|||
private IJobRecord Job { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private INotificationEngine NotificationEngine { get; }
|
||||
|
||||
private IRepository<PlexContent> PlexContent { get; }
|
||||
|
||||
public void CheckAndUpdateAll()
|
||||
{
|
||||
|
@ -87,18 +89,17 @@ namespace PlexRequests.Services.Jobs
|
|||
Log.Debug("Validation of the plex settings failed.");
|
||||
return;
|
||||
}
|
||||
//var libraries = CachedLibraries(plexSettings, true); //force setting the cache (10 min intervals via scheduler)
|
||||
|
||||
var libraries = CachedLibraries(plexSettings, true); //force setting the cache (10 min intervals via scheduler)
|
||||
|
||||
if (libraries == null || !libraries.Any())
|
||||
{
|
||||
Log.Debug("Did not find any libraries in Plex.");
|
||||
return;
|
||||
}
|
||||
|
||||
var movies = GetPlexMovies().ToArray();
|
||||
var shows = GetPlexTvShows().ToArray();
|
||||
var albums = GetPlexAlbums().ToArray();
|
||||
//if (libraries == null || !libraries.Any())
|
||||
//{
|
||||
// Log.Debug("Did not find any libraries in Plex.");
|
||||
// return;
|
||||
//}
|
||||
var content = PlexContent.GetAll().ToList();
|
||||
var movies = GetPlexMovies(content).ToArray();
|
||||
var shows = GetPlexTvShows(content).ToArray();
|
||||
var albums = GetPlexAlbums(content).ToArray();
|
||||
|
||||
var requests = RequestService.GetAll();
|
||||
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
|
||||
|
@ -153,15 +154,12 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
if (modifiedModel.Any())
|
||||
{
|
||||
NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken);
|
||||
NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken, NotificationType.RequestAvailable);
|
||||
RequestService.BatchUpdate(modifiedModel);
|
||||
}
|
||||
|
||||
Job.Record(JobNames.PlexChecker);
|
||||
|
||||
}
|
||||
|
||||
public List<PlexMovie> GetPlexMovies()
|
||||
public List<PlexMovie> GetPlexMoviesOld()
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var movies = new List<PlexMovie>();
|
||||
|
@ -188,13 +186,18 @@ namespace PlexRequests.Services.Jobs
|
|||
return movies;
|
||||
}
|
||||
|
||||
public bool IsMovieAvailable(PlexMovie[] plexMovies, string title, string year, string providerId = null)
|
||||
public IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content)
|
||||
{
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Movie);
|
||||
}
|
||||
|
||||
public bool IsMovieAvailable(PlexContent[] plexMovies, string title, string year, string providerId = null)
|
||||
{
|
||||
var movie = GetMovie(plexMovies, title, year, providerId);
|
||||
return movie != null;
|
||||
}
|
||||
|
||||
public PlexMovie GetMovie(PlexMovie[] plexMovies, string title, string year, string providerId = null)
|
||||
public PlexContent GetMovie(PlexContent[] plexMovies, string title, string year, string providerId = null)
|
||||
{
|
||||
if (plexMovies.Length == 0)
|
||||
{
|
||||
|
@ -225,45 +228,19 @@ namespace PlexRequests.Services.Jobs
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<PlexTvShow> GetPlexTvShows()
|
||||
public IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var shows = new List<PlexTvShow>();
|
||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||
if (libs != null)
|
||||
{
|
||||
var withDir = libs.Where(x => x.Directory != null);
|
||||
var tvLibs = withDir.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in tvLibs)
|
||||
{
|
||||
|
||||
shows.AddRange(lib.Directory.Select(x => new PlexTvShow // shows are in the directory list
|
||||
{
|
||||
Title = x.Title,
|
||||
ReleaseYear = x.Year,
|
||||
ProviderId = x.ProviderId,
|
||||
Seasons = x.Seasons?.Select(d => PlexHelper.GetSeasonNumberFromTitle(d.Title)).ToArray(),
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||
|
||||
}));
|
||||
}
|
||||
}
|
||||
return shows;
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Show);
|
||||
}
|
||||
|
||||
public bool IsTvShowAvailable(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null)
|
||||
public bool IsTvShowAvailable(PlexContent[] plexShows, string title, string year, string providerId = null, int[] seasons = null)
|
||||
{
|
||||
var show = GetTvShow(plexShows, title, year, providerId, seasons);
|
||||
return show != null;
|
||||
}
|
||||
|
||||
|
||||
public PlexTvShow GetTvShow(PlexTvShow[] plexShows, string title, string year, string providerId = null,
|
||||
public PlexContent GetTvShow(PlexContent[] plexShows, string title, string year, string providerId = null,
|
||||
int[] seasons = null)
|
||||
{
|
||||
var advanced = !string.IsNullOrEmpty(providerId);
|
||||
|
@ -273,7 +250,8 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
if (show.ProviderId == providerId && seasons != null)
|
||||
{
|
||||
if (seasons.Any(season => show.Seasons.Contains(season)))
|
||||
var showSeasons = ByteConverterHelper.ReturnObject<int[]>(show.Seasons);
|
||||
if (seasons.Any(season => showSeasons.Contains(season)))
|
||||
{
|
||||
return show;
|
||||
}
|
||||
|
@ -359,41 +337,19 @@ namespace PlexRequests.Services.Jobs
|
|||
return plexEpisodeses;
|
||||
}
|
||||
|
||||
public List<PlexAlbum> GetPlexAlbums()
|
||||
public IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var albums = new List<PlexAlbum>();
|
||||
var libs = Cache.Get<List<PlexSearch>>(CacheKeys.PlexLibaries);
|
||||
if (libs != null)
|
||||
{
|
||||
var albumLibs = libs.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Artist.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in albumLibs)
|
||||
{
|
||||
albums.AddRange(lib.Directory.Select(x => new PlexAlbum()
|
||||
{
|
||||
Title = x.Title,
|
||||
ReleaseYear = x.Year,
|
||||
Artist = x.ParentTitle,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||
}));
|
||||
}
|
||||
}
|
||||
return albums;
|
||||
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Artist);
|
||||
}
|
||||
|
||||
public bool IsAlbumAvailable(PlexAlbum[] plexAlbums, string title, string year, string artist)
|
||||
public bool IsAlbumAvailable(PlexContent[] plexAlbums, string title, string year, string artist)
|
||||
{
|
||||
return plexAlbums.Any(x =>
|
||||
x.Title.Contains(title) &&
|
||||
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
public PlexAlbum GetAlbum(PlexAlbum[] plexAlbums, string title, string year, string artist)
|
||||
public PlexContent GetAlbum(PlexContent[] plexAlbums, string title, string year, string artist)
|
||||
{
|
||||
return plexAlbums.FirstOrDefault(x =>
|
||||
x.Title.Contains(title) &&
|
||||
|
@ -419,11 +375,11 @@ namespace PlexRequests.Services.Jobs
|
|||
results = GetLibraries(plexSettings);
|
||||
if (plexSettings.AdvancedSearch)
|
||||
{
|
||||
for (var i = 0; i < results.Count; i++)
|
||||
foreach (PlexSearch t in results)
|
||||
{
|
||||
for (var j = 0; j < results[i].Directory.Count; j++)
|
||||
foreach (Directory1 t1 in t.Directory)
|
||||
{
|
||||
var currentItem = results[i].Directory[j];
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
|
@ -434,25 +390,21 @@ namespace PlexRequests.Services.Jobs
|
|||
currentItem.RatingKey);
|
||||
|
||||
// We do not want "all episodes" this as a season
|
||||
var filtered =
|
||||
seasons.Directory.Where(
|
||||
x =>
|
||||
!x.Title.Equals("All episodes",
|
||||
StringComparison.CurrentCultureIgnoreCase));
|
||||
var filtered = seasons.Directory.Where( x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
results[i].Directory[j].Seasons.AddRange(filtered);
|
||||
t1.Seasons.AddRange(filtered);
|
||||
}
|
||||
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Directory.Guid);
|
||||
results[i].Directory[j].ProviderId = providerId;
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
for (var j = 0; j < results[i].Video.Count; j++)
|
||||
foreach (Video t1 in t.Video)
|
||||
{
|
||||
var currentItem = results[i].Video[j];
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Video.Guid);
|
||||
results[i].Video[j].ProviderId = providerId;
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -479,10 +431,10 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||
|
||||
List<PlexSearch> libs = new List<PlexSearch>();
|
||||
var libs = new List<PlexSearch>();
|
||||
if (sections != null)
|
||||
{
|
||||
foreach (var dir in sections.Directories)
|
||||
foreach (var dir in sections.Directories ?? new List<Directory>())
|
||||
{
|
||||
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.Key);
|
||||
if (lib != null)
|
||||
|
@ -507,6 +459,8 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.PlexChecker);
|
||||
try
|
||||
{
|
||||
CheckAndUpdateAll();
|
||||
|
@ -515,6 +469,11 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.PlexChecker);
|
||||
Job.SetRunning(false, JobNames.PlexChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
361
PlexRequests.Services/Jobs/PlexContentCacher.cs
Normal file
361
PlexRequests.Services/Jobs/PlexContentCacher.cs
Normal file
|
@ -0,0 +1,361 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexAvailabilityChecker.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dapper;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using Org.BouncyCastle.Crypto.Modes.Gcm;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Services.Models;
|
||||
using PlexRequests.Services.Notification;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Models.Plex;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
using Quartz;
|
||||
|
||||
namespace PlexRequests.Services.Jobs
|
||||
{
|
||||
public class PlexContentCacher : IJob, IPlexContentCacher
|
||||
{
|
||||
public PlexContentCacher(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo, INotificationEngine e, IRepository<PlexContent> content)
|
||||
{
|
||||
Plex = plexSettings;
|
||||
RequestService = request;
|
||||
PlexApi = plex;
|
||||
Cache = cache;
|
||||
Notification = notify;
|
||||
Job = rec;
|
||||
UserNotifyRepo = users;
|
||||
EpisodeRepo = repo;
|
||||
NotificationEngine = e;
|
||||
PlexContent = content;
|
||||
}
|
||||
|
||||
private ISettingsService<PlexSettings> Plex { get; }
|
||||
private IRepository<PlexEpisodes> EpisodeRepo { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ICacheProvider Cache { get; }
|
||||
private INotificationService Notification { get; }
|
||||
private IJobRecord Job { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private INotificationEngine NotificationEngine { get; }
|
||||
private IRepository<PlexContent> PlexContent { get; }
|
||||
|
||||
public void CacheContent()
|
||||
{
|
||||
var plexSettings = Plex.GetSettings();
|
||||
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Debug("Validation of the plex settings failed.");
|
||||
return;
|
||||
}
|
||||
var libraries = CachedLibraries(plexSettings);
|
||||
|
||||
if (libraries == null || !libraries.Any())
|
||||
{
|
||||
Log.Debug("Did not find any libraries in Plex.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<PlexMovie> GetPlexMovies(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var movies = new List<PlexMovie>();
|
||||
if (libs != null)
|
||||
{
|
||||
var movieLibs = libs.Where(x =>
|
||||
x.Video.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in movieLibs)
|
||||
{
|
||||
movies.AddRange(lib.Video.Select(video => new PlexMovie
|
||||
{
|
||||
ReleaseYear = video.Year,
|
||||
Title = video.Title,
|
||||
ProviderId = video.ProviderId,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, video.RatingKey)
|
||||
}));
|
||||
}
|
||||
}
|
||||
return movies;
|
||||
}
|
||||
|
||||
public List<PlexTvShow> GetPlexTvShows(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var shows = new List<PlexTvShow>();
|
||||
if (libs != null)
|
||||
{
|
||||
var withDir = libs.Where(x => x.Directory != null);
|
||||
var tvLibs = withDir.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in tvLibs)
|
||||
{
|
||||
|
||||
shows.AddRange(lib.Directory.Select(x => new PlexTvShow // shows are in the directory list
|
||||
{
|
||||
Title = x.Title,
|
||||
ReleaseYear = x.Year,
|
||||
ProviderId = x.ProviderId,
|
||||
Seasons = x.Seasons?.Select(d => PlexHelper.GetSeasonNumberFromTitle(d.Title)).ToArray(),
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey),
|
||||
|
||||
}));
|
||||
}
|
||||
}
|
||||
return shows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public List<PlexAlbum> GetPlexAlbums(List<PlexSearch> libs)
|
||||
{
|
||||
var settings = Plex.GetSettings();
|
||||
var albums = new List<PlexAlbum>();
|
||||
if (libs != null)
|
||||
{
|
||||
var albumLibs = libs.Where(x =>
|
||||
x.Directory.Any(y =>
|
||||
y.Type.Equals(PlexMediaType.Artist.ToString(), StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
).ToArray();
|
||||
|
||||
foreach (var lib in albumLibs)
|
||||
{
|
||||
albums.AddRange(lib.Directory.Select(x => new PlexAlbum()
|
||||
{
|
||||
Title = x.Title,
|
||||
ProviderId = x.ProviderId,
|
||||
ReleaseYear = x.Year,
|
||||
Artist = x.ParentTitle,
|
||||
Url = PlexHelper.GetPlexMediaUrl(settings.MachineIdentifier, x.RatingKey)
|
||||
}));
|
||||
}
|
||||
}
|
||||
return albums;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<PlexSearch> CachedLibraries(PlexSettings plexSettings)
|
||||
{
|
||||
var results = new List<PlexSearch>();
|
||||
|
||||
if (!ValidateSettings(plexSettings))
|
||||
{
|
||||
Log.Warn("The settings are not configured");
|
||||
return results; // don't error out here, just let it go! let it goo!!!
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
results = GetLibraries(plexSettings);
|
||||
if (plexSettings.AdvancedSearch)
|
||||
{
|
||||
foreach (PlexSearch t in results)
|
||||
{
|
||||
foreach (Directory1 t1 in t.Directory)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// Get the seasons for each show
|
||||
if (currentItem.Type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var seasons = PlexApi.GetSeasons(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
|
||||
// We do not want "all episodes" this as a season
|
||||
var filtered = seasons.Directory.Where(x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
|
||||
|
||||
t1.Seasons.AddRange(filtered);
|
||||
}
|
||||
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Directory.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
foreach (Video t1 in t.Video)
|
||||
{
|
||||
var currentItem = t1;
|
||||
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
currentItem.RatingKey);
|
||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Video.Guid);
|
||||
t1.ProviderId = providerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results != null)
|
||||
{
|
||||
|
||||
var movies = GetPlexMovies(results);
|
||||
|
||||
// Time to destroy the plex movies from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 0 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
|
||||
foreach (var m in movies)
|
||||
{
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = m.ProviderId,
|
||||
ReleaseYear = m.ReleaseYear ?? string.Empty,
|
||||
Title = m.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Movie,
|
||||
Url = m.Url
|
||||
});
|
||||
}
|
||||
var tv = GetPlexTvShows(results);
|
||||
// Time to destroy the plex tv from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 1 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
foreach (var t in tv)
|
||||
{
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = t.ProviderId,
|
||||
ReleaseYear = t.ReleaseYear ?? string.Empty,
|
||||
Title = t.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Show,
|
||||
Url = t.Url,
|
||||
Seasons = ByteConverterHelper.ReturnBytes(t.Seasons)
|
||||
});
|
||||
}
|
||||
|
||||
var albums = GetPlexAlbums(results);
|
||||
// Time to destroy the plex movies from the DB
|
||||
PlexContent.Custom(connection =>
|
||||
{
|
||||
connection.Open();
|
||||
connection.Query("delete from PlexContent where type = @type", new { type = 2 });
|
||||
return new List<PlexContent>();
|
||||
});
|
||||
foreach (var a in albums)
|
||||
{
|
||||
PlexContent.Insert(new PlexContent
|
||||
{
|
||||
ProviderId = a.ProviderId,
|
||||
ReleaseYear = a.ReleaseYear ?? string.Empty,
|
||||
Title = a.Title,
|
||||
Type = Store.Models.Plex.PlexMediaType.Artist,
|
||||
Url = a.Url
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to obtain Plex libraries");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<PlexSearch> GetLibraries(PlexSettings plexSettings)
|
||||
{
|
||||
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||
|
||||
var libs = new List<PlexSearch>();
|
||||
if (sections != null)
|
||||
{
|
||||
foreach (var dir in sections.Directories ?? new List<Directory>())
|
||||
{
|
||||
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.Key);
|
||||
if (lib != null)
|
||||
{
|
||||
libs.Add(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return libs;
|
||||
}
|
||||
|
||||
private bool ValidateSettings(PlexSettings plex)
|
||||
{
|
||||
if (plex?.Ip == null || plex?.PlexAuthToken == null)
|
||||
{
|
||||
Log.Warn("A setting is null, Ensure Plex is configured correctly, and we have a Plex Auth token.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.PlexCacher);
|
||||
try
|
||||
{
|
||||
CacheContent();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Job.Record(JobNames.PlexCacher);
|
||||
Job.SetRunning(false, JobNames.PlexCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -145,6 +145,7 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var s = Plex.GetSettings();
|
||||
|
@ -162,6 +163,7 @@ namespace PlexRequests.Services.Jobs
|
|||
return;
|
||||
}
|
||||
}
|
||||
Job.SetRunning(true, JobNames.EpisodeCacher);
|
||||
CacheEpisodes(s);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -171,6 +173,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
Job.Record(JobNames.EpisodeCacher);
|
||||
Job.SetRunning(false, JobNames.EpisodeCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
175
PlexRequests.Services/Jobs/PlexUserChecker.cs
Normal file
175
PlexRequests.Services/Jobs/PlexUserChecker.cs
Normal file
|
@ -0,0 +1,175 @@
|
|||
#region Copyright
|
||||
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: StoreCleanup.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Core.Users;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
using Quartz;
|
||||
|
||||
namespace PlexRequests.Services.Jobs
|
||||
{
|
||||
public class PlexUserChecker : IJob
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public PlexUserChecker(IPlexUserRepository plexUsers, IPlexApi plexAPi, IJobRecord rec, ISettingsService<PlexSettings> plexSettings, ISettingsService<PlexRequestSettings> prSettings, ISettingsService<UserManagementSettings> umSettings,
|
||||
IRequestService requestService, IUserRepository localUser)
|
||||
{
|
||||
Repo = plexUsers;
|
||||
JobRecord = rec;
|
||||
PlexApi = plexAPi;
|
||||
PlexSettings = plexSettings;
|
||||
PlexRequestSettings = prSettings;
|
||||
UserManagementSettings = umSettings;
|
||||
RequestService = requestService;
|
||||
LocalUserRepository = localUser;
|
||||
}
|
||||
|
||||
private IJobRecord JobRecord { get; }
|
||||
private IPlexApi PlexApi { get; }
|
||||
private IPlexUserRepository Repo { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private ISettingsService<PlexRequestSettings> PlexRequestSettings { get; }
|
||||
private ISettingsService<UserManagementSettings> UserManagementSettings { get; }
|
||||
private IRequestService RequestService { get; }
|
||||
private IUserRepository LocalUserRepository { get; }
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.PlexUserChecker);
|
||||
|
||||
try
|
||||
{
|
||||
var settings = PlexSettings.GetSettings();
|
||||
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var plexUsers = PlexApi.GetUsers(settings.PlexAuthToken);
|
||||
var userManagementSettings = UserManagementSettings.GetSettings();
|
||||
var requests = RequestService.GetAll().ToList();
|
||||
|
||||
var dbUsers = Repo.GetAll().ToList();
|
||||
var localUsers = LocalUserRepository.GetAll().ToList();
|
||||
foreach (var user in plexUsers.User)
|
||||
{
|
||||
var dbUser = dbUsers.FirstOrDefault(x => x.PlexUserId == user.Id);
|
||||
if (dbUser != null)
|
||||
{
|
||||
// We already have the user, let's check if they have updated any of their info.
|
||||
var needToUpdate = false;
|
||||
var usernameChanged = false;
|
||||
|
||||
// Do we need up update any info?
|
||||
if (!dbUser.EmailAddress.Equals(user.Email, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
dbUser.EmailAddress = user.Email;
|
||||
needToUpdate = true;
|
||||
}
|
||||
if (!dbUser.Username.Equals(user.Username, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
needToUpdate = true;
|
||||
usernameChanged = true;
|
||||
}
|
||||
|
||||
if (needToUpdate)
|
||||
{
|
||||
if (usernameChanged)
|
||||
{
|
||||
// The username has changed, let's check if the username matches any local users
|
||||
var localUser = localUsers.FirstOrDefault(x => x.UserName.Equals(user.Username, StringComparison.CurrentCultureIgnoreCase));
|
||||
dbUser.Username = user.Username;
|
||||
if (localUser != null)
|
||||
{
|
||||
// looks like we have a local user with the same name...
|
||||
// We should delete the local user and the Plex user will become the master,
|
||||
// I am not going to update the Plex Users permissions as that could end up leading to a security vulnerability
|
||||
// Where anyone could change their Plex Username to the PR.Net server admins name and get all the admin permissions.
|
||||
|
||||
LocalUserRepository.Delete(localUser);
|
||||
}
|
||||
|
||||
// Since the username has changed, we need to update all requests with that username (unless we are using the alias! Since the alias won't change)
|
||||
if (string.IsNullOrEmpty(dbUser.UserAlias))
|
||||
{
|
||||
// Update all requests
|
||||
var requestsWithThisUser = requests.Where(x => x.RequestedUsers.Contains(user.Username)).ToList();
|
||||
foreach (var r in requestsWithThisUser)
|
||||
{
|
||||
r.RequestedUsers.Remove(user.Username); // Remove old
|
||||
r.RequestedUsers.Add(dbUser.Username); // Add new
|
||||
}
|
||||
|
||||
if (requestsWithThisUser.Any())
|
||||
{
|
||||
RequestService.BatchUpdate(requestsWithThisUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
Repo.Update(dbUser);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Looks like it's a new user!
|
||||
var m = new PlexUsers
|
||||
{
|
||||
PlexUserId = user.Id,
|
||||
Permissions = UserManagementHelper.GetPermissions(userManagementSettings),
|
||||
Features = UserManagementHelper.GetFeatures(userManagementSettings),
|
||||
UserAlias = string.Empty,
|
||||
EmailAddress = user.Email,
|
||||
Username = user.Username,
|
||||
LoginId = Guid.NewGuid().ToString()
|
||||
};
|
||||
|
||||
Repo.Insert(m);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
JobRecord.SetRunning(false, JobNames.PlexUserChecker);
|
||||
JobRecord.Record(JobNames.PlexUserChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,7 +39,9 @@ using PlexRequests.Api.Interfaces;
|
|||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Core.Users;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Services.Jobs.Templates;
|
||||
using PlexRequests.Store.Models.Plex;
|
||||
|
@ -52,8 +54,8 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
public RecentlyAdded(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
|
||||
ISettingsService<EmailNotificationSettings> email, IJobRecord rec,
|
||||
ISettingsService<NewletterSettings> newsletter,
|
||||
IPlexReadOnlyDatabase db)
|
||||
ISettingsService<NewletterSettings> newsletter,
|
||||
IPlexReadOnlyDatabase db, IUserHelper userHelper)
|
||||
{
|
||||
JobRecord = rec;
|
||||
Api = api;
|
||||
|
@ -61,6 +63,7 @@ namespace PlexRequests.Services.Jobs
|
|||
EmailSettings = email;
|
||||
NewsletterSettings = newsletter;
|
||||
PlexDb = db;
|
||||
UserHelper = userHelper;
|
||||
}
|
||||
|
||||
private IPlexApi Api { get; }
|
||||
|
@ -73,6 +76,7 @@ namespace PlexRequests.Services.Jobs
|
|||
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
||||
private IJobRecord JobRecord { get; }
|
||||
private IPlexReadOnlyDatabase PlexDb { get; }
|
||||
private IUserHelper UserHelper { get; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
@ -85,7 +89,7 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
JobRecord.SetRunning(true, JobNames.RecentlyAddedEmail);
|
||||
Start(settings);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -95,11 +99,13 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.RecentlyAddedEmail);
|
||||
JobRecord.SetRunning(false, JobNames.RecentlyAddedEmail);
|
||||
}
|
||||
}
|
||||
|
||||
public void Test()
|
||||
{
|
||||
Log.Debug("Starting Test Newsletter");
|
||||
var settings = NewsletterSettings.GetSettings();
|
||||
Start(settings, true);
|
||||
}
|
||||
|
@ -108,29 +114,103 @@ namespace PlexRequests.Services.Jobs
|
|||
{
|
||||
var sb = new StringBuilder();
|
||||
var plexSettings = PlexSettings.GetSettings();
|
||||
Log.Debug("Got Plex Settings");
|
||||
|
||||
var libs = Api.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||
var tvSection = libs.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
||||
var movieSection = libs.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
||||
Log.Debug("Getting Plex Library Sections");
|
||||
|
||||
var recentlyAddedTv = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection.Key);
|
||||
var recentlyAddedMovies = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, movieSection.Key);
|
||||
var tvSections = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib
|
||||
Log.Debug("Filtered sections for TV");
|
||||
var movieSection = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib
|
||||
Log.Debug("Filtered sections for Movies");
|
||||
|
||||
GenerateMovieHtml(recentlyAddedMovies, plexSettings, sb);
|
||||
GenerateTvHtml(recentlyAddedTv, plexSettings, sb);
|
||||
var plexVersion = Api.GetStatus(plexSettings.PlexAuthToken, plexSettings.FullUri).Version;
|
||||
|
||||
var html = string.Empty;
|
||||
if (plexVersion.StartsWith("1.3"))
|
||||
{
|
||||
var tvMetadata = new List<Metadata>();
|
||||
var movieMetadata = new List<Metadata>();
|
||||
foreach (var tvSection in tvSections)
|
||||
{
|
||||
var item = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
tvSection?.Key);
|
||||
if (item?.MediaContainer?.Metadata != null)
|
||||
{
|
||||
tvMetadata.AddRange(item?.MediaContainer?.Metadata);
|
||||
}
|
||||
}
|
||||
Log.Debug("Got RecentlyAdded TV Shows");
|
||||
foreach (var movie in movieSection)
|
||||
{
|
||||
var recentlyAddedMovies = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key);
|
||||
if (recentlyAddedMovies?.MediaContainer?.Metadata != null)
|
||||
{
|
||||
movieMetadata.AddRange(recentlyAddedMovies?.MediaContainer?.Metadata);
|
||||
}
|
||||
}
|
||||
Log.Debug("Got RecentlyAdded Movies");
|
||||
|
||||
Log.Debug("Started Generating Movie HTML");
|
||||
GenerateMovieHtml(movieMetadata, plexSettings, sb);
|
||||
Log.Debug("Finished Generating Movie HTML");
|
||||
Log.Debug("Started Generating TV HTML");
|
||||
GenerateTvHtml(tvMetadata, plexSettings, sb);
|
||||
Log.Debug("Finished Generating TV HTML");
|
||||
|
||||
var template = new RecentlyAddedTemplate();
|
||||
html = template.LoadTemplate(sb.ToString());
|
||||
Log.Debug("Loaded the template");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old API
|
||||
var tvChild = new List<RecentlyAddedChild>();
|
||||
var movieChild = new List<RecentlyAddedChild>();
|
||||
foreach (var tvSection in tvSections)
|
||||
{
|
||||
var recentlyAddedTv = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection?.Key);
|
||||
if (recentlyAddedTv?._children != null)
|
||||
{
|
||||
tvChild.AddRange(recentlyAddedTv?._children);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug("Got RecentlyAdded TV Shows");
|
||||
foreach (var movie in movieSection)
|
||||
{
|
||||
var recentlyAddedMovies = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key);
|
||||
if (recentlyAddedMovies?._children != null)
|
||||
{
|
||||
tvChild.AddRange(recentlyAddedMovies?._children);
|
||||
}
|
||||
}
|
||||
Log.Debug("Got RecentlyAdded Movies");
|
||||
|
||||
Log.Debug("Started Generating Movie HTML");
|
||||
GenerateMovieHtml(movieChild, plexSettings, sb);
|
||||
Log.Debug("Finished Generating Movie HTML");
|
||||
Log.Debug("Started Generating TV HTML");
|
||||
GenerateTvHtml(tvChild, plexSettings, sb);
|
||||
Log.Debug("Finished Generating TV HTML");
|
||||
|
||||
var template = new RecentlyAddedTemplate();
|
||||
html = template.LoadTemplate(sb.ToString());
|
||||
Log.Debug("Loaded the template");
|
||||
}
|
||||
|
||||
|
||||
var template = new RecentlyAddedTemplate();
|
||||
var html = template.LoadTemplate(sb.ToString());
|
||||
|
||||
Send(newletterSettings, html, plexSettings, testEmail);
|
||||
}
|
||||
|
||||
private void GenerateMovieHtml(RecentlyAddedModel movies, PlexSettings plexSettings, StringBuilder sb)
|
||||
private void GenerateMovieHtml(List<RecentlyAddedChild> movies, PlexSettings plexSettings, StringBuilder sb)
|
||||
{
|
||||
var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<RecentlyAddedChild>();
|
||||
sb.Append("<h1>New Movies:</h1><br/><br/>");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var movie in movies._children.OrderByDescending(x => x.addedAt.UnixTimeStampToDateTime()))
|
||||
foreach (var movie in orderedMovies)
|
||||
{
|
||||
var plexGUID = string.Empty;
|
||||
try
|
||||
|
@ -142,7 +222,10 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(plexGUID);
|
||||
var info = _movieApi.GetMovieInformation(imdbId).Result;
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
throw new Exception($"Movie with Imdb id {imdbId} returned null from the MovieApi");
|
||||
}
|
||||
AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}");
|
||||
|
||||
sb.Append("<tr>");
|
||||
|
@ -176,14 +259,131 @@ namespace PlexRequests.Services.Jobs
|
|||
}
|
||||
sb.Append("</table><br/><br/>");
|
||||
}
|
||||
|
||||
private void GenerateTvHtml(RecentlyAddedModel tv, PlexSettings plexSettings, StringBuilder sb)
|
||||
|
||||
private void GenerateMovieHtml(List<Metadata> movies, PlexSettings plexSettings, StringBuilder sb)
|
||||
{
|
||||
var orderedMovies = movies.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList() ?? new List<Metadata>();
|
||||
sb.Append("<h1>New Movies:</h1><br/><br/>");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var movie in orderedMovies)
|
||||
{
|
||||
var plexGUID = string.Empty;
|
||||
try
|
||||
{
|
||||
var metaData = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
movie.ratingKey.ToString());
|
||||
|
||||
plexGUID = metaData.Video.Guid;
|
||||
|
||||
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(plexGUID);
|
||||
var info = _movieApi.GetMovieInformation(imdbId).Result;
|
||||
if (info == null)
|
||||
{
|
||||
throw new Exception($"Movie with Imdb id {imdbId} returned null from the MovieApi");
|
||||
}
|
||||
AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}");
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.ImdbId}/");
|
||||
Header(sb, 3, $"{info.Title} {info.ReleaseDate?.ToString("yyyy") ?? string.Empty}");
|
||||
EndTag(sb, "a");
|
||||
|
||||
if (info.Genres.Any())
|
||||
{
|
||||
AddParagraph(sb,
|
||||
$"Genre: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, info.Overview);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.Error(
|
||||
"Exception when trying to process a Movie, either in getting the metadata from Plex OR getting the information from TheMovieDB, Plex GUID = {0}",
|
||||
plexGUID);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
|
||||
}
|
||||
sb.Append("</table><br/><br/>");
|
||||
}
|
||||
|
||||
private void GenerateTvHtml(List<RecentlyAddedChild> tv, PlexSettings plexSettings, StringBuilder sb)
|
||||
{
|
||||
var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList();
|
||||
// TV
|
||||
sb.Append("<h1>New Episodes:</h1><br/><br/>");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var t in tv._children.OrderByDescending(x => x.addedAt.UnixTimeStampToDateTime()))
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
var plexGUID = string.Empty;
|
||||
try
|
||||
{
|
||||
|
||||
var parentMetaData = Api.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||
t.parentRatingKey.ToString());
|
||||
|
||||
plexGUID = parentMetaData.Directory.Guid;
|
||||
|
||||
var info = TvApi.ShowLookupByTheTvDbId(int.Parse(PlexHelper.GetProviderIdFromPlexGuid(plexGUID)));
|
||||
|
||||
var banner = info.image?.original;
|
||||
if (!string.IsNullOrEmpty(banner))
|
||||
{
|
||||
banner = banner.Replace("http", "https"); // Always use the Https banners
|
||||
}
|
||||
AddImageInsideTable(sb, banner);
|
||||
|
||||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
var title = $"{t.grandparentTitle} - {t.title} {t.originallyAvailableAt?.Substring(0, 4)}";
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.externals.imdb}/");
|
||||
Header(sb, 3, title);
|
||||
EndTag(sb, "a");
|
||||
|
||||
AddParagraph(sb, $"Season: {t.parentIndex}, Episode: {t.index}");
|
||||
if (info.genres.Any())
|
||||
{
|
||||
AddParagraph(sb, $"Genre: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}");
|
||||
}
|
||||
|
||||
AddParagraph(sb, string.IsNullOrEmpty(t.summary) ? info.summary : t.summary);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
Log.Error(
|
||||
"Exception when trying to process a TV Show, either in getting the metadata from Plex OR getting the information from TVMaze, Plex GUID = {0}",
|
||||
plexGUID);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndLoopHtml(sb);
|
||||
}
|
||||
}
|
||||
sb.Append("</table><br/><br/>");
|
||||
}
|
||||
|
||||
private void GenerateTvHtml(List<Metadata> tv, PlexSettings plexSettings, StringBuilder sb)
|
||||
{
|
||||
var orderedTv = tv.OrderByDescending(x => x?.addedAt.UnixTimeStampToDateTime()).ToList();
|
||||
// TV
|
||||
sb.Append("<h1>New Episodes:</h1><br/><br/>");
|
||||
sb.Append(
|
||||
"<table border=\"0\" cellpadding=\"0\" align=\"center\" cellspacing=\"0\" style=\"border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;\" width=\"100%\">");
|
||||
foreach (var t in orderedTv)
|
||||
{
|
||||
var plexGUID = string.Empty;
|
||||
try
|
||||
|
@ -238,6 +438,7 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false)
|
||||
{
|
||||
Log.Debug("Entering Send");
|
||||
var settings = EmailSettings.GetSettings();
|
||||
|
||||
if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost))
|
||||
|
@ -246,22 +447,24 @@ namespace PlexRequests.Services.Jobs
|
|||
}
|
||||
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = "New Content on Plex!",
|
||||
};
|
||||
Log.Debug("Created Plain/HTML MIME body");
|
||||
|
||||
if (!testEmail)
|
||||
{
|
||||
if (newletterSettings.SendToPlexUsers)
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification);
|
||||
if (users != null)
|
||||
{
|
||||
var users = Api.GetUsers(plexSettings.PlexAuthToken);
|
||||
if (users != null)
|
||||
foreach (var user in users)
|
||||
{
|
||||
foreach (var user in users.User)
|
||||
if (!string.IsNullOrEmpty(user.EmailAddress))
|
||||
{
|
||||
message.Bcc.Add(new MailboxAddress(user.Username, user.Email));
|
||||
message.Bcc.Add(new MailboxAddress(user.Username, user.EmailAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,6 +478,7 @@ namespace PlexRequests.Services.Jobs
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
message.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin
|
||||
|
||||
message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender));
|
||||
|
@ -293,7 +497,9 @@ namespace PlexRequests.Services.Jobs
|
|||
client.Authenticate(settings.EmailUsername, settings.EmailPassword);
|
||||
}
|
||||
Log.Info("sending message to {0} \r\n from: {1}\r\n Are we authenticated: {2}", message.To, message.From, client.IsAuthenticated);
|
||||
Log.Debug("Sending");
|
||||
client.Send(message);
|
||||
Log.Debug("Sent");
|
||||
client.Disconnect(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ namespace PlexRequests.Services.Jobs
|
|||
var settings = SrSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
|
||||
Job.SetRunning(true, JobNames.SrCacher);
|
||||
|
||||
Log.Trace("Getting all shows from SickRage");
|
||||
try
|
||||
{
|
||||
|
@ -79,6 +82,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
Job.Record(JobNames.SrCacher);
|
||||
Job.SetRunning(false, JobNames.SrCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
|||
var settings = SonarrSettings.GetSettings();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
Job.SetRunning(true, JobNames.SonarrCacher);
|
||||
try
|
||||
{
|
||||
var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri);
|
||||
|
@ -80,6 +81,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
Job.Record(JobNames.SonarrCacher);
|
||||
Job.SetRunning(false, JobNames.SonarrCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
TakeBackup();
|
||||
Cleanup();
|
||||
}
|
||||
|
@ -91,6 +92,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.StoreBackup);
|
||||
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -78,12 +78,14 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
JobRecord.Record(JobNames.StoreCleanup);
|
||||
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||
Cleanup();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ namespace PlexRequests.Services.Jobs
|
|||
|
||||
public void Execute(IJobExecutionContext context)
|
||||
{
|
||||
Record.SetRunning(true, JobNames.CpCacher);
|
||||
try
|
||||
{
|
||||
var settings = Settings.GetSettings();
|
||||
|
@ -115,6 +116,7 @@ namespace PlexRequests.Services.Jobs
|
|||
finally
|
||||
{
|
||||
Record.Record(JobNames.RequestLimitReset);
|
||||
Record.SetRunning(false, JobNames.CpCacher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,7 @@
|
|||
public string Artist { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{
|
||||
public class PlexMovie
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
{
|
||||
public class PlexTvShow
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
|
|
|
@ -79,14 +79,22 @@ namespace PlexRequests.Services.Notification
|
|||
await EmailAvailableRequest(model, emailSettings);
|
||||
break;
|
||||
case NotificationType.RequestApproved:
|
||||
throw new NotImplementedException();
|
||||
|
||||
await EmailRequestApproved(model, emailSettings);
|
||||
break;
|
||||
case NotificationType.AdminNote:
|
||||
throw new NotImplementedException();
|
||||
|
||||
case NotificationType.Test:
|
||||
await EmailTest(model, emailSettings);
|
||||
break;
|
||||
case NotificationType.RequestDeclined:
|
||||
await EmailRequestDeclined(model, emailSettings);
|
||||
break;
|
||||
case NotificationType.ItemAddedToFaultQueue:
|
||||
await EmailAddedToRequestQueue(model, emailSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -129,7 +137,7 @@ namespace PlexRequests.Services.Notification
|
|||
$"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!",
|
||||
$"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
|
@ -150,7 +158,7 @@ namespace PlexRequests.Services.Notification
|
|||
$"Plex Requests: New issue for {model.Title}!",
|
||||
$"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!"};
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
|
@ -164,6 +172,69 @@ namespace PlexRequests.Services.Notification
|
|||
await Send(message, settings);
|
||||
}
|
||||
|
||||
private async Task EmailAddedToRequestQueue(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Plex Requests: A request could not be added.",
|
||||
$"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying" };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = $"Plex Requests: A request could not be added"
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
|
||||
message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail));
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
private async Task EmailRequestDeclined(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Plex Requests: Your request has been declined",
|
||||
$"Hello! Your request for {model.Title} has been declined, Sorry!",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! Your request for {model.Title} has been declined, Sorry!", };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = $"Plex Requests: Your request has been declined"
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
|
||||
message.To.Add(new MailboxAddress(model.UserEmail, model.UserEmail));
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
private async Task EmailRequestApproved(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
var email = new EmailBasicTemplate();
|
||||
var html = email.LoadTemplate(
|
||||
"Plex Requests: Your request has been approved!",
|
||||
$"Hello! Your request for {model.Title} has been approved!",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! Your request for {model.Title} has been approved!", };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
Body = body.ToMessageBody(),
|
||||
Subject = $"Plex Requests: Your request has been approved!"
|
||||
};
|
||||
message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender));
|
||||
message.To.Add(new MailboxAddress(model.UserEmail, model.UserEmail));
|
||||
|
||||
|
||||
await Send(message, settings);
|
||||
}
|
||||
|
||||
private async Task EmailAvailableRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||
{
|
||||
if (!settings.EnableUserEmailNotifications)
|
||||
|
@ -175,7 +246,7 @@ namespace PlexRequests.Services.Notification
|
|||
$"Plex Requests: {model.Title} is now available!",
|
||||
$"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)",
|
||||
model.ImgSrc);
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||
var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)" };
|
||||
|
||||
var message = new MimeMessage
|
||||
{
|
||||
|
|
|
@ -34,6 +34,8 @@ using NLog.Fluent;
|
|||
using PlexRequests.Api;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Core.Models;
|
||||
using PlexRequests.Core.Users;
|
||||
using PlexRequests.Helpers.Permissions;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
|
@ -43,19 +45,21 @@ namespace PlexRequests.Services.Notification
|
|||
{
|
||||
public class NotificationEngine : INotificationEngine
|
||||
{
|
||||
public NotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service)
|
||||
public NotificationEngine(IPlexApi p, IRepository<UsersToNotify> repo, INotificationService service, IUserHelper userHelper)
|
||||
{
|
||||
PlexApi = p;
|
||||
UserNotifyRepo = repo;
|
||||
Notification = service;
|
||||
UserHelper = userHelper;
|
||||
}
|
||||
|
||||
private IPlexApi PlexApi { get; }
|
||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private INotificationService Notification { get; }
|
||||
private IUserHelper UserHelper { get; }
|
||||
|
||||
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey)
|
||||
public async Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -63,24 +67,38 @@ namespace PlexRequests.Services.Notification
|
|||
var userAccount = PlexApi.GetAccount(apiKey);
|
||||
|
||||
var adminUsername = userAccount.Username ?? string.Empty;
|
||||
|
||||
var users = UserNotifyRepo.GetAll().ToList();
|
||||
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
foreach (var model in modelChanged)
|
||||
{
|
||||
var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
|
||||
var selectedUsers = new List<string>();
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
var requestUser = model.RequestedUsers.FirstOrDefault(
|
||||
x => x.Equals(u.Username, StringComparison.CurrentCultureIgnoreCase) || x.Equals(u.UserAlias, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (string.IsNullOrEmpty(requestUser))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
selectedUsers.Add(requestUser);
|
||||
}
|
||||
|
||||
//var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
|
||||
foreach (var user in selectedUsers)
|
||||
{
|
||||
Log.Info("Notifying user {0}", user);
|
||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Plex server owner");
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath);
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath, type);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (email == null)
|
||||
if (string.IsNullOrEmpty(email?.Email))
|
||||
{
|
||||
Log.Info("There is no email address for this Plex user, cannot send notification");
|
||||
// We do not have a plex user that requested this!
|
||||
|
@ -88,7 +106,7 @@ namespace PlexRequests.Services.Notification
|
|||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +116,7 @@ namespace PlexRequests.Services.Notification
|
|||
}
|
||||
}
|
||||
|
||||
public async Task NotifyUsers(RequestedModel model, string apiKey)
|
||||
public async Task NotifyUsers(RequestedModel model, string apiKey, NotificationType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -107,7 +125,7 @@ namespace PlexRequests.Services.Notification
|
|||
|
||||
var adminUsername = userAccount.Username ?? string.Empty;
|
||||
|
||||
var users = UserNotifyRepo.GetAll().ToList();
|
||||
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification).ToList();
|
||||
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||
|
||||
var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
|
||||
|
@ -117,7 +135,7 @@ namespace PlexRequests.Services.Notification
|
|||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Log.Info("This user is the Plex server owner");
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath);
|
||||
await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath, type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -130,7 +148,7 @@ namespace PlexRequests.Services.Notification
|
|||
}
|
||||
|
||||
Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath);
|
||||
await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath, type);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -139,13 +157,13 @@ namespace PlexRequests.Services.Notification
|
|||
}
|
||||
}
|
||||
|
||||
private async Task PublishUserNotification(string username, string email, string title, string img)
|
||||
private async Task PublishUserNotification(string username, string email, string title, string img, NotificationType type)
|
||||
{
|
||||
var notificationModel = new NotificationModel
|
||||
{
|
||||
User = username,
|
||||
UserEmail = email,
|
||||
NotificationType = NotificationType.RequestAvailable,
|
||||
NotificationType = type,
|
||||
Title = title,
|
||||
ImgSrc = img
|
||||
};
|
||||
|
|
|
@ -81,6 +81,11 @@ namespace PlexRequests.Services.Notification
|
|||
case NotificationType.Test:
|
||||
await PushTestAsync(pushSettings);
|
||||
break;
|
||||
case NotificationType.RequestDeclined:
|
||||
break;
|
||||
case NotificationType.ItemAddedToFaultQueue:
|
||||
await PushFaultQueue(model, pushSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
@ -125,6 +130,13 @@ namespace PlexRequests.Services.Notification
|
|||
await Push(settings, message, pushTitle);
|
||||
}
|
||||
|
||||
private async Task PushFaultQueue(NotificationModel model, PushbulletNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
var pushTitle = $"Plex Requests: The {model.RequestType.GetString()?.ToLower()} {model.Title} has been requested but could not be added!";
|
||||
await Push(settings, message, pushTitle);
|
||||
}
|
||||
|
||||
private async Task Push(PushbulletNotificationSettings settings, string message, string title)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -81,6 +81,11 @@ namespace PlexRequests.Services.Notification
|
|||
case NotificationType.Test:
|
||||
await PushTestAsync(model, pushSettings);
|
||||
break;
|
||||
case NotificationType.RequestDeclined:
|
||||
break;
|
||||
case NotificationType.ItemAddedToFaultQueue:
|
||||
await PushFaultQueue(model, pushSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
@ -122,6 +127,12 @@ namespace PlexRequests.Services.Notification
|
|||
await Push(settings, message);
|
||||
}
|
||||
|
||||
private async Task PushFaultQueue(NotificationModel model, PushoverNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
await Push(settings, message);
|
||||
}
|
||||
|
||||
private async Task Push(PushoverNotificationSettings settings, string message)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -88,6 +88,11 @@ namespace PlexRequests.Services.Notification
|
|||
case NotificationType.Test:
|
||||
await PushTest(pushSettings);
|
||||
break;
|
||||
case NotificationType.RequestDeclined:
|
||||
break;
|
||||
case NotificationType.ItemAddedToFaultQueue:
|
||||
await PushFaultQueue(model, pushSettings);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
@ -111,6 +116,12 @@ namespace PlexRequests.Services.Notification
|
|||
await Push(settings, message);
|
||||
}
|
||||
|
||||
private async Task PushFaultQueue(NotificationModel model, SlackNotificationSettings settings)
|
||||
{
|
||||
var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||
await Push(settings, message);
|
||||
}
|
||||
|
||||
private async Task Push(SlackNotificationSettings config, string message)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -81,18 +89,22 @@
|
|||
<Compile Include="Interfaces\IJobRecord.cs" />
|
||||
<Compile Include="Interfaces\INotificationEngine.cs" />
|
||||
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
||||
<Compile Include="Jobs\IPlexContentCacher.cs" />
|
||||
<Compile Include="Jobs\IRecentlyAdded.cs" />
|
||||
<Compile Include="Jobs\JobRecord.cs" />
|
||||
<Compile Include="Jobs\JobNames.cs" />
|
||||
<Compile Include="Jobs\PlexContentCacher.cs" />
|
||||
<Compile Include="Jobs\PlexEpisodeCacher.cs" />
|
||||
<Compile Include="Jobs\RecentlyAdded.cs" />
|
||||
<Compile Include="Jobs\StoreBackup.cs" />
|
||||
<Compile Include="Jobs\PlexUserChecker.cs" />
|
||||
<Compile Include="Jobs\StoreCleanup.cs" />
|
||||
<Compile Include="Jobs\CouchPotatoCacher.cs" />
|
||||
<Compile Include="Jobs\PlexAvailabilityChecker.cs" />
|
||||
<Compile Include="Jobs\SickRageCacher.cs" />
|
||||
<Compile Include="Jobs\SonarrCacher.cs" />
|
||||
<Compile Include="Jobs\Templates\RecentlyAddedTemplate.cs" />
|
||||
<Compile Include="Jobs\FaultQueueHandler.cs" />
|
||||
<Compile Include="Jobs\UserRequestLimitResetter.cs" />
|
||||
<Compile Include="Models\PlexAlbum.cs" />
|
||||
<Compile Include="Models\PlexEpisodeModel.cs" />
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
||||
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
||||
<package id="MimeKit" version="1.2.22" targetFramework="net45" />
|
||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||
</packages>
|
52
PlexRequests.Store/Models/Plex/PlexContent.cs
Normal file
52
PlexRequests.Store/Models/Plex/PlexContent.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexContent.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Data.Linq.Mapping;
|
||||
|
||||
namespace PlexRequests.Store.Models.Plex
|
||||
{
|
||||
[Table(Name = nameof(PlexContent))]
|
||||
public class PlexContent : Entity
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string ReleaseYear { get; set; }
|
||||
public string ProviderId { get; set; }
|
||||
public PlexMediaType Type { get; set; }
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only used for TV Shows
|
||||
/// </summary>
|
||||
public byte[] Seasons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only used for Albums
|
||||
/// </summary>
|
||||
public string Artist { get; set; }
|
||||
}
|
||||
}
|
35
PlexRequests.Store/Models/Plex/PlexMediaType .cs
Normal file
35
PlexRequests.Store/Models/Plex/PlexMediaType .cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: PlexMediaType .cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
namespace PlexRequests.Store.Models.Plex
|
||||
{
|
||||
public enum PlexMediaType
|
||||
{
|
||||
Movie = 0,
|
||||
Show = 1,
|
||||
Artist = 2
|
||||
}
|
||||
}
|
|
@ -24,11 +24,21 @@
|
|||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Dapper.Contrib.Extensions;
|
||||
|
||||
namespace PlexRequests.Store.Models
|
||||
{
|
||||
[Table(nameof(PlexUsers))]
|
||||
public class PlexUsers : Entity
|
||||
{
|
||||
public int PlexUserId { get; set; }
|
||||
public string PlexUserId { get; set; }
|
||||
public string UserAlias { get; set; }
|
||||
public int Permissions { get; set; }
|
||||
public int Features { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
}
|
||||
}
|
52
PlexRequests.Store/Models/RequestQueue.cs
Normal file
52
PlexRequests.Store/Models/RequestQueue.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: RequestQueue.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Dapper.Contrib.Extensions;
|
||||
|
||||
namespace PlexRequests.Store.Models
|
||||
{
|
||||
[Table("RequestFaultQueue")]
|
||||
public class RequestQueue : Entity
|
||||
{
|
||||
public string PrimaryIdentifier { get; set; }
|
||||
|
||||
public RequestType Type { get; set; }
|
||||
|
||||
public byte[] Content { get; set; }
|
||||
|
||||
public FaultType FaultType { get; set; }
|
||||
public DateTime? LastRetry { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public enum FaultType
|
||||
{
|
||||
RequestFault,
|
||||
MissingInformation
|
||||
}
|
||||
}
|
|
@ -35,5 +35,6 @@ namespace PlexRequests.Store.Models
|
|||
{
|
||||
public string Name { get; set; }
|
||||
public DateTime LastRun { get; set; }
|
||||
public bool Running { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
<Compile Include="Models\PlexEpisodes.cs" />
|
||||
<Compile Include="Models\PlexUsers.cs" />
|
||||
<Compile Include="Models\Plex\MetadataItems.cs" />
|
||||
<Compile Include="Models\Plex\PlexContent.cs" />
|
||||
<Compile Include="Models\Plex\PlexMediaType .cs" />
|
||||
<Compile Include="Models\RequestQueue.cs" />
|
||||
<Compile Include="Models\ScheduledJobs.cs" />
|
||||
<Compile Include="Models\RequestLimit.cs" />
|
||||
<Compile Include="Models\UsersToNotify.cs" />
|
||||
|
@ -85,6 +88,8 @@
|
|||
<Compile Include="Repository\SettingsJsonRepository.cs" />
|
||||
<Compile Include="Repository\RequestJsonRepository.cs" />
|
||||
<Compile Include="Repository\GenericRepository.cs" />
|
||||
<Compile Include="Repository\PlexUserRepository.cs" />
|
||||
<Compile Include="Repository\UserRepository.cs" />
|
||||
<Compile Include="RequestedModel.cs" />
|
||||
<Compile Include="UserEntity.cs" />
|
||||
<Compile Include="UserLogins.cs" />
|
||||
|
|
|
@ -327,5 +327,22 @@ namespace PlexRequests.Store.Repository
|
|||
throw;
|
||||
}
|
||||
}
|
||||
public async Task DeleteAllAsync(string tableName)
|
||||
{
|
||||
try
|
||||
{
|
||||
ResetCache();
|
||||
using (var db = Config.DbConnection())
|
||||
{
|
||||
db.Open();
|
||||
await db.ExecuteAsync($"delete from {tableName}");
|
||||
}
|
||||
}
|
||||
catch (SqliteException e) when (e.ErrorCode == SQLiteErrorCode.Corrupt)
|
||||
{
|
||||
Log.Fatal(CorruptMessage);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,5 +85,6 @@ namespace PlexRequests.Store.Repository
|
|||
IEnumerable<T> Custom(Func<IDbConnection, IEnumerable<T>> func);
|
||||
Task<IEnumerable<T>> CustomAsync(Func<IDbConnection, Task<IEnumerable<T>>> func);
|
||||
void DeleteAll(string tableName);
|
||||
Task DeleteAllAsync(string tableName);
|
||||
}
|
||||
}
|
||||
|
|
118
PlexRequests.Store/Repository/PlexUserRepository.cs
Normal file
118
PlexRequests.Store/Repository/PlexUserRepository.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserRepository.cs
|
||||
// Created By:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using Dapper.Contrib.Extensions;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Store.Models;
|
||||
|
||||
namespace PlexRequests.Store.Repository
|
||||
{
|
||||
public class PlexUserRepository : BaseGenericRepository<PlexUsers>, IPlexUserRepository
|
||||
{
|
||||
public PlexUserRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config,cache)
|
||||
{
|
||||
DbConfig = config;
|
||||
}
|
||||
|
||||
private ISqliteConfiguration DbConfig { get; }
|
||||
private IDbConnection Db => DbConfig.DbConnection();
|
||||
|
||||
public PlexUsers GetUser(string userGuid)
|
||||
{
|
||||
var sql = @"SELECT * FROM PlexUsers
|
||||
WHERE PlexUserId = @UserGuid";
|
||||
return Db.QueryFirstOrDefault<PlexUsers>(sql, new {UserGuid = userGuid});
|
||||
}
|
||||
|
||||
public PlexUsers GetUserByUsername(string username)
|
||||
{
|
||||
var sql = @"SELECT * FROM PlexUsers
|
||||
WHERE Username = @UserName";
|
||||
return Db.QueryFirstOrDefault<PlexUsers>(sql, new {UserName = username});
|
||||
}
|
||||
|
||||
public async Task<PlexUsers> GetUserAsync(string userguid)
|
||||
{
|
||||
var sql = @"SELECT * FROM PlexUsers
|
||||
WHERE PlexUserId = @UserGuid";
|
||||
return await Db.QueryFirstOrDefaultAsync<PlexUsers>(sql, new {UserGuid = userguid});
|
||||
}
|
||||
|
||||
#region abstract implementation
|
||||
|
||||
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
|
||||
[Obsolete]
|
||||
public override PlexUsers Get(string id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override Task<PlexUsers> GetAsync(int id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override PlexUsers Get(int id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override Task<PlexUsers> GetAsync(string id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public interface IPlexUserRepository
|
||||
{
|
||||
PlexUsers GetUser(string userGuid);
|
||||
PlexUsers GetUserByUsername(string username);
|
||||
Task<PlexUsers> GetUserAsync(string userguid);
|
||||
IEnumerable<PlexUsers> Custom(Func<IDbConnection, IEnumerable<PlexUsers>> func);
|
||||
long Insert(PlexUsers entity);
|
||||
void Delete(PlexUsers entity);
|
||||
IEnumerable<PlexUsers> GetAll();
|
||||
bool UpdateAll(IEnumerable<PlexUsers> entity);
|
||||
bool Update(PlexUsers entity);
|
||||
Task<IEnumerable<PlexUsers>> GetAllAsync();
|
||||
Task<bool> UpdateAsync(PlexUsers users);
|
||||
Task<int> InsertAsync(PlexUsers users);
|
||||
}
|
||||
}
|
||||
|
114
PlexRequests.Store/Repository/UserRepository.cs
Normal file
114
PlexRequests.Store/Repository/UserRepository.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: UserRepository.cs
|
||||
// Created By:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using Dapper.Contrib.Extensions;
|
||||
using PlexRequests.Helpers;
|
||||
|
||||
namespace PlexRequests.Store.Repository
|
||||
{
|
||||
public class UserRepository : BaseGenericRepository<UsersModel>, IUserRepository
|
||||
{
|
||||
public UserRepository(ISqliteConfiguration config, ICacheProvider cache) : base(config,cache)
|
||||
{
|
||||
DbConfig = config;
|
||||
}
|
||||
|
||||
private ISqliteConfiguration DbConfig { get; }
|
||||
private IDbConnection Db => DbConfig.DbConnection();
|
||||
|
||||
public UsersModel GetUser(string userGuid)
|
||||
{
|
||||
var sql = @"SELECT * FROM Users
|
||||
WHERE Userguid = @UserGuid";
|
||||
return Db.QueryFirstOrDefault<UsersModel>(sql, new {UserGuid = userGuid});
|
||||
}
|
||||
|
||||
public UsersModel GetUserByUsername(string username)
|
||||
{
|
||||
var sql = @"SELECT * FROM Users
|
||||
WHERE UserName = @UserName";
|
||||
return Db.QueryFirstOrDefault<UsersModel>(sql, new {UserName = username});
|
||||
}
|
||||
|
||||
public async Task<UsersModel> GetUserAsync(string userguid)
|
||||
{
|
||||
var sql = @"SELECT * FROM Users
|
||||
WHERE UserGuid = @UserGuid";
|
||||
return await Db.QueryFirstOrDefaultAsync<UsersModel>(sql, new {UserGuid = userguid});
|
||||
}
|
||||
|
||||
#region abstract implementation
|
||||
|
||||
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
|
||||
[Obsolete]
|
||||
public override UsersModel Get(string id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override Task<UsersModel> GetAsync(int id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override UsersModel Get(int id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public override Task<UsersModel> GetAsync(string id)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public interface IUserRepository
|
||||
{
|
||||
UsersModel GetUser(string userGuid);
|
||||
UsersModel GetUserByUsername(string username);
|
||||
Task<UsersModel> GetUserAsync(string userguid);
|
||||
IEnumerable<UsersModel> Custom(Func<IDbConnection, IEnumerable<UsersModel>> func);
|
||||
long Insert(UsersModel entity);
|
||||
void Delete(UsersModel entity);
|
||||
IEnumerable<UsersModel> GetAll();
|
||||
bool UpdateAll(IEnumerable<UsersModel> entity);
|
||||
bool Update(UsersModel entity);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,10 @@ CREATE TABLE IF NOT EXISTS Users
|
|||
UserName varchar(50) NOT NULL,
|
||||
Salt BLOB NOT NULL,
|
||||
Hash BLOB NOT NULL,
|
||||
Claims BLOB NOT NULL,
|
||||
UserProperties BLOB
|
||||
UserProperties BLOB,
|
||||
Permissions INTEGER,
|
||||
Features INTEGER,
|
||||
Claims BLOB
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS UserLogins
|
||||
|
@ -78,7 +80,8 @@ CREATE TABLE IF NOT EXISTS ScheduledJobs
|
|||
(
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Name varchar(100) NOT NULL,
|
||||
LastRun varchar(100) NOT NULL
|
||||
LastRun varchar(100) NOT NULL,
|
||||
Running INTEGER
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS ScheduledJobs_Id ON ScheduledJobs (Id);
|
||||
|
||||
|
@ -111,8 +114,13 @@ CREATE UNIQUE INDEX IF NOT EXISTS RequestLimit_Id ON RequestLimit (Id);
|
|||
CREATE TABLE IF NOT EXISTS PlexUsers
|
||||
(
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
PlexUserId INTEGER NOT NULL,
|
||||
UserAlias varchar(100) NOT NULL
|
||||
PlexUserId varchar(100) NOT NULL,
|
||||
UserAlias varchar(100) NOT NULL,
|
||||
Permissions INTEGER,
|
||||
Features INTEGER,
|
||||
Username VARCHAR(100),
|
||||
EmailAddress VARCHAR(100),
|
||||
LoginId VARCHAR(100)
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id);
|
||||
|
||||
|
@ -129,4 +137,31 @@ CREATE TABLE IF NOT EXISTS PlexEpisodes
|
|||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS PlexEpisodes_Id ON PlexEpisodes (Id);
|
||||
CREATE INDEX IF NOT EXISTS PlexEpisodes_ProviderId ON PlexEpisodes (ProviderId);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS RequestFaultQueue
|
||||
(
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
PrimaryIdentifier VARCHAR(100) NOT NULL,
|
||||
Type INTEGER NOT NULL,
|
||||
FaultType INTEGER NOT NULL,
|
||||
Content BLOB NOT NULL,
|
||||
LastRetry VARCHAR(100),
|
||||
Description VARCHAR(100)
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PlexContent
|
||||
(
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Title VARCHAR(100) NOT NULL,
|
||||
ReleaseYear VARCHAR(100) NOT NULL,
|
||||
ProviderId VARCHAR(100) NOT NULL,
|
||||
Url VARCHAR(100) NOT NULL,
|
||||
Artist VARCHAR(100),
|
||||
Seasons BLOB,
|
||||
Type INTEGER NOT NULL
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS PlexContent_Id ON PlexContent (Id);
|
||||
|
||||
COMMIT;
|
|
@ -57,12 +57,13 @@ namespace PlexRequests.Store
|
|||
}
|
||||
}
|
||||
|
||||
public static void AddColumn(this IDbConnection connection, string tableName, string alterType, string newColumn, bool allowNulls, string dataType)
|
||||
public static void AlterTable(this IDbConnection connection, string tableName, string alterType, string newColumn, bool allowNulls, string dataType)
|
||||
{
|
||||
connection.Open();
|
||||
var result = connection.Query<TableInfo>($"PRAGMA table_info({tableName});");
|
||||
if (result.Any(x => x.name == newColumn))
|
||||
{
|
||||
connection.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,10 @@ namespace PlexRequests.Store
|
|||
{
|
||||
public byte[] Hash { get; set; }
|
||||
public byte[] Salt { get; set; }
|
||||
[Obsolete]
|
||||
public byte[] Claims { get; set; }
|
||||
public byte[] UserProperties { get; set; }
|
||||
public int Permissions { get; set; }
|
||||
public int Features { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,164 +1,167 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SearchModuleTests.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
//#region Copyright
|
||||
//// /************************************************************************
|
||||
//// Copyright (c) 2016 Jamie Rees
|
||||
//// File: SearchModuleTests.cs
|
||||
//// Created By: Jamie Rees
|
||||
////
|
||||
//// Permission is hereby granted, free of charge, to any person obtaining
|
||||
//// a copy of this software and associated documentation files (the
|
||||
//// "Software"), to deal in the Software without restriction, including
|
||||
//// without limitation the rights to use, copy, modify, merge, publish,
|
||||
//// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
//// permit persons to whom the Software is furnished to do so, subject to
|
||||
//// the following conditions:
|
||||
////
|
||||
//// The above copyright notice and this permission notice shall be
|
||||
//// included in all copies or substantial portions of the Software.
|
||||
////
|
||||
//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
//// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
//// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
//// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
//// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
//// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
//// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//// ************************************************************************/
|
||||
//#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Analytics;
|
||||
using PlexRequests.Services.Interfaces;
|
||||
using PlexRequests.Services.Jobs;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.Store.Models;
|
||||
using PlexRequests.Store.Repository;
|
||||
using PlexRequests.UI.Modules;
|
||||
using Ploeh.AutoFixture;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using Moq;
|
||||
//using NUnit.Framework;
|
||||
//using PlexRequests.Api.Interfaces;
|
||||
//using PlexRequests.Api.Models.Plex;
|
||||
//using PlexRequests.Core;
|
||||
//using PlexRequests.Core.Queue;
|
||||
//using PlexRequests.Core.SettingModels;
|
||||
//using PlexRequests.Helpers;
|
||||
//using PlexRequests.Helpers.Analytics;
|
||||
//using PlexRequests.Services.Interfaces;
|
||||
//using PlexRequests.Services.Jobs;
|
||||
//using PlexRequests.Store;
|
||||
//using PlexRequests.Store.Models;
|
||||
//using PlexRequests.Store.Repository;
|
||||
//using PlexRequests.UI.Modules;
|
||||
//using Ploeh.AutoFixture;
|
||||
|
||||
namespace PlexRequests.UI.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SearchModuleTests
|
||||
{
|
||||
private Mock<ISettingsService<HeadphonesSettings>> _headphonesSettings;
|
||||
private Mock<INotificationService> _notificationService;
|
||||
private Mock<ISettingsService<SickRageSettings>> _sickRageSettingsMock;
|
||||
private Mock<ICouchPotatoApi> _cpApi;
|
||||
private Mock<ISettingsService<SonarrSettings>> _sonarrSettingsMock;
|
||||
private Mock<ISonarrApi> _sonarrApiMock;
|
||||
private Mock<ISettingsService<PlexSettings>> _plexSettingsMock;
|
||||
private Mock<ISettingsService<CouchPotatoSettings>> _cpMock;
|
||||
private Mock<ISettingsService<PlexRequestSettings>> _plexRequestMock;
|
||||
private Mock<ISettingsService<AuthenticationSettings>> _authMock;
|
||||
private Mock<IAnalytics> _analytics;
|
||||
private Mock<IAvailabilityChecker> _availabilityMock;
|
||||
private Mock<IRequestService> _rServiceMock;
|
||||
private Mock<ISickRageApi> _srApi;
|
||||
private Mock<IMusicBrainzApi> _music;
|
||||
private Mock<IHeadphonesApi> _hpAPi;
|
||||
private Mock<ICouchPotatoCacher> _cpCache;
|
||||
private Mock<ISonarrCacher> _sonarrCache;
|
||||
private Mock<ISickRageCacher> _srCache;
|
||||
private Mock<IPlexApi> _plexApi;
|
||||
private Mock<IRepository<UsersToNotify>> _userRepo;
|
||||
private Mock<ISettingsService<EmailNotificationSettings>> _emailSettings;
|
||||
private Mock<IIssueService> _issueService;
|
||||
private Mock<ICacheProvider> _cache;
|
||||
private Mock<IRepository<RequestLimit>> RequestLimitRepo { get; set; }
|
||||
private SearchModule Search { get; set; }
|
||||
private readonly Fixture F = new Fixture();
|
||||
//namespace PlexRequests.UI.Tests
|
||||
//{
|
||||
// [TestFixture]
|
||||
// public class SearchModuleTests
|
||||
// {
|
||||
// private Mock<ISettingsService<HeadphonesSettings>> _headphonesSettings;
|
||||
// private Mock<INotificationService> _notificationService;
|
||||
// private Mock<ISettingsService<SickRageSettings>> _sickRageSettingsMock;
|
||||
// private Mock<ICouchPotatoApi> _cpApi;
|
||||
// private Mock<ISettingsService<SonarrSettings>> _sonarrSettingsMock;
|
||||
// private Mock<ISonarrApi> _sonarrApiMock;
|
||||
// private Mock<ISettingsService<PlexSettings>> _plexSettingsMock;
|
||||
// private Mock<ISettingsService<CouchPotatoSettings>> _cpMock;
|
||||
// private Mock<ISettingsService<PlexRequestSettings>> _plexRequestMock;
|
||||
// private Mock<ISettingsService<AuthenticationSettings>> _authMock;
|
||||
// private Mock<IAnalytics> _analytics;
|
||||
// private Mock<IAvailabilityChecker> _availabilityMock;
|
||||
// private Mock<IRequestService> _rServiceMock;
|
||||
// private Mock<ISickRageApi> _srApi;
|
||||
// private Mock<IMusicBrainzApi> _music;
|
||||
// private Mock<IHeadphonesApi> _hpAPi;
|
||||
// private Mock<ICouchPotatoCacher> _cpCache;
|
||||
// private Mock<ISonarrCacher> _sonarrCache;
|
||||
// private Mock<ISickRageCacher> _srCache;
|
||||
// private Mock<IPlexApi> _plexApi;
|
||||
// private Mock<IRepository<UsersToNotify>> _userRepo;
|
||||
// private Mock<ISettingsService<EmailNotificationSettings>> _emailSettings;
|
||||
// private Mock<IIssueService> _issueService;
|
||||
// private Mock<ICacheProvider> _cache;
|
||||
// private Mock<ITransientFaultQueue> _faultQueue;
|
||||
// private Mock<IRepository<RequestLimit>> RequestLimitRepo { get; set; }
|
||||
// private SearchModule Search { get; set; }
|
||||
// private readonly Fixture F = new Fixture();
|
||||
|
||||
[Test]
|
||||
public void CheckNoRequestLimitTest()
|
||||
{
|
||||
var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 2, TvWeeklyRequestLimit = 0 };
|
||||
var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
||||
// [Test]
|
||||
// public void CheckNoRequestLimitTest()
|
||||
// {
|
||||
// var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 2, TvWeeklyRequestLimit = 0 };
|
||||
// var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
||||
|
||||
Assert.That(result, Is.True);
|
||||
RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
||||
}
|
||||
// Assert.That(result, Is.True);
|
||||
// RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
||||
// }
|
||||
|
||||
[TestCaseSource(nameof(MovieLimitData))]
|
||||
public bool CheckMovieLimitTest(int requestCount)
|
||||
{
|
||||
var users = F.CreateMany<RequestLimit>().ToList();
|
||||
users.Add(new RequestLimit { Username = "", RequestCount = requestCount, RequestType = RequestType.Movie});
|
||||
RequestLimitRepo.Setup(x => x.GetAllAsync()).ReturnsAsync(users);
|
||||
var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 5, TvWeeklyRequestLimit = 0 };
|
||||
var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
||||
// [TestCaseSource(nameof(MovieLimitData))]
|
||||
// public bool CheckMovieLimitTest(int requestCount)
|
||||
// {
|
||||
// var users = F.CreateMany<RequestLimit>().ToList();
|
||||
// users.Add(new RequestLimit { Username = "", RequestCount = requestCount, RequestType = RequestType.Movie});
|
||||
// RequestLimitRepo.Setup(x => x.GetAllAsync()).ReturnsAsync(users);
|
||||
// var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 5, TvWeeklyRequestLimit = 0 };
|
||||
// var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
||||
|
||||
RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
||||
// RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
||||
|
||||
return result;
|
||||
}
|
||||
// return result;
|
||||
// }
|
||||
|
||||
private static IEnumerable<TestCaseData> MovieLimitData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData(1).Returns(true).SetName("1 Request of 5");
|
||||
yield return new TestCaseData(2).Returns(true).SetName("2 Request of 5");
|
||||
yield return new TestCaseData(3).Returns(true).SetName("3 Request of 5");
|
||||
yield return new TestCaseData(4).Returns(true).SetName("4 Request of 5");
|
||||
yield return new TestCaseData(5).Returns(false).SetName("5 Request of 5");
|
||||
yield return new TestCaseData(6).Returns(false).SetName("6 Request of 5");
|
||||
yield return new TestCaseData(0).Returns(true).SetName("0 Request of 5");
|
||||
}
|
||||
}
|
||||
// private static IEnumerable<TestCaseData> MovieLimitData
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return new TestCaseData(1).Returns(true).SetName("1 Request of 5");
|
||||
// yield return new TestCaseData(2).Returns(true).SetName("2 Request of 5");
|
||||
// yield return new TestCaseData(3).Returns(true).SetName("3 Request of 5");
|
||||
// yield return new TestCaseData(4).Returns(true).SetName("4 Request of 5");
|
||||
// yield return new TestCaseData(5).Returns(false).SetName("5 Request of 5");
|
||||
// yield return new TestCaseData(6).Returns(false).SetName("6 Request of 5");
|
||||
// yield return new TestCaseData(0).Returns(true).SetName("0 Request of 5");
|
||||
// }
|
||||
// }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_authMock = new Mock<Core.ISettingsService<AuthenticationSettings>>();
|
||||
_plexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
|
||||
_plexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
|
||||
_cpMock = new Mock<Core.ISettingsService<CouchPotatoSettings>>();
|
||||
_plexSettingsMock = new Mock<Core.ISettingsService<PlexSettings>>();
|
||||
_sonarrApiMock = new Mock<ISonarrApi>();
|
||||
_sonarrSettingsMock = new Mock<Core.ISettingsService<SonarrSettings>>();
|
||||
_cpApi = new Mock<ICouchPotatoApi>();
|
||||
_sickRageSettingsMock = new Mock<Core.ISettingsService<SickRageSettings>>();
|
||||
_notificationService = new Mock<INotificationService>();
|
||||
_headphonesSettings = new Mock<Core.ISettingsService<HeadphonesSettings>>();
|
||||
_cache = new Mock<ICacheProvider>();
|
||||
// [SetUp]
|
||||
// public void Setup()
|
||||
// {
|
||||
// _authMock = new Mock<Core.ISettingsService<AuthenticationSettings>>();
|
||||
// _plexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
|
||||
// _plexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
|
||||
// _cpMock = new Mock<Core.ISettingsService<CouchPotatoSettings>>();
|
||||
// _plexSettingsMock = new Mock<Core.ISettingsService<PlexSettings>>();
|
||||
// _sonarrApiMock = new Mock<ISonarrApi>();
|
||||
// _sonarrSettingsMock = new Mock<Core.ISettingsService<SonarrSettings>>();
|
||||
// _cpApi = new Mock<ICouchPotatoApi>();
|
||||
// _sickRageSettingsMock = new Mock<Core.ISettingsService<SickRageSettings>>();
|
||||
// _notificationService = new Mock<INotificationService>();
|
||||
// _headphonesSettings = new Mock<Core.ISettingsService<HeadphonesSettings>>();
|
||||
// _cache = new Mock<ICacheProvider>();
|
||||
|
||||
_analytics = new Mock<IAnalytics>();
|
||||
_availabilityMock = new Mock<IAvailabilityChecker>();
|
||||
_rServiceMock = new Mock<IRequestService>();
|
||||
_srApi = new Mock<ISickRageApi>();
|
||||
_music = new Mock<IMusicBrainzApi>();
|
||||
_hpAPi = new Mock<IHeadphonesApi>();
|
||||
_cpCache = new Mock<ICouchPotatoCacher>();
|
||||
_sonarrCache = new Mock<ISonarrCacher>();
|
||||
_srCache = new Mock<ISickRageCacher>();
|
||||
_plexApi = new Mock<IPlexApi>();
|
||||
_userRepo = new Mock<IRepository<UsersToNotify>>();
|
||||
RequestLimitRepo = new Mock<IRepository<RequestLimit>>();
|
||||
_emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
||||
_issueService = new Mock<IIssueService>();
|
||||
CreateModule();
|
||||
}
|
||||
// _analytics = new Mock<IAnalytics>();
|
||||
// _availabilityMock = new Mock<IAvailabilityChecker>();
|
||||
// _rServiceMock = new Mock<IRequestService>();
|
||||
// _srApi = new Mock<ISickRageApi>();
|
||||
// _music = new Mock<IMusicBrainzApi>();
|
||||
// _hpAPi = new Mock<IHeadphonesApi>();
|
||||
// _cpCache = new Mock<ICouchPotatoCacher>();
|
||||
// _sonarrCache = new Mock<ISonarrCacher>();
|
||||
// _srCache = new Mock<ISickRageCacher>();
|
||||
// _plexApi = new Mock<IPlexApi>();
|
||||
// _userRepo = new Mock<IRepository<UsersToNotify>>();
|
||||
// RequestLimitRepo = new Mock<IRepository<RequestLimit>>();
|
||||
// _emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
||||
// _issueService = new Mock<IIssueService>();
|
||||
// _faultQueue = new Mock<ITransientFaultQueue>();
|
||||
// CreateModule();
|
||||
// }
|
||||
|
||||
private void CreateModule()
|
||||
{
|
||||
Search = new SearchModule(_cache.Object, _cpMock.Object, _plexRequestMock.Object, _availabilityMock.Object,
|
||||
_rServiceMock.Object, _sonarrApiMock.Object, _sonarrSettingsMock.Object,
|
||||
_sickRageSettingsMock.Object, _cpApi.Object, _srApi.Object, _notificationService.Object,
|
||||
_music.Object, _hpAPi.Object, _headphonesSettings.Object, _cpCache.Object, _sonarrCache.Object,
|
||||
_srCache.Object, _plexApi.Object, _plexSettingsMock.Object, _authMock.Object,
|
||||
_userRepo.Object, _emailSettings.Object, _issueService.Object, _analytics.Object, RequestLimitRepo.Object);
|
||||
}
|
||||
// private void CreateModule()
|
||||
// {
|
||||
// Search = new SearchModule(_cache.Object, _cpMock.Object, _plexRequestMock.Object, _availabilityMock.Object,
|
||||
// _rServiceMock.Object, _sonarrApiMock.Object, _sonarrSettingsMock.Object,
|
||||
// _sickRageSettingsMock.Object, _cpApi.Object, _srApi.Object, _notificationService.Object,
|
||||
// _music.Object, _hpAPi.Object, _headphonesSettings.Object, _cpCache.Object, _sonarrCache.Object,
|
||||
// _srCache.Object, _plexApi.Object, _plexSettingsMock.Object, _authMock.Object,
|
||||
// _userRepo.Object, _emailSettings.Object, _issueService.Object, _analytics.Object, RequestLimitRepo.Object, _faultQueue.Object);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
// }
|
||||
//}
|
|
@ -35,6 +35,7 @@ using NUnit.Framework;
|
|||
|
||||
using PlexRequests.Api.Interfaces;
|
||||
using PlexRequests.Api.Models.Sonarr;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Store;
|
||||
using PlexRequests.UI.Helpers;
|
||||
|
@ -146,32 +147,6 @@ namespace PlexRequests.UI.Tests
|
|||
true, It.IsAny<bool>()), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RequestEpisodesWithExistingSeriesTest()
|
||||
{
|
||||
var episodesReturned = new List<SonarrEpisodes>
|
||||
{
|
||||
new SonarrEpisodes {episodeNumber = 1, seasonNumber = 2, monitored = false, id=22}
|
||||
};
|
||||
SonarrMock.Setup(x => x.GetEpisodes(It.IsAny<string>(), It.IsAny<string>(),
|
||||
It.IsAny<Uri>())).Returns(episodesReturned);
|
||||
SonarrMock.Setup(x => x.GetEpisode("22", It.IsAny<string>(), It.IsAny<Uri>())).Returns(new SonarrEpisode {id=22});
|
||||
|
||||
|
||||
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object);
|
||||
|
||||
var model = new RequestedModel
|
||||
{
|
||||
Episodes = new List<EpisodesModel> { new EpisodesModel { EpisodeNumber = 1, SeasonNumber = 2 } }
|
||||
};
|
||||
|
||||
var series = new Series();
|
||||
await Sender.RequestEpisodesWithExistingSeries(model, series, GetSonarrSettings());
|
||||
|
||||
SonarrMock.Verify(x => x.UpdateEpisode(It.Is<SonarrEpisode>(e => e.monitored), It.IsAny<string>(), It.IsAny<Uri>()));
|
||||
SonarrMock.Verify(x => x.GetEpisode("22", It.IsAny<string>(), It.IsAny<Uri>()),Times.Once);
|
||||
SonarrMock.Verify(x => x.SearchForEpisodes(It.IsAny<int[]>(), It.IsAny<string>(), It.IsAny<Uri>()), Times.Once);
|
||||
}
|
||||
|
||||
private SonarrSettings GetSonarrSettings()
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@ using PlexRequests.Api.Interfaces;
|
|||
using PlexRequests.Api.Models.Plex;
|
||||
using PlexRequests.Core;
|
||||
using PlexRequests.Core.SettingModels;
|
||||
using PlexRequests.Helpers;
|
||||
using PlexRequests.Helpers.Analytics;
|
||||
using PlexRequests.UI.Models;
|
||||
using PlexRequests.UI.Modules;
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: CustomAuthenticationConfiguration.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using Nancy.Cryptography;
|
||||
using PlexRequests.Store.Repository;
|
||||
|
||||
namespace PlexRequests.UI.Authentication
|
||||
{
|
||||
public class CustomAuthenticationConfiguration
|
||||
{
|
||||
internal const string DefaultRedirectQuerystringKey = "returnUrl";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the forms authentication query string key for storing the return url
|
||||
/// </summary>
|
||||
public string RedirectQuerystringKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the redirect url for pages that require authentication
|
||||
/// </summary>
|
||||
public string RedirectUrl { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the username/identifier mapper</summary>
|
||||
public IUserRepository LocalUserRepository { get; set; }
|
||||
|
||||
public IPlexUserRepository PlexUserRepository { get; set; }
|
||||
|
||||
/// <summary>Gets or sets RequiresSSL property</summary>
|
||||
/// <value>The flag that indicates whether SSL is required</value>
|
||||
public bool RequiresSSL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to redirect to login page during unauthorized access.
|
||||
/// </summary>
|
||||
public bool DisableRedirect { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the domain of the auth cookie</summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the path of the auth cookie</summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the cryptography configuration</summary>
|
||||
public CryptographyConfiguration CryptographyConfiguration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the configuration is valid or not.
|
||||
/// </summary>
|
||||
public virtual bool IsValid => (this.DisableRedirect || !string.IsNullOrEmpty(this.RedirectUrl)) && (this.LocalUserRepository != null && PlexUserRepository != null && this.CryptographyConfiguration != null) && (this.CryptographyConfiguration.EncryptionProvider != null && this.CryptographyConfiguration.HmacProvider != null);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Nancy.Authentication.Forms.FormsAuthenticationConfiguration" /> class.
|
||||
/// </summary>
|
||||
public CustomAuthenticationConfiguration()
|
||||
: this(CryptographyConfiguration.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Nancy.Authentication.Forms.FormsAuthenticationConfiguration" /> class.
|
||||
/// </summary>
|
||||
/// <param name="cryptographyConfiguration">Cryptography configuration</param>
|
||||
public CustomAuthenticationConfiguration(CryptographyConfiguration cryptographyConfiguration)
|
||||
{
|
||||
this.CryptographyConfiguration = cryptographyConfiguration;
|
||||
this.RedirectQuerystringKey = "returnUrl";
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue