mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -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
|
||||||
PlexRequests.UI/Content/* linguist-vendored
|
PlexRequests.UI/Content/* linguist-vendored
|
||||||
base.scss linguist-vendored=false
|
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
|
|
||||||
|
|
2
.github/ISSUE_TEMPLATE.md
vendored
2
.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:
|
#### Plex Requests.Net Version:
|
||||||
|
|
||||||
|
#### update Branch:
|
||||||
|
|
||||||
|
|
||||||
#### Operating System:
|
#### Operating System:
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace PlexRequests.Api.Interfaces
|
||||||
PlexSearch GetAllEpisodes(string authToken, Uri host, string section, int startPage, int returnCount);
|
PlexSearch GetAllEpisodes(string authToken, Uri host, string section, int startPage, int returnCount);
|
||||||
PlexServer GetServer(string authToken);
|
PlexServer GetServer(string authToken);
|
||||||
PlexSeasonMetadata GetSeasons(string authToken, Uri plexFullHost, string ratingKey);
|
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
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: RecentlyAddedModel.cs
|
// File: RecentlyAddedModelOld.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// 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 string tag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RecentlyAddedModel
|
public class RecentlyAddedModelOld
|
||||||
{
|
{
|
||||||
public string _elementType { get; set; }
|
public string _elementType { get; set; }
|
||||||
public string allowSync { get; set; }
|
public string allowSync { get; set; }
|
||||||
|
@ -130,4 +130,112 @@ namespace PlexRequests.Api.Models.Plex
|
||||||
public string viewMode { get; set; }
|
public string viewMode { get; set; }
|
||||||
public List<RecentlyAddedChild> _children { 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\PlexStatus.cs" />
|
||||||
<Compile Include="Plex\PlexMediaType.cs" />
|
<Compile Include="Plex\PlexMediaType.cs" />
|
||||||
<Compile Include="Plex\PlexUserRequest.cs" />
|
<Compile Include="Plex\PlexUserRequest.cs" />
|
||||||
<Compile Include="Plex\RecentlyAddedModel.cs" />
|
<Compile Include="Plex\RecentlyAddedModelOld.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SickRage\SickRageBase.cs" />
|
<Compile Include="SickRage\SickRageBase.cs" />
|
||||||
<Compile Include="SickRage\SickrageShows.cs" />
|
<Compile Include="SickRage\SickrageShows.cs" />
|
||||||
|
|
|
@ -104,8 +104,7 @@ namespace PlexRequests.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = DeserializeXml<T>(response.Content);
|
var result = DeserializeXml<T>(response.Content);
|
||||||
return result;
|
return result;}
|
||||||
}
|
|
||||||
|
|
||||||
public T ExecuteJson<T>(IRestRequest request, Uri baseUri) where T : new()
|
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),
|
var obj = RetryHandler.Execute(() => Api.ExecuteJson<JObject>(request, baseUrl),
|
||||||
(exception, timespan) => Log.Error(exception, "Exception when calling AddMovie for CP, Retrying {0}", timespan), new[] {
|
(exception, timespan) => Log.Error(exception, "Exception when calling AddMovie for CP, Retrying {0}", timespan), new[] {
|
||||||
TimeSpan.FromSeconds (2),
|
TimeSpan.FromSeconds (2)});
|
||||||
TimeSpan.FromSeconds(5),
|
|
||||||
TimeSpan.FromSeconds(10)});
|
|
||||||
|
|
||||||
|
|
||||||
if (obj.Count > 0)
|
if (obj.Count > 0)
|
||||||
|
|
|
@ -346,7 +346,7 @@ namespace PlexRequests.Api
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecentlyAddedModel RecentlyAdded(string authToken, Uri plexFullHost, string sectionId)
|
public RecentlyAddedModelOld RecentlyAddedOld(string authToken, Uri plexFullHost, string sectionId)
|
||||||
{
|
{
|
||||||
var request = new RestRequest
|
var request = new RestRequest
|
||||||
{
|
{
|
||||||
|
@ -360,7 +360,7 @@ namespace PlexRequests.Api
|
||||||
|
|
||||||
try
|
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[] {
|
(exception, timespan) => Log.Error(exception, "Exception when calling RecentlyAddedModel for Plex, Retrying {0}", timespan), new[] {
|
||||||
TimeSpan.FromSeconds (5),
|
TimeSpan.FromSeconds (5),
|
||||||
TimeSpan.FromSeconds(10),
|
TimeSpan.FromSeconds(10),
|
||||||
|
@ -372,7 +372,37 @@ namespace PlexRequests.Api
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Error(e, "There has been a API Exception when attempting to get the Plex RecentlyAddedModel");
|
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
|
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)
|
public static T Execute<T>(Func<T> action, TimeSpan[] timeSpan = null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -117,8 +117,7 @@ namespace PlexRequests.Api
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
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));
|
result = policy.Execute(() => Api.ExecuteJson<SonarrAddSeries>(request, baseUrl));
|
||||||
|
@ -186,8 +185,7 @@ namespace PlexRequests.Api
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] {
|
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));
|
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[] {
|
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 (5),
|
||||||
TimeSpan.FromSeconds(10),
|
TimeSpan.FromSeconds(5),
|
||||||
TimeSpan.FromSeconds(30)
|
TimeSpan.FromSeconds(5)
|
||||||
});
|
});
|
||||||
|
|
||||||
return policy.Execute(() => Api.ExecuteJson<List<Series>>(request, baseUrl));
|
return policy.Execute(() => Api.ExecuteJson<List<Series>>(request, baseUrl));
|
||||||
|
|
|
@ -47,25 +47,18 @@ namespace PlexRequests.Api
|
||||||
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
|
public async Task<List<SearchMovie>> SearchMovie(string searchTerm)
|
||||||
{
|
{
|
||||||
var results = await Client.SearchMovie(searchTerm);
|
var results = await Client.SearchMovie(searchTerm);
|
||||||
return results.Results;
|
return results?.Results ?? new List<SearchMovie>();
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("Should use TvMaze for TV")]
|
|
||||||
public async Task<List<SearchTv>> SearchTv(string searchTerm)
|
|
||||||
{
|
|
||||||
var results = await Client.SearchTvShow(searchTerm);
|
|
||||||
return results.Results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<MovieResult>> GetCurrentPlayingMovies()
|
public async Task<List<MovieResult>> GetCurrentPlayingMovies()
|
||||||
{
|
{
|
||||||
var movies = await Client.GetMovieList(MovieListType.NowPlaying);
|
var movies = await Client.GetMovieList(MovieListType.NowPlaying);
|
||||||
return movies.Results;
|
return movies?.Results ?? new List<MovieResult>();
|
||||||
}
|
}
|
||||||
public async Task<List<MovieResult>> GetUpcomingMovies()
|
public async Task<List<MovieResult>> GetUpcomingMovies()
|
||||||
{
|
{
|
||||||
var movies = await Client.GetMovieList(MovieListType.Upcoming);
|
var movies = await Client.GetMovieList(MovieListType.Upcoming);
|
||||||
return movies.Results;
|
return movies?.Results ?? new List<MovieResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Movie> GetMovieInformation(int tmdbId)
|
public async Task<Movie> GetMovieInformation(int tmdbId)
|
||||||
|
@ -77,14 +70,7 @@ namespace PlexRequests.Api
|
||||||
public async Task<Movie> GetMovieInformation(string imdbId)
|
public async Task<Movie> GetMovieInformation(string imdbId)
|
||||||
{
|
{
|
||||||
var movies = await Client.GetMovie(imdbId);
|
var movies = await Client.GetMovie(imdbId);
|
||||||
return movies;
|
return movies ?? new Movie();
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("Should use TvMaze for TV")]
|
|
||||||
public async Task<TvShow> GetTvShowInformation(int tmdbId)
|
|
||||||
{
|
|
||||||
var show = await Client.GetTvShow(tmdbId);
|
|
||||||
return show;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,42 +22,31 @@ namespace PlexRequests.Core.Migration
|
||||||
public void MigrateToLatest()
|
public void MigrateToLatest()
|
||||||
{
|
{
|
||||||
var con = Db.DbConnection();
|
var con = Db.DbConnection();
|
||||||
var versions = GetMigrations().OrderBy(x => x.Key);
|
var versions = GetMigrations();
|
||||||
|
|
||||||
var dbVersion = con.GetVersionInfo().OrderByDescending(x => x.Version).FirstOrDefault();
|
var dbVersion = con.GetVersionInfo().OrderByDescending(x => x.Version).FirstOrDefault() ??
|
||||||
if (dbVersion == null)
|
new TableCreation.VersionInfo { Version = 0 };
|
||||||
{
|
|
||||||
dbVersion = new TableCreation.VersionInfo { Version = 0 };
|
|
||||||
}
|
|
||||||
foreach (var v in versions)
|
foreach (var v in versions)
|
||||||
{
|
{
|
||||||
|
#if !DEBUG
|
||||||
if (v.Value.Version > dbVersion.Version)
|
if (v.Value.Version > dbVersion.Version)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
// Assuming only one constructor
|
// Assuming only one constructor
|
||||||
var ctor = v.Key.GetConstructors().FirstOrDefault();
|
var ctor = v.Key.GetConstructors().FirstOrDefault();
|
||||||
var dependencies = new List<object>();
|
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 dep = Kernel.Get(param.ParameterType);
|
|
||||||
dependencies.Add(dep);
|
|
||||||
}
|
|
||||||
|
|
||||||
var method = v.Key.GetMethod("Start");
|
var method = v.Key.GetMethod("Start");
|
||||||
if (method != null)
|
if (method != null)
|
||||||
{
|
{
|
||||||
object result = null;
|
|
||||||
var classInstance = Activator.CreateInstance(v.Key, dependencies.Any() ? dependencies.ToArray() : null);
|
var classInstance = Activator.CreateInstance(v.Key, dependencies.Any() ? dependencies.ToArray() : null);
|
||||||
|
|
||||||
var parametersArray = new object[] { Db.DbConnection() };
|
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">
|
<Reference Include="Ninject">
|
||||||
<HintPath>..\packages\Ninject.3.2.0.0\lib\net45-full\Ninject.dll</HintPath>
|
<HintPath>..\packages\Ninject.3.2.0.0\lib\net45-full\Ninject.dll</HintPath>
|
||||||
</Reference>
|
</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">
|
<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>
|
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -65,14 +69,27 @@
|
||||||
<Compile Include="MigrationAttribute.cs" />
|
<Compile Include="MigrationAttribute.cs" />
|
||||||
<Compile Include="MigrationRunner.cs" />
|
<Compile Include="MigrationRunner.cs" />
|
||||||
<Compile Include="Migrations\BaseMigration.cs" />
|
<Compile Include="Migrations\BaseMigration.cs" />
|
||||||
|
<Compile Include="Migrations\Version1100.cs" />
|
||||||
<Compile Include="Migrations\Version195.cs" />
|
<Compile Include="Migrations\Version195.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<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">
|
<ProjectReference Include="..\PlexRequests.Core\PlexRequests.Core.csproj">
|
||||||
<Project>{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}</Project>
|
<Project>{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}</Project>
|
||||||
<Name>PlexRequests.Core</Name>
|
<Name>PlexRequests.Core</Name>
|
||||||
</ProjectReference>
|
</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">
|
<ProjectReference Include="..\PlexRequests.Store\PlexRequests.Store.csproj">
|
||||||
<Project>{92433867-2B7B-477B-A566-96C382427525}</Project>
|
<Project>{92433867-2B7B-477B-A566-96C382427525}</Project>
|
||||||
<Name>PlexRequests.Store</Name>
|
<Name>PlexRequests.Store</Name>
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||||
<package id="Common.Logging.Core" 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" />
|
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -60,7 +60,6 @@
|
||||||
</Choose>
|
</Choose>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AuthenticationSettingsTests.cs" />
|
<Compile Include="AuthenticationSettingsTests.cs" />
|
||||||
<Compile Include="StatusCheckerTests.cs" />
|
|
||||||
<Compile Include="NotificationMessageResolverTests.cs" />
|
<Compile Include="NotificationMessageResolverTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace PlexRequests.Core
|
||||||
{
|
{
|
||||||
public struct TimeFrameMinutes
|
public struct TimeFrameMinutes
|
||||||
{
|
{
|
||||||
public const int SchedulerCaching = 60;
|
public const int SchedulerCaching = 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
public const string PlexLibaries = nameof(PlexLibaries);
|
public const string PlexLibaries = nameof(PlexLibaries);
|
||||||
|
|
|
@ -24,18 +24,16 @@
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Core;
|
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
|
|
||||||
namespace PlexRequests.UI.Helpers
|
namespace PlexRequests.Core
|
||||||
{
|
{
|
||||||
public class HeadphonesSender
|
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,
|
RequestApproved,
|
||||||
AdminNote,
|
AdminNote,
|
||||||
Test,
|
Test,
|
||||||
|
RequestDeclined,
|
||||||
|
ItemAddedToFaultQueue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@ namespace PlexRequests.Core.Models
|
||||||
{
|
{
|
||||||
public class StatusModel
|
public class StatusModel
|
||||||
{
|
{
|
||||||
public string Version { get; set; }
|
public string CurrentVersion { get; set; }
|
||||||
|
public string NewVersion { get; set; }
|
||||||
public bool UpdateAvailable { get; set; }
|
public bool UpdateAvailable { get; set; }
|
||||||
public string UpdateUri { get; set; }
|
public string UpdateUri { get; set; }
|
||||||
public string DownloadUri { 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>
|
<HintPath>..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</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">
|
<Reference Include="Mono.Data.Sqlite">
|
||||||
<HintPath>..\Assemblies\Mono.Data.Sqlite.dll</HintPath>
|
<HintPath>..\Assemblies\Mono.Data.Sqlite.dll</HintPath>
|
||||||
</Reference>
|
</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">
|
<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>
|
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -54,7 +62,12 @@
|
||||||
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
<HintPath>..\packages\Quartz.2.3.3\lib\net40\Quartz.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</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" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
@ -81,7 +94,10 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CacheKeys.cs" />
|
<Compile Include="CacheKeys.cs" />
|
||||||
|
<Compile Include="HeadphonesSender.cs" />
|
||||||
<Compile Include="IPlexReadOnlyDatabase.cs" />
|
<Compile Include="IPlexReadOnlyDatabase.cs" />
|
||||||
|
<Compile Include="ISecurityExtensions.cs" />
|
||||||
|
<Compile Include="IStatusChecker.cs" />
|
||||||
<Compile Include="Notification\NotificationMessage.cs" />
|
<Compile Include="Notification\NotificationMessage.cs" />
|
||||||
<Compile Include="Notification\NotificationMessageContent.cs" />
|
<Compile Include="Notification\NotificationMessageContent.cs" />
|
||||||
<Compile Include="Notification\NotificationMessageCurlys.cs" />
|
<Compile Include="Notification\NotificationMessageCurlys.cs" />
|
||||||
|
@ -99,6 +115,9 @@
|
||||||
<Compile Include="Notification\Templates\IEmailBasicTemplate.cs" />
|
<Compile Include="Notification\Templates\IEmailBasicTemplate.cs" />
|
||||||
<Compile Include="Notification\TransportType.cs" />
|
<Compile Include="Notification\TransportType.cs" />
|
||||||
<Compile Include="PlexReadOnlyDatabase.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\AuthenticationSettings.cs" />
|
||||||
<Compile Include="SettingModels\ExternalSettings.cs" />
|
<Compile Include="SettingModels\ExternalSettings.cs" />
|
||||||
<Compile Include="SettingModels\HeadphonesSettings.cs" />
|
<Compile Include="SettingModels\HeadphonesSettings.cs" />
|
||||||
|
@ -119,12 +138,22 @@
|
||||||
<Compile Include="SettingModels\CouchPotatoSettings.cs" />
|
<Compile Include="SettingModels\CouchPotatoSettings.cs" />
|
||||||
<Compile Include="SettingModels\PlexRequestSettings.cs" />
|
<Compile Include="SettingModels\PlexRequestSettings.cs" />
|
||||||
<Compile Include="SettingModels\Settings.cs" />
|
<Compile Include="SettingModels\Settings.cs" />
|
||||||
|
<Compile Include="SettingModels\SystemSettings.cs" />
|
||||||
|
<Compile Include="SettingModels\UserManagementSettings.cs" />
|
||||||
<Compile Include="SettingsServiceV2.cs" />
|
<Compile Include="SettingsServiceV2.cs" />
|
||||||
<Compile Include="Setup.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="UserIdentity.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="UserMapper.cs" />
|
<Compile Include="UserMapper.cs" />
|
||||||
|
<Compile Include="Users\UserHelperModel.cs" />
|
||||||
|
<Compile Include="Users\UserManagementHelper.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="app.config" />
|
<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 SearchForMovies { get; set; }
|
||||||
public bool SearchForTvShows { get; set; }
|
public bool SearchForTvShows { get; set; }
|
||||||
public bool SearchForMusic { get; set; }
|
public bool SearchForMusic { get; set; }
|
||||||
|
[Obsolete("Use the user management settings")]
|
||||||
public bool RequireMovieApproval { get; set; }
|
public bool RequireMovieApproval { get; set; }
|
||||||
|
[Obsolete("Use the user management settings")]
|
||||||
public bool RequireTvShowApproval { get; set; }
|
public bool RequireTvShowApproval { get; set; }
|
||||||
|
[Obsolete("Use the user management settings")]
|
||||||
public bool RequireMusicApproval { get; set; }
|
public bool RequireMusicApproval { get; set; }
|
||||||
|
|
||||||
|
[Obsolete("Use the user management settings")]
|
||||||
public bool UsersCanViewOnlyOwnRequests { get; set; }
|
public bool UsersCanViewOnlyOwnRequests { get; set; }
|
||||||
|
[Obsolete("Use the user management settings")]
|
||||||
public bool UsersCanViewOnlyOwnIssues { get; set; }
|
public bool UsersCanViewOnlyOwnIssues { get; set; }
|
||||||
public int MovieWeeklyRequestLimit { get; set; }
|
public int MovieWeeklyRequestLimit { get; set; }
|
||||||
public int TvWeeklyRequestLimit { get; set; }
|
public int TvWeeklyRequestLimit { get; set; }
|
||||||
public int AlbumWeeklyRequestLimit { get; set; }
|
public int AlbumWeeklyRequestLimit { get; set; }
|
||||||
public string NoApprovalUsers { get; set; }
|
|
||||||
public bool CollectAnalyticData { get; set; }
|
public bool CollectAnalyticData { get; set; }
|
||||||
public bool IgnoreNotifyForAutoApprovedRequests { get; set; }
|
public bool IgnoreNotifyForAutoApprovedRequests { get; set; }
|
||||||
public bool Wizard { get; set; }
|
public bool Wizard { get; set; }
|
||||||
|
@ -69,26 +74,5 @@ namespace PlexRequests.Core.SettingModels
|
||||||
public string ThemeName { get; set; }
|
public string ThemeName { get; set; }
|
||||||
|
|
||||||
public string ApiKey { 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")]
|
[Obsolete("We use the CRON job now")]
|
||||||
public int RecentlyAdded { get; set; }
|
public int RecentlyAdded { get; set; }
|
||||||
public string RecentlyAddedCron { 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,65 +61,35 @@ namespace PlexRequests.Core
|
||||||
TableCreation.Vacuum(Db.DbConnection());
|
TableCreation.Vacuum(Db.DbConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the new 'running' item into the scheduled jobs so we can check if the cachers are running
|
||||||
// The below code is obsolete, we should use PlexRequests.Core.Migrations.MigrationRunner
|
Db.DbConnection().AlterTable("ScheduledJobs", "ADD", "Running", true, "INTEGER");
|
||||||
var version = CheckSchema();
|
|
||||||
if (version > 0)
|
|
||||||
{
|
|
||||||
if (version > 1899 && version <= 1900)
|
|
||||||
{
|
|
||||||
MigrateToVersion1900();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(version > 1899 && version <= 1910)
|
|
||||||
{
|
|
||||||
MigrateToVersion1910();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Db.DbConnection().ConnectionString;
|
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)
|
private void CreateDefaultSettingsPage(string baseUrl)
|
||||||
{
|
{
|
||||||
|
var defaultUserSettings = new UserManagementSettings
|
||||||
|
{
|
||||||
|
RequestMovies = true,
|
||||||
|
RequestTvShows = true,
|
||||||
|
ReportIssues = true,
|
||||||
|
|
||||||
|
};
|
||||||
var defaultSettings = new PlexRequestSettings
|
var defaultSettings = new PlexRequestSettings
|
||||||
{
|
{
|
||||||
RequireTvShowApproval = true,
|
|
||||||
RequireMovieApproval = true,
|
|
||||||
SearchForMovies = true,
|
SearchForMovies = true,
|
||||||
SearchForTvShows = true,
|
SearchForTvShows = true,
|
||||||
BaseUrl = baseUrl ?? string.Empty,
|
BaseUrl = baseUrl ?? string.Empty,
|
||||||
CollectAnalyticData = true,
|
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);
|
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 cron = (Quartz.Impl.Triggers.CronTriggerImpl)CronScheduleBuilder.WeeklyOnDayAndHourAndMinute(DayOfWeek.Friday, 7, 0).Build();
|
||||||
var scheduled = new ScheduledJobsSettings
|
var scheduled = new ScheduledJobsSettings
|
||||||
|
@ -148,7 +118,6 @@ namespace PlexRequests.Core
|
||||||
Task.Run(() => { CacheSonarrQualityProfiles(mc); });
|
Task.Run(() => { CacheSonarrQualityProfiles(mc); });
|
||||||
Task.Run(() => { CacheCouchPotatoQualityProfiles(mc); });
|
Task.Run(() => { CacheCouchPotatoQualityProfiles(mc); });
|
||||||
// we don't need to cache sickrage profiles, those are static
|
// we don't need to cache sickrage profiles, those are static
|
||||||
// TODO: cache headphones profiles?
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -156,12 +125,12 @@ namespace PlexRequests.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CacheSonarrQualityProfiles(MemoryCacheProvider cacheProvider)
|
private void CacheSonarrQualityProfiles(ICacheProvider cacheProvider)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.Info("Executing GetSettings call to Sonarr for quality profiles");
|
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();
|
var sonarrSettings = sonarrSettingsService.GetSettings();
|
||||||
if (sonarrSettings.Enabled)
|
if (sonarrSettings.Enabled)
|
||||||
{
|
{
|
||||||
|
@ -178,12 +147,12 @@ namespace PlexRequests.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CacheCouchPotatoQualityProfiles(MemoryCacheProvider cacheProvider)
|
private void CacheCouchPotatoQualityProfiles(ICacheProvider cacheProvider)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.Info("Executing GetSettings call to CouchPotato for quality profiles");
|
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();
|
var cpSettings = cpSettingsService.GetSettings();
|
||||||
if (cpSettings.Enabled)
|
if (cpSettings.Enabled)
|
||||||
{
|
{
|
||||||
|
@ -199,102 +168,5 @@ namespace PlexRequests.Core
|
||||||
Log.Error(ex, "Failed to cache CouchPotato quality profiles!");
|
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.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Api.Models.SickRage;
|
using PlexRequests.Api.Models.SickRage;
|
||||||
using PlexRequests.Api.Models.Sonarr;
|
using PlexRequests.Api.Models.Sonarr;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PlexRequests.UI.Helpers
|
namespace PlexRequests.Core
|
||||||
{
|
{
|
||||||
public class TvSender
|
public class TvSender
|
||||||
{
|
{
|
|
@ -36,7 +36,7 @@ using PlexRequests.Api.Models.Sonarr;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
|
|
||||||
namespace PlexRequests.UI.Helpers
|
namespace PlexRequests.Core
|
||||||
{
|
{
|
||||||
public class TvSenderOld
|
public class TvSenderOld
|
||||||
{
|
{
|
|
@ -36,6 +36,7 @@ using Nancy.Security;
|
||||||
|
|
||||||
using PlexRequests.Core.Models;
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
|
using PlexRequests.Helpers.Permissions;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using PlexRequests.Store.Repository;
|
using PlexRequests.Store.Repository;
|
||||||
|
|
||||||
|
@ -60,7 +61,6 @@ namespace PlexRequests.Core
|
||||||
return new UserIdentity
|
return new UserIdentity
|
||||||
{
|
{
|
||||||
UserName = user.UserName,
|
UserName = user.UserName,
|
||||||
Claims = ByteConverterHelper.ReturnObject<string[]>(user.Claims)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ namespace PlexRequests.Core
|
||||||
return users.Any();
|
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();
|
var salt = PasswordHasher.GenerateSalt();
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace PlexRequests.Core
|
||||||
UserGuid = Guid.NewGuid().ToString(),
|
UserGuid = Guid.NewGuid().ToString(),
|
||||||
Salt = salt,
|
Salt = salt,
|
||||||
Hash = PasswordHasher.ComputeHash(password, salt),
|
Hash = PasswordHasher.ComputeHash(password, salt),
|
||||||
Claims = ByteConverterHelper.ReturnBytes(claims),
|
Claims = new byte[] {0},
|
||||||
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties()),
|
UserProperties = ByteConverterHelper.ReturnBytes(properties ?? new UserProperties()),
|
||||||
};
|
};
|
||||||
Repo.Insert(userModel);
|
Repo.Insert(userModel);
|
||||||
|
@ -118,32 +118,33 @@ namespace PlexRequests.Core
|
||||||
return new Guid(userRecord.UserGuid);
|
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)
|
public void DeleteUser(string userId)
|
||||||
{
|
{
|
||||||
var user = Repo.Get(userId);
|
var user = Repo.Get(userId);
|
||||||
Repo.Delete(user);
|
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)
|
public bool UpdatePassword(string username, string oldPassword, string newPassword)
|
||||||
{
|
{
|
||||||
|
@ -186,8 +187,8 @@ namespace PlexRequests.Core
|
||||||
|
|
||||||
public interface ICustomUserMapper
|
public interface ICustomUserMapper
|
||||||
{
|
{
|
||||||
Guid? CreateUser(string username, string password, string[] claims, UserProperties props);
|
Guid? CreateUser(string username, string password, int permissions, int features,
|
||||||
IEnumerable<string> GetAllClaims();
|
UserProperties properties = null);
|
||||||
IEnumerable<UsersModel> GetUsers();
|
IEnumerable<UsersModel> GetUsers();
|
||||||
Task<IEnumerable<UsersModel>> GetUsersAsync();
|
Task<IEnumerable<UsersModel>> GetUsersAsync();
|
||||||
UsersModel GetUser(Guid userId);
|
UsersModel GetUser(Guid userId);
|
||||||
|
@ -195,9 +196,6 @@ namespace PlexRequests.Core
|
||||||
bool DoUsersExist();
|
bool DoUsersExist();
|
||||||
Guid? ValidateUser(string username, string password);
|
Guid? ValidateUser(string username, string password);
|
||||||
bool UpdatePassword(string username, string oldPassword, string newPassword);
|
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);
|
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>
|
<packages>
|
||||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||||
<package id="Common.Logging.Core" 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" version="1.4.3" targetFramework="net45" />
|
||||||
<package id="Nancy.Authentication.Forms" version="1.4.1" 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="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||||
<package id="Octokit" version="0.19.0" targetFramework="net45" />
|
<package id="Octokit" version="0.19.0" targetFramework="net45" />
|
||||||
<package id="Quartz" version="2.3.3" 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" />
|
<package id="valueinjecter" version="3.1.1.2" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -54,7 +54,7 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
Track(HitType.@event, username, cat, act, label, clientId, value);
|
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 cat = category.ToString();
|
||||||
var act = action.ToString();
|
var act = action.ToString();
|
||||||
|
@ -146,7 +146,7 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
request.Method = RequestMethod;
|
request.Method = RequestMethod;
|
||||||
// set the Content-Length header to the correct value
|
// set the Content-Length header to the correct value
|
||||||
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
||||||
|
#if !DEBUG
|
||||||
// write the request body to the request
|
// write the request body to the request
|
||||||
using (var writer = new StreamWriter(request.GetRequestStream()))
|
using (var writer = new StreamWriter(request.GetRequestStream()))
|
||||||
{
|
{
|
||||||
|
@ -165,7 +165,10 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Analytics tracking failed");
|
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)
|
private async Task SendRequestAsync(string postDataString)
|
||||||
{
|
{
|
||||||
var request = (HttpWebRequest)WebRequest.Create(AnalyticsUri);
|
var request = (HttpWebRequest)WebRequest.Create(AnalyticsUri);
|
||||||
|
@ -173,6 +176,7 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
// set the Content-Length header to the correct value
|
// set the Content-Length header to the correct value
|
||||||
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
request.ContentLength = Encoding.UTF8.GetByteCount(postDataString);
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
// write the request body to the request
|
// write the request body to the request
|
||||||
using (var writer = new StreamWriter(await request.GetRequestStreamAsync()))
|
using (var writer = new StreamWriter(await request.GetRequestStreamAsync()))
|
||||||
{
|
{
|
||||||
|
@ -191,7 +195,9 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Analytics tracking failed");
|
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)
|
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,
|
Issues,
|
||||||
UserLogin,
|
UserLogin,
|
||||||
Services,
|
Services,
|
||||||
Navbar
|
Navbar,
|
||||||
|
UserManagement
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -51,7 +51,7 @@ namespace PlexRequests.Helpers.Analytics
|
||||||
/// <param name="clientId">The client identifier.</param>
|
/// <param name="clientId">The client identifier.</param>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <returns></returns>
|
/// <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>
|
/// <summary>
|
||||||
/// Tracks the page view.
|
/// Tracks the page view.
|
||||||
|
|
|
@ -45,5 +45,13 @@ namespace PlexRequests.Helpers
|
||||||
var retVersion = fvi.ProductVersion;
|
var retVersion = fvi.ProductVersion;
|
||||||
return retVersion;
|
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
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: AuthenticationSettingsTests.cs
|
// File: Features.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
@ -26,21 +26,17 @@
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace PlexRequests.Core.Tests
|
namespace PlexRequests.Helpers.Permissions
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[Flags]
|
||||||
public class StatusCheckerTests
|
public enum Features
|
||||||
{
|
{
|
||||||
[Test]
|
[Display(Name = "Newsletter")]
|
||||||
[Ignore("API Limit")]
|
Newsletter = 1,
|
||||||
public void CheckStatusTest()
|
[Display(Name = "Request Added Notification")]
|
||||||
{
|
RequestAddedNotification = 2,
|
||||||
var checker = new StatusChecker();
|
|
||||||
var status = checker.GetStatus();
|
|
||||||
|
|
||||||
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>
|
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</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">
|
<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>
|
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -48,6 +52,7 @@
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Runtime.Caching" />
|
<Reference Include="System.Runtime.Caching" />
|
||||||
<Reference Include="System.Web" />
|
<Reference Include="System.Web" />
|
||||||
|
@ -69,6 +74,7 @@
|
||||||
<Compile Include="ByteConverterHelper.cs" />
|
<Compile Include="ByteConverterHelper.cs" />
|
||||||
<Compile Include="CookieHelper.cs" />
|
<Compile Include="CookieHelper.cs" />
|
||||||
<Compile Include="DateTimeHelper.cs" />
|
<Compile Include="DateTimeHelper.cs" />
|
||||||
|
<Compile Include="EnumHelper.cs" />
|
||||||
<Compile Include="Exceptions\ApiRequestException.cs" />
|
<Compile Include="Exceptions\ApiRequestException.cs" />
|
||||||
<Compile Include="Exceptions\ApplicationSettingsException.cs" />
|
<Compile Include="Exceptions\ApplicationSettingsException.cs" />
|
||||||
<Compile Include="HtmlRemover.cs" />
|
<Compile Include="HtmlRemover.cs" />
|
||||||
|
@ -78,9 +84,13 @@
|
||||||
<Compile Include="MemoryCacheProvider.cs" />
|
<Compile Include="MemoryCacheProvider.cs" />
|
||||||
<Compile Include="ObjectCopier.cs" />
|
<Compile Include="ObjectCopier.cs" />
|
||||||
<Compile Include="PasswordHasher.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="PlexHelper.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SerializerSettings.cs" />
|
<Compile Include="SerializerSettings.cs" />
|
||||||
|
<Compile Include="SessionKeys.cs" />
|
||||||
<Compile Include="StringCipher.cs" />
|
<Compile Include="StringCipher.cs" />
|
||||||
<Compile Include="StringHasher.cs" />
|
<Compile Include="StringHasher.cs" />
|
||||||
<Compile Include="StringHelper.cs" />
|
<Compile Include="StringHelper.cs" />
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
namespace PlexRequests.UI.Models
|
namespace PlexRequests.Helpers
|
||||||
{
|
{
|
||||||
public class SessionKeys
|
public class SessionKeys
|
||||||
{
|
{
|
|
@ -2,6 +2,7 @@
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" 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="NLog" version="4.3.6" targetFramework="net45" />
|
||||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -1,284 +1,284 @@
|
||||||
#region Copyright
|
//#region Copyright
|
||||||
// /************************************************************************
|
//// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
//// Copyright (c) 2016 Jamie Rees
|
||||||
// File: PlexAvailabilityCheckerTests.cs
|
//// File: PlexAvailabilityCheckerTests.cs
|
||||||
// Created By: Jamie Rees
|
//// Created By: Jamie Rees
|
||||||
//
|
////
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
//// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
//// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
//// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
//// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
//// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
//// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
//// the following conditions:
|
||||||
//
|
////
|
||||||
// The above copyright notice and this permission notice shall be
|
//// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
//// included in all copies or substantial portions of the Software.
|
||||||
//
|
////
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
//// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
//// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
//// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
//// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
//// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
//// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
//// ************************************************************************/
|
||||||
#endregion
|
//#endregion
|
||||||
using System;
|
//using System;
|
||||||
using System.Collections.Generic;
|
//using System.Collections.Generic;
|
||||||
using System.Data;
|
//using System.Data;
|
||||||
using System.Linq;
|
//using System.Linq;
|
||||||
using System.Threading.Tasks;
|
//using System.Threading.Tasks;
|
||||||
|
|
||||||
using Moq;
|
//using Moq;
|
||||||
|
|
||||||
using NUnit.Framework;
|
//using NUnit.Framework;
|
||||||
|
|
||||||
using PlexRequests.Api.Interfaces;
|
//using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Api.Models.Plex;
|
//using PlexRequests.Api.Models.Plex;
|
||||||
using PlexRequests.Core;
|
//using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
//using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Services.Interfaces;
|
//using PlexRequests.Services.Interfaces;
|
||||||
using PlexRequests.Helpers;
|
//using PlexRequests.Helpers;
|
||||||
using PlexRequests.Services.Jobs;
|
//using PlexRequests.Services.Jobs;
|
||||||
using PlexRequests.Services.Models;
|
//using PlexRequests.Services.Models;
|
||||||
using PlexRequests.Services.Notification;
|
//using PlexRequests.Services.Notification;
|
||||||
using PlexRequests.Store.Models;
|
//using PlexRequests.Store.Models;
|
||||||
using PlexRequests.Store.Repository;
|
//using PlexRequests.Store.Repository;
|
||||||
|
|
||||||
using Ploeh.AutoFixture;
|
//using Ploeh.AutoFixture;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Tests
|
//namespace PlexRequests.Services.Tests
|
||||||
{
|
//{
|
||||||
[TestFixture]
|
// [TestFixture]
|
||||||
public class PlexAvailabilityCheckerTests
|
// public class PlexAvailabilityCheckerTests
|
||||||
{
|
// {
|
||||||
public IAvailabilityChecker Checker { get; set; }
|
// public IAvailabilityChecker Checker { get; set; }
|
||||||
private Fixture F { get; set; } = new Fixture();
|
// private Fixture F { get; set; } = new Fixture();
|
||||||
private Mock<ISettingsService<PlexSettings>> SettingsMock { get; set; }
|
// private Mock<ISettingsService<PlexSettings>> SettingsMock { get; set; }
|
||||||
private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
|
// private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
|
||||||
private Mock<IRequestService> RequestMock { get; set; }
|
// private Mock<IRequestService> RequestMock { get; set; }
|
||||||
private Mock<IPlexApi> PlexMock { get; set; }
|
// private Mock<IPlexApi> PlexMock { get; set; }
|
||||||
private Mock<ICacheProvider> CacheMock { get; set; }
|
// private Mock<ICacheProvider> CacheMock { get; set; }
|
||||||
private Mock<INotificationService> NotificationMock { get; set; }
|
// private Mock<INotificationService> NotificationMock { get; set; }
|
||||||
private Mock<IJobRecord> JobRec { get; set; }
|
// private Mock<IJobRecord> JobRec { get; set; }
|
||||||
private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
// private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
||||||
private Mock<IRepository<PlexEpisodes>> PlexEpisodes { get; set; }
|
// private Mock<IRepository<PlexEpisodes>> PlexEpisodes { get; set; }
|
||||||
private Mock<INotificationEngine> Engine
|
// private Mock<INotificationEngine> Engine
|
||||||
{
|
// {
|
||||||
get;
|
// get;
|
||||||
set;
|
// set;
|
||||||
}
|
// }
|
||||||
|
|
||||||
[SetUp]
|
// [SetUp]
|
||||||
public void Setup()
|
// public void Setup()
|
||||||
{
|
// {
|
||||||
SettingsMock = new Mock<ISettingsService<PlexSettings>>();
|
// SettingsMock = new Mock<ISettingsService<PlexSettings>>();
|
||||||
AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
|
// AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
|
||||||
RequestMock = new Mock<IRequestService>();
|
// RequestMock = new Mock<IRequestService>();
|
||||||
PlexMock = new Mock<IPlexApi>();
|
// PlexMock = new Mock<IPlexApi>();
|
||||||
NotificationMock = new Mock<INotificationService>();
|
// NotificationMock = new Mock<INotificationService>();
|
||||||
CacheMock = new Mock<ICacheProvider>();
|
// CacheMock = new Mock<ICacheProvider>();
|
||||||
NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
// NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
||||||
PlexEpisodes = new Mock<IRepository<PlexEpisodes>>();
|
// PlexEpisodes = new Mock<IRepository<PlexEpisodes>>();
|
||||||
JobRec = new Mock<IJobRecord>();
|
// JobRec = new Mock<IJobRecord>();
|
||||||
Engine = new Mock<INotificationEngine>();
|
// 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);
|
// Checker = new PlexAvailabilityChecker(SettingsMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object, PlexEpisodes.Object, Engine.Object);
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void InvalidSettings()
|
// public void InvalidSettings()
|
||||||
{
|
// {
|
||||||
Checker.CheckAndUpdateAll();
|
// Checker.CheckAndUpdateAll();
|
||||||
PlexMock.Verify(x => x.GetLibrary(It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()), Times.Never);
|
// 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.GetAccount(It.IsAny<string>()), Times.Never);
|
||||||
PlexMock.Verify(x => x.GetLibrarySections(It.IsAny<string>(), It.IsAny<Uri>()), 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.GetStatus(It.IsAny<string>(), It.IsAny<Uri>()), Times.Never);
|
||||||
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
|
// PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsMovieAvailableTestData))]
|
// [TestCaseSource(nameof(IsMovieAvailableTestData))]
|
||||||
public bool IsMovieAvailableTest(string title, string year)
|
// public bool IsMovieAvailableTest(string title, string year)
|
||||||
{
|
// {
|
||||||
var movies = new List<PlexMovie>
|
// var movies = new List<PlexMovie>
|
||||||
{
|
// {
|
||||||
new PlexMovie {Title = title, ProviderId = null, ReleaseYear = year}
|
// new PlexMovie {Title = title, ProviderId = null, ReleaseYear = year}
|
||||||
};
|
// };
|
||||||
var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011");
|
// var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011");
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> IsMovieAvailableTestData
|
// private static IEnumerable<TestCaseData> IsMovieAvailableTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("title", "2011").Returns(true).SetName("IsMovieAvailable True");
|
// 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("title2", "2011").Returns(false).SetName("IsMovieAvailable False different title");
|
||||||
yield return new TestCaseData("title", "2001").Returns(false).SetName("IsMovieAvailable False different year");
|
// yield return new TestCaseData("title", "2001").Returns(false).SetName("IsMovieAvailable False different year");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsMovieAvailableAdvancedTestData))]
|
// [TestCaseSource(nameof(IsMovieAvailableAdvancedTestData))]
|
||||||
public bool IsMovieAvailableAdvancedTest(string title, string year, string providerId)
|
// public bool IsMovieAvailableAdvancedTest(string title, string year, string providerId)
|
||||||
{
|
// {
|
||||||
var movies = new List<PlexMovie>
|
// var movies = new List<PlexMovie>
|
||||||
{
|
// {
|
||||||
new PlexMovie {Title = title, ProviderId = providerId, ReleaseYear = year }
|
// new PlexMovie {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||||
};
|
// };
|
||||||
var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
// var result = Checker.IsMovieAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> IsMovieAvailableAdvancedTestData
|
// private static IEnumerable<TestCaseData> IsMovieAvailableAdvancedTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsMovieAvailable True");
|
// 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("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", "99939").Returns(false).SetName("Advanced IsMovieAvailable False different year");
|
||||||
yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsMovieAvailable False different providerID");
|
// yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsMovieAvailable False different providerID");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsTvAvailableTestData))]
|
// [TestCaseSource(nameof(IsTvAvailableTestData))]
|
||||||
public bool IsTvAvailableTest(string title, string year)
|
// public bool IsTvAvailableTest(string title, string year)
|
||||||
{
|
// {
|
||||||
var tv = new List<PlexTvShow>
|
// var tv = new List<PlexTvShow>
|
||||||
{
|
// {
|
||||||
new PlexTvShow {Title = title, ProviderId = null, ReleaseYear = year}
|
// new PlexTvShow {Title = title, ProviderId = null, ReleaseYear = year}
|
||||||
};
|
// };
|
||||||
var result = Checker.IsTvShowAvailable(tv.ToArray(), "title", "2011");
|
// var result = Checker.IsTvShowAvailable(tv.ToArray(), "title", "2011");
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> IsTvAvailableTestData
|
// private static IEnumerable<TestCaseData> IsTvAvailableTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("title", "2011").Returns(true).SetName("IsTvAvailable True");
|
// 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("title2", "2011").Returns(false).SetName("IsTvAvailable False different title");
|
||||||
yield return new TestCaseData("title", "2001").Returns(false).SetName("IsTvAvailable False different year");
|
// yield return new TestCaseData("title", "2001").Returns(false).SetName("IsTvAvailable False different year");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsTvAvailableAdvancedTestData))]
|
// [TestCaseSource(nameof(IsTvAvailableAdvancedTestData))]
|
||||||
public bool IsTvAvailableAdvancedTest(string title, string year, string providerId)
|
// public bool IsTvAvailableAdvancedTest(string title, string year, string providerId)
|
||||||
{
|
// {
|
||||||
var movies = new List<PlexTvShow>
|
// var movies = new List<PlexTvShow>
|
||||||
{
|
// {
|
||||||
new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year }
|
// new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year }
|
||||||
};
|
// };
|
||||||
var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
// var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString());
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> IsTvAvailableAdvancedTestData
|
// private static IEnumerable<TestCaseData> IsTvAvailableAdvancedTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("title", "2011", "9999").Returns(true).SetName("Advanced IsTvAvailable True");
|
// 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("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", "99939").Returns(false).SetName("Advanced IsTvAvailable False different year");
|
||||||
yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsTvAvailable False different providerID");
|
// yield return new TestCaseData("title", "2001", "44445").Returns(false).SetName("Advanced IsTvAvailable False different providerID");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsTvAvailableAdvancedSeasonsTestData))]
|
// [TestCaseSource(nameof(IsTvAvailableAdvancedSeasonsTestData))]
|
||||||
public bool IsTvAvailableAdvancedSeasonsTest(string title, string year, string providerId, int[] seasons)
|
// public bool IsTvAvailableAdvancedSeasonsTest(string title, string year, string providerId, int[] seasons)
|
||||||
{
|
// {
|
||||||
var movies = new List<PlexTvShow>
|
// var movies = new List<PlexTvShow>
|
||||||
{
|
// {
|
||||||
new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year , Seasons = seasons}
|
// new PlexTvShow {Title = title, ProviderId = providerId, ReleaseYear = year , Seasons = seasons}
|
||||||
};
|
// };
|
||||||
var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString(), new[] { 1, 2, 3 });
|
// var result = Checker.IsTvShowAvailable(movies.ToArray(), "title", "2011", 9999.ToString(), new[] { 1, 2, 3 });
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> IsTvAvailableAdvancedSeasonsTestData
|
// private static IEnumerable<TestCaseData> IsTvAvailableAdvancedSeasonsTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("title", "2011", "9999", new[] { 1, 2, 3 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable True");
|
// 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", "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");
|
// yield return new TestCaseData("title2", "2011", "9999", new[] { 1, 6 }).Returns(true).SetName("Advanced IsTvSeasonsAvailable true one season");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(IsEpisodeAvailableTestData))]
|
// [TestCaseSource(nameof(IsEpisodeAvailableTestData))]
|
||||||
public bool IsEpisodeAvailableTest(string providerId, int season, int episode)
|
// public bool IsEpisodeAvailableTest(string providerId, int season, int episode)
|
||||||
{
|
// {
|
||||||
var expected = new List<PlexEpisodes>
|
// var expected = new List<PlexEpisodes>
|
||||||
{
|
// {
|
||||||
new PlexEpisodes {EpisodeNumber = 1, ShowTitle = "The Flash",ProviderId = 23.ToString(), SeasonNumber = 1, EpisodeTitle = "Pilot"}
|
// 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);
|
// 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
|
// private static IEnumerable<TestCaseData> IsEpisodeAvailableTestData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData("23", 1, 1).Returns(true).SetName("IsEpisodeAvailable True S01E01");
|
// 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", 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("23", 99, 99).Returns(false).SetName("IsEpisodeAvailable False S99E99");
|
||||||
yield return new TestCaseData("230", 99, 99).Returns(false).SetName("IsEpisodeAvailable False Incorrect ProviderId");
|
// yield return new TestCaseData("230", 99, 99).Returns(false).SetName("IsEpisodeAvailable False Incorrect ProviderId");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void GetPlexMoviesTests()
|
// public void GetPlexMoviesTests()
|
||||||
{
|
// {
|
||||||
var cachedMovies = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
// var cachedMovies = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||||
cachedMovies.Add(new PlexSearch
|
// cachedMovies.Add(new PlexSearch
|
||||||
{
|
// {
|
||||||
Video = new List<Video>
|
// Video = new List<Video>
|
||||||
{
|
// {
|
||||||
new Video {Type = "movie", Title = "title1", Year = "2016", ProviderId = "1212"}
|
// new Video {Type = "movie", Title = "title1", Year = "2016", ProviderId = "1212"}
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedMovies);
|
||||||
SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||||
var movies = Checker.GetPlexMovies();
|
// var movies = Checker.GetPlexMovies();
|
||||||
|
|
||||||
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
// Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void GetPlexTvShowsTests()
|
// public void GetPlexTvShowsTests()
|
||||||
{
|
// {
|
||||||
var cachedTv = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
// var cachedTv = F.Build<PlexSearch>().Without(x => x.Directory).CreateMany().ToList();
|
||||||
cachedTv.Add(new PlexSearch
|
// cachedTv.Add(new PlexSearch
|
||||||
{
|
// {
|
||||||
Directory = new List<Directory1>
|
// Directory = new List<Directory1>
|
||||||
{
|
// {
|
||||||
new Directory1 {Type = "show", Title = "title1", Year = "2016", ProviderId = "1212", Seasons = 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>());
|
// SettingsMock.Setup(x => x.GetSettings()).Returns(F.Create<PlexSettings>());
|
||||||
CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
// CacheMock.Setup(x => x.Get<List<PlexSearch>>(CacheKeys.PlexLibaries)).Returns(cachedTv);
|
||||||
var movies = Checker.GetPlexTvShows();
|
// var movies = Checker.GetPlexTvShows();
|
||||||
|
|
||||||
Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
// Assert.That(movies.Any(x => x.ProviderId == "1212"));
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public async Task GetAllPlexEpisodes()
|
// public async Task GetAllPlexEpisodes()
|
||||||
{
|
// {
|
||||||
PlexEpisodes.Setup(x => x.GetAllAsync()).ReturnsAsync(F.CreateMany<PlexEpisodes>().ToList());
|
// PlexEpisodes.Setup(x => x.GetAllAsync()).ReturnsAsync(F.CreateMany<PlexEpisodes>().ToList());
|
||||||
var episodes = await Checker.GetEpisodes();
|
// 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 System.Threading.Tasks;
|
||||||
|
|
||||||
using PlexRequests.Store.Models;
|
using PlexRequests.Store.Models;
|
||||||
|
using PlexRequests.Store.Models.Plex;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Interfaces
|
namespace PlexRequests.Services.Interfaces
|
||||||
{
|
{
|
||||||
public interface IAvailabilityChecker
|
public interface IAvailabilityChecker
|
||||||
{
|
{
|
||||||
void CheckAndUpdateAll();
|
void CheckAndUpdateAll();
|
||||||
List<PlexMovie> GetPlexMovies();
|
IEnumerable<PlexContent> GetPlexMovies(IEnumerable<PlexContent> content);
|
||||||
bool IsMovieAvailable(PlexMovie[] plexMovies, string title, string year, string providerId = null);
|
bool IsMovieAvailable(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
||||||
List<PlexTvShow> GetPlexTvShows();
|
IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content);
|
||||||
bool IsTvShowAvailable(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
bool IsTvShowAvailable(PlexContent[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||||
List<PlexAlbum> GetPlexAlbums();
|
IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content);
|
||||||
bool IsAlbumAvailable(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
bool IsAlbumAvailable(PlexContent[] plexAlbums, string title, string year, string artist);
|
||||||
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
bool IsEpisodeAvailable(string theTvDbId, int season, int episode);
|
||||||
PlexAlbum GetAlbum(PlexAlbum[] plexAlbums, string title, string year, string artist);
|
PlexContent GetAlbum(PlexContent[] plexAlbums, string title, string year, string artist);
|
||||||
PlexMovie GetMovie(PlexMovie[] plexMovies, string title, string year, string providerId = null);
|
PlexContent GetMovie(PlexContent[] plexMovies, string title, string year, string providerId = null);
|
||||||
PlexTvShow GetTvShow(PlexTvShow[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
PlexContent GetTvShow(PlexContent[] plexShows, string title, string year, string providerId = null, int[] seasons = null);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the episode's stored in the cache.
|
/// Gets the episode's stored in the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -36,5 +36,6 @@ namespace PlexRequests.Services.Interfaces
|
||||||
void Record(string jobName);
|
void Record(string jobName);
|
||||||
Task<IEnumerable<ScheduledJobs>> GetJobsAsync();
|
Task<IEnumerable<ScheduledJobs>> GetJobsAsync();
|
||||||
IEnumerable<ScheduledJobs> GetJobs();
|
IEnumerable<ScheduledJobs> GetJobs();
|
||||||
|
void SetRunning(bool running, string jobName);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,13 +27,14 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Interfaces
|
namespace PlexRequests.Services.Interfaces
|
||||||
{
|
{
|
||||||
public interface INotificationEngine
|
public interface INotificationEngine
|
||||||
{
|
{
|
||||||
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey);
|
Task NotifyUsers(IEnumerable<RequestedModel> modelChanged, string apiKey, NotificationType type);
|
||||||
Task NotifyUsers(RequestedModel modelChanged, string apiKey);
|
Task NotifyUsers(RequestedModel modelChanged, string apiKey, NotificationType type);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -65,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
var settings = CpSettings.GetSettings();
|
var settings = CpSettings.GetSettings();
|
||||||
if (settings.Enabled)
|
if (settings.Enabled)
|
||||||
{
|
{
|
||||||
|
Job.SetRunning(true, JobNames.CpCacher);
|
||||||
Log.Trace("Getting all movies from CouchPotato");
|
Log.Trace("Getting all movies from CouchPotato");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -81,6 +82,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Job.Record(JobNames.CpCacher);
|
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 SonarrCacher = "Sonarr Cacher";
|
||||||
public const string SrCacher = "SickRage Cacher";
|
public const string SrCacher = "SickRage Cacher";
|
||||||
public const string PlexChecker = "Plex Availability Cacher";
|
public const string PlexChecker = "Plex Availability Cacher";
|
||||||
|
public const string PlexCacher = "Plex Cacher";
|
||||||
public const string StoreCleanup = "Database Cleanup";
|
public const string StoreCleanup = "Database Cleanup";
|
||||||
public const string RequestLimitReset = "Request Limit Reset";
|
public const string RequestLimitReset = "Request Limit Reset";
|
||||||
public const string EpisodeCacher = "Plex Episode Cacher";
|
public const string EpisodeCacher = "Plex Episode Cacher";
|
||||||
public const string RecentlyAddedEmail = "Recently Added Email Notification";
|
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()
|
public async Task<IEnumerable<ScheduledJobs>> GetJobsAsync()
|
||||||
{
|
{
|
||||||
return await Repo.GetAllAsync();
|
return await Repo.GetAllAsync();
|
||||||
|
|
|
@ -30,7 +30,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
|
@ -44,6 +44,7 @@ using PlexRequests.Services.Models;
|
||||||
using PlexRequests.Services.Notification;
|
using PlexRequests.Services.Notification;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using PlexRequests.Store.Models;
|
using PlexRequests.Store.Models;
|
||||||
|
using PlexRequests.Store.Models.Plex;
|
||||||
using PlexRequests.Store.Repository;
|
using PlexRequests.Store.Repository;
|
||||||
|
|
||||||
using Quartz;
|
using Quartz;
|
||||||
|
@ -53,7 +54,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
||||||
{
|
{
|
||||||
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
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;
|
Plex = plexSettings;
|
||||||
RequestService = request;
|
RequestService = request;
|
||||||
|
@ -64,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
UserNotifyRepo = users;
|
UserNotifyRepo = users;
|
||||||
EpisodeRepo = repo;
|
EpisodeRepo = repo;
|
||||||
NotificationEngine = e;
|
NotificationEngine = e;
|
||||||
|
PlexContent = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<PlexSettings> Plex { get; }
|
private ISettingsService<PlexSettings> Plex { get; }
|
||||||
|
@ -76,7 +78,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
private IJobRecord Job { get; }
|
private IJobRecord Job { get; }
|
||||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||||
private INotificationEngine NotificationEngine { get; }
|
private INotificationEngine NotificationEngine { get; }
|
||||||
|
private IRepository<PlexContent> PlexContent { get; }
|
||||||
|
|
||||||
public void CheckAndUpdateAll()
|
public void CheckAndUpdateAll()
|
||||||
{
|
{
|
||||||
|
@ -87,18 +89,17 @@ namespace PlexRequests.Services.Jobs
|
||||||
Log.Debug("Validation of the plex settings failed.");
|
Log.Debug("Validation of the plex settings failed.");
|
||||||
return;
|
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())
|
||||||
|
//{
|
||||||
if (libraries == null || !libraries.Any())
|
// Log.Debug("Did not find any libraries in Plex.");
|
||||||
{
|
// return;
|
||||||
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 movies = GetPlexMovies().ToArray();
|
var albums = GetPlexAlbums(content).ToArray();
|
||||||
var shows = GetPlexTvShows().ToArray();
|
|
||||||
var albums = GetPlexAlbums().ToArray();
|
|
||||||
|
|
||||||
var requests = RequestService.GetAll();
|
var requests = RequestService.GetAll();
|
||||||
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
|
var requestedModels = requests as RequestedModel[] ?? requests.Where(x => !x.Available).ToArray();
|
||||||
|
@ -153,15 +154,12 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
if (modifiedModel.Any())
|
if (modifiedModel.Any())
|
||||||
{
|
{
|
||||||
NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken);
|
NotificationEngine.NotifyUsers(modifiedModel, plexSettings.PlexAuthToken, NotificationType.RequestAvailable);
|
||||||
RequestService.BatchUpdate(modifiedModel);
|
RequestService.BatchUpdate(modifiedModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
Job.Record(JobNames.PlexChecker);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlexMovie> GetPlexMovies()
|
public List<PlexMovie> GetPlexMoviesOld()
|
||||||
{
|
{
|
||||||
var settings = Plex.GetSettings();
|
var settings = Plex.GetSettings();
|
||||||
var movies = new List<PlexMovie>();
|
var movies = new List<PlexMovie>();
|
||||||
|
@ -188,13 +186,18 @@ namespace PlexRequests.Services.Jobs
|
||||||
return movies;
|
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);
|
var movie = GetMovie(plexMovies, title, year, providerId);
|
||||||
return movie != null;
|
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)
|
if (plexMovies.Length == 0)
|
||||||
{
|
{
|
||||||
|
@ -225,45 +228,19 @@ namespace PlexRequests.Services.Jobs
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlexTvShow> GetPlexTvShows()
|
public IEnumerable<PlexContent> GetPlexTvShows(IEnumerable<PlexContent> content)
|
||||||
{
|
{
|
||||||
var settings = Plex.GetSettings();
|
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Show);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
var show = GetTvShow(plexShows, title, year, providerId, seasons);
|
||||||
return show != null;
|
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)
|
int[] seasons = null)
|
||||||
{
|
{
|
||||||
var advanced = !string.IsNullOrEmpty(providerId);
|
var advanced = !string.IsNullOrEmpty(providerId);
|
||||||
|
@ -273,7 +250,8 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
if (show.ProviderId == providerId && seasons != null)
|
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;
|
return show;
|
||||||
}
|
}
|
||||||
|
@ -359,41 +337,19 @@ namespace PlexRequests.Services.Jobs
|
||||||
return plexEpisodeses;
|
return plexEpisodeses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlexAlbum> GetPlexAlbums()
|
public IEnumerable<PlexContent> GetPlexAlbums(IEnumerable<PlexContent> content)
|
||||||
{
|
{
|
||||||
var settings = Plex.GetSettings();
|
return content.Where(x => x.Type == Store.Models.Plex.PlexMediaType.Artist);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 =>
|
return plexAlbums.Any(x =>
|
||||||
x.Title.Contains(title) &&
|
x.Title.Contains(title) &&
|
||||||
x.Artist.Equals(artist, StringComparison.CurrentCultureIgnoreCase));
|
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 =>
|
return plexAlbums.FirstOrDefault(x =>
|
||||||
x.Title.Contains(title) &&
|
x.Title.Contains(title) &&
|
||||||
|
@ -419,11 +375,11 @@ namespace PlexRequests.Services.Jobs
|
||||||
results = GetLibraries(plexSettings);
|
results = GetLibraries(plexSettings);
|
||||||
if (plexSettings.AdvancedSearch)
|
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,
|
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||||
currentItem.RatingKey);
|
currentItem.RatingKey);
|
||||||
|
|
||||||
|
@ -434,25 +390,21 @@ namespace PlexRequests.Services.Jobs
|
||||||
currentItem.RatingKey);
|
currentItem.RatingKey);
|
||||||
|
|
||||||
// We do not want "all episodes" this as a season
|
// We do not want "all episodes" this as a season
|
||||||
var filtered =
|
var filtered = seasons.Directory.Where( x => !x.Title.Equals("All episodes", StringComparison.CurrentCultureIgnoreCase));
|
||||||
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);
|
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,
|
var metaData = PlexApi.GetMetadata(plexSettings.PlexAuthToken, plexSettings.FullUri,
|
||||||
currentItem.RatingKey);
|
currentItem.RatingKey);
|
||||||
var providerId = PlexHelper.GetProviderIdFromPlexGuid(metaData.Video.Guid);
|
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);
|
var sections = PlexApi.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||||
|
|
||||||
List<PlexSearch> libs = new List<PlexSearch>();
|
var libs = new List<PlexSearch>();
|
||||||
if (sections != null)
|
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);
|
var lib = PlexApi.GetLibrary(plexSettings.PlexAuthToken, plexSettings.FullUri, dir.Key);
|
||||||
if (lib != null)
|
if (lib != null)
|
||||||
|
@ -507,6 +459,8 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Job.SetRunning(true, JobNames.PlexChecker);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CheckAndUpdateAll();
|
CheckAndUpdateAll();
|
||||||
|
@ -515,6 +469,11 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
Log.Error(e);
|
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)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var s = Plex.GetSettings();
|
var s = Plex.GetSettings();
|
||||||
|
@ -162,6 +163,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Job.SetRunning(true, JobNames.EpisodeCacher);
|
||||||
CacheEpisodes(s);
|
CacheEpisodes(s);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -171,6 +173,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Job.Record(JobNames.EpisodeCacher);
|
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.Api.Models.Plex;
|
||||||
using PlexRequests.Core;
|
using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
|
using PlexRequests.Core.Users;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
|
using PlexRequests.Helpers.Permissions;
|
||||||
using PlexRequests.Services.Interfaces;
|
using PlexRequests.Services.Interfaces;
|
||||||
using PlexRequests.Services.Jobs.Templates;
|
using PlexRequests.Services.Jobs.Templates;
|
||||||
using PlexRequests.Store.Models.Plex;
|
using PlexRequests.Store.Models.Plex;
|
||||||
|
@ -53,7 +55,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
public RecentlyAdded(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
|
public RecentlyAdded(IPlexApi api, ISettingsService<PlexSettings> plexSettings,
|
||||||
ISettingsService<EmailNotificationSettings> email, IJobRecord rec,
|
ISettingsService<EmailNotificationSettings> email, IJobRecord rec,
|
||||||
ISettingsService<NewletterSettings> newsletter,
|
ISettingsService<NewletterSettings> newsletter,
|
||||||
IPlexReadOnlyDatabase db)
|
IPlexReadOnlyDatabase db, IUserHelper userHelper)
|
||||||
{
|
{
|
||||||
JobRecord = rec;
|
JobRecord = rec;
|
||||||
Api = api;
|
Api = api;
|
||||||
|
@ -61,6 +63,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
EmailSettings = email;
|
EmailSettings = email;
|
||||||
NewsletterSettings = newsletter;
|
NewsletterSettings = newsletter;
|
||||||
PlexDb = db;
|
PlexDb = db;
|
||||||
|
UserHelper = userHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPlexApi Api { get; }
|
private IPlexApi Api { get; }
|
||||||
|
@ -73,6 +76,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
private ISettingsService<NewletterSettings> NewsletterSettings { get; }
|
||||||
private IJobRecord JobRecord { get; }
|
private IJobRecord JobRecord { get; }
|
||||||
private IPlexReadOnlyDatabase PlexDb { get; }
|
private IPlexReadOnlyDatabase PlexDb { get; }
|
||||||
|
private IUserHelper UserHelper { get; }
|
||||||
|
|
||||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
@ -85,7 +89,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
JobRecord.SetRunning(true, JobNames.RecentlyAddedEmail);
|
||||||
Start(settings);
|
Start(settings);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -95,11 +99,13 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
JobRecord.Record(JobNames.RecentlyAddedEmail);
|
JobRecord.Record(JobNames.RecentlyAddedEmail);
|
||||||
|
JobRecord.SetRunning(false, JobNames.RecentlyAddedEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Test()
|
public void Test()
|
||||||
{
|
{
|
||||||
|
Log.Debug("Starting Test Newsletter");
|
||||||
var settings = NewsletterSettings.GetSettings();
|
var settings = NewsletterSettings.GetSettings();
|
||||||
Start(settings, true);
|
Start(settings, true);
|
||||||
}
|
}
|
||||||
|
@ -108,29 +114,103 @@ namespace PlexRequests.Services.Jobs
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
var plexSettings = PlexSettings.GetSettings();
|
var plexSettings = PlexSettings.GetSettings();
|
||||||
|
Log.Debug("Got Plex Settings");
|
||||||
|
|
||||||
var libs = Api.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
var libs = Api.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri);
|
||||||
var tvSection = libs.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
Log.Debug("Getting Plex Library Sections");
|
||||||
var movieSection = libs.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
|
||||||
|
|
||||||
var recentlyAddedTv = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection.Key);
|
var tvSections = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib
|
||||||
var recentlyAddedMovies = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, movieSection.Key);
|
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);
|
var plexVersion = Api.GetStatus(plexSettings.PlexAuthToken, plexSettings.FullUri).Version;
|
||||||
GenerateTvHtml(recentlyAddedTv, plexSettings, sb);
|
|
||||||
|
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();
|
var template = new RecentlyAddedTemplate();
|
||||||
var html = template.LoadTemplate(sb.ToString());
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Send(newletterSettings, html, plexSettings, testEmail);
|
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("<h1>New Movies:</h1><br/><br/>");
|
||||||
sb.Append(
|
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%\">");
|
"<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;
|
var plexGUID = string.Empty;
|
||||||
try
|
try
|
||||||
|
@ -142,7 +222,10 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(plexGUID);
|
var imdbId = PlexHelper.GetProviderIdFromPlexGuid(plexGUID);
|
||||||
var info = _movieApi.GetMovieInformation(imdbId).Result;
|
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}");
|
AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}");
|
||||||
|
|
||||||
sb.Append("<tr>");
|
sb.Append("<tr>");
|
||||||
|
@ -177,13 +260,130 @@ namespace PlexRequests.Services.Jobs
|
||||||
sb.Append("</table><br/><br/>");
|
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
|
// TV
|
||||||
sb.Append("<h1>New Episodes:</h1><br/><br/>");
|
sb.Append("<h1>New Episodes:</h1><br/><br/>");
|
||||||
sb.Append(
|
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%\">");
|
"<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;
|
var plexGUID = string.Empty;
|
||||||
try
|
try
|
||||||
|
@ -238,6 +438,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false)
|
private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false)
|
||||||
{
|
{
|
||||||
|
Log.Debug("Entering Send");
|
||||||
var settings = EmailSettings.GetSettings();
|
var settings = EmailSettings.GetSettings();
|
||||||
|
|
||||||
if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost))
|
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 body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." };
|
||||||
|
|
||||||
var message = new MimeMessage
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
Body = body.ToMessageBody(),
|
Body = body.ToMessageBody(),
|
||||||
Subject = "New Content on Plex!",
|
Subject = "New Content on Plex!",
|
||||||
};
|
};
|
||||||
|
Log.Debug("Created Plain/HTML MIME body");
|
||||||
|
|
||||||
if (!testEmail)
|
if (!testEmail)
|
||||||
{
|
{
|
||||||
if (newletterSettings.SendToPlexUsers)
|
var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification);
|
||||||
{
|
|
||||||
var users = Api.GetUsers(plexSettings.PlexAuthToken);
|
|
||||||
if (users != null)
|
if (users != null)
|
||||||
{
|
{
|
||||||
foreach (var user in users.User)
|
foreach (var user in users)
|
||||||
{
|
{
|
||||||
message.Bcc.Add(new MailboxAddress(user.Username, user.Email));
|
if (!string.IsNullOrEmpty(user.EmailAddress))
|
||||||
|
{
|
||||||
|
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.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin
|
||||||
|
|
||||||
message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender));
|
message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender));
|
||||||
|
@ -293,7 +497,9 @@ namespace PlexRequests.Services.Jobs
|
||||||
client.Authenticate(settings.EmailUsername, settings.EmailPassword);
|
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.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);
|
client.Send(message);
|
||||||
|
Log.Debug("Sent");
|
||||||
client.Disconnect(true);
|
client.Disconnect(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,9 @@ namespace PlexRequests.Services.Jobs
|
||||||
var settings = SrSettings.GetSettings();
|
var settings = SrSettings.GetSettings();
|
||||||
if (settings.Enabled)
|
if (settings.Enabled)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Job.SetRunning(true, JobNames.SrCacher);
|
||||||
|
|
||||||
Log.Trace("Getting all shows from SickRage");
|
Log.Trace("Getting all shows from SickRage");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -79,6 +82,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Job.Record(JobNames.SrCacher);
|
Job.Record(JobNames.SrCacher);
|
||||||
|
Job.SetRunning(false, JobNames.SrCacher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
var settings = SonarrSettings.GetSettings();
|
var settings = SonarrSettings.GetSettings();
|
||||||
if (settings.Enabled)
|
if (settings.Enabled)
|
||||||
{
|
{
|
||||||
|
Job.SetRunning(true, JobNames.SonarrCacher);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri);
|
var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri);
|
||||||
|
@ -80,6 +81,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Job.Record(JobNames.SonarrCacher);
|
Job.Record(JobNames.SonarrCacher);
|
||||||
|
Job.SetRunning(false, JobNames.SonarrCacher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
TakeBackup();
|
TakeBackup();
|
||||||
Cleanup();
|
Cleanup();
|
||||||
}
|
}
|
||||||
|
@ -91,6 +92,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
JobRecord.Record(JobNames.StoreBackup);
|
JobRecord.Record(JobNames.StoreBackup);
|
||||||
|
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,12 +78,14 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
JobRecord.Record(JobNames.StoreCleanup);
|
JobRecord.Record(JobNames.StoreCleanup);
|
||||||
|
JobRecord.SetRunning(false, JobNames.CpCacher);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
JobRecord.SetRunning(true, JobNames.CpCacher);
|
||||||
Cleanup();
|
Cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public void Execute(IJobExecutionContext context)
|
public void Execute(IJobExecutionContext context)
|
||||||
{
|
{
|
||||||
|
Record.SetRunning(true, JobNames.CpCacher);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = Settings.GetSettings();
|
var settings = Settings.GetSettings();
|
||||||
|
@ -115,6 +116,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Record.Record(JobNames.RequestLimitReset);
|
Record.Record(JobNames.RequestLimitReset);
|
||||||
|
Record.SetRunning(false, JobNames.CpCacher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,7 @@
|
||||||
public string Artist { get; set; }
|
public string Artist { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public string Url { 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 class PlexMovie
|
||||||
{
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{
|
{
|
||||||
public class PlexTvShow
|
public class PlexTvShow
|
||||||
{
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string ReleaseYear { get; set; }
|
public string ReleaseYear { get; set; }
|
||||||
public string ProviderId { get; set; }
|
public string ProviderId { get; set; }
|
||||||
|
|
|
@ -79,14 +79,22 @@ namespace PlexRequests.Services.Notification
|
||||||
await EmailAvailableRequest(model, emailSettings);
|
await EmailAvailableRequest(model, emailSettings);
|
||||||
break;
|
break;
|
||||||
case NotificationType.RequestApproved:
|
case NotificationType.RequestApproved:
|
||||||
throw new NotImplementedException();
|
await EmailRequestApproved(model, emailSettings);
|
||||||
|
break;
|
||||||
case NotificationType.AdminNote:
|
case NotificationType.AdminNote:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
||||||
case NotificationType.Test:
|
case NotificationType.Test:
|
||||||
await EmailTest(model, emailSettings);
|
await EmailTest(model, emailSettings);
|
||||||
break;
|
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}!",
|
$"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")}",
|
$"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);
|
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
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
|
@ -150,7 +158,7 @@ namespace PlexRequests.Services.Notification
|
||||||
$"Plex Requests: New issue for {model.Title}!",
|
$"Plex Requests: New issue for {model.Title}!",
|
||||||
$"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
$"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!",
|
||||||
model.ImgSrc);
|
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
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
|
@ -164,6 +172,69 @@ namespace PlexRequests.Services.Notification
|
||||||
await Send(message, settings);
|
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)
|
private async Task EmailAvailableRequest(NotificationModel model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
if (!settings.EnableUserEmailNotifications)
|
if (!settings.EnableUserEmailNotifications)
|
||||||
|
@ -175,7 +246,7 @@ namespace PlexRequests.Services.Notification
|
||||||
$"Plex Requests: {model.Title} is now available!",
|
$"Plex Requests: {model.Title} is now available!",
|
||||||
$"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)",
|
$"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)",
|
||||||
model.ImgSrc);
|
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
|
var message = new MimeMessage
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,8 @@ using NLog.Fluent;
|
||||||
using PlexRequests.Api;
|
using PlexRequests.Api;
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Core.Models;
|
using PlexRequests.Core.Models;
|
||||||
|
using PlexRequests.Core.Users;
|
||||||
|
using PlexRequests.Helpers.Permissions;
|
||||||
using PlexRequests.Services.Interfaces;
|
using PlexRequests.Services.Interfaces;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using PlexRequests.Store.Models;
|
using PlexRequests.Store.Models;
|
||||||
|
@ -43,19 +45,21 @@ namespace PlexRequests.Services.Notification
|
||||||
{
|
{
|
||||||
public class NotificationEngine : INotificationEngine
|
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;
|
PlexApi = p;
|
||||||
UserNotifyRepo = repo;
|
UserNotifyRepo = repo;
|
||||||
Notification = service;
|
Notification = service;
|
||||||
|
UserHelper = userHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
private IRepository<UsersToNotify> UserNotifyRepo { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private INotificationService Notification { get; }
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -64,23 +68,37 @@ namespace PlexRequests.Services.Notification
|
||||||
|
|
||||||
var adminUsername = userAccount.Username ?? string.Empty;
|
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);
|
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||||
foreach (var model in modelChanged)
|
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)
|
foreach (var user in selectedUsers)
|
||||||
{
|
{
|
||||||
Log.Info("Notifying user {0}", user);
|
Log.Info("Notifying user {0}", user);
|
||||||
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
Log.Info("This user is the Plex server owner");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var email = plexUser.User.FirstOrDefault(x => x.Username.Equals(user, StringComparison.CurrentCultureIgnoreCase));
|
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");
|
Log.Info("There is no email address for this Plex user, cannot send notification");
|
||||||
// We do not have a plex user that requested this!
|
// 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);
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -107,7 +125,7 @@ namespace PlexRequests.Services.Notification
|
||||||
|
|
||||||
var adminUsername = userAccount.Username ?? string.Empty;
|
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);
|
Log.Debug("Notifying Users Count {0}", users.Count);
|
||||||
|
|
||||||
var selectedUsers = users.Select(x => x.Username).Intersect(model.RequestedUsers, StringComparer.CurrentCultureIgnoreCase);
|
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))
|
if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
Log.Info("This user is the Plex server owner");
|
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;
|
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);
|
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)
|
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
|
var notificationModel = new NotificationModel
|
||||||
{
|
{
|
||||||
User = username,
|
User = username,
|
||||||
UserEmail = email,
|
UserEmail = email,
|
||||||
NotificationType = NotificationType.RequestAvailable,
|
NotificationType = type,
|
||||||
Title = title,
|
Title = title,
|
||||||
ImgSrc = img
|
ImgSrc = img
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,6 +81,11 @@ namespace PlexRequests.Services.Notification
|
||||||
case NotificationType.Test:
|
case NotificationType.Test:
|
||||||
await PushTestAsync(pushSettings);
|
await PushTestAsync(pushSettings);
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.RequestDeclined:
|
||||||
|
break;
|
||||||
|
case NotificationType.ItemAddedToFaultQueue:
|
||||||
|
await PushFaultQueue(model, pushSettings);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +130,13 @@ namespace PlexRequests.Services.Notification
|
||||||
await Push(settings, message, pushTitle);
|
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)
|
private async Task Push(PushbulletNotificationSettings settings, string message, string title)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -81,6 +81,11 @@ namespace PlexRequests.Services.Notification
|
||||||
case NotificationType.Test:
|
case NotificationType.Test:
|
||||||
await PushTestAsync(model, pushSettings);
|
await PushTestAsync(model, pushSettings);
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.RequestDeclined:
|
||||||
|
break;
|
||||||
|
case NotificationType.ItemAddedToFaultQueue:
|
||||||
|
await PushFaultQueue(model, pushSettings);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -122,6 +127,12 @@ namespace PlexRequests.Services.Notification
|
||||||
await Push(settings, message);
|
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)
|
private async Task Push(PushoverNotificationSettings settings, string message)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -88,6 +88,11 @@ namespace PlexRequests.Services.Notification
|
||||||
case NotificationType.Test:
|
case NotificationType.Test:
|
||||||
await PushTest(pushSettings);
|
await PushTest(pushSettings);
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.RequestDeclined:
|
||||||
|
break;
|
||||||
|
case NotificationType.ItemAddedToFaultQueue:
|
||||||
|
await PushFaultQueue(model, pushSettings);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
@ -111,6 +116,12 @@ namespace PlexRequests.Services.Notification
|
||||||
await Push(settings, message);
|
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)
|
private async Task Push(SlackNotificationSettings config, string message)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -36,6 +36,14 @@
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.Build.Framework" />
|
<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">
|
<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>
|
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -81,18 +89,22 @@
|
||||||
<Compile Include="Interfaces\IJobRecord.cs" />
|
<Compile Include="Interfaces\IJobRecord.cs" />
|
||||||
<Compile Include="Interfaces\INotificationEngine.cs" />
|
<Compile Include="Interfaces\INotificationEngine.cs" />
|
||||||
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
<Compile Include="Jobs\HtmlTemplateGenerator.cs" />
|
||||||
|
<Compile Include="Jobs\IPlexContentCacher.cs" />
|
||||||
<Compile Include="Jobs\IRecentlyAdded.cs" />
|
<Compile Include="Jobs\IRecentlyAdded.cs" />
|
||||||
<Compile Include="Jobs\JobRecord.cs" />
|
<Compile Include="Jobs\JobRecord.cs" />
|
||||||
<Compile Include="Jobs\JobNames.cs" />
|
<Compile Include="Jobs\JobNames.cs" />
|
||||||
|
<Compile Include="Jobs\PlexContentCacher.cs" />
|
||||||
<Compile Include="Jobs\PlexEpisodeCacher.cs" />
|
<Compile Include="Jobs\PlexEpisodeCacher.cs" />
|
||||||
<Compile Include="Jobs\RecentlyAdded.cs" />
|
<Compile Include="Jobs\RecentlyAdded.cs" />
|
||||||
<Compile Include="Jobs\StoreBackup.cs" />
|
<Compile Include="Jobs\StoreBackup.cs" />
|
||||||
|
<Compile Include="Jobs\PlexUserChecker.cs" />
|
||||||
<Compile Include="Jobs\StoreCleanup.cs" />
|
<Compile Include="Jobs\StoreCleanup.cs" />
|
||||||
<Compile Include="Jobs\CouchPotatoCacher.cs" />
|
<Compile Include="Jobs\CouchPotatoCacher.cs" />
|
||||||
<Compile Include="Jobs\PlexAvailabilityChecker.cs" />
|
<Compile Include="Jobs\PlexAvailabilityChecker.cs" />
|
||||||
<Compile Include="Jobs\SickRageCacher.cs" />
|
<Compile Include="Jobs\SickRageCacher.cs" />
|
||||||
<Compile Include="Jobs\SonarrCacher.cs" />
|
<Compile Include="Jobs\SonarrCacher.cs" />
|
||||||
<Compile Include="Jobs\Templates\RecentlyAddedTemplate.cs" />
|
<Compile Include="Jobs\Templates\RecentlyAddedTemplate.cs" />
|
||||||
|
<Compile Include="Jobs\FaultQueueHandler.cs" />
|
||||||
<Compile Include="Jobs\UserRequestLimitResetter.cs" />
|
<Compile Include="Jobs\UserRequestLimitResetter.cs" />
|
||||||
<Compile Include="Models\PlexAlbum.cs" />
|
<Compile Include="Models\PlexAlbum.cs" />
|
||||||
<Compile Include="Models\PlexEpisodeModel.cs" />
|
<Compile Include="Models\PlexEpisodeModel.cs" />
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
||||||
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
||||||
<package id="MimeKit" version="1.2.22" targetFramework="net45" />
|
<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="NLog" version="4.3.6" targetFramework="net45" />
|
||||||
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
<package id="Quartz" version="2.3.3" targetFramework="net45" />
|
||||||
</packages>
|
</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.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Dapper.Contrib.Extensions;
|
||||||
|
|
||||||
namespace PlexRequests.Store.Models
|
namespace PlexRequests.Store.Models
|
||||||
{
|
{
|
||||||
|
[Table(nameof(PlexUsers))]
|
||||||
public class PlexUsers : Entity
|
public class PlexUsers : Entity
|
||||||
{
|
{
|
||||||
public int PlexUserId { get; set; }
|
public string PlexUserId { get; set; }
|
||||||
public string UserAlias { 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 string Name { get; set; }
|
||||||
public DateTime LastRun { get; set; }
|
public DateTime LastRun { get; set; }
|
||||||
|
public bool Running { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,9 @@
|
||||||
<Compile Include="Models\PlexEpisodes.cs" />
|
<Compile Include="Models\PlexEpisodes.cs" />
|
||||||
<Compile Include="Models\PlexUsers.cs" />
|
<Compile Include="Models\PlexUsers.cs" />
|
||||||
<Compile Include="Models\Plex\MetadataItems.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\ScheduledJobs.cs" />
|
||||||
<Compile Include="Models\RequestLimit.cs" />
|
<Compile Include="Models\RequestLimit.cs" />
|
||||||
<Compile Include="Models\UsersToNotify.cs" />
|
<Compile Include="Models\UsersToNotify.cs" />
|
||||||
|
@ -85,6 +88,8 @@
|
||||||
<Compile Include="Repository\SettingsJsonRepository.cs" />
|
<Compile Include="Repository\SettingsJsonRepository.cs" />
|
||||||
<Compile Include="Repository\RequestJsonRepository.cs" />
|
<Compile Include="Repository\RequestJsonRepository.cs" />
|
||||||
<Compile Include="Repository\GenericRepository.cs" />
|
<Compile Include="Repository\GenericRepository.cs" />
|
||||||
|
<Compile Include="Repository\PlexUserRepository.cs" />
|
||||||
|
<Compile Include="Repository\UserRepository.cs" />
|
||||||
<Compile Include="RequestedModel.cs" />
|
<Compile Include="RequestedModel.cs" />
|
||||||
<Compile Include="UserEntity.cs" />
|
<Compile Include="UserEntity.cs" />
|
||||||
<Compile Include="UserLogins.cs" />
|
<Compile Include="UserLogins.cs" />
|
||||||
|
|
|
@ -327,5 +327,22 @@ namespace PlexRequests.Store.Repository
|
||||||
throw;
|
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);
|
IEnumerable<T> Custom(Func<IDbConnection, IEnumerable<T>> func);
|
||||||
Task<IEnumerable<T>> CustomAsync(Func<IDbConnection, Task<IEnumerable<T>>> func);
|
Task<IEnumerable<T>> CustomAsync(Func<IDbConnection, Task<IEnumerable<T>>> func);
|
||||||
void DeleteAll(string tableName);
|
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,
|
UserName varchar(50) NOT NULL,
|
||||||
Salt BLOB NOT NULL,
|
Salt BLOB NOT NULL,
|
||||||
Hash 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
|
CREATE TABLE IF NOT EXISTS UserLogins
|
||||||
|
@ -78,7 +80,8 @@ CREATE TABLE IF NOT EXISTS ScheduledJobs
|
||||||
(
|
(
|
||||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
Name varchar(100) NOT NULL,
|
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);
|
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
|
CREATE TABLE IF NOT EXISTS PlexUsers
|
||||||
(
|
(
|
||||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
PlexUserId INTEGER NOT NULL,
|
PlexUserId varchar(100) NOT NULL,
|
||||||
UserAlias 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);
|
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 UNIQUE INDEX IF NOT EXISTS PlexEpisodes_Id ON PlexEpisodes (Id);
|
||||||
CREATE INDEX IF NOT EXISTS PlexEpisodes_ProviderId ON PlexEpisodes (ProviderId);
|
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;
|
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();
|
connection.Open();
|
||||||
var result = connection.Query<TableInfo>($"PRAGMA table_info({tableName});");
|
var result = connection.Query<TableInfo>($"PRAGMA table_info({tableName});");
|
||||||
if (result.Any(x => x.name == newColumn))
|
if (result.Any(x => x.name == newColumn))
|
||||||
{
|
{
|
||||||
|
connection.Close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,10 @@ namespace PlexRequests.Store
|
||||||
{
|
{
|
||||||
public byte[] Hash { get; set; }
|
public byte[] Hash { get; set; }
|
||||||
public byte[] Salt { get; set; }
|
public byte[] Salt { get; set; }
|
||||||
|
[Obsolete]
|
||||||
public byte[] Claims { get; set; }
|
public byte[] Claims { get; set; }
|
||||||
public byte[] UserProperties { get; set; }
|
public byte[] UserProperties { get; set; }
|
||||||
|
public int Permissions { get; set; }
|
||||||
|
public int Features { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,164 +1,167 @@
|
||||||
#region Copyright
|
//#region Copyright
|
||||||
// /************************************************************************
|
//// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
//// Copyright (c) 2016 Jamie Rees
|
||||||
// File: SearchModuleTests.cs
|
//// File: SearchModuleTests.cs
|
||||||
// Created By: Jamie Rees
|
//// Created By: Jamie Rees
|
||||||
//
|
////
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
//// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
//// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
//// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
//// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
//// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
//// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
//// the following conditions:
|
||||||
//
|
////
|
||||||
// The above copyright notice and this permission notice shall be
|
//// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
//// included in all copies or substantial portions of the Software.
|
||||||
//
|
////
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
//// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
//// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
//// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
//// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
//// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
//// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
//// ************************************************************************/
|
||||||
#endregion
|
//#endregion
|
||||||
|
|
||||||
using System;
|
//using System;
|
||||||
using System.Collections.Generic;
|
//using System.Collections.Generic;
|
||||||
using System.Linq;
|
//using System.Linq;
|
||||||
using Moq;
|
//using Moq;
|
||||||
using NUnit.Framework;
|
//using NUnit.Framework;
|
||||||
using PlexRequests.Api.Interfaces;
|
//using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Api.Models.Plex;
|
//using PlexRequests.Api.Models.Plex;
|
||||||
using PlexRequests.Core;
|
//using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
//using PlexRequests.Core.Queue;
|
||||||
using PlexRequests.Helpers;
|
//using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Helpers.Analytics;
|
//using PlexRequests.Helpers;
|
||||||
using PlexRequests.Services.Interfaces;
|
//using PlexRequests.Helpers.Analytics;
|
||||||
using PlexRequests.Services.Jobs;
|
//using PlexRequests.Services.Interfaces;
|
||||||
using PlexRequests.Store;
|
//using PlexRequests.Services.Jobs;
|
||||||
using PlexRequests.Store.Models;
|
//using PlexRequests.Store;
|
||||||
using PlexRequests.Store.Repository;
|
//using PlexRequests.Store.Models;
|
||||||
using PlexRequests.UI.Modules;
|
//using PlexRequests.Store.Repository;
|
||||||
using Ploeh.AutoFixture;
|
//using PlexRequests.UI.Modules;
|
||||||
|
//using Ploeh.AutoFixture;
|
||||||
|
|
||||||
namespace PlexRequests.UI.Tests
|
//namespace PlexRequests.UI.Tests
|
||||||
{
|
//{
|
||||||
[TestFixture]
|
// [TestFixture]
|
||||||
public class SearchModuleTests
|
// public class SearchModuleTests
|
||||||
{
|
// {
|
||||||
private Mock<ISettingsService<HeadphonesSettings>> _headphonesSettings;
|
// private Mock<ISettingsService<HeadphonesSettings>> _headphonesSettings;
|
||||||
private Mock<INotificationService> _notificationService;
|
// private Mock<INotificationService> _notificationService;
|
||||||
private Mock<ISettingsService<SickRageSettings>> _sickRageSettingsMock;
|
// private Mock<ISettingsService<SickRageSettings>> _sickRageSettingsMock;
|
||||||
private Mock<ICouchPotatoApi> _cpApi;
|
// private Mock<ICouchPotatoApi> _cpApi;
|
||||||
private Mock<ISettingsService<SonarrSettings>> _sonarrSettingsMock;
|
// private Mock<ISettingsService<SonarrSettings>> _sonarrSettingsMock;
|
||||||
private Mock<ISonarrApi> _sonarrApiMock;
|
// private Mock<ISonarrApi> _sonarrApiMock;
|
||||||
private Mock<ISettingsService<PlexSettings>> _plexSettingsMock;
|
// private Mock<ISettingsService<PlexSettings>> _plexSettingsMock;
|
||||||
private Mock<ISettingsService<CouchPotatoSettings>> _cpMock;
|
// private Mock<ISettingsService<CouchPotatoSettings>> _cpMock;
|
||||||
private Mock<ISettingsService<PlexRequestSettings>> _plexRequestMock;
|
// private Mock<ISettingsService<PlexRequestSettings>> _plexRequestMock;
|
||||||
private Mock<ISettingsService<AuthenticationSettings>> _authMock;
|
// private Mock<ISettingsService<AuthenticationSettings>> _authMock;
|
||||||
private Mock<IAnalytics> _analytics;
|
// private Mock<IAnalytics> _analytics;
|
||||||
private Mock<IAvailabilityChecker> _availabilityMock;
|
// private Mock<IAvailabilityChecker> _availabilityMock;
|
||||||
private Mock<IRequestService> _rServiceMock;
|
// private Mock<IRequestService> _rServiceMock;
|
||||||
private Mock<ISickRageApi> _srApi;
|
// private Mock<ISickRageApi> _srApi;
|
||||||
private Mock<IMusicBrainzApi> _music;
|
// private Mock<IMusicBrainzApi> _music;
|
||||||
private Mock<IHeadphonesApi> _hpAPi;
|
// private Mock<IHeadphonesApi> _hpAPi;
|
||||||
private Mock<ICouchPotatoCacher> _cpCache;
|
// private Mock<ICouchPotatoCacher> _cpCache;
|
||||||
private Mock<ISonarrCacher> _sonarrCache;
|
// private Mock<ISonarrCacher> _sonarrCache;
|
||||||
private Mock<ISickRageCacher> _srCache;
|
// private Mock<ISickRageCacher> _srCache;
|
||||||
private Mock<IPlexApi> _plexApi;
|
// private Mock<IPlexApi> _plexApi;
|
||||||
private Mock<IRepository<UsersToNotify>> _userRepo;
|
// private Mock<IRepository<UsersToNotify>> _userRepo;
|
||||||
private Mock<ISettingsService<EmailNotificationSettings>> _emailSettings;
|
// private Mock<ISettingsService<EmailNotificationSettings>> _emailSettings;
|
||||||
private Mock<IIssueService> _issueService;
|
// private Mock<IIssueService> _issueService;
|
||||||
private Mock<ICacheProvider> _cache;
|
// private Mock<ICacheProvider> _cache;
|
||||||
private Mock<IRepository<RequestLimit>> RequestLimitRepo { get; set; }
|
// private Mock<ITransientFaultQueue> _faultQueue;
|
||||||
private SearchModule Search { get; set; }
|
// private Mock<IRepository<RequestLimit>> RequestLimitRepo { get; set; }
|
||||||
private readonly Fixture F = new Fixture();
|
// private SearchModule Search { get; set; }
|
||||||
|
// private readonly Fixture F = new Fixture();
|
||||||
|
|
||||||
[Test]
|
// [Test]
|
||||||
public void CheckNoRequestLimitTest()
|
// public void CheckNoRequestLimitTest()
|
||||||
{
|
// {
|
||||||
var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 2, TvWeeklyRequestLimit = 0 };
|
// var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 2, TvWeeklyRequestLimit = 0 };
|
||||||
var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
// var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
||||||
|
|
||||||
Assert.That(result, Is.True);
|
// Assert.That(result, Is.True);
|
||||||
RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
// RequestLimitRepo.Verify(x => x.GetAllAsync(), Times.Once);
|
||||||
}
|
// }
|
||||||
|
|
||||||
[TestCaseSource(nameof(MovieLimitData))]
|
// [TestCaseSource(nameof(MovieLimitData))]
|
||||||
public bool CheckMovieLimitTest(int requestCount)
|
// public bool CheckMovieLimitTest(int requestCount)
|
||||||
{
|
// {
|
||||||
var users = F.CreateMany<RequestLimit>().ToList();
|
// var users = F.CreateMany<RequestLimit>().ToList();
|
||||||
users.Add(new RequestLimit { Username = "", RequestCount = requestCount, RequestType = RequestType.Movie});
|
// users.Add(new RequestLimit { Username = "", RequestCount = requestCount, RequestType = RequestType.Movie});
|
||||||
RequestLimitRepo.Setup(x => x.GetAllAsync()).ReturnsAsync(users);
|
// RequestLimitRepo.Setup(x => x.GetAllAsync()).ReturnsAsync(users);
|
||||||
var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 5, TvWeeklyRequestLimit = 0 };
|
// var settings = new PlexRequestSettings { AlbumWeeklyRequestLimit = 0, MovieWeeklyRequestLimit = 5, TvWeeklyRequestLimit = 0 };
|
||||||
var result = Search.CheckRequestLimit(settings, RequestType.Movie).Result;
|
// 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
|
// private static IEnumerable<TestCaseData> MovieLimitData
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
yield return new TestCaseData(1).Returns(true).SetName("1 Request of 5");
|
// 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(2).Returns(true).SetName("2 Request of 5");
|
||||||
yield return new TestCaseData(3).Returns(true).SetName("3 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(4).Returns(true).SetName("4 Request of 5");
|
||||||
yield return new TestCaseData(5).Returns(false).SetName("5 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(6).Returns(false).SetName("6 Request of 5");
|
||||||
yield return new TestCaseData(0).Returns(true).SetName("0 Request of 5");
|
// yield return new TestCaseData(0).Returns(true).SetName("0 Request of 5");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[SetUp]
|
// [SetUp]
|
||||||
public void Setup()
|
// public void Setup()
|
||||||
{
|
// {
|
||||||
_authMock = new Mock<Core.ISettingsService<AuthenticationSettings>>();
|
// _authMock = new Mock<Core.ISettingsService<AuthenticationSettings>>();
|
||||||
_plexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
|
// _plexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
|
||||||
_plexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
|
// _plexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
|
||||||
_cpMock = new Mock<Core.ISettingsService<CouchPotatoSettings>>();
|
// _cpMock = new Mock<Core.ISettingsService<CouchPotatoSettings>>();
|
||||||
_plexSettingsMock = new Mock<Core.ISettingsService<PlexSettings>>();
|
// _plexSettingsMock = new Mock<Core.ISettingsService<PlexSettings>>();
|
||||||
_sonarrApiMock = new Mock<ISonarrApi>();
|
// _sonarrApiMock = new Mock<ISonarrApi>();
|
||||||
_sonarrSettingsMock = new Mock<Core.ISettingsService<SonarrSettings>>();
|
// _sonarrSettingsMock = new Mock<Core.ISettingsService<SonarrSettings>>();
|
||||||
_cpApi = new Mock<ICouchPotatoApi>();
|
// _cpApi = new Mock<ICouchPotatoApi>();
|
||||||
_sickRageSettingsMock = new Mock<Core.ISettingsService<SickRageSettings>>();
|
// _sickRageSettingsMock = new Mock<Core.ISettingsService<SickRageSettings>>();
|
||||||
_notificationService = new Mock<INotificationService>();
|
// _notificationService = new Mock<INotificationService>();
|
||||||
_headphonesSettings = new Mock<Core.ISettingsService<HeadphonesSettings>>();
|
// _headphonesSettings = new Mock<Core.ISettingsService<HeadphonesSettings>>();
|
||||||
_cache = new Mock<ICacheProvider>();
|
// _cache = new Mock<ICacheProvider>();
|
||||||
|
|
||||||
_analytics = new Mock<IAnalytics>();
|
// _analytics = new Mock<IAnalytics>();
|
||||||
_availabilityMock = new Mock<IAvailabilityChecker>();
|
// _availabilityMock = new Mock<IAvailabilityChecker>();
|
||||||
_rServiceMock = new Mock<IRequestService>();
|
// _rServiceMock = new Mock<IRequestService>();
|
||||||
_srApi = new Mock<ISickRageApi>();
|
// _srApi = new Mock<ISickRageApi>();
|
||||||
_music = new Mock<IMusicBrainzApi>();
|
// _music = new Mock<IMusicBrainzApi>();
|
||||||
_hpAPi = new Mock<IHeadphonesApi>();
|
// _hpAPi = new Mock<IHeadphonesApi>();
|
||||||
_cpCache = new Mock<ICouchPotatoCacher>();
|
// _cpCache = new Mock<ICouchPotatoCacher>();
|
||||||
_sonarrCache = new Mock<ISonarrCacher>();
|
// _sonarrCache = new Mock<ISonarrCacher>();
|
||||||
_srCache = new Mock<ISickRageCacher>();
|
// _srCache = new Mock<ISickRageCacher>();
|
||||||
_plexApi = new Mock<IPlexApi>();
|
// _plexApi = new Mock<IPlexApi>();
|
||||||
_userRepo = new Mock<IRepository<UsersToNotify>>();
|
// _userRepo = new Mock<IRepository<UsersToNotify>>();
|
||||||
RequestLimitRepo = new Mock<IRepository<RequestLimit>>();
|
// RequestLimitRepo = new Mock<IRepository<RequestLimit>>();
|
||||||
_emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
// _emailSettings = new Mock<ISettingsService<EmailNotificationSettings>>();
|
||||||
_issueService = new Mock<IIssueService>();
|
// _issueService = new Mock<IIssueService>();
|
||||||
CreateModule();
|
// _faultQueue = new Mock<ITransientFaultQueue>();
|
||||||
}
|
// CreateModule();
|
||||||
|
// }
|
||||||
|
|
||||||
private void CreateModule()
|
// private void CreateModule()
|
||||||
{
|
// {
|
||||||
Search = new SearchModule(_cache.Object, _cpMock.Object, _plexRequestMock.Object, _availabilityMock.Object,
|
// Search = new SearchModule(_cache.Object, _cpMock.Object, _plexRequestMock.Object, _availabilityMock.Object,
|
||||||
_rServiceMock.Object, _sonarrApiMock.Object, _sonarrSettingsMock.Object,
|
// _rServiceMock.Object, _sonarrApiMock.Object, _sonarrSettingsMock.Object,
|
||||||
_sickRageSettingsMock.Object, _cpApi.Object, _srApi.Object, _notificationService.Object,
|
// _sickRageSettingsMock.Object, _cpApi.Object, _srApi.Object, _notificationService.Object,
|
||||||
_music.Object, _hpAPi.Object, _headphonesSettings.Object, _cpCache.Object, _sonarrCache.Object,
|
// _music.Object, _hpAPi.Object, _headphonesSettings.Object, _cpCache.Object, _sonarrCache.Object,
|
||||||
_srCache.Object, _plexApi.Object, _plexSettingsMock.Object, _authMock.Object,
|
// _srCache.Object, _plexApi.Object, _plexSettingsMock.Object, _authMock.Object,
|
||||||
_userRepo.Object, _emailSettings.Object, _issueService.Object, _analytics.Object, RequestLimitRepo.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.Interfaces;
|
||||||
using PlexRequests.Api.Models.Sonarr;
|
using PlexRequests.Api.Models.Sonarr;
|
||||||
|
using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Store;
|
using PlexRequests.Store;
|
||||||
using PlexRequests.UI.Helpers;
|
using PlexRequests.UI.Helpers;
|
||||||
|
@ -146,32 +147,6 @@ namespace PlexRequests.UI.Tests
|
||||||
true, It.IsAny<bool>()), Times.Once);
|
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()
|
private SonarrSettings GetSonarrSettings()
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,7 @@ using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Api.Models.Plex;
|
using PlexRequests.Api.Models.Plex;
|
||||||
using PlexRequests.Core;
|
using PlexRequests.Core;
|
||||||
using PlexRequests.Core.SettingModels;
|
using PlexRequests.Core.SettingModels;
|
||||||
|
using PlexRequests.Helpers;
|
||||||
using PlexRequests.Helpers.Analytics;
|
using PlexRequests.Helpers.Analytics;
|
||||||
using PlexRequests.UI.Models;
|
using PlexRequests.UI.Models;
|
||||||
using PlexRequests.UI.Modules;
|
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