mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-12 08:16:05 -07:00
Added the request limits in the ui for music
This commit is contained in:
parent
550028b9eb
commit
be2d88c9ea
17 changed files with 107 additions and 9 deletions
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.UI;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
|
||||
namespace Ombi.Core.Engine
|
||||
|
@ -20,5 +22,6 @@ namespace Ombi.Core.Engine
|
|||
Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model);
|
||||
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
|
||||
Task<bool> UserHasRequest(string userId);
|
||||
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ 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;
|
||||
|
@ -409,6 +410,49 @@ namespace Ombi.Core.Engine
|
|||
Result = true
|
||||
};
|
||||
}
|
||||
public async Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
user = await GetUser();
|
||||
|
||||
// If user is still null after attempting to get the logged in user, return null.
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int limit = user.MusicRequestLimit ?? 0;
|
||||
|
||||
if (limit <= 0)
|
||||
{
|
||||
return new RequestQuotaCountModel()
|
||||
{
|
||||
HasLimit = false,
|
||||
Limit = 0,
|
||||
Remaining = 0,
|
||||
NextRequest = DateTime.Now,
|
||||
};
|
||||
}
|
||||
|
||||
IQueryable<RequestLog> log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Album);
|
||||
|
||||
int count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7));
|
||||
|
||||
DateTime oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7))
|
||||
.OrderBy(x => x.RequestDate)
|
||||
.Select(x => x.RequestDate)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return new RequestQuotaCountModel()
|
||||
{
|
||||
HasLimit = true,
|
||||
Limit = limit,
|
||||
Remaining = count,
|
||||
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> MarkAvailable(int modelId)
|
||||
{
|
||||
|
@ -453,5 +497,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!" };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ namespace Ombi.Core.Models.UI
|
|||
public int EpisodeRequestLimit { get; set; }
|
||||
public RequestQuotaCountModel EpisodeRequestQuota { get; set; }
|
||||
public RequestQuotaCountModel MovieRequestQuota { get; set; }
|
||||
public RequestQuotaCountModel MusicRequestQuota { get; set; }
|
||||
public int MusicRequestLimit { get; set; }
|
||||
public UserQualityProfiles UserQualityProfiles { get; set; }
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ export interface IUser {
|
|||
// FOR UI
|
||||
episodeRequestQuota: IRemainingRequests | null;
|
||||
movieRequestQuota: IRemainingRequests | null;
|
||||
musicRequestQuota: IRemainingRequests | null;
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ import { Observable } from "rxjs";
|
|||
export class RemainingRequestsComponent implements OnInit {
|
||||
public remaining: IRemainingRequests;
|
||||
@Input() public movie: boolean;
|
||||
@Input() public tv: boolean;
|
||||
@Input() public music: boolean;
|
||||
public daysUntil: number;
|
||||
public hoursUntil: number;
|
||||
public minutesUntil: number;
|
||||
|
@ -42,9 +44,13 @@ export class RemainingRequestsComponent implements OnInit {
|
|||
|
||||
if (this.movie) {
|
||||
this.requestService.getRemainingMovieRequests().subscribe(callback);
|
||||
} else {
|
||||
}
|
||||
if(this.tv) {
|
||||
this.requestService.getRemainingTvRequests().subscribe(callback);
|
||||
}
|
||||
if(this.music) {
|
||||
this.requestService.getRemainingMusicRequests().subscribe(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private calculateTime(): void {
|
||||
|
|
|
@ -89,9 +89,9 @@ export class MovieSearchComponent implements OnInit {
|
|||
try {
|
||||
this.requestService.requestMovie({ theMovieDbId: searchResult.id })
|
||||
.subscribe(x => {
|
||||
this.movieRequested.next();
|
||||
this.result = x;
|
||||
if (this.result.result) {
|
||||
this.movieRequested.next();
|
||||
this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => {
|
||||
this.notificationService.success(x);
|
||||
searchResult.processed = true;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
import { Subject } from "rxjs";
|
||||
import { AuthService } from "../../auth/auth.service";
|
||||
import { IIssueCategory, IRequestEngineResult } from "../../interfaces";
|
||||
import { ISearchAlbumResult } from "../../interfaces/ISearchMusicResult";
|
||||
|
@ -18,6 +19,8 @@ export class AlbumSearchComponent {
|
|||
|
||||
@Input() public issueCategories: IIssueCategory[];
|
||||
@Input() public issuesEnabled: boolean;
|
||||
|
||||
@Input() public musicRequested: Subject<void>;
|
||||
public issuesBarVisible = false;
|
||||
public issueRequestTitle: string;
|
||||
public issueRequestId: number;
|
||||
|
@ -56,10 +59,12 @@ export class AlbumSearchComponent {
|
|||
try {
|
||||
this.requestService.requestAlbum({ foreignAlbumId: searchResult.foreignAlbumId })
|
||||
.subscribe(x => {
|
||||
|
||||
this.engineResult = x;
|
||||
|
||||
if (this.engineResult.result) {
|
||||
this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => {
|
||||
this.musicRequested.next();
|
||||
this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => {
|
||||
this.notificationService.success(x);
|
||||
searchResult.processed = true;
|
||||
});
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
<div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<remaining-requests [music]="true" [quotaRefreshEvents]="musicRequested.asObservable()" #remainingAlbums></remaining-requests>
|
||||
|
||||
<div *ngFor="let result of artistResult">
|
||||
<artist-search [result]="result" [defaultPoster]="defaultPoster" (viewAlbumsResult)="viewAlbumsForArtist($event)"></artist-search>
|
||||
<br/>
|
||||
|
@ -35,7 +38,7 @@
|
|||
</div>
|
||||
<div class="col-md-12">
|
||||
<div *ngFor="let result of albumResult" class="col-md-4">
|
||||
<album-search [result]="result" [defaultPoster]="defaultPoster" (setSearch)="setArtistSearch($event)"></album-search>
|
||||
<album-search [musicRequested]="musicRequested" [result]="result" [defaultPoster]="defaultPoster" (setSearch)="setArtistSearch($event)"></album-search>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
|
|
@ -24,6 +24,7 @@ export class MusicSearchComponent implements OnInit {
|
|||
public searchApplied = false;
|
||||
public searchAlbum: boolean = true;
|
||||
|
||||
public musicRequested: Subject<void> = new Subject<void>();
|
||||
@Input() public issueCategories: IIssueCategory[];
|
||||
@Input() public issuesEnabled: boolean;
|
||||
public issuesBarVisible = false;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<remaining-requests [movie]="false" [quotaRefreshEvents]="tvRequested.asObservable()" #remainingTvShows></remaining-requests>
|
||||
<remaining-requests [tv]="true" [quotaRefreshEvents]="tvRequested.asObservable()" #remainingTvShows></remaining-requests>
|
||||
|
||||
<!-- Movie content -->
|
||||
<div id="actorMovieList">
|
||||
|
|
|
@ -26,6 +26,10 @@ export class RequestService extends ServiceHelpers {
|
|||
return this.http.get<IRemainingRequests>(`${this.url}tv/remaining`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public getRemainingMusicRequests(): Observable<IRemainingRequests> {
|
||||
return this.http.get<IRemainingRequests>(`${this.url}music/remaining`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public requestMovie(movie: IMovieRequestModel): Observable<IRequestEngineResult> {
|
||||
return this.http.post<IRequestEngineResult>(`${this.url}Movie/`, JSON.stringify(movie), {headers: this.headers});
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ export class UserManagementUserComponent implements OnInit {
|
|||
sonarrRootPath: 0,
|
||||
sonarrRootPathAnime: 0,
|
||||
},
|
||||
musicRequestQuota: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,9 @@
|
|||
<div *ngIf="u.episodeRequestQuota != null && u.episodeRequestQuota.hasLimit">
|
||||
{{'UserManagment.TvRemaining' | translate: {remaining: u.episodeRequestQuota.remaining, total: u.episodeRequestLimit} }}
|
||||
</div>
|
||||
<div *ngIf="u.musicRequestQuota != null && u.musicRequestQuota.hasLimit">
|
||||
{{'UserManagment.MusicRemaining' | translate: {remaining: u.musicRequestQuota.remaining, total: u.musicRequestLimit} }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="td-labelled" data-label="Request Due">
|
||||
<div *ngIf="u.movieRequestQuota != null && u.movieRequestQuota.remaining != u.movieRequestLimit">
|
||||
|
@ -106,6 +109,9 @@
|
|||
<div *ngIf="u.episodeRequestQuota != null && u.episodeRequestQuota.remaining != u.episodeRequestLimit">
|
||||
{{'UserManagment.TvDue' | translate: {date: (u.episodeRequestQuota.nextRequest | date: 'short')} }}
|
||||
</div>
|
||||
<div *ngIf="u.musicRequestQuota != null && u.musicRequestQuota.remaining != u.musicRequestLimit">
|
||||
{{'UserManagment.MusicDue' | translate: {date: (u.musicRequestQuota.nextRequest | date: 'short')} }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="td-labelled" data-label="Last Logged In:">
|
||||
{{u.lastLoggedIn | date: 'short'}}
|
||||
|
|
|
@ -16,6 +16,7 @@ using Ombi.Api.Plex;
|
|||
using Ombi.Attributes;
|
||||
using Ombi.Config;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Helpers;
|
||||
using Ombi.Core.Models.UI;
|
||||
|
@ -66,7 +67,8 @@ namespace Ombi.Controllers
|
|||
IRepository<UserQualityProfiles> userProfiles,
|
||||
IMusicRequestRepository musicRepo,
|
||||
IMovieRequestEngine movieRequestEngine,
|
||||
ITvRequestEngine tvRequestEngine)
|
||||
ITvRequestEngine tvRequestEngine,
|
||||
IMusicRequestEngine musicEngine)
|
||||
{
|
||||
UserManager = user;
|
||||
Mapper = mapper;
|
||||
|
@ -92,6 +94,7 @@ namespace Ombi.Controllers
|
|||
MovieRequestEngine = movieRequestEngine;
|
||||
_userNotificationPreferences = notificationPreferences;
|
||||
_userQualityProfiles = userProfiles;
|
||||
MusicRequestEngine = musicEngine;
|
||||
}
|
||||
|
||||
private OmbiUserManager UserManager { get; }
|
||||
|
@ -106,6 +109,7 @@ namespace Ombi.Controllers
|
|||
private IMovieRequestRepository MovieRepo { get; }
|
||||
private ITvRequestRepository TvRepo { get; }
|
||||
private IMovieRequestEngine MovieRequestEngine { get; }
|
||||
private IMusicRequestEngine MusicRequestEngine { get; }
|
||||
private ITvRequestEngine TvRequestEngine { get; }
|
||||
private IMusicRequestRepository MusicRepo { get; }
|
||||
private readonly ILogger<IdentityController> _log;
|
||||
|
@ -342,6 +346,11 @@ namespace Ombi.Controllers
|
|||
vm.MovieRequestQuota = await MovieRequestEngine.GetRemainingRequests(user);
|
||||
}
|
||||
|
||||
if (vm.MusicRequestLimit > 0)
|
||||
{
|
||||
vm.MusicRequestQuota = await MusicRequestEngine.GetRemainingRequests(user);
|
||||
}
|
||||
|
||||
// Get the quality profiles
|
||||
vm.UserQualityProfiles = await _userQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == user.Id);
|
||||
if (vm.UserQualityProfiles == null)
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using Ombi.Attributes;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Core.Models.UI;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
|
@ -140,5 +141,14 @@ namespace Ombi.Controllers
|
|||
{
|
||||
return await _engine.DenyAlbumById(model.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets model containing remaining number of music requests.
|
||||
/// </summary>
|
||||
[HttpGet("remaining")]
|
||||
public async Task<RequestQuotaCountModel> GetRemainingMusicRequests()
|
||||
{
|
||||
return await _engine.GetRemainingRequests();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -467,7 +467,7 @@ namespace Ombi.Controllers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets model containing remaining number of requests.
|
||||
/// Gets model containing remaining number of movie requests.
|
||||
/// </summary>
|
||||
[HttpGet("movie/remaining")]
|
||||
public async Task<RequestQuotaCountModel> GetRemainingMovieRequests()
|
||||
|
@ -476,7 +476,7 @@ namespace Ombi.Controllers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets model containing remaining number of requests.
|
||||
/// Gets model containing remaining number of tv requests.
|
||||
/// </summary>
|
||||
[HttpGet("tv/remaining")]
|
||||
public async Task<RequestQuotaCountModel> GetRemainingTvRequests()
|
||||
|
|
|
@ -189,7 +189,9 @@
|
|||
"UserManagment": {
|
||||
"TvRemaining": "TV: {{remaining}}/{{total}} remaining",
|
||||
"MovieRemaining": "Movies: {{remaining}}/{{total}} remaining",
|
||||
"MusicRemaining": "Music: {{remaining}}/{{total}} remaining",
|
||||
"TvDue": "TV: {{date}}",
|
||||
"MovieDue": "Movie: {{date}}"
|
||||
"MovieDue": "Movie: {{date}}",
|
||||
"MusicDue": "Music: {{date}}"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue