diff --git a/CHANGELOG.md b/CHANGELOG.md index c83cdf157..e8995ab76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,45 @@ ### **New Features** +- Added the subscribe on the sarch page. [Jamie Rees] + +- Added the subscribe button to the search page if we have an existing request. [Jamie Rees] + +### **Fixes** + +- Use selected episodes in submitRequest. [Calvin] + +- Fixed where the test button wouldn't work on the mobile notifications page. [Jamie] + +- Fixed the sorting and filtering on the Movie Requests page, it all functions correctly now. [Jamie] + +- Fixed #2288. [Jamie] + +- Fixed the SickRage/Medusa Issue where it was always being set as Skipped/Ignore #2084. [Jamie] + +- Fixed UI typo refrencing discord in mattermost notifications #2175. [Anojh] + +- Fix #2175. [Anojh] + +- Fixed #2013. [Jamie Rees] + +- Fixed #2147. [Jamie Rees] + + +## v3.0.3346 (2018-05-26) + +### **New Features** + - Added a default set of root folders and qualities for Anime in Sonarr. [Jamie Rees] ### **Fixes** +- Made the Open on Mobile link less hidden. [Jamie Rees] + +- Fixed #2263. [Jamie Rees] + +- !changelog. [Jamie Rees] + - Fixed #2243 The refresh metadata was being run everytime we launched Ombi... [Jamie] - Fixed a issue where the Plex Content Sync wouldn't pick up new shows #2276 #2244 #2261. [Jamie] diff --git a/src/Ombi.Api.Mattermost/Models/MattermostClient.cs b/src/Ombi.Api.Mattermost/Models/MattermostClient.cs index 96d3e33f4..ad04947b1 100644 --- a/src/Ombi.Api.Mattermost/Models/MattermostClient.cs +++ b/src/Ombi.Api.Mattermost/Models/MattermostClient.cs @@ -120,8 +120,10 @@ namespace Ombi.Api.Mattermost.Models var attIndex = outMessages[msgCount].Attachments.Count - 1; //Get the text lines - lines = att.Text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); - + if (!String.IsNullOrEmpty(att.Text)) + { + lines = att.Text.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + } foreach (var line in lines) { //Get the total length of all attachments on the current outgoing message @@ -153,8 +155,9 @@ namespace Ombi.Api.Mattermost.Models foreach (var msg in outMessages) { - var request = new Request("", _webhookUrl.ToString(), HttpMethod.Post); + var request = new Request(_webhookUrl.ToString(), "", HttpMethod.Post); request.AddJsonBody(msg); + request.AddHeader("Host", _webhookUrl.Host); await api.Request(request); } } diff --git a/src/Ombi.Api.Mattermost/Models/MattermostMessage.cs b/src/Ombi.Api.Mattermost/Models/MattermostMessage.cs index d8fe52b09..83171627a 100644 --- a/src/Ombi.Api.Mattermost/Models/MattermostMessage.cs +++ b/src/Ombi.Api.Mattermost/Models/MattermostMessage.cs @@ -33,7 +33,7 @@ namespace Ombi.Api.Mattermost.Models /// Bot/User Icon /// [JsonProperty(PropertyName = "icon_url")] - public Uri IconUrl { get; set; } + public string IconUrl { get; set; } /// /// Message body. Supports Markdown @@ -142,7 +142,7 @@ namespace Ombi.Api.Mattermost.Models /// Large images are resized to a maximum width of 400px or a maximum height of 300px, while still maintaining the original aspect ratio. /// [JsonProperty(PropertyName = "image_url")] - public Uri ImageUrl { get; set; } + public string ImageUrl { get; set; } /// /// An optional URL to an image file(GIF, JPEG, PNG, or BMP) that is displayed as a 75x75 pixel thumbnail on the right side of an attachment. diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs index c1ba76a7c..91cbb9e72 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs @@ -17,7 +17,6 @@ namespace Ombi.Core.Engine.Interfaces Task ApproveMovie(MovieRequests request); Task ApproveMovieById(int requestId); Task DenyMovieById(int modelId); - Task> Filter(FilterViewModel vm); } diff --git a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs index 553ad79dd..740428ec7 100644 --- a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Ombi.Core.Models.Requests; +using Ombi.Core.Models.UI; using Ombi.Store.Entities; namespace Ombi.Core.Engine.Interfaces @@ -12,7 +13,7 @@ namespace Ombi.Core.Engine.Interfaces //Task> GetNewRequests(); //Task> GetAvailableRequests(); RequestCountModel RequestCount(); - Task> GetRequests(int count, int position); + Task> GetRequests(int count, int position, OrderFilterModel model); Task> GetRequests(); Task UserHasRequest(string userId); diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 460752bb1..15383ed12 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging; using Ombi.Api.TheMovieDb.Models; using Ombi.Core.Authentication; using Ombi.Core.Engine.Interfaces; +using Ombi.Core.Models.UI; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Settings; using Ombi.Settings.Settings.Models; @@ -25,7 +26,8 @@ namespace Ombi.Core.Engine { public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger log, - OmbiUserManager manager, IRepository rl, ICacheService cache, ISettingsService ombiSettings, IRepository sub) + OmbiUserManager manager, IRepository rl, ICacheService cache, + ISettingsService ombiSettings, IRepository sub) : base(user, requestService, r, manager, cache, ombiSettings, sub) { MovieApi = movieApi; @@ -58,6 +60,7 @@ namespace Ombi.Core.Engine ErrorMessage = $"Please try again later" }; } + var fullMovieName = $"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}"; @@ -82,7 +85,8 @@ namespace Ombi.Core.Engine }; var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); - requestModel.DigitalReleaseDate = usDates?.ReleaseDate?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; + requestModel.DigitalReleaseDate = usDates?.ReleaseDate + ?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; var ruleResults = (await RunRequestRules(requestModel)).ToList(); if (ruleResults.Any(x => !x.Success)) @@ -125,25 +129,93 @@ namespace Ombi.Core.Engine /// /// The count. /// The position. + /// The order/filter type. /// - public async Task> GetRequests(int count, int position) + public async Task> GetRequests(int count, int position, + OrderFilterModel orderFilter) { var shouldHide = await HideFromOtherUsers(); - List allRequests; + IQueryable allRequests; if (shouldHide.Hide) { - allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); + allRequests = + MovieRepository.GetWithUser(shouldHide + .UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); } else { - allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); + allRequests = + MovieRepository + .GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); } - allRequests.ForEach(async x => + + switch (orderFilter.AvailabilityFilter) + { + case FilterType.None: + break; + case FilterType.Available: + allRequests = allRequests.Where(x => x.Available); + break; + case FilterType.NotAvailable: + allRequests = allRequests.Where(x => !x.Available); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + switch (orderFilter.StatusFilter) + { + case FilterType.None: + break; + case FilterType.Approved: + allRequests = allRequests.Where(x => x.Approved); + break; + case FilterType.Processing: + allRequests = allRequests.Where(x => x.Approved && !x.Available); + break; + case FilterType.PendingApproval: + allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false)); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + var total = allRequests.Count(); + + var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) + .ToListAsync(); + + requests.ForEach(async x => { x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); await CheckForSubscription(shouldHide, x); }); - return allRequests; + return new RequestsViewModel + { + Collection = requests, + Total = total + }; + } + + private IQueryable OrderMovies(IQueryable allRequests, OrderType type) + { + switch (type) + { + case OrderType.RequestedDateAsc: + return allRequests.OrderBy(x => x.RequestedDate); + case OrderType.RequestedDateDesc: + return allRequests.OrderByDescending(x => x.RequestedDate); + case OrderType.TitleAsc: + return allRequests.OrderBy(x => x.Title); + case OrderType.TitleDesc: + return allRequests.OrderByDescending(x => x.Title); + case OrderType.StatusAsc: + return allRequests.OrderBy(x => x.Status); + case OrderType.StatusDesc: + return allRequests.OrderByDescending(x => x.Status); + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } } public async Task GetTotal() @@ -216,6 +288,7 @@ namespace Ombi.Core.Engine { allRequests = await MovieRepository.GetWithUser().ToListAsync(); } + var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); results.ForEach(async x => { @@ -241,6 +314,7 @@ namespace Ombi.Core.Engine ErrorMessage = "Request does not exist" }; } + request.Denied = true; // We are denying a request NotificationHelper.Notify(request, NotificationType.RequestDeclined); @@ -261,6 +335,7 @@ namespace Ombi.Core.Engine ErrorMessage = "Request does not exist" }; } + request.Approved = true; request.Denied = false; await MovieRepository.Update(request); @@ -281,6 +356,7 @@ namespace Ombi.Core.Engine Result = true }; } + if (!result.Success) { Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); @@ -291,6 +367,7 @@ namespace Ombi.Core.Engine Result = false }; } + // If there are no providers then it's successful but movie has not been sent } @@ -352,6 +429,7 @@ namespace Ombi.Core.Engine ErrorMessage = "Request does not exist" }; } + request.Available = false; await MovieRepository.Update(request); @@ -372,6 +450,7 @@ namespace Ombi.Core.Engine ErrorMessage = "Request does not exist" }; } + request.Available = true; NotificationHelper.Notify(request, NotificationType.RequestAvailable); await MovieRepository.Update(request); @@ -401,55 +480,7 @@ namespace Ombi.Core.Engine RequestType = RequestType.Movie, }); - return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!" }; - } - - public async Task> Filter(FilterViewModel vm) - { - var shouldHide = await HideFromOtherUsers(); - var requests = shouldHide.Hide - ? MovieRepository.GetWithUser(shouldHide.UserId) - : MovieRepository.GetWithUser(); - - switch (vm.AvailabilityFilter) - { - case FilterType.None: - break; - case FilterType.Available: - requests = requests.Where(x => x.Available); - break; - case FilterType.NotAvailable: - requests = requests.Where(x => !x.Available); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - switch (vm.StatusFilter) - { - case FilterType.None: - break; - case FilterType.Approved: - requests = requests.Where(x => x.Approved); - break; - case FilterType.Processing: - requests = requests.Where(x => x.Approved && !x.Available); - break; - case FilterType.PendingApproval: - requests = requests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false)); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - var count = await requests.CountAsync(); - requests = requests.Skip(vm.Position).Take(vm.Count); - var retVal = new FilterResult - { - Total = count, - Collection = requests - }; - return retVal; + return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"}; } } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MovieSearchEngine.cs b/src/Ombi.Core/Engine/MovieSearchEngine.cs index 915eefe02..fbda62023 100644 --- a/src/Ombi.Core/Engine/MovieSearchEngine.cs +++ b/src/Ombi.Core/Engine/MovieSearchEngine.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Ombi.Core.Rule.Interfaces; using Microsoft.Extensions.Caching.Memory; using Ombi.Core.Authentication; @@ -166,10 +167,31 @@ namespace Ombi.Core.Engine viewMovie.TheMovieDbId = viewMovie.Id.ToString(); await RunSearchRules(viewMovie); - + + // This requires the rules to be run first to populate the RequestId property + await CheckForSubscription(viewMovie); + return viewMovie; } + private async Task CheckForSubscription(SearchMovieViewModel viewModel) + { + // Check if this user requested it + var user = await GetUser(); + var request = await RequestService.MovieRequestService.GetAll() + .AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.TheMovieDbId == viewModel.Id); + if (request) + { + viewModel.ShowSubscribe = false; + } + else + { + viewModel.ShowSubscribe = true; + var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => s.UserId == user.Id + && s.RequestId == viewModel.RequestId && s.RequestType == RequestType.Movie); + viewModel.Subscribed = sub != null; + } + } private async Task ProcessSingleMovie(MovieSearchResult movie) { diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index ddf84376e..8bb6d86e6 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -15,6 +15,7 @@ using Microsoft.EntityFrameworkCore; using Ombi.Core.Authentication; using Ombi.Core.Engine.Interfaces; using Ombi.Core.Helpers; +using Ombi.Core.Models.UI; using Ombi.Core.Rule; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Senders; @@ -132,7 +133,7 @@ namespace Ombi.Core.Engine return await AddRequest(newRequest.NewRequest); } - public async Task> GetRequests(int count, int position) + public async Task> GetRequests(int count, int position, OrderFilterModel type) { var shouldHide = await HideFromOtherUsers(); List allRequests; @@ -161,7 +162,10 @@ namespace Ombi.Core.Engine allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); }); - return allRequests; + return new RequestsViewModel + { + Collection = allRequests + }; } public async Task>>> GetRequestsTreeNode(int count, int position) diff --git a/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs b/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs index a91d75d65..c421af45f 100644 --- a/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs +++ b/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs @@ -56,7 +56,6 @@ namespace Ombi.Core.Models.Search public bool FullyAvailable { get; set; } // We only have some episodes public bool PartlyAvailable { get; set; } - public override RequestType Type => RequestType.TvShow; } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/Search/SearchViewModel.cs b/src/Ombi.Core/Models/Search/SearchViewModel.cs index 0de295a69..a388ccfff 100644 --- a/src/Ombi.Core/Models/Search/SearchViewModel.cs +++ b/src/Ombi.Core/Models/Search/SearchViewModel.cs @@ -8,13 +8,13 @@ namespace Ombi.Core.Models.Search public int Id { get; set; } public bool Approved { get; set; } public bool Requested { get; set; } + public int RequestId { get; set; } public bool Available { get; set; } public string PlexUrl { get; set; } public string EmbyUrl { get; set; } public string Quality { get; set; } public abstract RequestType Type { get; } - /// /// This is used for the PlexAvailabilityCheck/EmbyAvailabilityRule rule /// @@ -27,5 +27,11 @@ namespace Ombi.Core.Models.Search public string TheTvDbId { get; set; } [NotMapped] public string TheMovieDbId { get; set; } + + + [NotMapped] + public bool Subscribed { get; set; } + [NotMapped] + public bool ShowSubscribe { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/UI/OrderFilterModel.cs b/src/Ombi.Core/Models/UI/OrderFilterModel.cs new file mode 100644 index 000000000..3e3192829 --- /dev/null +++ b/src/Ombi.Core/Models/UI/OrderFilterModel.cs @@ -0,0 +1,11 @@ +using Ombi.Core.Models.Requests; + +namespace Ombi.Core.Models.UI +{ + public class OrderFilterModel + { + public FilterType AvailabilityFilter { get; set; } + public FilterType StatusFilter { get; set; } + public OrderType OrderType { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Models/UI/OrderType.cs b/src/Ombi.Core/Models/UI/OrderType.cs new file mode 100644 index 000000000..67d20b127 --- /dev/null +++ b/src/Ombi.Core/Models/UI/OrderType.cs @@ -0,0 +1,12 @@ +namespace Ombi.Core.Models.UI +{ + public enum OrderType + { + RequestedDateAsc =1, + RequestedDateDesc =2, + TitleAsc =3, + TitleDesc=4, + StatusAsc=5, + StatusDesc=6 + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Models/UI/RequestsViewModel.cs b/src/Ombi.Core/Models/UI/RequestsViewModel.cs new file mode 100644 index 000000000..9d772bc53 --- /dev/null +++ b/src/Ombi.Core/Models/UI/RequestsViewModel.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Ombi.Core.Models.UI +{ + public class RequestsViewModel + { + public IEnumerable Collection { get; set; } + public int Total { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs b/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs index 2118e2a96..6ca0b966b 100644 --- a/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs @@ -29,6 +29,7 @@ namespace Ombi.Core.Rule.Rules.Search { obj.Requested = true; + obj.RequestId = movieRequests.Id; obj.Approved = movieRequests.Approved; obj.Available = movieRequests.Available; @@ -67,6 +68,7 @@ namespace Ombi.Core.Rule.Rules.Search existingRequestChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == season.SeasonNumber); if (existingSeason == null) continue; + foreach (var ep in existingSeason.Episodes) { // Find the episode from what we are searching @@ -92,7 +94,6 @@ namespace Ombi.Core.Rule.Rules.Search request.PartlyAvailable = true; } - return Task.FromResult(Success()); } } diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index 151ad0f7b..12124d270 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -314,9 +314,17 @@ namespace Ombi.Core.Senders foreach (var seasonRequests in model.SeasonRequests) { var srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); - while (srEpisodes.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase) && srEpisodes.data.Count <= 0) + int retryTimes = 10; + var currentRetry = 0; + while (srEpisodes.message.Equals("Show not found", StringComparison.CurrentCultureIgnoreCase) || srEpisodes.message.Equals("Season not found", StringComparison.CurrentCultureIgnoreCase) && srEpisodes.data.Count <= 0) { + if (currentRetry > retryTimes) + { + Logger.LogWarning("Couldnt find the SR Season or Show, message: {0}", srEpisodes.message); + break; + } await Task.Delay(TimeSpan.FromSeconds(1)); + currentRetry++; srEpisodes = await SickRageApi.GetEpisodesForSeason(tvdbid, seasonRequests.SeasonNumber, settings.ApiKey, settings.FullUri); } diff --git a/src/Ombi.Notifications/Agents/MattermostNotification.cs b/src/Ombi.Notifications/Agents/MattermostNotification.cs index 8590bfaae..8199d8bfe 100644 --- a/src/Ombi.Notifications/Agents/MattermostNotification.cs +++ b/src/Ombi.Notifications/Agents/MattermostNotification.cs @@ -203,13 +203,13 @@ namespace Ombi.Notifications.Agents Username = string.IsNullOrEmpty(settings.Username) ? "Ombi" : settings.Username, Channel = settings.Channel, Text = model.Message, - IconUrl = new Uri(settings.IconUrl), + IconUrl = settings.IconUrl, Attachments = new List { new MattermostAttachment { Title = model.Other.ContainsKey("title") ? model.Other["title"] : string.Empty, - ImageUrl = model.Other.ContainsKey("image") ? new Uri(model.Other["image"]) : null, + ImageUrl = model.Other.ContainsKey("image") ? model.Other["image"] : string.Empty, } } }; diff --git a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts index 1895914c3..236e694fc 100644 --- a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts +++ b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts @@ -20,7 +20,7 @@ export interface IMovieRequests extends IFullBaseRequest { qualityOverrideTitle: string; } -export interface IFilterResult { +export interface IRequestsViewModel { total: number; collection: T[]; } @@ -87,6 +87,15 @@ export interface ITvUpdateModel { id: number; } +export enum OrderType { + RequestedDateAsc = 1, + RequestedDateDesc = 2, + TitleAsc = 3, + TitleDesc = 4, + StatusAsc = 5, + StatusDesc = 6, +} + export interface INewSeasonRequests { id: number; seasonNumber: number; @@ -112,8 +121,6 @@ export interface IMovieRequestModel { export interface IFilter { availabilityFilter: FilterType; statusFilter: FilterType; - position: number; - count: number; } export enum FilterType { diff --git a/src/Ombi/ClientApp/app/interfaces/ISearchMovieResult.ts b/src/Ombi/ClientApp/app/interfaces/ISearchMovieResult.ts index ee66598fd..3ea282351 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISearchMovieResult.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISearchMovieResult.ts @@ -19,11 +19,14 @@ imdbId: string; approved: boolean; requested: boolean; + requestId: number; available: boolean; plexUrl: string; embyUrl: string; quality: string; digitalReleaseDate: Date; + subscribed: boolean; + showSubscribe: boolean; // for the UI requestProcessing: boolean; diff --git a/src/Ombi/ClientApp/app/interfaces/IUser.ts b/src/Ombi/ClientApp/app/interfaces/IUser.ts index 69bc49d0f..bab851420 100644 --- a/src/Ombi/ClientApp/app/interfaces/IUser.ts +++ b/src/Ombi/ClientApp/app/interfaces/IUser.ts @@ -47,6 +47,7 @@ export interface IResetPasswordToken { export interface IMobileUsersViewModel { username: string; + userId: string; devices: number; } diff --git a/src/Ombi/ClientApp/app/issues/issueDetails.component.ts b/src/Ombi/ClientApp/app/issues/issueDetails.component.ts index 38adbe390..a00f4e89b 100644 --- a/src/Ombi/ClientApp/app/issues/issueDetails.component.ts +++ b/src/Ombi/ClientApp/app/issues/issueDetails.component.ts @@ -117,8 +117,10 @@ export class IssueDetailsComponent implements OnInit { } else { this.imageService.getTvBackground(Number(issue.providerId)).subscribe(x => { - this.backgroundPath = this.sanitizer.bypassSecurityTrustStyle - ("url(" + x + ")"); + if(x) { + this.backgroundPath = this.sanitizer.bypassSecurityTrustStyle + ("url(" + x + ")"); + } }); this.imageService.getTvPoster(Number(issue.providerId)).subscribe(x => { if (x.length === 0) { diff --git a/src/Ombi/ClientApp/app/recentlyAdded/recentlyAdded.component.ts b/src/Ombi/ClientApp/app/recentlyAdded/recentlyAdded.component.ts index 53d652070..2d5ec2bd6 100644 --- a/src/Ombi/ClientApp/app/recentlyAdded/recentlyAdded.component.ts +++ b/src/Ombi/ClientApp/app/recentlyAdded/recentlyAdded.component.ts @@ -88,7 +88,9 @@ export class RecentlyAddedComponent implements OnInit { this.tv.forEach((t) => { this.imageService.getTvPoster(t.tvDbId).subscribe(p => { - t.posterPath = p; + if(p) { + t.posterPath = p; + } }); }); }); @@ -98,7 +100,9 @@ export class RecentlyAddedComponent implements OnInit { this.tv.forEach((t) => { this.imageService.getTvPoster(t.tvDbId).subscribe(p => { - t.posterPath = p; + if(p) { + t.posterPath = p; + } }); }); }); diff --git a/src/Ombi/ClientApp/app/requests/movierequests.component.html b/src/Ombi/ClientApp/app/requests/movierequests.component.html index b2ea68db2..241e0af6b 100644 --- a/src/Ombi/ClientApp/app/requests/movierequests.component.html +++ b/src/Ombi/ClientApp/app/requests/movierequests.component.html @@ -1,57 +1,45 @@ - + +
@@ -59,9 +47,7 @@
-
- - +
@@ -99,7 +85,7 @@ + [translate]="'Common.PendingApproval'">
@@ -125,11 +111,15 @@
-
+
@@ -171,7 +161,7 @@
- +
- @@ -198,7 +190,7 @@
- +
diff --git a/src/Ombi/ClientApp/app/requests/movierequests.component.ts b/src/Ombi/ClientApp/app/requests/movierequests.component.ts index fe6f3b73f..0848daf53 100644 --- a/src/Ombi/ClientApp/app/requests/movierequests.component.ts +++ b/src/Ombi/ClientApp/app/requests/movierequests.component.ts @@ -9,7 +9,7 @@ import { Subject } from "rxjs/Subject"; import { AuthService } from "../auth/auth.service"; import { NotificationService, RadarrService, RequestService } from "../services"; -import { FilterType, IFilter, IIssueCategory, IMovieRequests, IPagenator, IRadarrProfile, IRadarrRootFolder } from "../interfaces"; +import { FilterType, IFilter, IIssueCategory, IMovieRequests, IPagenator, IRadarrProfile, IRadarrRootFolder, OrderType } from "../interfaces"; @Component({ selector: "movie-requests", @@ -38,9 +38,9 @@ export class MovieRequestsComponent implements OnInit { public filter: IFilter; public filterType = FilterType; - public order: string = "requestedDate"; - public reverse = true; - + public orderType: OrderType = OrderType.RequestedDateDesc; + public OrderType = OrderType; + public totalMovies: number = 100; private currentlyLoaded: number; private amountToLoad: number; @@ -75,20 +75,17 @@ export class MovieRequestsComponent implements OnInit { public ngOnInit() { this.amountToLoad = 10; - this.currentlyLoaded = 10; - this.loadInit(); - this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + this.currentlyLoaded = 10; this.filter = { availabilityFilter: FilterType.None, statusFilter: FilterType.None, - count: this.amountToLoad, - position: 0, }; + this.loadInit(); + this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); } public paginate(event: IPagenator) { - const skipAmount = event.first; - + const skipAmount = event.first; this.loadRequests(this.amountToLoad, skipAmount); } @@ -99,7 +96,7 @@ export class MovieRequestsComponent implements OnInit { public removeRequest(request: IMovieRequests) { this.requestService.removeMovieRequest(request); this.removeRequestFromUi(request); - this.loadRequests(1, this.currentlyLoaded); + this.loadRequests(this.amountToLoad, this.currentlyLoaded = 0); } public changeAvailability(request: IMovieRequests, available: boolean) { @@ -183,38 +180,27 @@ export class MovieRequestsComponent implements OnInit { public filterAvailability(filter: FilterType, el: any) { this.filterActiveStyle(el); this.filter.availabilityFilter = filter; - this.requestService.filterMovies(this.filter) - .subscribe(x => { - this.totalMovies = x.total; - this.setOverrides(x.collection); - this.movieRequests = x.collection; - }); + this.loadInit(); } public filterStatus(filter: FilterType, el: any) { this.filterActiveStyle(el); this.filter.statusFilter = filter; - this.requestService.filterMovies(this.filter) - .subscribe(x => { - this.totalMovies = x.total; - this.setOverrides(x.collection); - this.movieRequests = x.collection; - }); + this.loadInit(); } - public setOrder(value: string, el: any) { + public setOrder(value: OrderType, el: any) { el = el.toElement || el.relatedTarget || el.target || el.srcElement; const parent = el.parentElement; const previousFilter = parent.querySelector(".active"); - if (this.order === value) { - this.reverse = !this.reverse; - } else { - previousFilter.className = ""; - el.className = "active"; - } - this.order = value; + previousFilter.className = ""; + el.className = "active"; + + this.orderType = value; + + this.loadInit(); } public subscribe(request: IMovieRequests) { @@ -252,26 +238,16 @@ export class MovieRequestsComponent implements OnInit { } private loadRequests(amountToLoad: number, currentlyLoaded: number) { - if(this.filter.availabilityFilter === FilterType.None && this.filter.statusFilter === FilterType.None) { - this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1) + this.requestService.getMovieRequests(amountToLoad, currentlyLoaded, this.orderType, this.filter) .subscribe(x => { - this.setOverrides(x); + this.setOverrides(x.collection); if(!this.movieRequests) { this.movieRequests = []; } - this.movieRequests = x; + this.movieRequests = x.collection; + this.totalMovies = x.total; this.currentlyLoaded = currentlyLoaded + amountToLoad; }); - } else { - this.filter.position = currentlyLoaded; - this.requestService.filterMovies(this.filter) - .subscribe(x => { - this.setOverrides(x.collection); - this.totalMovies = x.total; - this.movieRequests = x.collection; - this.currentlyLoaded = currentlyLoaded + amountToLoad; - }); - } } private updateRequest(request: IMovieRequests) { @@ -310,23 +286,25 @@ export class MovieRequestsComponent implements OnInit { } private loadInit() { - this.requestService.getTotalMovies().subscribe(x => this.totalMovies = x); - this.requestService.getMovieRequests(this.amountToLoad, 0) + this.requestService.getMovieRequests(this.amountToLoad, 0, this.orderType, this.filter) .subscribe(x => { - this.movieRequests = x; + this.movieRequests = x.collection; + this.totalMovies = x.total; this.movieRequests.forEach((req) => { - this.setBackground(req); - this.setPoster(req); - }); - this.radarrService.getQualityProfilesFromSettings().subscribe(c => { - this.radarrProfiles = c; - this.movieRequests.forEach((req) => this.setQualityOverrides(req)); - }); - this.radarrService.getRootFoldersFromSettings().subscribe(c => { - this.radarrRootFolders = c; - this.movieRequests.forEach((req) => this.setRootFolderOverrides(req)); + this.setBackground(req); + this.setPoster(req); }); + if (this.isAdmin) { + this.radarrService.getQualityProfilesFromSettings().subscribe(c => { + this.radarrProfiles = c; + this.movieRequests.forEach((req) => this.setQualityOverrides(req)); + }); + this.radarrService.getRootFoldersFromSettings().subscribe(c => { + this.radarrRootFolders = c; + this.movieRequests.forEach((req) => this.setRootFolderOverrides(req)); + }); + } }); } diff --git a/src/Ombi/ClientApp/app/requests/tvrequests.component.ts b/src/Ombi/ClientApp/app/requests/tvrequests.component.ts index 10b1b750e..202b6dbf6 100644 --- a/src/Ombi/ClientApp/app/requests/tvrequests.component.ts +++ b/src/Ombi/ClientApp/app/requests/tvrequests.component.ts @@ -240,8 +240,10 @@ export class TvRequestsComponent implements OnInit { ("url(https://image.tmdb.org/t/p/w1280" + val.data.background + ")"); } else { this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => { - val.data.background = this.sanitizer.bypassSecurityTrustStyle + if(x) { + val.data.background = this.sanitizer.bypassSecurityTrustStyle ("url(" + x + ")"); + } }); } } diff --git a/src/Ombi/ClientApp/app/search/moviesearch.component.html b/src/Ombi/ClientApp/app/search/moviesearch.component.html index a2b59df79..44dc345bc 100644 --- a/src/Ombi/ClientApp/app/search/moviesearch.component.html +++ b/src/Ombi/ClientApp/app/search/moviesearch.component.html @@ -65,7 +65,13 @@
- +
+
+ + + +
+
diff --git a/src/Ombi/ClientApp/app/search/moviesearch.component.ts b/src/Ombi/ClientApp/app/search/moviesearch.component.ts index c8c7514a7..ff570441a 100644 --- a/src/Ombi/ClientApp/app/search/moviesearch.component.ts +++ b/src/Ombi/ClientApp/app/search/moviesearch.component.ts @@ -79,6 +79,7 @@ export class MovieSearchComponent implements OnInit { public request(searchResult: ISearchMovieResult) { searchResult.requested = true; searchResult.requestProcessing = true; + searchResult.showSubscribe = false; if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) { searchResult.approved = true; } @@ -103,6 +104,7 @@ export class MovieSearchComponent implements OnInit { searchResult.approved = false; searchResult.processed = false; searchResult.requestProcessing = false; + } }); } catch (e) { @@ -162,6 +164,22 @@ export class MovieSearchComponent implements OnInit { this.getExtraInfo(); }); } + + public subscribe(r: ISearchMovieResult) { + r.subscribed = true; + this.requestService.subscribeToMovie(r.requestId) + .subscribe(x => { + this.notificationService.success("Subscribed To Movie!"); + }); + } + + public unSubscribe(r: ISearchMovieResult) { + r.subscribed = false; + this.requestService.unSubscribeToMovie(r.requestId) + .subscribe(x => { + this.notificationService.success("Unsubscribed Movie!"); + }); + } private getExtraInfo() { diff --git a/src/Ombi/ClientApp/app/search/search.module.ts b/src/Ombi/ClientApp/app/search/search.module.ts index 1b7f1310f..d5b8669ef 100644 --- a/src/Ombi/ClientApp/app/search/search.module.ts +++ b/src/Ombi/ClientApp/app/search/search.module.ts @@ -11,7 +11,7 @@ import { SearchComponent } from "./search.component"; import { SeriesInformationComponent } from "./seriesinformation.component"; import { TvSearchComponent } from "./tvsearch.component"; -import { SidebarModule, TreeTableModule } from "primeng/primeng"; +import { SidebarModule, TooltipModule, TreeTableModule } from "primeng/primeng"; import { RequestService } from "../services"; import { SearchService } from "../services"; @@ -33,6 +33,7 @@ const routes: Routes = [ TreeTableModule, SharedModule, SidebarModule, + TooltipModule, ], declarations: [ SearchComponent, diff --git a/src/Ombi/ClientApp/app/search/seriesinformation.component.ts b/src/Ombi/ClientApp/app/search/seriesinformation.component.ts index c4a50ae38..f2eef3d57 100644 --- a/src/Ombi/ClientApp/app/search/seriesinformation.component.ts +++ b/src/Ombi/ClientApp/app/search/seriesinformation.component.ts @@ -52,7 +52,7 @@ export class SeriesInformationComponent implements OnInit { const seasonsViewModel = {seasonNumber: season.seasonNumber, episodes: []}; season.episodes.forEach(ep => { if(!this.series.latestSeason || !this.series.requestAll || !this.series.firstSeason) { - if(ep.requested) { + if(ep.selected) { seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber}); } } diff --git a/src/Ombi/ClientApp/app/search/tvsearch.component.ts b/src/Ombi/ClientApp/app/search/tvsearch.component.ts index cdb3e1c6e..8db75125c 100644 --- a/src/Ombi/ClientApp/app/search/tvsearch.component.ts +++ b/src/Ombi/ClientApp/app/search/tvsearch.component.ts @@ -138,9 +138,11 @@ export class TvSearchComponent implements OnInit { public getExtraInfo() { this.tvResults.forEach((val, index) => { this.imageService.getTvBanner(val.data.id).subscribe(x => { - val.data.background = this.sanitizer. - bypassSecurityTrustStyle - ("url(" + x + ")"); + if(x) { + val.data.background = this.sanitizer. + bypassSecurityTrustStyle + ("url(" + x + ")"); + } }); this.searchService.getShowInformationTreeNode(val.data.id) .subscribe(x => { diff --git a/src/Ombi/ClientApp/app/services/request.service.ts b/src/Ombi/ClientApp/app/services/request.service.ts index 2da0c1a8a..e52ab3057 100644 --- a/src/Ombi/ClientApp/app/services/request.service.ts +++ b/src/Ombi/ClientApp/app/services/request.service.ts @@ -6,7 +6,7 @@ import { Observable } from "rxjs/Rx"; import { TreeNode } from "primeng/primeng"; import { IRequestEngineResult } from "../interfaces"; -import { IChildRequests, IFilter, IFilterResult, IMovieRequestModel, IMovieRequests, IMovieUpdateModel, ITvRequests,ITvUpdateModel } from "../interfaces"; +import { IChildRequests, IFilter, IMovieRequestModel, IMovieRequests, IMovieUpdateModel, IRequestsViewModel, ITvRequests,ITvUpdateModel, OrderType } from "../interfaces"; import { ITvRequestViewModel } from "../interfaces"; import { ServiceHelpers } from "./service.helpers"; @@ -48,8 +48,8 @@ export class RequestService extends ServiceHelpers { return this.http.post(`${this.url}Movie/unavailable`, JSON.stringify(movie), {headers: this.headers}); } - public getMovieRequests(count: number, position: number): Observable { - return this.http.get(`${this.url}movie/${count}/${position}`, {headers: this.headers}); + public getMovieRequests(count: number, position: number, order: OrderType, filter: IFilter): Observable> { + return this.http.get>(`${this.url}movie/${count}/${position}/${order}/${filter.statusFilter}/${filter.availabilityFilter}`, {headers: this.headers}); } public searchMovieRequests(search: string): Observable { @@ -114,10 +114,7 @@ export class RequestService extends ServiceHelpers { public deleteChild(child: IChildRequests): Observable { return this.http.delete(`${this.url}tv/child/${child.id}`, {headers: this.headers}); } - public filterMovies(filter: IFilter): Observable> { - return this.http.post>(`${this.url}movie/filter`, JSON.stringify(filter), {headers: this.headers}); - } - + public subscribeToMovie(requestId: number): Observable { return this.http.post(`${this.url}movie/subscribe/${requestId}`, {headers: this.headers}); } diff --git a/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.ts b/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.ts index b512d6a86..cb0bf81c0 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.ts +++ b/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.ts @@ -62,7 +62,7 @@ export class MattermostComponent implements OnInit { this.testerService.mattermostTest(form.value).subscribe(x => { if (x) { - this.notificationService.success( "Successfully sent a Mattermost message, please check the discord channel"); + this.notificationService.success( "Successfully sent a Mattermost message, please check the appropriate channel"); } else { this.notificationService.error("There was an error when sending the Mattermost message. Please check your settings"); } diff --git a/src/Ombi/ClientApp/app/settings/notifications/mobile.component.html b/src/Ombi/ClientApp/app/settings/notifications/mobile.component.html index 3aad31ff8..5c82e03d5 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/mobile.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/mobile.component.html @@ -39,7 +39,7 @@
diff --git a/src/Ombi/ClientApp/app/settings/notifications/mobile.component.ts b/src/Ombi/ClientApp/app/settings/notifications/mobile.component.ts index b40b4aa94..61a0253c8 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/mobile.component.ts +++ b/src/Ombi/ClientApp/app/settings/notifications/mobile.component.ts @@ -34,7 +34,7 @@ export class MobileComponent implements OnInit { this.mobileService.getUserDeviceList().subscribe(x => { if(x.length <= 0) { this.userList = []; - this.userList.push({username:"None",devices:0}); + this.userList.push({username:"None",devices:0, userId:""}); } else { this.userList = x; } diff --git a/src/Ombi/Controllers/ImagesController.cs b/src/Ombi/Controllers/ImagesController.cs index 692966258..69ec9e328 100644 --- a/src/Ombi/Controllers/ImagesController.cs +++ b/src/Ombi/Controllers/ImagesController.cs @@ -35,6 +35,10 @@ namespace Ombi.Controllers [HttpGet("tv/{tvdbid}")] public async Task GetTvBanner(int tvdbid) { + if (tvdbid <= 0) + { + return string.Empty; + } var key = await _cache.GetOrAdd(CacheKeys.FanartTv, async () => await Config.Get(Store.Entities.ConfigurationTypes.FanartTv), DateTime.Now.AddDays(1)); var images = await FanartTvApi.GetTvImages(tvdbid, key.Value); @@ -90,6 +94,10 @@ namespace Ombi.Controllers [HttpGet("poster/tv/{tvdbid}")] public async Task GetTvPoster(int tvdbid) { + if (tvdbid <= 0) + { + return string.Empty; + } var key = await _cache.GetOrAdd(CacheKeys.FanartTv, async () => await Config.Get(Store.Entities.ConfigurationTypes.FanartTv), DateTime.Now.AddDays(1)); var images = await FanartTvApi.GetTvImages(tvdbid, key.Value); @@ -145,6 +153,10 @@ namespace Ombi.Controllers [HttpGet("background/tv/{tvdbid}")] public async Task GetTvBackground(int tvdbid) { + if (tvdbid <= 0) + { + return string.Empty; + } var key = await _cache.GetOrAdd(CacheKeys.FanartTv, async () => await Config.Get(Store.Entities.ConfigurationTypes.FanartTv), DateTime.Now.AddDays(1)); var images = await FanartTvApi.GetTvImages(tvdbid, key.Value); diff --git a/src/Ombi/Controllers/IssuesController.cs b/src/Ombi/Controllers/IssuesController.cs index 507c04f78..7984785d4 100644 --- a/src/Ombi/Controllers/IssuesController.cs +++ b/src/Ombi/Controllers/IssuesController.cs @@ -133,7 +133,11 @@ namespace Ombi.Controllers i.IssueCategory = null; i.UserReportedId = (await _userManager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name)).Id; await _issues.Add(i); - + var category = await _categories.GetAll().FirstOrDefaultAsync(x => i.IssueCategoryId == x.Id); + if (category != null) + { + i.IssueCategory = category; + } var notificationModel = new NotificationOptions { RequestId = i.RequestId ?? 0, @@ -142,7 +146,7 @@ namespace Ombi.Controllers RequestType = i.RequestType, Recipient = string.Empty, AdditionalInformation = $"{i.Subject} | {i.Description}", - UserId = i.UserReportedId + UserId = i.UserReportedId, }; AddIssueNotificationSubstitutes(notificationModel, i, User.Identity.Name); @@ -195,7 +199,7 @@ namespace Ombi.Controllers { var user = await _userManager.Users.Where(x => User.Identity.Name == x.UserName) .FirstOrDefaultAsync(); - var issue = await _issues.GetAll().Include(x => x.UserReported).FirstOrDefaultAsync(x => x.Id == comment.IssueId); + var issue = await _issues.GetAll().Include(x => x.UserReported).Include(x => x.IssueCategory).FirstOrDefaultAsync(x => x.Id == comment.IssueId); if (issue == null) { return null; @@ -242,7 +246,7 @@ namespace Ombi.Controllers { var user = await _userManager.Users.Where(x => User.Identity.Name == x.UserName) .FirstOrDefaultAsync(); - var issue = await _issues.GetAll().Include(x => x.UserReported).FirstOrDefaultAsync(x => x.Id == model.IssueId); + var issue = await _issues.GetAll().Include(x => x.UserReported).Include(x => x.IssueCategory).FirstOrDefaultAsync(x => x.Id == model.IssueId); if (issue == null) { return false; diff --git a/src/Ombi/Controllers/MobileController.cs b/src/Ombi/Controllers/MobileController.cs index 95703351c..70a6f1053 100644 --- a/src/Ombi/Controllers/MobileController.cs +++ b/src/Ombi/Controllers/MobileController.cs @@ -68,6 +68,7 @@ namespace Ombi.Controllers { vm.Add(new MobileUsersViewModel { + UserId = u.Id, Username = u.UserAlias, Devices = u.NotificationUserIds.Count }); diff --git a/src/Ombi/Controllers/RequestController.cs b/src/Ombi/Controllers/RequestController.cs index 0a56c32b6..47329a0ec 100644 --- a/src/Ombi/Controllers/RequestController.cs +++ b/src/Ombi/Controllers/RequestController.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Ombi.Store.Entities.Requests; using System.Diagnostics; +using Ombi.Core.Models.UI; using Ombi.Models; using Ombi.Store.Entities; @@ -32,10 +33,18 @@ namespace Ombi.Controllers /// /// The count of items you want to return. /// The position. - [HttpGet("movie/{count:int}/{position:int}")] - public async Task> GetRequests(int count, int position) + /// The way we want to order. + /// + /// + [HttpGet("movie/{count:int}/{position:int}/{orderType:int}/{statusType:int}/{availabilityType:int}")] + public async Task> GetRequests(int count, int position, int orderType, int statusType, int availabilityType) { - return await MovieRequestEngine.GetRequests(count, position); + return await MovieRequestEngine.GetRequests(count, position, new OrderFilterModel + { + OrderType = (OrderType)orderType, + AvailabilityFilter = (FilterType)availabilityType, + StatusFilter = (FilterType)statusType, + }); } /// @@ -170,11 +179,19 @@ namespace Ombi.Controllers /// /// The count of items you want to return. /// The position. + /// + /// + /// /// - [HttpGet("tv/{count:int}/{position:int}")] - public async Task> GetTvRequests(int count, int position) + [HttpGet("tv/{count:int}/{position:int}/{orderType:int}/{statusFilterType:int}/{availabilityFilterType:int}")] + public async Task> GetTvRequests(int count, int position, int orderType, int statusType, int availabilityType) { - return await TvRequestEngine.GetRequests(count, position); + return await TvRequestEngine.GetRequests(count, position, new OrderFilterModel + { + OrderType = (OrderType)orderType, + AvailabilityFilter = (FilterType) availabilityType, + StatusFilter = (FilterType) statusType, + }); } /// @@ -347,17 +364,6 @@ namespace Ombi.Controllers return movies || tv; } - /// - /// Returns a filtered list - /// - /// - /// - [HttpPost("movie/filter")] - public async Task> Filter([FromBody] FilterViewModel vm) - { - return await MovieRequestEngine.Filter(vm); - } - /// /// Subscribes for notifications to a movie request /// diff --git a/src/Ombi/Models/MobileUsersViewModel.cs b/src/Ombi/Models/MobileUsersViewModel.cs index e7d99569f..d10ed68bc 100644 --- a/src/Ombi/Models/MobileUsersViewModel.cs +++ b/src/Ombi/Models/MobileUsersViewModel.cs @@ -2,6 +2,7 @@ { public class MobileUsersViewModel { + public string UserId { get; set; } public string Username { get; set; } public int Devices { get; set; } } diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index cb7c0fe8b..289db8be5 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -138,10 +138,12 @@ "Filter":"Filter", "Sort":"Sort", "SeasonNumberHeading":"Season: {seasonNumber}", - "SortTitle":"Title", - "SortRequestDate": "Request Date", - "SortRequestedBy":"Requested By", - "SortStatus":"Status" + "SortTitleAsc":"Title ▲", + "SortTitleDesc":"Title ▼", + "SortRequestDateAsc": "Request Date ▲", + "SortRequestDateDesc": "Request Date ▼", + "SortStatusAsc":"Status ▲", + "SortStatusDesc":"Status ▼" }, "Issues":{ "Title":"Issues",