You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Ombi/src/Ombi.Core/Engine/MusicRequestEngine.cs

603 lines
22 KiB

using Ombi.Api.TheMovieDb;
using Ombi.Core.Models.Requests;
using Ombi.Helpers;
using Ombi.Store.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
5 years ago
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr;
using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models;
using Ombi.Core.Models.UI;
using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Senders;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using System.ComponentModel;
using Ombi.Core.Helpers;
namespace Ombi.Core.Engine
{
public class MusicRequestEngine : BaseMediaEngine, IMusicRequestEngine
{
public MusicRequestEngine(IRequestServiceMain requestService, ICurrentUser user,
INotificationHelper helper, IRuleEvaluator r, ILogger<MusicRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,
ISettingsService<LidarrSettings> lidarrSettings, IMusicSender sender)
: base(user, requestService, r, manager, cache, ombiSettings, sub)
{
NotificationHelper = helper;
_musicSender = sender;
Logger = log;
_requestLog = rl;
_lidarrApi = lidarr;
_lidarrSettings = lidarrSettings;
}
private INotificationHelper NotificationHelper { get; }
//private IMovieSender Sender { get; }
private ILogger Logger { get; }
private readonly IRepository<RequestLog> _requestLog;
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi;
private readonly IMusicSender _musicSender;
/// <summary>
/// Requests the Album.
/// </summary>
/// <param name="model">The model.</param>
/// <returns></returns>
public async Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model)
{
var s = await _lidarrSettings.GetSettingsAsync();
var album = await _lidarrApi.GetAlbumByForeignId(model.ForeignAlbumId, s.ApiKey, s.FullUri);
if (album == null)
{
return new RequestEngineResult
{
Result = false,
Message = "There was an issue adding this album!",
ErrorMessage = "Please try again later"
};
}
var userDetails = await GetUser();
var requestModel = new AlbumRequest
{
ForeignAlbumId = model.ForeignAlbumId,
ArtistName = album.artist?.artistName,
ReleaseDate = album.releaseDate,
RequestedDate = DateTime.Now,
RequestType = RequestType.Album,
Rating = album.ratings?.value ?? 0m,
RequestedUserId = userDetails.Id,
Title = album.title,
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty, // This needs to be populated to send to Lidarr for new requests
RequestedByAlias = model.RequestedByAlias
};
if (requestModel.Cover.IsNullOrEmpty())
{
requestModel.Cover = album.remoteCover;
}
var ruleResults = (await RunRequestRules(requestModel)).ToList();
if (ruleResults.Any(x => !x.Success))
{
return new RequestEngineResult
{
ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message
};
}
if (requestModel.Approved) // The rules have auto approved this
{
var requestEngineResult = await AddAlbumRequest(requestModel);
if (requestEngineResult.Result)
{
var result = await ApproveAlbum(requestModel);
if (result.IsError)
{
Logger.LogWarning("Tried auto sending Album but failed. Message: {0}", result.Message);
return new RequestEngineResult
{
Message = result.Message,
ErrorMessage = result.Message,
Result = false
};
}
return requestEngineResult;
}
// If there are no providers then it's successful but album has not been sent
}
return await AddAlbumRequest(requestModel);
}
/// <summary>
/// Gets the requests.
/// </summary>
/// <param name="count">The count.</param>
/// <param name="position">The position.</param>
/// <param name="orderFilter">The order/filter type.</param>
/// <returns></returns>
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position,
OrderFilterModel orderFilter)
{
var shouldHide = await HideFromOtherUsers();
IQueryable<AlbumRequest> allRequests;
if (shouldHide.Hide)
{
allRequests =
MusicRepository.GetWithUser(shouldHide
.UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
}
else
{
allRequests =
MusicRepository
.GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
}
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 (OrderAlbums(allRequests, orderFilter.OrderType)).Skip(position).Take(count)
.ToListAsync();
requests.ForEach(async x =>
{
await CheckForSubscription(shouldHide, x);
});
return new RequestsViewModel<AlbumRequest>
{
Collection = requests,
Total = total
};
}
private IQueryable<AlbumRequest> OrderAlbums(IQueryable<AlbumRequest> 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);
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
public async Task<int> GetTotal()
{
var shouldHide = await HideFromOtherUsers();
if (shouldHide.Hide)
{
return await MusicRepository.GetWithUser(shouldHide.UserId).CountAsync();
}
else
{
return await MusicRepository.GetWithUser().CountAsync();
}
}
/// <summary>
/// Gets the requests.
/// </summary>
/// <returns></returns>
public async Task<IEnumerable<AlbumRequest>> GetRequests()
{
var shouldHide = await HideFromOtherUsers();
List<AlbumRequest> allRequests;
if (shouldHide.Hide)
{
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
}
else
{
allRequests = await MusicRepository.GetWithUser().ToListAsync();
}
allRequests.ForEach(async x =>
{
await CheckForSubscription(shouldHide, x);
});
return allRequests;
}
private async Task CheckForSubscription(HideResult shouldHide, List<AlbumRequest> albumRequests)
{
var requestIds = albumRequests.Select(x => x.Id);
var sub = await _subscriptionRepository.GetAll().Where(s =>
s.UserId == shouldHide.UserId && requestIds.Contains(s.RequestId) && s.RequestType == RequestType.Movie)
.ToListAsync();
foreach (var x in albumRequests)
{
if (shouldHide.UserId == x.RequestedUserId)
{
x.ShowSubscribe = false;
}
else
{
develop to master (#4718) * Remove dead code * Localize TV requests messages on TV details page * Transform buttons with link into anchors * Sonarr sync: stop using seasonpass API * chore(release): :rocket: v4.16.13 * Fix requests when 4k available and 4k disabled Fixes #4610 * chore(release): :rocket: v4.16.14 * Hide subscribe button when request is available * Hide subscribe button when request is denied * Add Title to Partially Available Message If the Title of the show is not menitoned it can be unclear what Episodes are now available. * Better error message when test email fails due to missing recipient * feat(discover): Add original language filter * chore(release): :rocket: v4.16.15 * fix(4616): :bug: fixed mandatory fields * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.16.16 * added test results into the PR pipeline * chore(release): :rocket: v4.16.17 * Add information about cache refresh * Update pr.yml [skip ci] * Update pr.yml [skip ci] * Update pr.yml [skip ci] * chore(release): :rocket: v4.17.0 * feat(discover): Add new trending source experimental feature * fix(settings): Allow toggling features when there are more than one * fix(discover): Fix new trending feature detection * fix(discover): Fix cache mix up * refactor(discover): Move movie trending feature toggle to backend * feat(discover): Default trending source to new logic * chore(release): :rocket: v4.18.0 * feat(sync): Detect reidentified movies in Emby and Jellyfin * feat(sync): Detect reidentified series in Emby and Jellyfin * Fix sync log criticity * Update pr.yml [skip ci] * Update label.yml [skip ci] * Fix formatting * Update pr.yml [skip ci] * Update label.yml [skip ci] * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.19.0 * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish a series * refactor(newsletter): Clarify very rare cases where newsletter doesn't publish movie * chore(release): :rocket: v4.19.1 * feat(discover): Show more relevant shows in upcoming TV * chore(release): :rocket: v4.20.0 * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes * perf(sync): Emby+Jellyfin - use a more reliable filter to missing items * fix(sync): Emby+Jellyfin - sync multi-episode files of 3+ episodes [skip ci] * fix: added media type tag to media type text (#4638) [skip ci] * fix(sickrage): Fixed issue with incorrect handling of SiCKRAGE episode results returned during episode status changes, now expects array of objects from data path if present (#4648) [skip ci] * fix: Missing Poster broken link fix (#4637) [skip ci] * 🌐 Translations Update (#4622) [skip ci] * Update launch.json (#4650) [skip ci] * fix: Improve Swagger documentation (#4652) * Upgrade Swashbuckle dependency * Document /token response * Add support for Newtonsoft annotations in Swagger * Remove unecessary ActionResult [skip ci] * fix(API): Fix pagination in some edge cases (#4649) [skip ci] * 🌐 Translations Update (#4655) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): Carousel touch not working when scrolling page and recommendations and similar movie navigation (#4633) * fixed touch not working on carousels * fixed touch not working * Movie details component fixes Fixed recommendations and similar not changing the data on the component by calling the init function again on param change Moved the ngif results > 0 to the mat-expansion panel to avoid rendering the entire element if it doesn't have any results instead of having an empty panel. * removed unused line, added scroll to top on init * updated recommendation refresh implementation Changed the implementation to use the router instead in order to reload the component instead of just reloading the data. This implementation makes sure the component gets destroyed on navigation eliminating any memory leaks, reloading CSS in case of having animations on page load and generally a continuation of the experience you get when you browse into a movie from the discover page. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.20.1 [skip ci] * fix: :bug: Fixed the Request on Behalf of having blanks (#4667) * chore(release): :rocket: v4.20.2 [skip ci] * fix(plex): 🐛 Fixed an issue with the Plex Sync * chore(release): :rocket: v4.20.3 [skip ci] * fix (technical): Improved some of the date time parsing handling * fix: fixed build * chore(release): :rocket: v4.20.4 [skip ci] * feat: Upgrade to Angular14 (#4668) * refactor: :fire: removed angular-bootstrap-md dependancy * chore: update tsconfig * yeah * ng14 upgrade * refactor: migration changes * fix: fixed CLI * test: Fixed automation * chore: :busts_in_silhouette: Updated Contributors [skip ci] * perf: stop populating obsolete subscribe fields (#4625) * chore(release): :rocket: v4.21.0 [skip ci] * fix(images): Retry images with a backoff when we get a Too Many requests from TheMovieDb #4685 * chore(release): :rocket: v4.21.1 [skip ci] * 🌐 Translations Update (#4683) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix: Landing and Login page improvements (#4690) * chore(release): :rocket: v4.21.2 [skip ci] * feat(discover): ✨ Added infinite scroll on advanced search results * feat(discover): :sparkles: Added infinite scroll on advanced search results * chore(release): :rocket: v4.22.0 [skip ci] * 🌐 Translations Update (#4694) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(discover): :bug: Created new Image component to handle 429's from TMDB (#4698) and fixed #4635 (#4699) * chore(release): :rocket: v4.22.1 [skip ci] * fix: fixed an issue where I broke images for some users * chore(release): :rocket: v4.22.2 [skip ci] * ci(Mergify): configuration update (#4701) Signed-off-by: Jamie <tidusjar@gmail.com> [skip ci] * fix: Override Sonarr V3 Profiles endpoint (#4678) * Override Sonarr V3 Profiles endpoint [skip ci] * fix(4K) :4K request fixes (#4702) * GetRequestsByStatus wasn't implementing the MovieRequests object correctly for 4K quality requests with the ProcessingRequest status. * Fixed 4K requests not getting automatically approved if the user has the "Auto Approve Movie" role flag enabled. * Fixed "Request Date" values for the "left-panel-details" div class. Previously when the movie was exclusively 4K (regular request was absent), then "Request Date" equaled DateTime.MinValue (January 1, 0001). * Fixed "Request Status" evaluation in the "left-panel-details" div class. Now it shows the appropriate status instead of an empty spot. "Request Status" displays both regular and 4K statuses at the same time if needed. Added a comma to the end of the "RequestStatus" label to maintain design consistency with the other labels. Also added a "Denied Reason" element for 4K requests. * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.3 [skip ci] * chore: Storybook (#4700) [skip ci] * chore: Translations [skip ci] * 🌐 Translations Update (#4704) * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] * fix(translations): 🌐 New translations from Crowdin [skip ci] (#4713) * build: Run automation tests in docker (#4715) [skip ci] * fix: fixed trakt image not loading when base url present (#4711) [skip ci] * fix: :bug: Fixed missing externals (#4712) * chore: :busts_in_silhouette: Updated Contributors [skip ci] * chore(release): :rocket: v4.22.4 [skip ci] * test: fixed automationt tests [skip ci] Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com> Co-authored-by: Conventional Changelog Action <conventional.changelog.action@github.com> Co-authored-by: Teifun2 <Teifun2@users.noreply.github.com> Co-authored-by: contrib-readme-bot <contrib-readme-action@noreply.com> Co-authored-by: dr3amer <91037083+dr3am37@users.noreply.github.com> Co-authored-by: echel0n <echel0n@sickrage.ca> Co-authored-by: Marley <55280588+marleypowell@users.noreply.github.com> Co-authored-by: Igor Borges <igor@borges.dev> Co-authored-by: Lucane <Lucane@users.noreply.github.com> Co-authored-by: mkgeeky <github@mkgeeky.xyz>
2 years ago
if (!x.Available && (!x.Denied ?? false))
{
x.ShowSubscribe = true;
}
var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id);
x.Subscribed = hasSub != null;
}
}
}
private async Task CheckForSubscription(HideResult shouldHide, AlbumRequest x)
{
if (shouldHide.UserId == x.RequestedUserId)
{
x.ShowSubscribe = false;
}
else
{
x.ShowSubscribe = true;
var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Album);
x.Subscribed = sub != null;
}
}
/// <summary>
/// Searches the album request.
/// </summary>
/// <param name="search">The search.</param>
/// <returns></returns>
public async Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search)
{
var shouldHide = await HideFromOtherUsers();
List<AlbumRequest> allRequests;
if (shouldHide.Hide)
{
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
}
else
{
allRequests = await MusicRepository.GetWithUser().ToListAsync();
}
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
results.ForEach(async x =>
{
await CheckForSubscription(shouldHide, x);
});
return results;
}
public async Task<RequestEngineResult> ApproveAlbumById(int requestId)
{
var request = await MusicRepository.Find(requestId);
return await ApproveAlbum(request);
}
public async Task<RequestEngineResult> DenyAlbumById(int modelId, string reason)
{
var request = await MusicRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult
{
ErrorMessage = "Request does not exist"
};
}
request.Denied = true;
request.DeniedReason = reason;
// We are denying a request
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await MusicRepository.Update(request);
return new RequestEngineResult
{
Message = "Request successfully deleted",
};
}
public async Task<RequestEngineResult> ApproveAlbum(AlbumRequest request)
{
if (request == null)
{
return new RequestEngineResult
{
ErrorMessage = "Request does not exist"
};
}
request.MarkedAsApproved = DateTime.Now;
request.Approved = true;
request.Denied = false;
await MusicRepository.Update(request);
3 years ago
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
if (canNotify.Success)
{
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
}
if (request.Approved)
{
var result = await _musicSender.Send(request);
if (result.Success && result.Sent)
{
return new RequestEngineResult
{
Result = true
};
}
if (!result.Success)
{
Logger.LogWarning("Tried auto sending album but failed. Message: {0}", result.Message);
return new RequestEngineResult
{
Message = result.Message,
ErrorMessage = result.Message,
Result = false
};
}
// If there are no providers then it's successful but movie has not been sent
}
return new RequestEngineResult
{
Result = true
};
}
/// <summary>
/// Removes the Album request.
/// </summary>
/// <param name="requestId">The request identifier.</param>
/// <returns></returns>
public async Task<RequestEngineResult> RemoveAlbumRequest(int requestId)
{
var request = await MusicRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MusicRepository.Delete(request);
return new RequestEngineResult
{
Result = true,
};
}
public async Task<bool> UserHasRequest(string userId)
{
return await MusicRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
}
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
{
var request = await MusicRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult
{
ErrorMessage = "Request does not exist"
};
}
request.Available = false;
await MusicRepository.Update(request);
return new RequestEngineResult
{
Message = "Request is now unavailable",
Result = true
};
}
public async Task<RequestEngineResult> MarkAvailable(int modelId)
{
var request = await MusicRepository.Find(modelId);
if (request == null)
{
return new RequestEngineResult
{
ErrorMessage = "Request does not exist"
};
}
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MusicRepository.Update(request);
return new RequestEngineResult
{
Message = "Request is now available",
Result = true
};
}
private async Task<RequestEngineResult> AddAlbumRequest(AlbumRequest model)
{
await MusicRepository.Add(model);
3 years ago
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, string.Empty);
if (result.Success)
{
await NotificationHelper.NewRequest(model);
}
await _requestLog.Add(new RequestLog
{
UserId = (await GetUser()).Id,
RequestDate = DateTime.UtcNow,
RequestId = model.Id,
RequestType = RequestType.Album,
});
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!", RequestId = model.Id };
}
public async Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
{
var shouldHide = await HideFromOtherUsers();
IQueryable<AlbumRequest> allRequests;
if (shouldHide.Hide)
{
allRequests =
MusicRepository.GetWithUser(shouldHide
.UserId);
}
else
{
allRequests =
MusicRepository
.GetWithUser();
}
switch (status)
{
case RequestStatus.PendingApproval:
allRequests = allRequests.Where(x => !x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value));
break;
case RequestStatus.ProcessingRequest:
allRequests = allRequests.Where(x => x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value));
break;
case RequestStatus.Available:
allRequests = allRequests.Where(x => x.Available);
break;
case RequestStatus.Denied:
allRequests = allRequests.Where(x => x.Denied.HasValue && x.Denied.Value && !x.Available);
break;
default:
break;
}
var prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find(sortProperty, true);
if (sortProperty.Contains('.'))
{
// This is a navigation property currently not supported
prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find("RequestedDate", true);
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
//var propType = firstProp.PropertyType;
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
}
// TODO fix this so we execute this on the server
var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
? allRequests.ToList().OrderBy(x => x.RequestedDate).ToList()
: allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList();
var total = requests.Count();
requests = requests.Skip(position).Take(count).ToList();
await CheckForSubscription(shouldHide, requests);
return new RequestsViewModel<AlbumRequest>
{
Collection = requests,
Total = total
};
}
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sortProperty, string sortOrder)
{
var shouldHide = await HideFromOtherUsers();
IQueryable<AlbumRequest> allRequests;
if (shouldHide.Hide)
{
allRequests =
MusicRepository.GetWithUser(shouldHide
.UserId);
}
else
{
allRequests =
MusicRepository
.GetWithUser();
}
var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true);
if (sortProperty.Contains('.'))
{
// This is a navigation property currently not supported
prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find("RequestedDate", true);
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
//var propType = firstProp.PropertyType;
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
}
// TODO fix this so we execute this on the server
var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
? allRequests.ToList().OrderBy(x => x.RequestedDate).ToList()
: allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList();
var total = requests.Count();
requests = requests.Skip(position).Take(count).ToList();
await CheckForSubscription(shouldHide, requests);
return new RequestsViewModel<AlbumRequest>
{
Collection = requests,
Total = total
};
}
}
}