Started on custom quality profiles and root paths !wip

pull/2525/head
TidusJar 6 years ago
parent afdd80ac72
commit 68c4368490

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Ombi.Store.Entities;
namespace Ombi.Core.Models.UI
{
@ -19,6 +20,7 @@ namespace Ombi.Core.Models.UI
public RequestQuotaCountModel EpisodeRequestQuota { get; set; }
public RequestQuotaCountModel MovieRequestQuota { get; set; }
public int MusicRequestLimit { get; set; }
public UserQualityProfiles UserQualityProfiles { get; set; }
}
public class ClaimCheckboxes

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Api.DogNzb;
using Ombi.Api.DogNzb.Models;
@ -12,7 +13,9 @@ using Ombi.Api.Sonarr.Models;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
namespace Ombi.Core.Senders
{
@ -20,7 +23,7 @@ namespace Ombi.Core.Senders
{
public TvSender(ISonarrApi sonarrApi, ILogger<TvSender> log, ISettingsService<SonarrSettings> sonarrSettings,
ISettingsService<DogNzbSettings> dog, IDogNzbApi dogApi, ISettingsService<SickRageSettings> srSettings,
ISickRageApi srApi)
ISickRageApi srApi, IRepository<UserQualityProfiles> userProfiles)
{
SonarrApi = sonarrApi;
Logger = log;
@ -29,6 +32,7 @@ namespace Ombi.Core.Senders
DogNzbApi = dogApi;
SickRageSettings = srSettings;
SickRageApi = srApi;
UserQualityProfiles = userProfiles;
}
private ISonarrApi SonarrApi { get; }
@ -38,6 +42,7 @@ namespace Ombi.Core.Senders
private ISettingsService<SonarrSettings> SonarrSettings { get; }
private ISettingsService<DogNzbSettings> DogNzbSettings { get; }
private ISettingsService<SickRageSettings> SickRageSettings { get; }
private IRepository<UserQualityProfiles> UserQualityProfiles { get; }
public async Task<SenderResult> Send(ChildRequests model)
{
@ -122,13 +127,25 @@ namespace Ombi.Core.Senders
string rootFolderPath;
string seriesType;
var profiles = await UserQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == model.RequestedUserId);
if (model.SeriesType == SeriesType.Anime)
{
// Get the root path from the rootfolder selected.
// For some reason, if we haven't got one use the first root folder in Sonarr
// TODO make this overrideable via the UI
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPathAnime), s);
int.TryParse(s.QualityProfileAnime, out qualityToUse);
if (profiles != null)
{
if (profiles.SonarrRootPathAnime > 0)
{
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPathAnime, s);
}
if (profiles.SonarrQualityProfileAnime > 0)
{
qualityToUse = profiles.SonarrQualityProfileAnime;
}
}
seriesType = "anime";
}
@ -137,8 +154,18 @@ namespace Ombi.Core.Senders
int.TryParse(s.QualityProfile, out qualityToUse);
// Get the root path from the rootfolder selected.
// For some reason, if we haven't got one use the first root folder in Sonarr
// TODO make this overrideable via the UI
rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
if (profiles != null)
{
if (profiles.SonarrRootPath > 0)
{
rootFolderPath = await GetSonarrRootPath(profiles.SonarrRootPath, s);
}
if (profiles.SonarrQualityProfile > 0)
{
qualityToUse = profiles.SonarrQualityProfile;
}
}
seriesType = "standard";
}

@ -51,7 +51,8 @@ namespace Ombi.Store.Context
public DbSet<SickRageCache> SickRageCache { get; set; }
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
public DbSet<RequestSubscription> RequestSubscription { get; set; }
public DbSet<UserNotificationPreferences> UserNotificationPreferences { get; set; }
public DbSet<UserQualityProfiles> UserQualityProfileses { get; set; }
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using Ombi.Helpers;
namespace Ombi.Store.Entities
{
[Table(nameof(UserQualityProfiles))]
public class UserQualityProfiles : Entity
{
public string UserId { get; set; }
public int SonarrQualityProfileAnime { get; set; }
public int SonarrRootPathAnime { get; set; }
public int SonarrRootPath { get; set; }
public int SonarrQualityProfile { get; set; }
public int RadarrRootPath { get; set; }
public int RadarrQualityProfile { get; set; }
[ForeignKey(nameof(UserId))]
[JsonIgnore]
public OmbiUser User { get; set; }
}
}

@ -15,6 +15,7 @@ export interface IUser {
episodeRequestLimit: number;
musicRequestLimit: number;
userAccessToken: string;
userQualityProfiles: IUserQualityProfiles;
// FOR UI
episodeRequestQuota: IRemainingRequests | null;
@ -22,6 +23,15 @@ export interface IUser {
checked: boolean;
}
export interface IUserQualityProfiles {
sonarrQualityProfileAnime: string;
sonarrRootPathAnime: string;
sonarrRootPath: string;
sonarrQualityProfile: string;
radarrRootPath: string;
radarrQualityProfile: string;
}
export interface ICreateWizardUser {
username: string;
password: string;

@ -89,55 +89,115 @@
</ng-template>
</ngb-panel>
<ngb-panel title="Request Limits">
<ng-template ngbPanelContent>
<div class="panel panel-default a">
<div class="panel-body">
<ng-template ngbPanelContent>
<div class="panel panel-default a">
<div class="panel-body">
<div class="form-group">
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom "
id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
</div>
</div>
<div class="form-group">
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom "
id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
</div>
</div>
<div class="form-group">
<label for="musicRequestLimit" class="control-label">Music Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.musicRequestLimit" class="form-control form-small form-control-custom "
id="musicRequestLimit" name="musicRequestLimit" value="{{user?.musicRequestLimit}}">
</div>
</div>
</div>
</div>
</ng-template>
</ngb-panel>
<ngb-panel title="Notification Preferences" *ngIf="notificationPreferences">
<ng-template ngbPanelContent>
<div class="panel panel-default a">
<div class="panel-body">
<div *ngFor="let pref of notificationPreferences">
<div class="form-group">
<label for="movieRequestLimit" class="control-label">Movie Request Limit</label>
<label for="{{pref.agent}}" class="control-label">{{NotificationAgent[pref.agent]
| humanize}}</label>
<div>
<input type="text" [(ngModel)]="user.movieRequestLimit" class="form-control form-small form-control-custom "
id="movieRequestLimit" name="movieRequestLimit" value="{{user?.movieRequestLimit}}">
<input type="text" [(ngModel)]="pref.value" class="form-control form-control-custom"
name="{{pref.agent}}" value="{{pref?.value}}">
</div>
</div>
<div class="form-group">
<label for="episodeRequestLimit" class="control-label">Episode Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.episodeRequestLimit" class="form-control form-small form-control-custom "
id="episodeRequestLimit" name="episodeRequestLimit" value="{{user?.episodeRequestLimit}}">
</div>
</div>
<div class="form-group">
<label for="musicRequestLimit" class="control-label">Music Request Limit</label>
<div>
<input type="text" [(ngModel)]="user.musicRequestLimit" class="form-control form-small form-control-custom "
id="musicRequestLimit" name="musicRequestLimit" value="{{user?.musicRequestLimit}}">
</div>
</div>
</div>
</div>
</ng-template>
</ngb-panel>
<ngb-panel title="Notification Preferences" *ngIf="notificationPreferences">
<ng-template ngbPanelContent>
<div class="panel panel-default a">
<div class="panel-body">
<div *ngFor="let pref of notificationPreferences">
<div class="form-group">
<label for="{{pref.agent}}" class="control-label">{{NotificationAgent[pref.agent] | humanize}}</label>
<div>
<input type="text" [(ngModel)]="pref.value" class="form-control form-control-custom"
name="{{pref.agent}}" value="{{pref?.value}}">
</div>
</div>
</div>
</div>
</ng-template>
</ngb-panel>
<ngb-panel title="Quality & Root Path Preferences" *ngIf="user.userQualityProfiles && false">
<ng-template ngbPanelContent>
<div class="panel panel-default a">
<div class="panel-body">
<div class="form-group">
<label for="sonarrQualityProfile" class="control-label">Sonarr Quality Profile</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.sonarrQualityProfile"
class="form-control form-control-custom" name="sonarrQualityProfile"
value="{{user.userQualityProfiles.sonarrQualityProfile}}">
</div>
</div>
<div class="form-group">
<label for="sonarrQualityProfileAnime" class="control-label">Sonarr Quality Profile (Anime)</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.sonarrQualityProfileAnime"
class="form-control form-control-custom" name="sonarrQualityProfileAnime"
value="{{user.userQualityProfiles.sonarrQualityProfileAnime}}">
</div>
</div>
<div class="form-group">
<label for="sonarrRootPath" class="control-label">Sonarr Root Folder</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.sonarrRootPath"
class="form-control form-control-custom" name="sonarrRootPath"
value="{{user.userQualityProfiles.sonarrRootPath}}">
</div>
</div>
</ng-template>
</ngb-panel>
<div class="form-group">
<label for="sonarrRootPathAnime" class="control-label">Sonarr Root Folder (Anime)</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.sonarrRootPathAnime"
class="form-control form-control-custom" name="sonarrRootPathAnime"
value="{{user.userQualityProfiles.sonarrRootPathAnime}}">
</div>
</div>
<div class="form-group">
<label for="radarrQualityProfile" class="control-label">Radarr Quality Profile</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.radarrQualityProfile"
class="form-control form-control-custom" name="radarrQualityProfile"
value="{{user.userQualityProfiles.radarrQualityProfile}}">
</div>
</div>
<div class="form-group">
<label for="radarrRootPath" class="control-label">Radarr Root Folder</label>
<div>
<input type="text" [(ngModel)]="user.userQualityProfiles.radarrRootPath"
class="form-control form-control-custom" name="radarrRootPath"
value="{{user.userQualityProfiles.radarrRootPath}}">
</div>
</div>
</div>
</div>
</ng-template>
</ngb-panel>
</ngb-accordion>
</div>

@ -63,6 +63,14 @@ export class UserManagementUserComponent implements OnInit {
musicRequestLimit: 0,
episodeRequestQuota: null,
movieRequestQuota: null,
userQualityProfiles: {
radarrQualityProfile: "",
radarrRootPath: "",
sonarrQualityProfile: "",
sonarrQualityProfileAnime: "",
sonarrRootPath: "",
sonarrRootPathAnime: "",
},
};
}
}

@ -63,6 +63,7 @@ namespace Ombi.Controllers
IRepository<RequestSubscription> subscriptionRepository,
ISettingsService<UserManagementSettings> umSettings,
IRepository<UserNotificationPreferences> notificationPreferences,
IRepository<UserQualityProfiles> userProfiles,
IMusicRequestRepository musicRepo,
IMovieRequestEngine movieRequestEngine,
ITvRequestEngine tvRequestEngine)
@ -90,6 +91,7 @@ namespace Ombi.Controllers
TvRequestEngine = tvRequestEngine;
MovieRequestEngine = movieRequestEngine;
_userNotificationPreferences = notificationPreferences;
_userQualityProfiles = userProfiles;
}
private OmbiUserManager UserManager { get; }
@ -115,6 +117,7 @@ namespace Ombi.Controllers
private readonly IRepository<NotificationUserId> _notificationRepository;
private readonly IRepository<RequestSubscription> _requestSubscriptionRepository;
private readonly IRepository<UserNotificationPreferences> _userNotificationPreferences;
private readonly IRepository<UserQualityProfiles> _userQualityProfiles;
/// <summary>
/// This is what the Wizard will call when creating the user for the very first time.
@ -329,16 +332,26 @@ namespace Ombi.Controllers
});
}
if (vm.EpisodeRequestLimit > 0)
if (vm.EpisodeRequestLimit > 0)
{
vm.EpisodeRequestQuota = await TvRequestEngine.GetRemainingRequests(user);
}
if (vm.MovieRequestLimit > 0)
if (vm.MovieRequestLimit > 0)
{
vm.MovieRequestQuota = await MovieRequestEngine.GetRemainingRequests(user);
}
// Get the quality profiles
vm.UserQualityProfiles = await _userQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == user.Id);
if (vm.UserQualityProfiles == null)
{
vm.UserQualityProfiles = new UserQualityProfiles
{
UserId = user.Id
};
}
return vm;
}
@ -397,6 +410,20 @@ namespace Ombi.Controllers
};
}
// Add the quality profiles
if (user.UserQualityProfiles != null)
{
user.UserQualityProfiles.UserId = ombiUser.Id;
await _userQualityProfiles.Add(user.UserQualityProfiles);
}
else
{
user.UserQualityProfiles = new UserQualityProfiles
{
UserId = ombiUser.Id
};
}
return new OmbiIdentityResult
{
Successful = true
@ -552,8 +579,24 @@ namespace Ombi.Controllers
{
Errors = messages
};
}
// Add the quality profiles
if (ui.UserQualityProfiles != null)
{
var currentQualityProfiles = await
_userQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == user.Id);
currentQualityProfiles.RadarrQualityProfile = ui.UserQualityProfiles.RadarrQualityProfile;
currentQualityProfiles.RadarrRootPath = ui.UserQualityProfiles.RadarrRootPath;
currentQualityProfiles.SonarrQualityProfile = ui.UserQualityProfiles.SonarrQualityProfile;
currentQualityProfiles.SonarrQualityProfileAnime = ui.UserQualityProfiles.SonarrQualityProfileAnime;
currentQualityProfiles.SonarrRootPath = ui.UserQualityProfiles.SonarrRootPath;
currentQualityProfiles.SonarrRootPathAnime = ui.UserQualityProfiles.SonarrRootPathAnime;
await _userQualityProfiles.SaveChangesAsync();
}
return new OmbiIdentityResult
{
Successful = true
@ -585,6 +628,8 @@ namespace Ombi.Controllers
var moviesUserRequested = MovieRepo.GetAll().Where(x => x.RequestedUserId == userId);
var tvUserRequested = TvRepo.GetChild().Where(x => x.RequestedUserId == userId);
var musicRequested = MusicRepo.GetAll().Where(x => x.RequestedUserId == userId);
var notificationPreferences = _userNotificationPreferences.GetAll().Where(x => x.UserId == userId);
var userQuality = await _userQualityProfiles.GetAll().FirstOrDefaultAsync(x => x.UserId == userId);
if (moviesUserRequested.Any())
{
@ -594,11 +639,18 @@ namespace Ombi.Controllers
{
await TvRepo.DeleteChildRange(tvUserRequested);
}
if (musicRequested.Any())
{
await MusicRepo.DeleteRange(musicRequested);
}
if (notificationPreferences.Any())
{
await _userNotificationPreferences.DeleteRange(notificationPreferences);
}
if (userQuality != null)
{
await _userQualityProfiles.Delete(userQuality);
}
// Delete any issues and request logs
var issues = _issuesRepository.GetAll().Where(x => x.UserReportedId == userId);
@ -903,7 +955,7 @@ namespace Ombi.Controllers
}
return Json(true);
}
private async Task<List<IdentityResult>> AddRoles(IEnumerable<ClaimCheckboxes> roles, OmbiUser ombiUser)
{
var roleResult = new List<IdentityResult>();

Loading…
Cancel
Save