mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-13 18:16:55 -07:00
Started on custom quality profiles and root paths !wip
This commit is contained in:
parent
afdd80ac72
commit
68c4368490
8 changed files with 235 additions and 52 deletions
|
@ -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)
|
||||
|
|
23
src/Ombi.Store/Entities/UserQualityProfiles.cs
Normal file
23
src/Ombi.Store/Entities/UserQualityProfiles.cs
Normal file
|
@ -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 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 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>
|
||||
</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>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
</ng-template>
|
||||
</ngb-panel>
|
||||
</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.
|
||||
|
@ -339,6 +342,16 @@ namespace Ombi.Controllers
|
|||
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
|
||||
|
@ -553,6 +580,22 @@ 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
|
||||
{
|
||||
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue