From a89585b85aa2ffabb36523e0e8c8fbc18687a213 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 20 Nov 2017 15:15:10 +0000 Subject: [PATCH] Added the ability to customize job scheudles --- src/Ombi.Schedule/JobSetup.cs | 25 +- .../Settings/Models/JobSettings.cs | 4 + .../Settings/Models/JobSettingsHelper.cs | 46 ++ .../JobSettingsMigration.Designer.cs | 782 ++++++++++++++++++ .../Migrations/JobSettingsMigration.cs | 15 + .../ClientApp/app/interfaces/ISettings.ts | 200 ++--- .../app/services/settings.service.ts | 14 +- .../app/settings/jobs/jobs.component.html | 65 ++ .../app/settings/jobs/jobs.component.ts | 46 ++ .../ClientApp/app/settings/settings.module.ts | 3 + src/Ombi/Controllers/SettingsController.cs | 31 + 11 files changed, 1125 insertions(+), 106 deletions(-) create mode 100644 src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs create mode 100644 src/Ombi.Store/Migrations/JobSettingsMigration.Designer.cs create mode 100644 src/Ombi.Store/Migrations/JobSettingsMigration.cs create mode 100644 src/Ombi/ClientApp/app/settings/jobs/jobs.component.html create mode 100644 src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index 5a9c8f4f3..f9bccc61b 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -1,4 +1,5 @@ using Hangfire; +using Ombi.Core.Settings; using Ombi.Schedule.Jobs; using Ombi.Schedule.Jobs.Couchpotato; using Ombi.Schedule.Jobs.Emby; @@ -6,6 +7,7 @@ using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Plex; using Ombi.Schedule.Jobs.Radarr; using Ombi.Schedule.Jobs.Sonarr; +using Ombi.Settings.Settings.Models; namespace Ombi.Schedule { @@ -13,7 +15,8 @@ namespace Ombi.Schedule { public JobSetup(IPlexContentSync plexContentSync, IRadarrSync radarrSync, IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter, - IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache) + IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache, + ISettingsService jobsettings) { PlexContentSync = plexContentSync; RadarrSync = radarrSync; @@ -23,6 +26,7 @@ namespace Ombi.Schedule EmbyUserImporter = embyUserImporter; SonarrSync = cache; CpCache = cpCache; + JobSettings = jobsettings; } private IPlexContentSync PlexContentSync { get; } @@ -33,19 +37,22 @@ namespace Ombi.Schedule private IEmbyUserImporter EmbyUserImporter { get; } private ISonarrSync SonarrSync { get; } private ICouchPotatoSync CpCache { get; } + private ISettingsService JobSettings { get; set; } public void Setup() { - RecurringJob.AddOrUpdate(() => EmbyContentSync.Start(), Cron.Hourly(5)); - RecurringJob.AddOrUpdate(() => SonarrSync.Start(), Cron.Hourly(10)); - RecurringJob.AddOrUpdate(() => RadarrSync.CacheContent(), Cron.Hourly(15)); - RecurringJob.AddOrUpdate(() => PlexContentSync.CacheContent(), Cron.Hourly(20)); - RecurringJob.AddOrUpdate(() => CpCache.Start(), Cron.Hourly(30)); + var s = JobSettings.GetSettings(); - RecurringJob.AddOrUpdate(() => Updater.Update(null), Cron.HourInterval(6)); + RecurringJob.AddOrUpdate(() => EmbyContentSync.Start(), JobSettingsHelper.EmbyContent(s)); + RecurringJob.AddOrUpdate(() => SonarrSync.Start(), JobSettingsHelper.Sonarr(s)); + RecurringJob.AddOrUpdate(() => RadarrSync.CacheContent(), JobSettingsHelper.Radarr(s)); + RecurringJob.AddOrUpdate(() => PlexContentSync.CacheContent(), JobSettingsHelper.PlexContent(s)); + RecurringJob.AddOrUpdate(() => CpCache.Start(), JobSettingsHelper.CouchPotato(s)); - RecurringJob.AddOrUpdate(() => EmbyUserImporter.Start(), Cron.Daily); - RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), Cron.Daily(5)); + RecurringJob.AddOrUpdate(() => Updater.Update(null), JobSettingsHelper.Updater(s)); + + RecurringJob.AddOrUpdate(() => EmbyUserImporter.Start(), JobSettingsHelper.UserImporter(s)); + RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), JobSettingsHelper.UserImporter(s)); } } } diff --git a/src/Ombi.Settings/Settings/Models/JobSettings.cs b/src/Ombi.Settings/Settings/Models/JobSettings.cs index eb40ba8a6..6d6ed9383 100644 --- a/src/Ombi.Settings/Settings/Models/JobSettings.cs +++ b/src/Ombi.Settings/Settings/Models/JobSettings.cs @@ -5,5 +5,9 @@ public string EmbyContentSync { get; set; } public string SonarrSync { get; set; } public string RadarrSync { get; set; } + public string PlexContentSync { get; set; } + public string CouchPotatoSync { get; set; } + public string AutomaticUpdater { get; set; } + public string UserImporter { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs new file mode 100644 index 000000000..024f79afa --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs @@ -0,0 +1,46 @@ +using Hangfire; +using Ombi.Helpers; + +namespace Ombi.Settings.Settings.Models +{ + public static class JobSettingsHelper + { + public static string Radarr(JobSettings s) + { + return Get(s.RadarrSync, Cron.Hourly(15)); + } + + public static string Sonarr(JobSettings s) + { + return Get(s.SonarrSync, Cron.Hourly(10)); + } + + public static string EmbyContent(JobSettings s) + { + return Get(s.EmbyContentSync, Cron.Hourly(5)); + } + public static string PlexContent(JobSettings s) + { + return Get(s.PlexContentSync, Cron.Hourly(20)); + } + public static string CouchPotato(JobSettings s) + { + return Get(s.CouchPotatoSync, Cron.Hourly(30)); + } + + public static string Updater(JobSettings s) + { + return Get(s.AutomaticUpdater, Cron.HourInterval(6)); + } + public static string UserImporter(JobSettings s) + { + return Get(s.UserImporter, Cron.Daily()); + } + + + private static string Get(string settings, string defaultCron) + { + return settings.HasValue() ? settings : defaultCron; + } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Migrations/JobSettingsMigration.Designer.cs b/src/Ombi.Store/Migrations/JobSettingsMigration.Designer.cs new file mode 100644 index 000000000..626fc5775 --- /dev/null +++ b/src/Ombi.Store/Migrations/JobSettingsMigration.Designer.cs @@ -0,0 +1,782 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using Ombi.Helpers; +using Ombi.Store.Context; +using Ombi.Store.Entities; +using System; + +namespace Ombi.Store.Migrations +{ + [DbContext(typeof(OmbiContext))] + [Migration("JobSettingsMigration")] + partial class JobSettingsMigration + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider"); + + b.Property("ProviderKey"); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider"); + + b.Property("Name"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Type"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("ApplicationConfiguration"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditArea"); + + b.Property("AuditType"); + + b.Property("DateTime"); + + b.Property("Description"); + + b.Property("User"); + + b.HasKey("Id"); + + b.ToTable("Audit"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("CouchPotatoCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId") + .IsRequired(); + + b.Property("ProviderId"); + + b.Property("Title"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId"); + + b.Property("EpisodeNumber"); + + b.Property("ParentId"); + + b.Property("ProviderId"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Content"); + + b.Property("SettingsName"); + + b.HasKey("Id"); + + b.ToTable("GlobalSettings"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Agent"); + + b.Property("Enabled"); + + b.Property("Message"); + + b.Property("NotificationType"); + + b.Property("Subject"); + + b.HasKey("Id"); + + b.ToTable("NotificationTemplates"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("Alias"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LastLoggedIn"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("ProviderUserId"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("UserType"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("GrandparentKey"); + + b.Property("Key"); + + b.Property("ParentKey"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ParentKey"); + + b.Property("PlexContentId"); + + b.Property("PlexServerContentId"); + + b.Property("SeasonKey"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("PlexServerContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("ImdbId"); + + b.Property("Key"); + + b.Property("Quality"); + + b.Property("ReleaseYear"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.Property("Type"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.ToTable("PlexServerContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("IssueId"); + + b.Property("ParentRequestId"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentRequestId"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("ChildRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueId"); + + b.Property("MovieId"); + + b.Property("Subect"); + + b.HasKey("Id"); + + b.HasIndex("IssueId"); + + b.HasIndex("MovieId"); + + b.ToTable("MovieIssues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Background"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("ImdbId"); + + b.Property("IssueId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + b.Property("ReleaseDate"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("RootPathOverride"); + + b.Property("Status"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("MovieRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueId"); + + b.Property("Subect"); + + b.Property("TvId"); + + b.HasKey("Id"); + + b.HasIndex("IssueId"); + + b.HasIndex("TvId"); + + b.ToTable("TvIssues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ImdbId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("ReleaseDate"); + + b.Property("RootFolder"); + + b.Property("Status"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("TvRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AirDate"); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("EpisodeNumber"); + + b.Property("Requested"); + + b.Property("SeasonId"); + + b.Property("Title"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("EpisodeRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChildRequestId"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("ChildRequestId"); + + b.ToTable("SeasonRequests"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent") + .WithMany("Seasons") + .HasForeignKey("PlexServerContentId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest") + .WithMany("ChildRequests") + .HasForeignKey("ParentRequestId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests", "Movie") + .WithMany() + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "Child") + .WithMany() + .HasForeignKey("TvId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest") + .WithMany("SeasonRequests") + .HasForeignKey("ChildRequestId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/JobSettingsMigration.cs b/src/Ombi.Store/Migrations/JobSettingsMigration.cs new file mode 100644 index 000000000..e1c89185d --- /dev/null +++ b/src/Ombi.Store/Migrations/JobSettingsMigration.cs @@ -0,0 +1,15 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Ombi.Store.Migrations +{ + public partial class JobSettingsMigration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + var settings = new JobSettings() + migrationBuilder.Sql(@" + + "); + } + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/app/interfaces/ISettings.ts index 39075a3b9..d5c748e7f 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISettings.ts @@ -1,154 +1,162 @@ import { ISettings } from "./ICommon"; export interface IExternalSettings extends ISettings { - ssl: boolean; - subDir: string; - ip: string; - port: number; + ssl: boolean; + subDir: string; + ip: string; + port: number; } export interface IOmbiSettings extends ISettings { - baseUrl: string; - collectAnalyticData: boolean; - wizard: boolean; - apiKey: string; - ignoreCertificateErrors: boolean; + baseUrl: string; + collectAnalyticData: boolean; + wizard: boolean; + apiKey: string; + ignoreCertificateErrors: boolean; } export interface IUpdateSettings extends ISettings { - autoUpdateEnabled: boolean; - username: string; - password: string; - processName: string; - useScript: boolean; - scriptLocation: string; + autoUpdateEnabled: boolean; + username: string; + password: string; + processName: string; + useScript: boolean; + scriptLocation: string; } export interface IEmbySettings extends ISettings { - enable: boolean; - servers: IEmbyServer[]; + enable: boolean; + servers: IEmbyServer[]; } export interface IEmbyServer extends IExternalSettings { - name: string; - apiKey: string; - administratorId: string; - enableEpisodeSearching: boolean; + name: string; + apiKey: string; + administratorId: string; + enableEpisodeSearching: boolean; } export interface IPlexSettings extends ISettings { - - enable: boolean; - servers: IPlexServer[]; + enable: boolean; + servers: IPlexServer[]; } export interface IPlexServer extends IExternalSettings { - name: string; - enableEpisodeSearching: boolean; - plexAuthToken: string; - machineIdentifier: string; - episodeBatchSize: number; - plexSelectedLibraries: IPlexLibrariesSettings[]; + name: string; + enableEpisodeSearching: boolean; + plexAuthToken: string; + machineIdentifier: string; + episodeBatchSize: number; + plexSelectedLibraries: IPlexLibrariesSettings[]; } export interface IPlexLibrariesSettings { - key: string; - title: string; - enabled: boolean; + key: string; + title: string; + enabled: boolean; } export interface ISonarrSettings extends IExternalSettings { - apiKey: string; - enabled: boolean; - qualityProfile: string; - seasonFolders: boolean; - rootPath: string; - fullRootPath: string; - addOnly: boolean; + apiKey: string; + enabled: boolean; + qualityProfile: string; + seasonFolders: boolean; + rootPath: string; + fullRootPath: string; + addOnly: boolean; } export interface IRadarrSettings extends IExternalSettings { - enabled: boolean; - apiKey: string; - defaultQualityProfile: string; - defaultRootPath: string; - fullRootPath: string; - addOnly: boolean; - minimumAvailability: string; + enabled: boolean; + apiKey: string; + defaultQualityProfile: string; + defaultRootPath: string; + fullRootPath: string; + addOnly: boolean; + minimumAvailability: string; } export interface ILandingPageSettings extends ISettings { - enabled: boolean; + enabled: boolean; - noticeEnabled: boolean; - noticeText: string; + noticeEnabled: boolean; + noticeText: string; - timeLimit: boolean; - startDateTime: Date; - endDateTime: Date; - expired: boolean; + timeLimit: boolean; + startDateTime: Date; + endDateTime: Date; + expired: boolean; } export interface ICustomizationSettings extends ISettings { - applicationName: string; - applicationUrl: string; - logo: string; - customCssLink: string; - hasPresetTheme: boolean; - presetThemeName: string; - presetThemeContent: string; - presetThemeDisplayName: string; - presetThemeVersion: string; + applicationName: string; + applicationUrl: string; + logo: string; + customCssLink: string; + hasPresetTheme: boolean; + presetThemeName: string; + presetThemeContent: string; + presetThemeDisplayName: string; + presetThemeVersion: string; } export interface IThemes { - fullName: string; - displayName: string; - version: string; - url: string; + fullName: string; + displayName: string; + version: string; + url: string; } -export interface IAuthenticationSettings extends ISettings { +export interface IJobSettings { + embyContentSync: string; + sonarrSync: string; + radarrSync: string; + plexContentSync: string; + couchPotatoSync: string; + automaticUpdater: string; + userImporter: string; +} - allowExternalUsersToAuthenticate: boolean; - // Password +export interface IAuthenticationSettings extends ISettings { + allowExternalUsersToAuthenticate: boolean; + // Password - requiredDigit: boolean; - requiredLength: number; - requiredLowercase: boolean; - requireNonAlphanumeric: boolean; - requireUppercase: boolean; + requiredDigit: boolean; + requiredLength: number; + requiredLowercase: boolean; + requireNonAlphanumeric: boolean; + requireUppercase: boolean; } export interface IUserManagementSettings extends ISettings { - importPlexUsers: boolean; - importPlexAdmin: boolean; - importEmbyUsers: boolean; - defaultRoles: string[]; - bannedPlexUserIds: string[]; - bannedEmbyUserIds: string[]; + importPlexUsers: boolean; + importPlexAdmin: boolean; + importEmbyUsers: boolean; + defaultRoles: string[]; + bannedPlexUserIds: string[]; + bannedEmbyUserIds: string[]; } export interface IAbout { - version: string; - branch: string; - osArchitecture: string; - osDescription: string; - processArchitecture: string; - applicationBasePath: string; + version: string; + branch: string; + osArchitecture: string; + osDescription: string; + processArchitecture: string; + applicationBasePath: string; } export interface ICouchPotatoSettings extends IExternalSettings { - enabled: boolean; - apiKey: string; - defaultProfileId: string; - username: string; - password: string; + enabled: boolean; + apiKey: string; + defaultProfileId: string; + username: string; + password: string; } export interface IDogNzbSettings extends ISettings { - enabled: boolean; - apiKey: string; - movies: boolean; - tvShows: boolean; + enabled: boolean; + apiKey: string; + movies: boolean; + tvShows: boolean; } diff --git a/src/Ombi/ClientApp/app/services/settings.service.ts b/src/Ombi/ClientApp/app/services/settings.service.ts index 7c54ca92e..114646a1f 100644 --- a/src/Ombi/ClientApp/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/app/services/settings.service.ts @@ -1,4 +1,5 @@ -import { PlatformLocation } from "@angular/common"; +import { IJobSettings } from './../interfaces/ISettings'; +import { PlatformLocation } from "@angular/common"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { AuthHttp } from "angular2-jwt"; @@ -13,6 +14,7 @@ import { IDogNzbSettings, IEmailNotificationSettings, IEmbySettings, + IJobSettings, ILandingPageSettings, IMattermostNotifcationSettings, IOmbiSettings, @@ -240,4 +242,14 @@ export class SettingsService extends ServiceAuthHelpers { .post(`${this.url}/notifications/telegram`, JSON.stringify(settings), { headers: this.headers }) .map(this.extractData).catch(this.handleError); } + + public getJobSettings(): Observable { + return this.httpAuth.get(`${this.url}/jobs`).map(this.extractData).catch(this.handleError); + } + + public saveJobSettings(settings: IJobSettings): Observable { + return this.httpAuth + .post(`${this.url}/jobs`, JSON.stringify(settings), { headers: this.headers }) + .map(this.extractData).catch(this.handleError); + } } diff --git a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html new file mode 100644 index 000000000..db1500b9c --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.html @@ -0,0 +1,65 @@ + + + + +
+
+ Job Settings +
+
+ Changes to any of the below requires you to restart Ombi. +
+ + + The Sonarr Sync is required +
+ +
+ + + The Radarr Sync is required +
+ +
+ + + The CouchPotato Sync is required +
+ +
+ + + The Automatic Update is required +
+ + + +
+
+ +
+
+
+
+
+ + + The Plex Sync is required +
+ +
+ + + The Emby Sync is required +
+ +
+ + + The User Importer is required +
+ +
+
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts new file mode 100644 index 000000000..524c980cd --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/jobs/jobs.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { NotificationService, SettingsService } from "../../services"; + +@Component({ + templateUrl: "./jobs.component.html", +}) +export class JobsComponent implements OnInit { + + public form: FormGroup; + + public profilesRunning: boolean; + + constructor(private readonly settingsService: SettingsService, + private readonly fb: FormBuilder, + private readonly notificationService: NotificationService) { } + + public ngOnInit() { + this.settingsService.getJobSettings().subscribe(x => { + this.form = this.fb.group({ + automaticUpdater: [x.automaticUpdater, Validators.required], + couchPotatoSync: [x.couchPotatoSync, Validators.required], + embyContentSync: [x.embyContentSync, Validators.required], + plexContentSync: [x.plexContentSync, Validators.required], + userImporter: [x.userImporter, Validators.required], + sonarrSync: [x.radarrSync, Validators.required], + radarrSync: [x.sonarrSync, Validators.required], + }); + }); + } + + public onSubmit(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Please check your entered values"); + return; + } + const settings = form.value; + this.settingsService.saveJobSettings(settings).subscribe(x => { + if (x) { + this.notificationService.success("Successfully saved the job settings"); + } else { + this.notificationService.success("There was an error when saving the job settings"); + } + }); + } +} diff --git a/src/Ombi/ClientApp/app/settings/settings.module.ts b/src/Ombi/ClientApp/app/settings/settings.module.ts index 8b5bf3137..dd0eb4b2c 100644 --- a/src/Ombi/ClientApp/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/app/settings/settings.module.ts @@ -16,6 +16,7 @@ import { CouchPotatoComponent } from "./couchpotato/couchpotato.component"; import { CustomizationComponent } from "./customization/customization.component"; import { DogNzbComponent } from "./dognzb/dognzb.component"; import { EmbyComponent } from "./emby/emby.component"; +import { JobsComponent } from "./jobs/jobs.component"; import { LandingPageComponent } from "./landingpage/landingpage.component"; import { DiscordComponent } from "./notifications/discord.component"; import { EmailNotificationComponent } from "./notifications/emailnotification.component"; @@ -57,6 +58,7 @@ const routes: Routes = [ { path: "Settings/CouchPotato", component: CouchPotatoComponent, canActivate: [AuthGuard] }, { path: "Settings/DogNzb", component: DogNzbComponent, canActivate: [AuthGuard] }, { path: "Settings/Telegram", component: TelegramComponent, canActivate: [AuthGuard] }, + { path: "Settings/Jobs", component: JobsComponent, canActivate: [AuthGuard] }, ]; @NgModule({ @@ -83,6 +85,7 @@ const routes: Routes = [ OmbiComponent, PlexComponent, EmbyComponent, + JobsComponent, LandingPageComponent, CustomizationComponent, DiscordComponent, diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index 40edf7a28..ed05af238 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -421,6 +421,37 @@ namespace Ombi.Controllers return await Save(settings); } + /// + /// Gets the JobSettings Settings. + /// + /// + [HttpGet("jobs")] + public async Task JobSettings() + { + var j = await Get(); + // Get the defaults if the jobs are not set + j.RadarrSync = j.RadarrSync.HasValue() ? j.RadarrSync : JobSettingsHelper.Radarr(j); + j.SonarrSync = j.SonarrSync.HasValue() ? j.SonarrSync : JobSettingsHelper.Sonarr(j); + j.AutomaticUpdater = j.AutomaticUpdater.HasValue() ? j.AutomaticUpdater : JobSettingsHelper.Updater(j); + j.CouchPotatoSync = j.CouchPotatoSync.HasValue() ? j.CouchPotatoSync : JobSettingsHelper.CouchPotato(j); + j.EmbyContentSync = j.EmbyContentSync.HasValue() ? j.EmbyContentSync : JobSettingsHelper.EmbyContent(j); + j.PlexContentSync = j.PlexContentSync.HasValue() ? j.PlexContentSync : JobSettingsHelper.PlexContent(j); + j.UserImporter = j.UserImporter.HasValue() ? j.UserImporter : JobSettingsHelper.UserImporter(j); + + return j; + } + + /// + /// Save the JobSettings settings. + /// + /// The settings. + /// + [HttpPost("jobs")] + public async Task JobSettings([FromBody]JobSettings settings) + { + return await Save(settings); + } + /// /// Saves the email notification settings. ///