diff --git a/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs b/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs index 7b4274b3f..db5a21b50 100644 --- a/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/BaseEngine.cs @@ -1,5 +1,4 @@ -using Ombi.Core.Claims; -using Ombi.Core.Rule; +using Ombi.Core.Rule; using System.Collections.Generic; using System.Security.Principal; using System.Threading.Tasks; @@ -18,24 +17,13 @@ namespace Ombi.Core.Engine.Interfaces } protected IPrincipal User { get; } - protected IRuleEvaluator Rules { get; } - protected string Username => User.Identity.Name; protected bool HasRole(string roleName) { return User.IsInRole(roleName); } - - protected bool ShouldSendNotification(BaseRequest req) - { - var sendNotification = !req.Approved; /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/ - - if (HasRole(OmbiClaims.Admin)) - sendNotification = false; // Don't bother sending a notification if the user is an admin - return sendNotification; - } public async Task> RunRequestRules(BaseRequest model) { diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 6f21f79df..4ea334571 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -182,7 +182,8 @@ namespace Ombi.Core.Engine { await MovieRepository.Add(model); - if (ShouldSendNotification(model)) + var result = await RunSpecificRule(model, SpecificRules.CanSendNotification); + if (result.Success) { NotificationHelper.NewRequest(model); } diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index b7261cb63..b6a71aac4 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -12,6 +12,7 @@ using System.Security.Principal; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Engine.Interfaces; +using Ombi.Core.Helpers; using Ombi.Core.IdentityResolver; using Ombi.Core.Rule; using Ombi.Core.Rule.Interfaces; @@ -42,128 +43,17 @@ namespace Ombi.Core.Engine public async Task RequestTvShow(SearchTvShowViewModel tv) { - var showInfo = await TvApi.ShowLookupByTheTvDbId(tv.Id); - DateTime.TryParse(showInfo.premiered, out DateTime firstAir); - - // For some reason the poster path is always http - var posterPath = showInfo.image?.medium.Replace("http:", "https:"); - - var tvRequests = new List(); - // Only have the TV requests we actually requested and not everything - foreach (var season in tv.SeasonRequests) - { - for (int i = season.Episodes.Count - 1; i >= 0; i--) - { - if (!season.Episodes[i].Requested) - { - season.Episodes.RemoveAt(i); // Remove the episode since it's not requested - } - } - - if (season.Episodes.Any()) - { - tvRequests.Add(season); - } - } - var user = await UserManager.GetUser(User.Identity.Name); - var childRequest = new ChildRequests - { - Id = tv.Id, - RequestType = RequestType.TvShow, - RequestedDate = DateTime.UtcNow, - Approved = false, - RequestedUserId = user.Id, - SeasonRequests = new List() - }; - if (tv.RequestAll) - { - var episodes = await TvApi.EpisodeLookup(showInfo.id); - foreach (var ep in episodes) - { - var season = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season); - if (season == null) - { - childRequest.SeasonRequests.Add(new SeasonRequests - { - Episodes = new List{ - new EpisodeRequests - { - EpisodeNumber = ep.number, - AirDate = DateTime.Parse(ep.airdate), - Title = ep.name, - Url = ep.url - } - }, - SeasonNumber = ep.season, - }); - } - else - { - season.Episodes.Add(new EpisodeRequests - { - EpisodeNumber = ep.number, - AirDate = DateTime.Parse(ep.airdate), - Title = ep.name, - Url = ep.url - }); - } - } + var tvBuilder = new TvShowRequestBuilder(TvApi); + (await tvBuilder + .GetShowInfo(tv.Id)) + .CreateTvList(tv) + .CreateChild(tv, user.Id); - } - else if (tv.LatestSeason) - { - var episodes = await TvApi.EpisodeLookup(showInfo.id); - var latest = episodes.OrderBy(x => x.season).FirstOrDefault(); - var episodesRequests = new List(); - foreach (var ep in episodes) - { - episodesRequests.Add(new EpisodeRequests - { - EpisodeNumber = ep.number, - AirDate = DateTime.Parse(ep.airdate), - Title = ep.name, - Url = ep.url - }); - } - childRequest.SeasonRequests.Add(new SeasonRequests - { - Episodes = episodesRequests, - SeasonNumber = latest.season, - }); - } - else if (tv.FirstSeason) - { - var episodes = await TvApi.EpisodeLookup(showInfo.id); - var first = episodes.OrderByDescending(x => x.season).FirstOrDefault(); - var episodesRequests = new List(); - foreach (var ep in episodes) - { - if (ep.season == first.season) - { - episodesRequests.Add(new EpisodeRequests - { - EpisodeNumber = ep.number, - AirDate = DateTime.Parse(ep.airdate), - Title = ep.name, - Url = ep.url - }); - } - } - childRequest.SeasonRequests.Add(new SeasonRequests - { - Episodes = episodesRequests, - SeasonNumber = first.season, - }); - } - else - { - // It's a custom request - childRequest.SeasonRequests = tvRequests; - } - - var ruleResults = await RunRequestRules(childRequest); + await tvBuilder.BuildEpisodes(tv); + + var ruleResults = await RunRequestRules(tvBuilder.ChildRequest); var results = ruleResults as RuleResult[] ?? ruleResults.ToArray(); if (results.Any(x => !x.Success)) { @@ -180,7 +70,7 @@ namespace Ombi.Core.Engine foreach (var existingSeason in existingRequest.ChildRequests) foreach (var existing in existingSeason.SeasonRequests) { - var newChild = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == existing.SeasonNumber); + var newChild = tvBuilder.ChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == existing.SeasonNumber); if (newChild != null) { // We have some requests in this season... @@ -197,32 +87,19 @@ namespace Ombi.Core.Engine if (!newChild.Episodes.Any()) { // We may have removed all episodes - childRequest.SeasonRequests.Remove(newChild); + tvBuilder.ChildRequest.SeasonRequests.Remove(newChild); } } } // Remove the ID since this is a new child - childRequest.Id = 0; - return await AddExistingRequest(childRequest, existingRequest); + tvBuilder.ChildRequest.Id = 0; + return await AddExistingRequest(tvBuilder.ChildRequest, existingRequest); } // This is a new request - var model = new TvRequests - { - Id = tv.Id, - Overview = showInfo.summary.RemoveHtml(), - PosterPath = posterPath, - Title = showInfo.name, - ReleaseDate = firstAir, - Status = showInfo.status, - ImdbId = showInfo.externals?.imdb ?? string.Empty, - TvDbId = tv.Id, - ChildRequests = new List(), - TotalSeasons = tv.SeasonRequests.Count() - }; - model.ChildRequests.Add(childRequest); - return await AddRequest(model); + var newRequest = tvBuilder.CreateNewRequest(tv); + return await AddRequest(newRequest.NewRequest); } public async Task> GetRequests(int count, int position) diff --git a/src/Ombi.Core/NotificationHelper.cs b/src/Ombi.Core/Helpers/NotificationHelper.cs similarity index 100% rename from src/Ombi.Core/NotificationHelper.cs rename to src/Ombi.Core/Helpers/NotificationHelper.cs diff --git a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs new file mode 100644 index 000000000..3f28d6ff2 --- /dev/null +++ b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ombi.Api.TvMaze; +using Ombi.Api.TvMaze.Models; +using Ombi.Core.Models.Search; +using Ombi.Helpers; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Core.Helpers +{ + public class TvShowRequestBuilder + { + + public TvShowRequestBuilder(ITvMazeApi tvApi) + { + TvApi = tvApi; + } + + private ITvMazeApi TvApi { get; } + + public ChildRequests ChildRequest { get; set; } + public List TvRequests { get; protected set; } + public string PosterPath { get; protected set; } + public DateTime FirstAir { get; protected set; } + public TvRequests NewRequest { get; protected set; } + protected TvMazeShow ShowInfo { get; set; } + + public async Task GetShowInfo(int id) + { + ShowInfo = await TvApi.ShowLookupByTheTvDbId(id); + + DateTime.TryParse(ShowInfo.premiered, out DateTime dt); + + FirstAir = dt; + + // For some reason the poster path is always http + PosterPath = ShowInfo.image?.medium.Replace("http:", "https:"); + + return this; + } + + public TvShowRequestBuilder CreateChild(SearchTvShowViewModel model, int userId) + { + ChildRequest = new ChildRequests + { + Id = model.Id, + RequestType = RequestType.TvShow, + RequestedDate = DateTime.UtcNow, + Approved = false, + RequestedUserId = userId, + SeasonRequests = new List() + }; + + return this; + } + + public TvShowRequestBuilder CreateTvList(SearchTvShowViewModel tv) + { + TvRequests = new List(); + // Only have the TV requests we actually requested and not everything + foreach (var season in tv.SeasonRequests) + { + for (int i = season.Episodes.Count - 1; i >= 0; i--) + { + if (!season.Episodes[i].Requested) + { + season.Episodes.RemoveAt(i); // Remove the episode since it's not requested + } + } + + if (season.Episodes.Any()) + { + TvRequests.Add(season); + } + } + + return this; + + } + + + public async Task BuildEpisodes(SearchTvShowViewModel tv) + { + if (tv.RequestAll) + { + var episodes = await TvApi.EpisodeLookup(ShowInfo.id); + foreach (var ep in episodes) + { + var season = ChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == ep.season); + if (season == null) + { + ChildRequest.SeasonRequests.Add(new SeasonRequests + { + Episodes = new List{ + new EpisodeRequests + { + EpisodeNumber = ep.number, + AirDate = DateTime.Parse(ep.airdate), + Title = ep.name, + Url = ep.url + } + }, + SeasonNumber = ep.season, + }); + } + else + { + season.Episodes.Add(new EpisodeRequests + { + EpisodeNumber = ep.number, + AirDate = DateTime.Parse(ep.airdate), + Title = ep.name, + Url = ep.url + }); + } + } + + } + else if (tv.LatestSeason) + { + var episodes = await TvApi.EpisodeLookup(ShowInfo.id); + var latest = episodes.OrderBy(x => x.season).FirstOrDefault(); + var episodesRequests = new List(); + foreach (var ep in episodes) + { + episodesRequests.Add(new EpisodeRequests + { + EpisodeNumber = ep.number, + AirDate = DateTime.Parse(ep.airdate), + Title = ep.name, + Url = ep.url + }); + } + ChildRequest.SeasonRequests.Add(new SeasonRequests + { + Episodes = episodesRequests, + SeasonNumber = latest.season, + }); + } + else if (tv.FirstSeason) + { + var episodes = await TvApi.EpisodeLookup(ShowInfo.id); + var first = episodes.OrderByDescending(x => x.season).FirstOrDefault(); + var episodesRequests = new List(); + foreach (var ep in episodes) + { + if (ep.season == first.season) + { + episodesRequests.Add(new EpisodeRequests + { + EpisodeNumber = ep.number, + AirDate = DateTime.Parse(ep.airdate), + Title = ep.name, + Url = ep.url + }); + } + } + ChildRequest.SeasonRequests.Add(new SeasonRequests + { + Episodes = episodesRequests, + SeasonNumber = first.season, + }); + } + else + { + // It's a custom request + ChildRequest.SeasonRequests = TvRequests; + } + return this; + } + + + public TvShowRequestBuilder CreateNewRequest(SearchTvShowViewModel tv) + { + NewRequest = new TvRequests + { + Id = tv.Id, + Overview = ShowInfo.summary.RemoveHtml(), + PosterPath = PosterPath, + Title = ShowInfo.name, + ReleaseDate = FirstAir, + Status = ShowInfo.status, + ImdbId = ShowInfo.externals?.imdb ?? string.Empty, + TvDbId = tv.Id, + ChildRequests = new List(), + TotalSeasons = tv.SeasonRequests.Count() + }; + NewRequest.ChildRequests.Add(ChildRequest); + + return this; + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/IMovieSender.cs b/src/Ombi.Core/Senders/IMovieSender.cs similarity index 100% rename from src/Ombi.Core/IMovieSender.cs rename to src/Ombi.Core/Senders/IMovieSender.cs diff --git a/src/Ombi.Core/INotificationHelper.cs b/src/Ombi.Core/Senders/INotificationHelper.cs similarity index 100% rename from src/Ombi.Core/INotificationHelper.cs rename to src/Ombi.Core/Senders/INotificationHelper.cs diff --git a/src/Ombi.Core/ITvSender.cs b/src/Ombi.Core/Senders/ITvSender.cs similarity index 100% rename from src/Ombi.Core/ITvSender.cs rename to src/Ombi.Core/Senders/ITvSender.cs diff --git a/src/Ombi.Core/MovieSender.cs b/src/Ombi.Core/Senders/MovieSender.cs similarity index 100% rename from src/Ombi.Core/MovieSender.cs rename to src/Ombi.Core/Senders/MovieSender.cs diff --git a/src/Ombi.Core/MovieSenderResult.cs b/src/Ombi.Core/Senders/MovieSenderResult.cs similarity index 100% rename from src/Ombi.Core/MovieSenderResult.cs rename to src/Ombi.Core/Senders/MovieSenderResult.cs diff --git a/src/Ombi.Core/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs similarity index 100% rename from src/Ombi.Core/TvSender.cs rename to src/Ombi.Core/Senders/TvSender.cs diff --git a/src/Ombi.Notifications.Tests/NotificationMessageResolverTests.cs b/src/Ombi.Notifications.Tests/NotificationMessageResolverTests.cs new file mode 100644 index 000000000..b3b66de43 --- /dev/null +++ b/src/Ombi.Notifications.Tests/NotificationMessageResolverTests.cs @@ -0,0 +1,32 @@ +//using System.Linq; +//using Ombi.Store.Entities; +//using Xunit; +//using Xunit.Abstractions; + +//namespace Ombi.Notifications.Tests +//{ +// public class NotificationMessageResolverTests +// { +// public NotificationMessageResolverTests(ITestOutputHelper helper) +// { +// _resolver = new NotificationMessageResolver(); +// output = helper; +// } + +// private readonly NotificationMessageResolver _resolver; +// private readonly ITestOutputHelper output; + +// [Fact] +// public void Resolved_ShouldResolve_RequestedUser() +// { +// var result = _resolver.ParseMessage(new NotificationTemplates +// { +// Subject = "This is a {RequestedUser}" +// }, new NotificationMessageCurlys {RequestedUser = "Abc"}); +// output.WriteLine(result.Message); +// //Assert.True(result.Message.Equals("This is a Abc")); + +// Assert.Contains("11a", result.Message); +// } +// } +//} diff --git a/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj b/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj new file mode 100644 index 000000000..d6b0a4d1a --- /dev/null +++ b/src/Ombi.Notifications.Tests/Ombi.Notifications.Tests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp1.1 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Ombi.Notifications/NotificationMessageContent.cs b/src/Ombi.Notifications/NotificationMessageContent.cs new file mode 100644 index 000000000..e70b88072 --- /dev/null +++ b/src/Ombi.Notifications/NotificationMessageContent.cs @@ -0,0 +1,9 @@ +namespace Ombi.Notifications +{ + public class NotificationMessageContent + { + public string Subject { get; set; } + public string Message { get; set; } + public string Image { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/NotificationMessageCurlys.cs b/src/Ombi.Notifications/NotificationMessageCurlys.cs new file mode 100644 index 000000000..d41036e81 --- /dev/null +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Ombi.Store.Entities.Requests; + +namespace Ombi.Notifications +{ + public class NotificationMessageCurlys + { + + public void Setup(FullBaseRequest req) + { + RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) + ? req.RequestedUser.Username + : req.RequestedUser.Alias; + Title = req.Title; + RequestedDate = req.RequestedDate.ToString("D"); + Type = req.RequestType.ToString(); + Overview = req.Overview; + Year = req.ReleaseDate.Year.ToString(); + PosterImage = req.PosterPath; + } + + public void Setup(ChildRequests req) + { + RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) + ? req.RequestedUser.Username + : req.RequestedUser.Alias; + Title = req.ParentRequest.Title; + RequestedDate = req.RequestedDate.ToString("D"); + Type = req.RequestType.ToString(); + Overview = req.ParentRequest.Overview; + Year = req.ParentRequest.ReleaseDate.Year.ToString(); + PosterImage = req.ParentRequest.PosterPath; + // DO Episode and Season Lists + } + + // User Defined + public string RequestedUser { get; set; } + public string Title { get; set; } + public string RequestedDate { get; set; } + public string Type { get; set; } + public string Issue { get; set; } + public string Overview { get; set; } + public string Year { get; set; } + public string EpisodesList { get; set; } + public string SeasonsList { get; set; } + public string PosterImage { get; set; } + + // System Defined + private string LongDate => DateTime.Now.ToString("D"); + private string ShortDate => DateTime.Now.ToString("d"); + private string LongTime => DateTime.Now.ToString("T"); + private string ShortTime => DateTime.Now.ToString("t"); + + public Dictionary Curlys => new Dictionary + { + {nameof(RequestedUser), RequestedUser }, + {nameof(Title), Title }, + {nameof(RequestedDate), RequestedDate }, + {nameof(Type), Type }, + {nameof(Issue), Issue }, + {nameof(LongDate),LongDate}, + {nameof(ShortDate),ShortDate}, + {nameof(LongTime),LongTime}, + {nameof(ShortTime),ShortTime}, + {nameof(Overview),Overview}, + {nameof(Year),Year}, + {nameof(EpisodesList),EpisodesList}, + {nameof(SeasonsList),SeasonsList}, + {nameof(PosterImage),PosterImage}, + }; + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/NotificationMessageResolver.cs b/src/Ombi.Notifications/NotificationMessageResolver.cs index 371a79583..451ef1b55 100644 --- a/src/Ombi.Notifications/NotificationMessageResolver.cs +++ b/src/Ombi.Notifications/NotificationMessageResolver.cs @@ -1,84 +1,10 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.Diagnostics; using Ombi.Store.Entities; -using Ombi.Store.Entities.Requests; namespace Ombi.Notifications { - public class NotificationMessageContent - { - public string Subject { get; set; } - public string Message { get; set; } - public string Image { get; set; } - } - public class NotificationMessageCurlys - { - - public void Setup(FullBaseRequest req) - { - RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) - ? req.RequestedUser.Username - : req.RequestedUser.Alias; - Title = req.Title; - RequestedDate = req.RequestedDate.ToString("D"); - Type = req.RequestType.ToString(); - Overview = req.Overview; - Year = req.ReleaseDate.Year.ToString(); - PosterImage = req.PosterPath; - } - - public void Setup(ChildRequests req) - { - RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias) - ? req.RequestedUser.Username - : req.RequestedUser.Alias; - Title = req.ParentRequest.Title; - RequestedDate = req.RequestedDate.ToString("D"); - Type = req.RequestType.ToString(); - Overview = req.ParentRequest.Overview; - Year = req.ParentRequest.ReleaseDate.Year.ToString(); - PosterImage = req.ParentRequest.PosterPath; - // DO Episode and Season Lists - } - - // User Defined - public string RequestedUser { get; set; } - public string Title { get; set; } - public string RequestedDate { get; set; } - public string Type { get; set; } - public string Issue { get; set; } - public string Overview { get; set; } - public string Year { get; set; } - public string EpisodesList { get; set; } - public string SeasonsList { get; set; } - public string PosterImage { get; set; } - - // System Defined - private string LongDate => DateTime.Now.ToString("D"); - private string ShortDate => DateTime.Now.ToString("d"); - private string LongTime => DateTime.Now.ToString("T"); - private string ShortTime => DateTime.Now.ToString("t"); - - public Dictionary Curlys => new Dictionary - { - {nameof(RequestedUser), RequestedUser }, - {nameof(Title), Title }, - {nameof(RequestedDate), RequestedDate }, - {nameof(Type), Type }, - {nameof(Issue), Issue }, - {nameof(LongDate),LongDate}, - {nameof(ShortDate),ShortDate}, - {nameof(LongTime),LongTime}, - {nameof(ShortTime),ShortTime}, - {nameof(Overview),Overview}, - {nameof(Year),Year}, - {nameof(EpisodesList),EpisodesList}, - {nameof(SeasonsList),SeasonsList}, - {nameof(PosterImage),PosterImage}, - }; - } - public class NotificationMessageResolver { /// @@ -113,20 +39,99 @@ namespace Ombi.Notifications private NotificationMessageContent Resolve(string body, string subject, IReadOnlyDictionary parameters) { // Find the fields - var bodyFields = FindCurlyFields(body); - var subjectFields = FindCurlyFields(subject); + var bodyFields = FindFields(body, StartChar, EndChar); + var subjectFields = FindFields(subject, StartChar, EndChar); + + //var conditionalFields = FindFields(body, '<', '>'); + //ProcessConditions(conditionalFields, parameters); body = ReplaceFields(bodyFields, parameters, body); subject = ReplaceFields(subjectFields, parameters, subject); return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty}; } + public IEnumerable ProcessConditions(IEnumerable conditionalFields, IReadOnlyDictionary parameters) + { + foreach (var f in conditionalFields) + { + var field = f.ToLower(); + if (field.StartsWith("if")) + { + var ifPosition = field.IndexOf("if", StringComparison.Ordinal); + Console.WriteLine(ifPosition); + var identifierStart = field.Substring(ifPosition + 3); + Console.WriteLine(identifierStart); + var identifierEnd = identifierStart.IndexOf(' '); + Console.WriteLine(identifierEnd); + + var identitifier = identifierStart.Substring(ifPosition, identifierEnd); + + if (identitifier.Equals("type")) + { + // Find the operator == or != + var stringWithoutIdentifier = identifierStart.Substring(identitifier.Length + 1); + var operatorValue = stringWithoutIdentifier.Substring(0,2); + + var stringWithoutOperator = stringWithoutIdentifier.Substring(operatorValue.Length + 1); + var endPosition = stringWithoutOperator.IndexOf(' '); + var comparison = stringWithoutOperator.Substring(0, endPosition); + + if (operatorValue == "==") + { + var type = (RequestType)int.Parse(parameters["Type"]); + if (comparison.Equals("Movie", StringComparison.CurrentCultureIgnoreCase)) + { + if (type == RequestType.Movie) + { + // Get the text + var stringWithoutComparison = stringWithoutOperator.Substring(comparison.Length + 2); + var endString = stringWithoutComparison.IndexOf(' '); + var text = stringWithoutComparison.Substring(0, endString - 1); + field = text; + } + else + { + // Get the text in the ELSE + var stringWithoutComparison = stringWithoutOperator.Substring(comparison.Length + 2); + var elseIndex = stringWithoutComparison.IndexOf("else", StringComparison.CurrentCultureIgnoreCase); + var endIndex = stringWithoutComparison.IndexOf(' '); + if (elseIndex >= 0) + { + var elseString = stringWithoutComparison.Substring(elseIndex, endIndex); + + } + else + { + // No else + } + } + } + else if(comparison.Equals("TvShow", StringComparison.CurrentCultureIgnoreCase) || comparison.Equals("Tv", StringComparison.CurrentCultureIgnoreCase)) + { + if (type == RequestType.TvShow) + { + + } + } + } + else if (operatorValue == "!=") + { + + } + } + + } + } + + return conditionalFields; + } + /// /// Finds the curly fields. /// /// The message. /// - private IEnumerable FindCurlyFields(string message) + private IEnumerable FindFields(string message, char start, char end) { if (string.IsNullOrEmpty(message)) { @@ -145,13 +150,13 @@ namespace Ombi.Notifications continue; } - if (c == StartChar) // Start of curly '{' + if (c == start) // Start of curly '{' { insideCurly = true; continue; } - if (c == EndChar) // End of curly '}' + if (c == end) // End of curly '}' { fields.Add(currentWord); // We have finished the curly, add the word into the list currentWord = string.Empty; diff --git a/src/Ombi.sln b/src/Ombi.sln index f59909602..6d46fa167 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}" EndProject @@ -13,58 +13,60 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Build\publish.bat = Build\publish.bat EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core", "Ombi.Core\Ombi.Core.csproj", "{F56E79C7-791D-4668-A0EC-29E3BBC8D24B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{9293CA11-360A-4C20-A674-B9E794431BF5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.TheMovieDb", "Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj", "{132DA282-5894-4570-8916-D8C18ED2CE84}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.TheMovieDb", "Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj", "{132DA282-5894-4570-8916-D8C18ED2CE84}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api", "Ombi.Api\Ombi.Api.csproj", "{EA31F915-31F9-4318-B521-1500CDF40DDF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api", "Ombi.Api\Ombi.Api.csproj", "{EA31F915-31F9-4318-B521-1500CDF40DDF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers", "Ombi.Helpers\Ombi.Helpers.csproj", "{C182B435-1FAB-49C5-9BF9-F7F5C6EF3C94}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Store", "Ombi.Store\Ombi.Store.csproj", "{68086581-1EFD-4390-8100-47F87D1CB628}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.DependencyInjection", "Ombi.DependencyInjection\Ombi.DependencyInjection.csproj", "{B39E4558-C557-48E7-AA74-19C5CD809617}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.DependencyInjection", "Ombi.DependencyInjection\Ombi.DependencyInjection.csproj", "{B39E4558-C557-48E7-AA74-19C5CD809617}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Mapping", "Ombi.Mapping\Ombi.Mapping.csproj", "{63E63511-1C7F-4162-8F92-8F7391B3C8A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Mapping", "Ombi.Mapping\Ombi.Mapping.csproj", "{63E63511-1C7F-4162-8F92-8F7391B3C8A3}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mappers", "Mappers", "{025FB189-2FFB-4F43-A64B-6F1B5A0D2065}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DI", "DI", "{410F36CF-9C60-428A-B191-6FD90610991A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Plex", "Ombi.Api.Plex\Ombi.Api.Plex.csproj", "{2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Plex", "Ombi.Api.Plex\Ombi.Api.Plex.csproj", "{2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Schedule", "Ombi.Schedule\Ombi.Schedule.csproj", "{5B42ADD4-757A-47C1-9CC5-320829C5E665}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Schedule", "Ombi.Schedule\Ombi.Schedule.csproj", "{5B42ADD4-757A-47C1-9CC5-320829C5E665}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Emby", "Ombi.Api.Emby\Ombi.Api.Emby.csproj", "{08FF107D-31E1-470D-AF86-E09B015CEE06}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Emby", "Ombi.Api.Emby\Ombi.Api.Emby.csproj", "{08FF107D-31E1-470D-AF86-E09B015CEE06}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Sonarr", "Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj", "{CFB5E008-D0D0-43C0-AA06-89E49D17F384}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Sonarr", "Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj", "{CFB5E008-D0D0-43C0-AA06-89E49D17F384}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6F42AB98-9196-44C4-B888-D5E409F415A1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.TvMaze", "Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj", "{0E8EF835-E4F0-4EE5-A2B6-678DEE973721}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.TvMaze", "Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj", "{0E8EF835-E4F0-4EE5-A2B6-678DEE973721}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications", "Ombi.Notifications\Ombi.Notifications.csproj", "{E6EE2830-E4AC-4F2E-AD93-2C9305605761}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Notifications", "Ombi.Notifications\Ombi.Notifications.csproj", "{E6EE2830-E4AC-4F2E-AD93-2C9305605761}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifications", "Notifications", "{EA30DD15-6280-4687-B370-2956EC2E54E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Templates", "Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj", "{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Notifications.Templates", "Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj", "{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Radarr", "Ombi.Api.Radarr\Ombi.Api.Radarr.csproj", "{94D04C1F-E35A-499C-B0A0-9FADEBDF8336}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Radarr", "Ombi.Api.Radarr\Ombi.Api.Radarr.csproj", "{94D04C1F-E35A-499C-B0A0-9FADEBDF8336}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Discord", "Ombi.Api.Discord\Ombi.Api.Discord.csproj", "{5AF2B6D2-5CC6-49FE-928A-BA27AF52B194}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Discord", "Ombi.Api.Discord\Ombi.Api.Discord.csproj", "{5AF2B6D2-5CC6-49FE-928A-BA27AF52B194}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Updater", "Ombi.Updater\Ombi.Updater.csproj", "{6294A82D-4915-4FC3-B301-8F985716F34C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Updater", "Ombi.Updater\Ombi.Updater.csproj", "{6294A82D-4915-4FC3-B301-8F985716F34C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Update", "Update", "{D11FE57E-1E57-491D-A1D4-01AEF4BE5CB6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Tests", "Ombi.Notifications.Tests\Ombi.Notifications.Tests.csproj", "{2C7836E7-B120-40A6-B641-DDAA02FBAE23}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -155,6 +157,10 @@ Global {6294A82D-4915-4FC3-B301-8F985716F34C}.Debug|Any CPU.Build.0 = Debug|Any CPU {6294A82D-4915-4FC3-B301-8F985716F34C}.Release|Any CPU.ActiveCfg = Release|Any CPU {6294A82D-4915-4FC3-B301-8F985716F34C}.Release|Any CPU.Build.0 = Release|Any CPU + {2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C7836E7-B120-40A6-B641-DDAA02FBAE23}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -175,5 +181,6 @@ Global {94D04C1F-E35A-499C-B0A0-9FADEBDF8336} = {9293CA11-360A-4C20-A674-B9E794431BF5} {5AF2B6D2-5CC6-49FE-928A-BA27AF52B194} = {9293CA11-360A-4C20-A674-B9E794431BF5} {6294A82D-4915-4FC3-B301-8F985716F34C} = {D11FE57E-1E57-491D-A1D4-01AEF4BE5CB6} + {2C7836E7-B120-40A6-B641-DDAA02FBAE23} = {6F42AB98-9196-44C4-B888-D5E409F415A1} EndGlobalSection EndGlobal diff --git a/src/Ombi/ClientApp/app/app.module.ts b/src/Ombi/ClientApp/app/app.module.ts index 91175e0f8..a547cd915 100644 --- a/src/Ombi/ClientApp/app/app.module.ts +++ b/src/Ombi/ClientApp/app/app.module.ts @@ -16,11 +16,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; // Components import { AppComponent } from './app.component'; + // Search -import { SearchComponent } from './search/search.component'; -import { MovieSearchComponent } from './search/moviesearch.component'; -import { TvSearchComponent } from './search/tvsearch.component'; -import { SeriesInformationComponent } from './search/seriesinformation.component'; // Request import { RequestComponent } from './requests/request.component'; @@ -32,10 +29,10 @@ import { RequestCardComponent } from './request-grid/request-card.component'; import { LoginComponent } from './login/login.component'; import { LandingPageComponent } from './landingpage/landingpage.component'; import { UserManagementComponent } from './usermanagement/usermanagement.component'; +import { UserManagementEditComponent } from './usermanagement/usermanagement-edit.component'; import { PageNotFoundComponent } from './errors/not-found.component'; // Services -import { SearchService } from './services/search.service'; import { RequestService } from './services/request.service'; import { NotificationService } from './services/notification.service'; import { SettingsService } from './services/settings.service'; @@ -49,17 +46,17 @@ import { StatusService } from './services/status.service'; // Modules import { SettingsModule } from './settings/settings.module'; import { WizardModule } from './wizard/wizard.module'; +import { SearchModule } from './search/search.module'; const routes: Routes = [ { path: '*', component: PageNotFoundComponent }, { path: '', redirectTo: '/search', pathMatch: 'full' }, - { path: 'search', component: SearchComponent, canActivate: [AuthGuard] }, - { path: 'search/show/:id', component: SeriesInformationComponent, canActivate: [AuthGuard] }, { path: 'requests', component: RequestComponent, canActivate: [AuthGuard] }, //{ path: 'requests-grid', component: RequestGridComponent }, { path: 'login', component: LoginComponent }, { path: 'landingpage', component: LandingPageComponent }, { path: 'usermanagement', component: UserManagementComponent, canActivate: [AuthGuard] }, + { path: 'usermanagement/edit/:id', component: UserManagementEditComponent, canActivate: [AuthGuard] }, ]; @NgModule({ @@ -77,6 +74,7 @@ const routes: Routes = [ InfiniteScrollModule, AuthModule, WizardModule, + SearchModule, DialogModule, MdButtonModule, NgbModule.forRoot(), @@ -89,21 +87,17 @@ const routes: Routes = [ declarations: [ AppComponent, PageNotFoundComponent, - SearchComponent, RequestComponent, LoginComponent, - MovieSearchComponent, - TvSearchComponent, LandingPageComponent, UserManagementComponent, MovieRequestsComponent, TvRequestsComponent, - SeriesInformationComponent, //RequestGridComponent, RequestCardComponent, + UserManagementEditComponent, ], providers: [ - SearchService, RequestService, NotificationService, AuthService, diff --git a/src/Ombi/ClientApp/app/login/login.component.html b/src/Ombi/ClientApp/app/login/login.component.html index e44985851..2104443a0 100644 --- a/src/Ombi/ClientApp/app/login/login.component.html +++ b/src/Ombi/ClientApp/app/login/login.component.html @@ -2,11 +2,11 @@ you can substitue the span of reauth email for a input with the email and include the remember me checkbox --> -
+
-
+

diff --git a/src/Ombi/ClientApp/app/search/search.module.ts b/src/Ombi/ClientApp/app/search/search.module.ts new file mode 100644 index 000000000..a1baa0bbe --- /dev/null +++ b/src/Ombi/ClientApp/app/search/search.module.ts @@ -0,0 +1,45 @@ +import { NgModule, } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; + +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; + +import { SearchComponent } from './search.component'; +import { MovieSearchComponent } from './moviesearch.component'; +import { TvSearchComponent } from './tvsearch.component'; +import { SeriesInformationComponent } from './seriesinformation.component'; + +import { SearchService } from '../services/search.service'; +import { RequestService } from '../services/request.service'; + +import { AuthGuard } from '../auth/auth.guard'; + +const routes: Routes = [ + { path: 'search', component: SearchComponent, canActivate: [AuthGuard] }, + { path: 'search/show/:id', component: SeriesInformationComponent, canActivate: [AuthGuard] }, +]; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + RouterModule.forChild(routes), + NgbModule.forRoot(), + ], + declarations: [ + SearchComponent, + MovieSearchComponent, + TvSearchComponent, + SeriesInformationComponent + ], + exports: [ + RouterModule + ], + providers: [ + SearchService, + RequestService + ], + +}) +export class SearchModule { } \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/services/identity.service.ts b/src/Ombi/ClientApp/app/services/identity.service.ts index 16c65d816..4d499b5e9 100644 --- a/src/Ombi/ClientApp/app/services/identity.service.ts +++ b/src/Ombi/ClientApp/app/services/identity.service.ts @@ -20,6 +20,10 @@ export class IdentityService extends ServiceAuthHelpers { return this.http.get(this.url).map(this.extractData); } + getUserById(id: number): Observable { + return this.http.get(`${this.url}User/${id}`).map(this.extractData); + } + getUsers(): Observable { return this.http.get(`${this.url}Users`).map(this.extractData); } diff --git a/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.html b/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.html new file mode 100644 index 000000000..5aee0ebf6 --- /dev/null +++ b/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.html @@ -0,0 +1,53 @@ +

User Management

+ + + + +
+ +
diff --git a/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.ts b/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.ts new file mode 100644 index 000000000..3ec116c3e --- /dev/null +++ b/src/Ombi/ClientApp/app/usermanagement/usermanagement-edit.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; + +import { IUser, ICheckbox } from '../interfaces/IUser'; +import { IdentityService } from '../services/identity.service'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + + templateUrl: './usermanagement-edit.component.html' +}) +export class UserManagementEditComponent implements OnInit { + constructor(private identityService: IdentityService, private route: ActivatedRoute) { + this.route.params + .subscribe(params => { + this.userId = +params['id']; // (+) converts string 'id' to a number + }); + } + + ngOnInit(): void { + + this.identityService.getAllAvailableClaims().subscribe(x => this.availableClaims = x); + this.identityService.getUserById(this.userId).subscribe(x => this.user = x); + } + + user: IUser; + userId: number; + + + availableClaims : ICheckbox[]; + +} \ No newline at end of file diff --git a/src/Ombi/Controllers/IdentityController.cs b/src/Ombi/Controllers/IdentityController.cs index dd913a05a..306b9ee6f 100644 --- a/src/Ombi/Controllers/IdentityController.cs +++ b/src/Ombi/Controllers/IdentityController.cs @@ -112,7 +112,7 @@ namespace Ombi.Controllers /// Gets the user by the user id. ///
/// Information about the user - [HttpGet("Users/{id}")] + [HttpGet("User/{id}")] public async Task GetUser(int id) { var type = typeof(OmbiClaims); @@ -121,7 +121,7 @@ namespace Ombi.Controllers var fields = fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList(); var allClaims = fields.Select(x => x.Name).ToList(); - var user = Mapper.Map(await IdentityManager.GetUser(id)).ToList(); + var user = Mapper.Map(await IdentityManager.GetUser(id)); var userClaims = user.Claims.Select(x => x.Value); diff --git a/src/Ombi/wwwroot/images/ms-icon-150x150.png b/src/Ombi/wwwroot/images/ms-icon-150x150.png new file mode 100644 index 000000000..33ba50221 Binary files /dev/null and b/src/Ombi/wwwroot/images/ms-icon-150x150.png differ diff --git a/src/Ombi/wwwroot/images/ms-icon-310x310.png b/src/Ombi/wwwroot/images/ms-icon-310x310.png new file mode 100644 index 000000000..a2044bbb1 Binary files /dev/null and b/src/Ombi/wwwroot/images/ms-icon-310x310.png differ