diff --git a/src/Ombi.Core/Engine/VoteEngine.cs b/src/Ombi.Core/Engine/VoteEngine.cs index 3875b6705..8f70a1ed5 100644 --- a/src/Ombi.Core/Engine/VoteEngine.cs +++ b/src/Ombi.Core/Engine/VoteEngine.cs @@ -40,7 +40,7 @@ namespace Ombi.Core.Engine { var vm = new List(); var movieRequests = await _movieRequestEngine.GetRequests(); - var tvRequestsTask = _tvRequestEngine.GetRequestsLite(); + var tvRequestsTask = _tvRequestEngine.GetRequests(); var musicRequestsTask = _musicRequestEngine.GetRequests(); foreach (var r in movieRequests) { @@ -55,8 +55,8 @@ namespace Ombi.Core.Engine RequestId = r.Id, RequestType = RequestType.Movie, Title = r.Title, - Image = r.PosterPath, - Background = r.Background, + Image = $"https://image.tmdb.org/t/p/w500/{r.PosterPath}", + Background = $"https://image.tmdb.org/t/p/w1280{r.Background}", Description = r.Overview }); } @@ -64,7 +64,7 @@ namespace Ombi.Core.Engine foreach (var r in await musicRequestsTask) { // Make model - var votes = GetVotes(r.Id, RequestType.Movie); + var votes = GetVotes(r.Id, RequestType.Album); var upVotes = await votes.Where(x => x.VoteType == VoteType.Upvote).CountAsync(); var downVotes = await votes.Where(x => x.VoteType == VoteType.Downvote).CountAsync(); vm.Add(new VoteViewModel @@ -72,9 +72,9 @@ namespace Ombi.Core.Engine Upvotes = upVotes, Downvotes = downVotes, RequestId = r.Id, - RequestType = RequestType.Movie, + RequestType = RequestType.Album, Title = r.Title, - Image = r.Disk, + Image = r.Cover, Background = r.Cover, Description = r.ArtistName }); @@ -83,7 +83,7 @@ namespace Ombi.Core.Engine foreach (var r in await tvRequestsTask) { // Make model - var votes = GetVotes(r.Id, RequestType.Movie); + var votes = GetVotes(r.Id, RequestType.TvShow); var upVotes = await votes.Where(x => x.VoteType == VoteType.Upvote).CountAsync(); var downVotes = await votes.Where(x => x.VoteType == VoteType.Downvote).CountAsync(); @@ -103,7 +103,7 @@ namespace Ombi.Core.Engine Upvotes = upVotes, Downvotes = downVotes, RequestId = r.Id, - RequestType = RequestType.Movie, + RequestType = RequestType.TvShow, Title = r.Title, Image = r.PosterPath, Background = r.Background, diff --git a/src/Ombi.Schedule.Tests/NewsletterTests.cs b/src/Ombi.Schedule.Tests/NewsletterTests.cs index b3c2ce98a..146cd97cf 100644 --- a/src/Ombi.Schedule.Tests/NewsletterTests.cs +++ b/src/Ombi.Schedule.Tests/NewsletterTests.cs @@ -1,11 +1,6 @@ using System.Collections.Generic; -using Moq; using NUnit.Framework; -using Ombi.Core.Settings; -using Ombi.Schedule.Jobs.Ombi; -using Ombi.Settings.Settings.Models; -using Ombi.Settings.Settings.Models.Notifications; -using Ombi.Store.Entities; +using static Ombi.Schedule.Jobs.Ombi.NewsletterJob; namespace Ombi.Schedule.Tests { @@ -15,17 +10,12 @@ namespace Ombi.Schedule.Tests [TestCaseSource(nameof(EpisodeListData))] public string BuildEpisodeListTest(List episodes) { - var emailSettings = new Mock>(); - var customziation = new Mock>(); - var newsletterSettings = new Mock>(); - var newsletter = new NewsletterJob(null, null, null, null, null, null, customziation.Object, emailSettings.Object, null, null, newsletterSettings.Object, null, null, null, null); - var ep = new List(); foreach (var i in episodes) { ep.Add(i); } - var result = newsletter.BuildEpisodeList(ep); + var result = BuildEpisodeList(ep); return result; } diff --git a/src/Ombi.Store/Migrations/20180928201334_Votes.Designer.cs b/src/Ombi.Store/Migrations/20180928201334_Votes.Designer.cs new file mode 100644 index 000000000..5d9b47c26 --- /dev/null +++ b/src/Ombi.Store/Migrations/20180928201334_Votes.Designer.cs @@ -0,0 +1,1182 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Ombi.Store.Context; + +namespace Ombi.Store.Migrations +{ + [DbContext(typeof(OmbiContext))] + [Migration("20180928201334_Votes")] + partial class Votes + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065"); + + 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("ImdbId"); + + b.Property("ProviderId"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.Property("Type"); + + b.Property("Url"); + + 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("ImdbId"); + + b.Property("ParentId"); + + b.Property("ProviderId"); + + b.Property("SeasonNumber"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + 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.LidarrAlbumCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("ArtistId"); + + b.Property("ForeignAlbumId"); + + b.Property("Monitored"); + + b.Property("PercentOfTracks"); + + b.Property("ReleaseDate"); + + b.Property("Title"); + + b.Property("TrackCount"); + + b.HasKey("Id"); + + b.ToTable("LidarrAlbumCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.LidarrArtistCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ArtistId"); + + b.Property("ArtistName"); + + b.Property("ForeignArtistId"); + + b.Property("Monitored"); + + b.HasKey("Id"); + + b.ToTable("LidarrArtistCache"); + }); + + 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.NotificationUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("PlayerId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("NotificationUserId"); + }); + + 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("EmbyConnectUserId"); + + b.Property("EpisodeRequestLimit"); + + b.Property("LastLoggedIn"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("MovieRequestLimit"); + + b.Property("MusicRequestLimit"); + + 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("UserAccessToken"); + + 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("HasFile"); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("AlbumId"); + + b.Property("ContentId"); + + b.Property("ContentType"); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("RecentlyAddedLog"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("ArtistName"); + + b.Property("Available"); + + b.Property("Cover"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("Disk"); + + b.Property("ForeignAlbumId"); + + b.Property("ForeignArtistId"); + + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + + b.Property("Rating"); + + b.Property("ReleaseDate"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("AlbumRequests"); + }); + + 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("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + + b.Property("ParentRequestId"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("SeriesType"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentRequestId"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("ChildRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("IssueCategory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Comment"); + + b.Property("Date"); + + b.Property("IssuesId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("IssuesId"); + + b.HasIndex("UserId"); + + b.ToTable("IssueComments"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueCategoryId"); + + b.Property("IssueId"); + + b.Property("ProviderId"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("ResovledDate"); + + b.Property("Status"); + + b.Property("Subject"); + + b.Property("Title"); + + b.Property("UserReportedId"); + + b.HasKey("Id"); + + b.HasIndex("IssueCategoryId"); + + b.HasIndex("IssueId"); + + b.HasIndex("UserReportedId"); + + b.ToTable("Issues"); + }); + + 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("DigitalReleaseDate"); + + b.Property("ImdbId"); + + b.Property("IssueId"); + + b.Property("MarkedAsApproved"); + + b.Property("MarkedAsAvailable"); + + b.Property("MarkedAsDenied"); + + 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.RequestLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeCount"); + + b.Property("RequestDate"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RequestLog"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Background"); + + b.Property("ImdbId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + 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.RequestSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("RequestSubscription"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageEpisodeCache"); + }); + + 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("HasFile"); + + 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.Entities.UserNotificationPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Agent"); + + b.Property("Enabled"); + + b.Property("UserId"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserNotificationPreferences"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.UserQualityProfiles", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("RadarrQualityProfile"); + + b.Property("RadarrRootPath"); + + b.Property("SonarrQualityProfile"); + + b.Property("SonarrQualityProfileAnime"); + + b.Property("SonarrRootPath"); + + b.Property("SonarrRootPathAnime"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserQualityProfiles"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Votes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Date"); + + b.Property("Deleted"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.Property("VoteType"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Votes"); + }); + + 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.NotificationUserId", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany("NotificationUserIds") + .HasForeignKey("UserId"); + }); + + 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.AlbumRequest", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + 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.IssueComments", b => + { + b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues") + .WithMany("Comments") + .HasForeignKey("IssuesId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory") + .WithMany() + .HasForeignKey("IssueCategoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported") + .WithMany() + .HasForeignKey("UserReportedId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.UserNotificationPreferences", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany("UserNotificationPreferences") + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.UserQualityProfiles", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Votes", 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/20180928201334_Votes.cs b/src/Ombi.Store/Migrations/20180928201334_Votes.cs new file mode 100644 index 000000000..1c64a19aa --- /dev/null +++ b/src/Ombi.Store/Migrations/20180928201334_Votes.cs @@ -0,0 +1,46 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Ombi.Store.Migrations +{ + public partial class Votes : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Votes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RequestId = table.Column(nullable: false), + VoteType = table.Column(nullable: false), + RequestType = table.Column(nullable: false), + UserId = table.Column(nullable: true), + Date = table.Column(nullable: false), + Deleted = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Votes", x => x.Id); + table.ForeignKey( + name: "FK_Votes_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_Votes_UserId", + table: "Votes", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Votes"); + } + } +} diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs index 86694ec23..60927b1ed 100644 --- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs @@ -916,6 +916,30 @@ namespace Ombi.Store.Migrations b.ToTable("UserQualityProfiles"); }); + modelBuilder.Entity("Ombi.Store.Entities.Votes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Date"); + + b.Property("Deleted"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("UserId"); + + b.Property("VoteType"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Votes"); + }); + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => { b.Property("Id") @@ -1128,6 +1152,13 @@ namespace Ombi.Store.Migrations .HasForeignKey("UserId"); }); + modelBuilder.Entity("Ombi.Store.Entities.Votes", 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") diff --git a/src/Ombi/ClientApp/app/app.module.ts b/src/Ombi/ClientApp/app/app.module.ts index d6eb29b53..0f268e4d2 100644 --- a/src/Ombi/ClientApp/app/app.module.ts +++ b/src/Ombi/ClientApp/app/app.module.ts @@ -15,7 +15,7 @@ import { TranslateLoader, TranslateModule } from "@ngx-translate/core"; import { TranslateHttpLoader } from "@ngx-translate/http-loader"; import { CookieService } from "ng2-cookies"; import { GrowlModule } from "primeng/components/growl/growl"; -import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule, DialogModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng"; +import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule, DialogModule, OverlayPanelModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng"; // Components import { AppComponent } from "./app.component"; @@ -55,6 +55,7 @@ const routes: Routes = [ { loadChildren: "./requests/requests.module#RequestsModule", path: "requests" }, { loadChildren: "./search/search.module#SearchModule", path: "search" }, { loadChildren: "./recentlyAdded/recentlyAdded.module#RecentlyAddedModule", path: "recentlyadded" }, + { loadChildren: "./vote/vote.module#VoteModule", path: "vote" }, ]; // AoT requires an exported function for factories @@ -97,6 +98,7 @@ export function JwtTokenGetter() { CaptchaModule, TooltipModule, ConfirmDialogModule, + OverlayPanelModule, CommonModule, JwtModule.forRoot({ config: { diff --git a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts index f7fe3df87..310aaa6fd 100644 --- a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts +++ b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts @@ -3,6 +3,7 @@ export enum RequestType { movie = 1, tvShow = 2, + } // NEW WORLD diff --git a/src/Ombi/ClientApp/app/interfaces/IVote.ts b/src/Ombi/ClientApp/app/interfaces/IVote.ts new file mode 100644 index 000000000..fb772fea6 --- /dev/null +++ b/src/Ombi/ClientApp/app/interfaces/IVote.ts @@ -0,0 +1,23 @@ +export interface IVoteViewModel { + requestId: number; + requestType: RequestTypes; + image: string; + background: string; + upvotes: number; + downvotes: number; + title: string; + description: string; +} + +export interface IVoteEngineResult { + result: boolean; + message: string; + isError: boolean; + errorMessage: string; +} + +export enum RequestTypes { + TvShow = 0, + Movie = 1, + Album = 2, +} diff --git a/src/Ombi/ClientApp/app/interfaces/index.ts b/src/Ombi/ClientApp/app/interfaces/index.ts index 74a39099e..bfc89edc6 100644 --- a/src/Ombi/ClientApp/app/interfaces/index.ts +++ b/src/Ombi/ClientApp/app/interfaces/index.ts @@ -16,3 +16,4 @@ export * from "./IIssues"; export * from "./IRecentlyAdded"; export * from "./ILidarr"; export * from "./ISearchMusicResult"; +export * from "./IVote"; diff --git a/src/Ombi/ClientApp/app/services/index.ts b/src/Ombi/ClientApp/app/services/index.ts index 59a299d3e..c1ccc2585 100644 --- a/src/Ombi/ClientApp/app/services/index.ts +++ b/src/Ombi/ClientApp/app/services/index.ts @@ -14,3 +14,4 @@ export * from "./issues.service"; export * from "./mobile.service"; export * from "./notificationMessage.service"; export * from "./recentlyAdded.service"; +export * from "./vote.service"; diff --git a/src/Ombi/ClientApp/app/services/vote.service.ts b/src/Ombi/ClientApp/app/services/vote.service.ts new file mode 100644 index 000000000..375f0fc33 --- /dev/null +++ b/src/Ombi/ClientApp/app/services/vote.service.ts @@ -0,0 +1,36 @@ +import { PlatformLocation } from "@angular/common"; +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; + +import { IVoteEngineResult, IVoteViewModel } from "../interfaces"; +import { ServiceHelpers } from "./service.helpers"; + +@Injectable() +export class VoteService extends ServiceHelpers { + constructor(public http: HttpClient, public platformLocation: PlatformLocation) { + super(http, "/api/v1/Vote/", platformLocation); + } + + public async getModel(): Promise { + return await this.http.get(`${this.url}`, {headers: this.headers}).toPromise(); + } + + public async upvoteMovie(requestId: number): Promise { + return await this.http.post(`${this.url}up/movie/${requestId}`, {headers: this.headers}).toPromise(); + } + public async upvoteTv(requestId: number): Promise { + return await this.http.post(`${this.url}up/tv/${requestId}`, {headers: this.headers}).toPromise(); + } + public async upvoteAlbum(requestId: number): Promise { + return await this.http.post(`${this.url}up/album/${requestId}`, {headers: this.headers}).toPromise(); + } + public async downvoteMovie(requestId: number): Promise { + return await this.http.post(`${this.url}down/movie/${requestId}`, {headers: this.headers}).toPromise(); + } + public async downvoteTv(requestId: number): Promise { + return await this.http.post(`${this.url}down/tv/${requestId}`, {headers: this.headers}).toPromise(); + } + public async downvoteAlbum(requestId: number): Promise { + return await this.http.post(`${this.url}down/album/${requestId}`, {headers: this.headers}).toPromise(); + } +} diff --git a/src/Ombi/ClientApp/app/vote/vote.component.html b/src/Ombi/ClientApp/app/vote/vote.component.html new file mode 100644 index 000000000..eaeb3ca5e --- /dev/null +++ b/src/Ombi/ClientApp/app/vote/vote.component.html @@ -0,0 +1,35 @@ +

Vote

+ +
+ + + + + + + + + + + + + + + + + + +
TitleDescription
+ + + poster{{vm.title}}
+ + +
+ + + poster + \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/vote/vote.component.scss b/src/Ombi/ClientApp/app/vote/vote.component.scss new file mode 100644 index 000000000..a57fb9749 --- /dev/null +++ b/src/Ombi/ClientApp/app/vote/vote.component.scss @@ -0,0 +1,12 @@ +.vcenter { + vertical-align: middle; + float: none; +} + +.hideBackground { + border: 0px solid transparent !important; + background: transparent !important; + -webkit-box-shadow: 0 0px 0px 0 transparent !important; + -moz-box-shadow: 0 0px 0px 0 transparent !important; + box-shadow: 0 0px 0px 0 transparent !important; +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/vote/vote.component.ts b/src/Ombi/ClientApp/app/vote/vote.component.ts new file mode 100644 index 000000000..908c1759a --- /dev/null +++ b/src/Ombi/ClientApp/app/vote/vote.component.ts @@ -0,0 +1,70 @@ +import { Component, OnInit, ViewChild } from "@angular/core"; + +import { OverlayPanel } from "primeng/primeng"; +import { NotificationService, VoteService } from "../services"; + +import { IVoteEngineResult, IVoteViewModel, RequestTypes } from "../interfaces"; + +@Component({ + templateUrl: "vote.component.html", + styleUrls: ["vote.component.scss"], +}) +export class VoteComponent implements OnInit { + + public viewModel: IVoteViewModel[]; + public panelImage: string; + @ViewChild("op") public overlayPanel: OverlayPanel; + + constructor(private voteService: VoteService, private notificationSerivce: NotificationService) { } + + public async ngOnInit() { + this.viewModel = await this.voteService.getModel(); + } + + public toggle(event: any, image: string) { + this.panelImage = image; + this.overlayPanel.toggle(event); + } + + public async upvote(vm: IVoteViewModel) { + let result: IVoteEngineResult = {errorMessage:"", isError: false, message:"",result:false}; + switch(vm.requestType) { + case RequestTypes.Album: + result = await this.voteService.upvoteAlbum(vm.requestId); + break; + case RequestTypes.Movie: + result = await this.voteService.upvoteMovie(vm.requestId); + break; + case RequestTypes.TvShow: + result = await this.voteService.upvoteTv(vm.requestId); + break; + } + + if(result.isError) { + this.notificationSerivce.error(result.errorMessage); + } else { + this.notificationSerivce.success("Voted!"); + } + } + + public async downvote(vm: IVoteViewModel) { + let result: IVoteEngineResult = {errorMessage:"", isError: false, message:"",result:false}; + switch(vm.requestType) { + case RequestTypes.Album: + result = await this.voteService.downvoteAlbum(vm.requestId); + break; + case RequestTypes.Movie: + result = await this.voteService.downvoteMovie(vm.requestId); + break; + case RequestTypes.TvShow: + result = await this.voteService.downvoteTv(vm.requestId); + break; + } + + if(result.isError) { + this.notificationSerivce.error(result.errorMessage); + } else { + this.notificationSerivce.success("Voted!"); + } + } +} diff --git a/src/Ombi/ClientApp/app/vote/vote.module.ts b/src/Ombi/ClientApp/app/vote/vote.module.ts new file mode 100644 index 000000000..ee7532da5 --- /dev/null +++ b/src/Ombi/ClientApp/app/vote/vote.module.ts @@ -0,0 +1,41 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +import { NgbModule } from "@ng-bootstrap/ng-bootstrap"; +import { OrderModule } from "ngx-order-pipe"; +import { OverlayPanelModule, SharedModule, TabViewModule } from "primeng/primeng"; + +import { VoteService } from "../services"; + +import { AuthGuard } from "../auth/auth.guard"; + +import { SharedModule as OmbiShared } from "../shared/shared.module"; + +import { VoteComponent } from "./vote.component"; + +const routes: Routes = [ + { path: "", component: VoteComponent, canActivate: [AuthGuard] }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + NgbModule.forRoot(), + SharedModule, + OrderModule, + OmbiShared, + TabViewModule, + OverlayPanelModule, + ], + declarations: [ + VoteComponent, + ], + exports: [ + RouterModule, + ], + providers: [ + VoteService, + ], + +}) +export class VoteModule { } diff --git a/src/Ombi/ClientApp/styles/base.scss b/src/Ombi/ClientApp/styles/base.scss index a9f3119fa..98f5e3e99 100644 --- a/src/Ombi/ClientApp/styles/base.scss +++ b/src/Ombi/ClientApp/styles/base.scss @@ -1007,5 +1007,4 @@ a > h4:hover { .album-cover { width:300px; -} - +} \ No newline at end of file diff --git a/src/Ombi/Controllers/VoteController.cs b/src/Ombi/Controllers/VoteController.cs index f1466e3ed..70ea0ec8c 100644 --- a/src/Ombi/Controllers/VoteController.cs +++ b/src/Ombi/Controllers/VoteController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Ombi.Core.Engine; +using Ombi.Core.Models; using Ombi.Core.Models.UI; using Ombi.Store.Entities; @@ -21,12 +22,69 @@ namespace Ombi.Controllers private readonly IVoteEngine _engine; + /// + /// Returns the viewmodel to render on the UI + /// [HttpGet] public Task> GetView() { return _engine.GetMovieViewModel(); } + /// + /// Upvotes a movie + /// + [HttpPost("up/movie/{requestId:int}")] + public Task UpvoteMovie(int requestId) + { + return _engine.UpVote(requestId, RequestType.Movie); + } + + /// + /// Upvotes a tv show + /// + [HttpPost("up/tv/{requestId:int}")] + public Task UpvoteTv(int requestId) + { + return _engine.UpVote(requestId, RequestType.TvShow); + } + + /// + /// Upvotes a album + /// + [HttpPost("up/album/{requestId:int}")] + public Task UpvoteAlbum(int requestId) + { + return _engine.UpVote(requestId, RequestType.Album); + } + + /// + /// Downvotes a movie + /// + [HttpPost("down/movie/{requestId:int}")] + public Task DownvoteMovie(int requestId) + { + return _engine.DownVote(requestId, RequestType.Movie); + } + + /// + /// Downvotes a tv show + /// + [HttpPost("down/tv/{requestId:int}")] + public Task DownvoteTv(int requestId) + { + return _engine.DownVote(requestId, RequestType.TvShow); + } + + /// + /// Downvotes a album + /// + [HttpPost("down/album/{requestId:int}")] + public Task DownvoteAlbum(int requestId) + { + return _engine.DownVote(requestId, RequestType.Album); + } + /// /// Get's all the votes for the request id ///