Merge develop into Webpack and Angular upgrade

pull/2411/head
TidusJar 6 years ago
commit 3d52998f3e

@ -1,6 +1,6 @@
# Changelog
## (unreleased)
## v3.0.3477 (2018-07-18)
### **New Features**

@ -452,6 +452,7 @@ namespace Ombi.Core.Engine
}
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MovieRepository.Update(request);

@ -467,6 +467,7 @@ namespace Ombi.Core.Engine
};
}
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
foreach (var season in request.SeasonRequests)
{
foreach (var e in season.Episodes)

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
using Ombi.Store.Entities;
using Ombi.Store.Repository.Requests;
namespace Ombi.Core.Engine
{
public class UserStatsEngine
{
public UserStatsEngine(OmbiUserManager um, IMovieRequestRepository movieRequest, ITvRequestRepository tvRequest)
{
_userManager = um;
_movieRequest = movieRequest;
_tvRequest = tvRequest;
}
private readonly OmbiUserManager _userManager;
private readonly IMovieRequestRepository _movieRequest;
private readonly ITvRequestRepository _tvRequest;
public async Task<UserStatsSummary> GetSummary(SummaryRequest request)
{
/* What do we want?
This is Per week/month/all time (filter by date)
1. Total Requests
2. Total Movie Requests
3. Total Tv Requests
4. Total Issues (If enabled)
5. Total Requests fufilled (now available)
Then
2. Most requested user Movie
3. Most requested user tv
Then
1.
*/
// get all movie requests
var movies = _movieRequest.GetWithUser();
var filteredMovies = movies.Where(x => x.RequestedDate >= request.From && x.RequestedDate <= request.To);
var tv = _tvRequest.GetLite();
var children = tv.SelectMany(x =>
x.ChildRequests.Where(c => c.RequestedDate >= request.From && c.RequestedDate <= request.To));
var moviesCount = filteredMovies.CountAsync();
var childrenCount = children.CountAsync();
var availableMovies =
movies.Select(x => x.MarkedAsAvailable >= request.From && x.MarkedAsAvailable <= request.To).CountAsync();
var availableChildren = tv.SelectMany(x =>
x.ChildRequests.Where(c => c.MarkedAsAvailable >= request.From && c.MarkedAsAvailable <= request.To)).CountAsync();
var userMovie = filteredMovies.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync();
var userTv = children.GroupBy(x => x.RequestedUserId).OrderBy(x => x.Key).FirstOrDefaultAsync();
return new UserStatsSummary
{
TotalMovieRequests = await moviesCount,
TotalTvRequests = await childrenCount,
CompletedRequestsTv = await availableChildren,
CompletedRequestsMovies = await availableMovies,
MostRequestedUserMovie = (await userMovie).FirstOrDefault().RequestedUser,
MostRequestedUserTv = (await userTv).FirstOrDefault().RequestedUser,
};
}
}
public class SummaryRequest
{
public DateTime From { get; set; }
public DateTime To { get; set; }
}
public class UserStatsSummary
{
public int TotalRequests => TotalTvRequests + TotalTvRequests;
public int TotalMovieRequests { get; set; }
public int TotalTvRequests { get; set; }
public int TotalIssues { get; set; }
public int CompletedRequestsMovies { get; set; }
public int CompletedRequestsTv { get; set; }
public int CompletedRequests => CompletedRequestsMovies + CompletedRequestsTv;
public OmbiUser MostRequestedUserMovie { get; set; }
public OmbiUser MostRequestedUserTv { get; set; }
}
}

@ -89,6 +89,7 @@ namespace Ombi.Schedule.Jobs.Emby
_log.LogInformation("We have found the request {0} on Emby, sending the notification", movie?.Title ?? string.Empty);
movie.Available = true;
movie.MarkedAsAvailable = DateTime.Now;
if (movie.Available)
{
var recipient = movie.RequestedUser.Email.HasValue() ? movie.RequestedUser.Email : string.Empty;
@ -185,6 +186,7 @@ namespace Ombi.Schedule.Jobs.Emby
{
// We have fulfulled this request!
child.Available = true;
child.MarkedAsAvailable = DateTime.Now;
BackgroundJob.Enqueue(() => _notificationService.Publish(new NotificationOptions
{
DateTime = DateTime.Now,

@ -123,6 +123,7 @@ namespace Ombi.Schedule.Jobs.Plex
{
// We have fulfulled this request!
child.Available = true;
child.MarkedAsAvailable = DateTime.Now;
_backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions
{
DateTime = DateTime.Now,
@ -163,6 +164,7 @@ namespace Ombi.Schedule.Jobs.Plex
}
movie.Available = true;
movie.MarkedAsAvailable = DateTime.Now;
if (movie.Available)
{
_backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions

@ -8,10 +8,13 @@ namespace Ombi.Store.Entities.Requests
{
public string Title { get; set; }
public bool Approved { get; set; }
public DateTime MarkedAsApproved { get; set; }
public DateTime RequestedDate { get; set; }
public bool Available { get; set; }
public DateTime? MarkedAsAvailable { get; set; }
public string RequestedUserId { get; set; }
public bool? Denied { get; set; }
public DateTime MarkedAsDenied { get; set; }
public string DeniedReason { get; set; }
public RequestType RequestType { get; set; }

@ -0,0 +1,988 @@
// <auto-generated />
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("20180730085903_UserStats")]
partial class UserStats
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Type");
b.Property<string>("Value");
b.HasKey("Id");
b.ToTable("ApplicationConfiguration");
});
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AuditArea");
b.Property<int>("AuditType");
b.Property<DateTime>("DateTime");
b.Property<string>("Description");
b.Property<string>("User");
b.HasKey("Id");
b.ToTable("Audit");
});
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TheMovieDbId");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("EmbyId")
.IsRequired();
b.Property<string>("ImdbId");
b.Property<string>("ProviderId");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.Property<int>("Type");
b.Property<string>("Url");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("EmbyId");
b.Property<int>("EpisodeNumber");
b.Property<string>("ImdbId");
b.Property<string>("ParentId");
b.Property<string>("ProviderId");
b.Property<int>("SeasonNumber");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Content");
b.Property<string>("SettingsName");
b.HasKey("Id");
b.ToTable("GlobalSettings");
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Agent");
b.Property<bool>("Enabled");
b.Property<string>("Message");
b.Property<int>("NotificationType");
b.Property<string>("Subject");
b.HasKey("Id");
b.ToTable("NotificationTemplates");
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("PlayerId");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("NotificationUserId");
});
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("Alias");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<string>("EmbyConnectUserId");
b.Property<int?>("EpisodeRequestLimit");
b.Property<DateTime?>("LastLoggedIn");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<int?>("MovieRequestLimit");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("ProviderUserId");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserAccessToken");
b.Property<string>("UserName")
.HasMaxLength(256);
b.Property<int>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<int>("GrandparentKey");
b.Property<int>("Key");
b.Property<int>("ParentKey");
b.Property<int>("SeasonNumber");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ParentKey");
b.Property<int>("PlexContentId");
b.Property<int?>("PlexServerContentId");
b.Property<int>("SeasonKey");
b.Property<int>("SeasonNumber");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("ImdbId");
b.Property<int>("Key");
b.Property<string>("Quality");
b.Property<string>("ReleaseYear");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.Property<int>("Type");
b.Property<string>("Url");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("HasFile");
b.Property<int>("TheMovieDbId");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<int>("ContentId");
b.Property<int>("ContentType");
b.Property<int?>("EpisodeNumber");
b.Property<int?>("SeasonNumber");
b.Property<int>("Type");
b.HasKey("Id");
b.ToTable("RecentlyAddedLog");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<bool?>("Denied");
b.Property<string>("DeniedReason");
b.Property<int?>("IssueId");
b.Property<DateTime>("MarkedAsApproved");
b.Property<DateTime?>("MarkedAsAvailable");
b.Property<DateTime>("MarkedAsDenied");
b.Property<int>("ParentRequestId");
b.Property<int>("RequestType");
b.Property<DateTime>("RequestedDate");
b.Property<string>("RequestedUserId");
b.Property<int>("SeriesType");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("ParentRequestId");
b.HasIndex("RequestedUserId");
b.ToTable("ChildRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Value");
b.HasKey("Id");
b.ToTable("IssueCategory");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Comment");
b.Property<DateTime>("Date");
b.Property<int?>("IssuesId");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("IssuesId");
b.HasIndex("UserId");
b.ToTable("IssueComments");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Description");
b.Property<int>("IssueCategoryId");
b.Property<int?>("IssueId");
b.Property<string>("ProviderId");
b.Property<int?>("RequestId");
b.Property<int>("RequestType");
b.Property<DateTime?>("ResovledDate");
b.Property<int>("Status");
b.Property<string>("Subject");
b.Property<string>("Title");
b.Property<string>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<string>("Background");
b.Property<bool?>("Denied");
b.Property<string>("DeniedReason");
b.Property<DateTime?>("DigitalReleaseDate");
b.Property<string>("ImdbId");
b.Property<int?>("IssueId");
b.Property<DateTime>("MarkedAsApproved");
b.Property<DateTime?>("MarkedAsAvailable");
b.Property<DateTime>("MarkedAsDenied");
b.Property<string>("Overview");
b.Property<string>("PosterPath");
b.Property<int>("QualityOverride");
b.Property<DateTime>("ReleaseDate");
b.Property<int>("RequestType");
b.Property<DateTime>("RequestedDate");
b.Property<string>("RequestedUserId");
b.Property<int>("RootPathOverride");
b.Property<string>("Status");
b.Property<int>("TheMovieDbId");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("RequestedUserId");
b.ToTable("MovieRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeCount");
b.Property<DateTime>("RequestDate");
b.Property<int>("RequestId");
b.Property<int>("RequestType");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RequestLog");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Background");
b.Property<string>("ImdbId");
b.Property<string>("Overview");
b.Property<string>("PosterPath");
b.Property<int?>("QualityOverride");
b.Property<DateTime>("ReleaseDate");
b.Property<int?>("RootFolder");
b.Property<string>("Status");
b.Property<string>("Title");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("TvRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("RequestId");
b.Property<int>("RequestType");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RequestSubscription");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<int>("SeasonNumber");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<bool>("HasFile");
b.Property<int>("SeasonNumber");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Token");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Tokens");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AirDate");
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<int>("EpisodeNumber");
b.Property<bool>("Requested");
b.Property<int>("SeasonId");
b.Property<string>("Title");
b.Property<string>("Url");
b.HasKey("Id");
b.HasIndex("SeasonId");
b.ToTable("EpisodeRequests");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ChildRequestId");
b.Property<int>("SeasonNumber");
b.HasKey("Id");
b.HasIndex("ChildRequestId");
b.ToTable("SeasonRequests");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", 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<string>", 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.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.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
}
}
}

@ -0,0 +1,72 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Ombi.Store.Migrations
{
public partial class UserStats : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsApproved",
table: "MovieRequests",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsAvailable",
table: "MovieRequests",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsDenied",
table: "MovieRequests",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsApproved",
table: "ChildRequests",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsAvailable",
table: "ChildRequests",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsDenied",
table: "ChildRequests",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MarkedAsApproved",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsAvailable",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsDenied",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsApproved",
table: "ChildRequests");
migrationBuilder.DropColumn(
name: "MarkedAsAvailable",
table: "ChildRequests");
migrationBuilder.DropColumn(
name: "MarkedAsDenied",
table: "ChildRequests");
}
}
}

@ -1,15 +1,9 @@
// <auto-generated />
using System;
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 Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ombi.Store.Context;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using System;
namespace Ombi.Store.Migrations
{
@ -20,7 +14,7 @@ namespace Ombi.Store.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
@ -481,6 +475,12 @@ namespace Ombi.Store.Migrations
b.Property<int?>("IssueId");
b.Property<DateTime>("MarkedAsApproved");
b.Property<DateTime?>("MarkedAsAvailable");
b.Property<DateTime>("MarkedAsDenied");
b.Property<int>("ParentRequestId");
b.Property<int>("RequestType");
@ -595,6 +595,12 @@ namespace Ombi.Store.Migrations
b.Property<int?>("IssueId");
b.Property<DateTime>("MarkedAsApproved");
b.Property<DateTime?>("MarkedAsAvailable");
b.Property<DateTime>("MarkedAsDenied");
b.Property<string>("Overview");
b.Property<string>("PosterPath");

@ -134,6 +134,12 @@
<li [ngClass]="{'active': 'no' === translate.currentLang}">
<a (click)="translate.use('no')" [translate]="'NavigationBar.Language.Norwegian'"></a>
</li>
<li [ngClass]="{'active': 'pt' === translate.currentLang}">
<a (click)="translate.use('pt')" [translate]="'NavigationBar.Language.BrazillianPortuguese'"></a>
</li>
<li [ngClass]="{'active': 'pl' === translate.currentLang}">
<a (click)="translate.use('pl')" [translate]="'NavigationBar.Language.Polish'"></a>
</li>
</ul>
</li>
</ul>

@ -39,14 +39,14 @@ export class AppComponent implements OnInit {
if (base.length > 1) {
__webpack_public_path__ = base + "/dist/";
}
this.translate.addLangs(["en", "de", "fr", "da", "es", "it", "nl", "sv", "no"]);
this.translate.addLangs(["en", "de", "fr", "da", "es", "it", "nl", "sv", "no", "pl", "pt"]);
// this language will be used as a fallback when a translation isn't found in the current language
this.translate.setDefaultLang("en");
// See if we can match the supported langs with the current browser lang
const browserLang: string = translate.getBrowserLang();
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no/) ? browserLang : "en");
this.translate.use(browserLang.match(/en|fr|da|de|es|it|nl|sv|no|pl|pt/) ? browserLang : "en");
}
public ngOnInit() {

@ -23,6 +23,11 @@ export interface ICreateWizardUser {
usePlexAdminAccount: boolean;
}
export interface IWizardUserResult {
result: boolean;
errors: string[];
}
export enum UserType {
LocalUser = 1,
PlexUser = 2,

@ -4,7 +4,7 @@ import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser } from "../interfaces";
import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser, IWizardUserResult } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";
@Injectable()
@ -12,8 +12,8 @@ export class IdentityService extends ServiceHelpers {
constructor(http: HttpClient, public platformLocation: PlatformLocation) {
super(http, "/api/v1/Identity/", platformLocation);
}
public createWizardUser(user: ICreateWizardUser): Observable<boolean> {
return this.http.post<boolean>(`${this.url}Wizard/`, JSON.stringify(user), {headers: this.headers});
public createWizardUser(user: ICreateWizardUser): Observable<IWizardUserResult> {
return this.http.post<IWizardUserResult>(`${this.url}Wizard/`, JSON.stringify(user), {headers: this.headers});
}
public getUser(): Observable<IUser> {

@ -17,10 +17,12 @@ export class CreateAdminComponent {
public createUser() {
this.identityService.createWizardUser({username: this.username, password: this.password, usePlexAdminAccount: false}).subscribe(x => {
if (x) {
if (x.result) {
this.router.navigate(["login"]);
} else {
this.notificationService.error("There was an error... You might want to put this on Github...");
if(x.errors.length > 0) {
this.notificationService.error(x.errors[0]);
}
}
});
}

@ -31,18 +31,21 @@ export class PlexComponent implements OnInit {
}
this.identityService.createWizardUser({
username: "",
password: "",
usePlexAdminAccount: true,
}).subscribe(y => {
if (y) {
this.router.navigate(["login"]);
} else {
this.notificationService.error("Could not get the Plex Admin Information");
return;
}
});
},
username: "",
password: "",
usePlexAdminAccount: true,
}).subscribe(y => {
if (y.result) {
this.router.navigate(["login"]);
} else {
this.notificationService.error("Could not get the Plex Admin Information");
if(y.errors.length > 0) {
this.notificationService.error(y.errors[0]);
}
return;
}
});
},
);
}

@ -1,7 +1,7 @@
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { IdentityService, PlexOAuthService, SettingsService } from "../../services";
import { IdentityService, PlexOAuthService } from "../../services";
import { AuthService } from "./../../auth/auth.service";
@Component({
@ -13,7 +13,6 @@ export class PlexOAuthComponent implements OnInit {
constructor(private route: ActivatedRoute,
private plexOauth: PlexOAuthService,
private identityService: IdentityService,
private settings: SettingsService,
private router: Router,
private auth: AuthService) {
@ -31,34 +30,24 @@ export class PlexOAuthComponent implements OnInit {
}
this.identityService.createWizardUser({
username: "",
password: "",
usePlexAdminAccount: true,
}).subscribe(u => {
if (u) {
this.auth.oAuth(this.pinId).subscribe(c => {
localStorage.setItem("id_token", c.access_token);
// Mark that we have done the settings now
this.settings.getOmbi().subscribe(ombi => {
ombi.wizard = true;
this.settings.saveOmbi(ombi).subscribe(s => {
this.settings.getUserManagementSettings().subscribe(usr => {
usr.importPlexAdmin = true;
this.settings.saveUserManagementSettings(usr).subscribe(saved => {
this.router.navigate(["login"]);
});
});
username: "",
password: "",
usePlexAdminAccount: true,
}).subscribe(u => {
if (u.result) {
this.auth.oAuth(this.pinId).subscribe(c => {
localStorage.setItem("id_token", c.access_token);
this.router.navigate(["login"]);
});
});
} else {
if(u.errors.length > 0) {
console.log(u.errors[0]);
}
return;
}
});
} else {
//this.notificationService.error("Could not get the Plex Admin Information");
return;
}
});
});
}
}

@ -455,7 +455,7 @@ $border-radius: 10px;
}
.checkbox input[type=checkbox] {
display: none;
opacity: 0;
}
.checkbox input[type=checkbox]:checked + label:before {
@ -965,4 +965,4 @@ a > h4:hover {
.subject-category,
.subject {
display: inline-block;
}
}

@ -59,7 +59,8 @@ namespace Ombi.Controllers
IRepository<Issues> issues,
IRepository<IssueComments> issueComments,
IRepository<NotificationUserId> notificationRepository,
IRepository<RequestSubscription> subscriptionRepository)
IRepository<RequestSubscription> subscriptionRepository,
ISettingsService<UserManagementSettings> umSettings)
{
UserManager = user;
Mapper = mapper;
@ -79,6 +80,7 @@ namespace Ombi.Controllers
OmbiSettings = ombiSettings;
_requestSubscriptionRepository = subscriptionRepository;
_notificationRepository = notificationRepository;
_userManagementSettings = umSettings;
}
private OmbiUserManager UserManager { get; }
@ -87,6 +89,7 @@ namespace Ombi.Controllers
private IEmailProvider EmailProvider { get; }
private ISettingsService<EmailNotificationSettings> EmailSettings { get; }
private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
private readonly ISettingsService<UserManagementSettings> _userManagementSettings;
private ISettingsService<OmbiSettings> OmbiSettings { get; }
private IWelcomeEmail WelcomeEmail { get; }
private IMovieRequestRepository MovieRepo { get; }
@ -113,13 +116,13 @@ namespace Ombi.Controllers
[HttpPost("Wizard")]
[ApiExplorerSettings(IgnoreApi = true)]
[AllowAnonymous]
public async Task<bool> CreateWizardUser([FromBody] CreateUserWizardModel user)
public async Task<SaveWizardResult> CreateWizardUser([FromBody] CreateUserWizardModel user)
{
var users = UserManager.Users;
if (users.Any(x => !x.UserName.Equals("api", StringComparison.CurrentCultureIgnoreCase)))
if (users.Any(x => !x.UserName.Equals("api", StringComparison.InvariantCultureIgnoreCase)))
{
// No one should be calling this. Only the wizard
return false;
return new SaveWizardResult{ Result = false, Errors = new List<string> {"Looks like there is an existing user!"} };
}
if (user.UsePlexAdminAccount)
@ -129,7 +132,7 @@ namespace Ombi.Controllers
if (authToken.IsNullOrEmpty())
{
_log.LogWarning("Could not find an auth token to create the plex user with");
return false;
return new SaveWizardResult { Result = false };
}
var plexUser = await _plexApi.GetAccount(authToken);
var adminUser = new OmbiUser
@ -140,6 +143,11 @@ namespace Ombi.Controllers
ProviderUserId = plexUser.user.id
};
await _userManagementSettings.SaveSettingsAsync(new UserManagementSettings
{
ImportPlexAdmin = true
});
return await SaveWizardUser(user, adminUser);
}
@ -152,9 +160,10 @@ namespace Ombi.Controllers
return await SaveWizardUser(user, userToCreate);
}
private async Task<bool> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate)
private async Task<SaveWizardResult> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate)
{
IdentityResult result;
var retVal = new SaveWizardResult();
// When creating the admin as the plex user, we do not pass in the password.
if (user.Password.HasValue())
{
@ -182,6 +191,7 @@ namespace Ombi.Controllers
if (!result.Succeeded)
{
LogErrors(result);
retVal.Errors.AddRange(result.Errors.Select(x => x.Description));
}
// Update the wizard flag
@ -189,7 +199,8 @@ namespace Ombi.Controllers
settings.Wizard = true;
await OmbiSettings.SaveSettingsAsync(settings);
return result.Succeeded;
retVal.Result = result.Succeeded;
return retVal;
}
private void LogErrors(IdentityResult result)

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Ombi.Models.Identity
{
public class SaveWizardResult
{
public bool Result { get; set; }
public List<string> Errors { get; set; } = new List<string>();
}
}

@ -62,9 +62,12 @@
"Italian": "Italiensk",
"Danish": "Dansk",
"Dutch": "Hollandsk",
"Norwegian": "Norsk"
"Norwegian": "Norsk",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Åbn mobilapp"
"OpenMobileApp": "Åbn mobilapp",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Søg",
@ -113,6 +116,7 @@
"RequestStatus": "Status for anmodning:",
"Denied": " Afvist:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Dato for anmodning:",
"QualityOverride": "Tilsidesæt kvalitet:",
@ -129,7 +133,14 @@
"GridStatus": "Status",
"ReportIssue": "Rapportér problem",
"Filter": "Filter",
"SeasonNumberHeading": "Sæson: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Sæson: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Problemer",
@ -154,6 +165,7 @@
"ClearFilter": "Nulstil filter",
"FilterHeaderAvailability": "Tilgængelighed",
"FilterHeaderRequestStatus": "Status",
"Approved": "Godkendt"
"Approved": "Godkendt",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italienisch",
"Danish": "Dänisch",
"Dutch": "Niederländisch",
"Norwegian": "Norwegisch"
"Norwegian": "Norwegisch",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Mobile App"
"OpenMobileApp": "Mobile App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Suche",
@ -113,6 +116,7 @@
"RequestStatus": "Anfrage Status:",
"Denied": " Abgelehnt:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Datum der Anfrage:",
"QualityOverride": "Qualitäts Überschreiben:",
@ -129,7 +133,14 @@
"GridStatus": "Status",
"ReportIssue": "Problem melden",
"Filter": "Filter",
"SeasonNumberHeading": "Staffel: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Staffel: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Probleme",
@ -154,6 +165,7 @@
"ClearFilter": "Filter zurücksetzen",
"FilterHeaderAvailability": "Verfügbarkeit",
"FilterHeaderRequestStatus": "Status",
"Approved": "Bestätigt"
"Approved": "Bestätigt",
"PendingApproval": "Pending Approval"
}
}

@ -65,7 +65,9 @@
"Italian": "Italian",
"Danish": "Danish",
"Dutch": "Dutch",
"Norwegian":"Norwegian"
"Norwegian":"Norwegian",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish":"Polish"
},
"OpenMobileApp":"Open Mobile App",
"RecentlyAdded":"Recently Added"

@ -62,9 +62,12 @@
"Italian": "Italiano",
"Danish": "Danés",
"Dutch": "Holandés",
"Norwegian": "Norwegian"
"Norwegian": "Norwegian",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Open Mobile App"
"OpenMobileApp": "Open Mobile App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Buscar",
@ -113,6 +116,7 @@
"RequestStatus": "Estado de la solicitud:",
"Denied": " Denegado:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Fecha de solicitud:",
"QualityOverride": "Sobreescribir calidad:",
@ -129,7 +133,14 @@
"GridStatus": "Estado",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"SeasonNumberHeading": "Season: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Incidencias",
@ -154,6 +165,7 @@
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved"
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italien",
"Danish": "Danois",
"Dutch": "Néerlandais",
"Norwegian": "Norvégien"
"Norwegian": "Norvégien",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Ouvrir l'application mobile"
"OpenMobileApp": "Ouvrir l'application mobile",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Rechercher",
@ -113,6 +116,7 @@
"RequestStatus": "Statut de la demande :",
"Denied": " Refusé :",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Date de la demande :",
"QualityOverride": "Remplacement de la qualité :",
@ -129,7 +133,14 @@
"GridStatus": "Statut",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"SeasonNumberHeading": "Season: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Problèmes",
@ -154,6 +165,7 @@
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved"
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italiano",
"Danish": "Danese",
"Dutch": "Olandese",
"Norwegian": "Norvegese"
"Norwegian": "Norvegese",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Apri l'applicazione mobile"
"OpenMobileApp": "Apri l'applicazione mobile",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Cerca",
@ -113,6 +116,7 @@
"RequestStatus": "Stato della richiesta:",
"Denied": " Rifiutato:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Data della richiesta:",
"QualityOverride": "Sovrascrivi qualità:",
@ -129,7 +133,14 @@
"GridStatus": "Stato",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"SeasonNumberHeading": "Season: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Problemi",
@ -154,6 +165,7 @@
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved"
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italiaans",
"Danish": "Deens",
"Dutch": "Nederlands",
"Norwegian": "Noors"
"Norwegian": "Noors",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Open Mobiele App"
"OpenMobileApp": "Open Mobiele App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Zoeken",
@ -113,6 +116,7 @@
"RequestStatus": "Aanvraagstatus:",
"Denied": " Geweigerd:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Aanvraag Datum:",
"QualityOverride": "Kwaliteit overschrijven:",
@ -129,7 +133,14 @@
"GridStatus": "Status",
"ReportIssue": "Probleem Melden",
"Filter": "Filter",
"SeasonNumberHeading": "Seizoen: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Seizoen: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Problemen",
@ -154,6 +165,7 @@
"ClearFilter": "Verwijder Filter",
"FilterHeaderAvailability": "Beschikbaarheid",
"FilterHeaderRequestStatus": "Status",
"Approved": "Goedgekeurd"
"Approved": "Goedgekeurd",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italiensk",
"Danish": "Dansk",
"Dutch": "Nederlandsk",
"Norwegian": "Norsk"
"Norwegian": "Norsk",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Åpne mobilapp"
"OpenMobileApp": "Åpne mobilapp",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Søk",
@ -113,6 +116,7 @@
"RequestStatus": "Status for forespørsel:",
"Denied": " Avslått:",
"TheatricalRelease": "Kinopremiere: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital utgivelse: {{date}}",
"RequestDate": "Dato for forespørsel:",
"QualityOverride": "Overstyr kvalitet:",
@ -129,7 +133,14 @@
"GridStatus": "Status",
"ReportIssue": "Rapportér en feil",
"Filter": "Filter",
"SeasonNumberHeading": "Sesong: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Sesong: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Mangler",
@ -154,6 +165,7 @@
"ClearFilter": "Tøm filter",
"FilterHeaderAvailability": "Tilgjengelighet",
"FilterHeaderRequestStatus": "Status",
"Approved": "Godkjent"
"Approved": "Godkjent",
"PendingApproval": "Pending Approval"
}
}

@ -0,0 +1,171 @@
{
"Login": {
"SignInButton": "Sign in",
"UsernamePlaceholder": "Username",
"PasswordPlaceholder": "Password",
"RememberMe": "Remember Me",
"ForgottenPassword": "Forgot your password?",
"Errors": {
"IncorrectCredentials": "Incorrect username or password"
}
},
"Common": {
"ContinueButton": "Continue",
"Available": "Available",
"NotAvailable": "Not Available",
"ProcessingRequest": "Processing Request",
"PendingApproval": "Pending Approval",
"RequestDenied": "Request Denied",
"NotRequested": "Not Requested",
"Requested": "Requested",
"Request": "Request",
"Denied": "Denied",
"Approve": "Approve",
"PartlyAvailable": "Partly Available",
"Errors": {
"Validation": "Please check your entered values"
}
},
"PasswordReset": {
"EmailAddressPlaceholder": "Email Address",
"ResetPasswordButton": "Reset Password"
},
"LandingPage": {
"OnlineHeading": "Currently Online",
"OnlineParagraph": "The media server is currently online",
"PartiallyOnlineHeading": "Partially Online",
"PartiallyOnlineParagraph": "The media server is partially online.",
"MultipleServersUnavailable": "There are {{serversUnavailable}} servers offline out of {{totalServers}}.",
"SingleServerUnavailable": "There is {{serversUnavailable}} server offline out of {{totalServers}}.",
"OfflineHeading": "Currently Offline",
"OfflineParagraph": "The media server is currently offline.",
"CheckPageForUpdates": "Check this page for continuous site updates."
},
"NavigationBar": {
"Search": "Search",
"Requests": "Requests",
"UserManagement": "User Management",
"Issues": "Issues",
"Donate": "Donate!",
"DonateLibraryMaintainer": "Donate to Library Maintainer",
"DonateTooltip": "This is how I convince my wife to let me spend my spare time developing Ombi ;)",
"UpdateAvailableTooltip": "Update Available!",
"Settings": "Settings",
"Welcome": "Welcome {{username}}",
"UpdateDetails": "Update Details",
"Logout": "Logout",
"Language": {
"English": "English",
"French": "French",
"Spanish": "Spanish",
"German": "German",
"Italian": "Italian",
"Danish": "Danish",
"Dutch": "Dutch",
"Norwegian": "Norwegian",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Open Mobile App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Search",
"Paragraph": "Want to watch something that is not currently available? No problem, just search for it below and request it!",
"MoviesTab": "Movies",
"TvTab": "TV Shows",
"Suggestions": "Suggestions",
"NoResults": "Sorry, we didn't find any results!",
"DigitalDate": "Digital Release: {{date}}",
"TheatricalRelease": "Theatrical Release: {{date}}",
"ViewOnPlex": "View On Plex",
"ViewOnEmby": "View On Emby",
"RequestAdded": "Request for {{title}} has been added successfully",
"Similar": "Similar",
"Movies": {
"PopularMovies": "Popular Movies",
"UpcomingMovies": "Upcoming Movies",
"TopRatedMovies": "Top Rated Movies",
"NowPlayingMovies": "Now Playing Movies",
"HomePage": "Home Page",
"Trailer": "Trailer"
},
"TvShows": {
"Popular": "Popular",
"Trending": "Trending",
"MostWatched": "Most Watched",
"MostAnticipated": "Most Anticipated",
"Results": "Results",
"AirDate": "Air Date:",
"AllSeasons": "All Seasons",
"FirstSeason": "First Season",
"LatestSeason": "Latest Season",
"Select": "Select ...",
"SubmitRequest": "Submit Request",
"Season": "Season: {{seasonNumber}}",
"SelectAllInSeason": "Select All in Season {{seasonNumber}}"
}
},
"Requests": {
"Title": "Requests",
"Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.",
"MoviesTab": "Movies",
"TvTab": "TV Shows",
"RequestedBy": "Requested By:",
"Status": "Status:",
"RequestStatus": "Request status:",
"Denied": " Denied:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Request Date:",
"QualityOverride": "Quality Override:",
"RootFolderOverride": "Root Folder Override:",
"ChangeRootFolder": "Root Folder",
"ChangeQualityProfile": "Quality Profile",
"MarkUnavailable": "Mark Unavailable",
"MarkAvailable": "Mark Available",
"Remove": "Remove",
"Deny": "Deny",
"Season": "Season:",
"GridTitle": "Title",
"AirDate": "AirDate",
"GridStatus": "Status",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Issues",
"PendingTitle": "Pending Issues",
"InProgressTitle": "In Progress Issues",
"ResolvedTitle": "Resolved Issues",
"ColumnTitle": "Title",
"Category": "Category",
"Status": "Status",
"Details": "Details",
"Description": "Description",
"NoComments": "No Comments!",
"MarkInProgress": "Mark In Progress",
"MarkResolved": "Mark Resolved",
"SendMessageButton": "Send",
"Subject": "Subject",
"Comments": "Comments",
"WriteMessagePlaceholder": "Write your message here...",
"ReportedBy": "Reported By"
},
"Filter": {
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}

@ -0,0 +1,171 @@
{
"Login": {
"SignInButton": "Sign in",
"UsernamePlaceholder": "Username",
"PasswordPlaceholder": "Password",
"RememberMe": "Remember Me",
"ForgottenPassword": "Forgot your password?",
"Errors": {
"IncorrectCredentials": "Incorrect username or password"
}
},
"Common": {
"ContinueButton": "Continue",
"Available": "Available",
"NotAvailable": "Not Available",
"ProcessingRequest": "Processing Request",
"PendingApproval": "Pending Approval",
"RequestDenied": "Request Denied",
"NotRequested": "Not Requested",
"Requested": "Requested",
"Request": "Request",
"Denied": "Denied",
"Approve": "Approve",
"PartlyAvailable": "Partly Available",
"Errors": {
"Validation": "Please check your entered values"
}
},
"PasswordReset": {
"EmailAddressPlaceholder": "Email Address",
"ResetPasswordButton": "Reset Password"
},
"LandingPage": {
"OnlineHeading": "Currently Online",
"OnlineParagraph": "The media server is currently online",
"PartiallyOnlineHeading": "Partially Online",
"PartiallyOnlineParagraph": "The media server is partially online.",
"MultipleServersUnavailable": "There are {{serversUnavailable}} servers offline out of {{totalServers}}.",
"SingleServerUnavailable": "There is {{serversUnavailable}} server offline out of {{totalServers}}.",
"OfflineHeading": "Currently Offline",
"OfflineParagraph": "The media server is currently offline.",
"CheckPageForUpdates": "Check this page for continuous site updates."
},
"NavigationBar": {
"Search": "Search",
"Requests": "Requests",
"UserManagement": "User Management",
"Issues": "Issues",
"Donate": "Donate!",
"DonateLibraryMaintainer": "Donate to Library Maintainer",
"DonateTooltip": "This is how I convince my wife to let me spend my spare time developing Ombi ;)",
"UpdateAvailableTooltip": "Update Available!",
"Settings": "Settings",
"Welcome": "Welcome {{username}}",
"UpdateDetails": "Update Details",
"Logout": "Logout",
"Language": {
"English": "English",
"French": "French",
"Spanish": "Spanish",
"German": "German",
"Italian": "Italian",
"Danish": "Danish",
"Dutch": "Dutch",
"Norwegian": "Norwegian",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Open Mobile App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Search",
"Paragraph": "Want to watch something that is not currently available? No problem, just search for it below and request it!",
"MoviesTab": "Movies",
"TvTab": "TV Shows",
"Suggestions": "Suggestions",
"NoResults": "Sorry, we didn't find any results!",
"DigitalDate": "Digital Release: {{date}}",
"TheatricalRelease": "Theatrical Release: {{date}}",
"ViewOnPlex": "View On Plex",
"ViewOnEmby": "View On Emby",
"RequestAdded": "Request for {{title}} has been added successfully",
"Similar": "Similar",
"Movies": {
"PopularMovies": "Popular Movies",
"UpcomingMovies": "Upcoming Movies",
"TopRatedMovies": "Top Rated Movies",
"NowPlayingMovies": "Now Playing Movies",
"HomePage": "Home Page",
"Trailer": "Trailer"
},
"TvShows": {
"Popular": "Popular",
"Trending": "Trending",
"MostWatched": "Most Watched",
"MostAnticipated": "Most Anticipated",
"Results": "Results",
"AirDate": "Air Date:",
"AllSeasons": "All Seasons",
"FirstSeason": "First Season",
"LatestSeason": "Latest Season",
"Select": "Select ...",
"SubmitRequest": "Submit Request",
"Season": "Season: {{seasonNumber}}",
"SelectAllInSeason": "Select All in Season {{seasonNumber}}"
}
},
"Requests": {
"Title": "Requests",
"Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.",
"MoviesTab": "Movies",
"TvTab": "TV Shows",
"RequestedBy": "Requested By:",
"Status": "Status:",
"RequestStatus": "Request status:",
"Denied": " Denied:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Request Date:",
"QualityOverride": "Quality Override:",
"RootFolderOverride": "Root Folder Override:",
"ChangeRootFolder": "Root Folder",
"ChangeQualityProfile": "Quality Profile",
"MarkUnavailable": "Mark Unavailable",
"MarkAvailable": "Mark Available",
"Remove": "Remove",
"Deny": "Deny",
"Season": "Season:",
"GridTitle": "Title",
"AirDate": "AirDate",
"GridStatus": "Status",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Issues",
"PendingTitle": "Pending Issues",
"InProgressTitle": "In Progress Issues",
"ResolvedTitle": "Resolved Issues",
"ColumnTitle": "Title",
"Category": "Category",
"Status": "Status",
"Details": "Details",
"Description": "Description",
"NoComments": "No Comments!",
"MarkInProgress": "Mark In Progress",
"MarkResolved": "Mark Resolved",
"SendMessageButton": "Send",
"Subject": "Subject",
"Comments": "Comments",
"WriteMessagePlaceholder": "Write your message here...",
"ReportedBy": "Reported By"
},
"Filter": {
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}

@ -62,9 +62,12 @@
"Italian": "Italienska",
"Danish": "Danska",
"Dutch": "Holländska",
"Norwegian": "Norska"
"Norwegian": "Norska",
"BrazillianPortuguese": "Brazillian Portuguese",
"Polish": "Polish"
},
"OpenMobileApp": "Öppna Mobil App"
"OpenMobileApp": "Öppna Mobil App",
"RecentlyAdded": "Recently Added"
},
"Search": {
"Title": "Sök",
@ -113,6 +116,7 @@
"RequestStatus": "Status för efterfrågan:",
"Denied": " Nekad:",
"TheatricalRelease": "Theatrical Release: {{date}}",
"TheatricalReleaseSort": "Theatrical Release",
"DigitalRelease": "Digital Release: {{date}}",
"RequestDate": "Datum för efterfrågan:",
"QualityOverride": "Kvalité överskridande:",
@ -129,7 +133,14 @@
"GridStatus": "Status",
"ReportIssue": "Report Issue",
"Filter": "Filter",
"SeasonNumberHeading": "Season: {seasonNumber}"
"Sort": "Sort",
"SeasonNumberHeading": "Season: {seasonNumber}",
"SortTitleAsc": "Title ▲",
"SortTitleDesc": "Title ▼",
"SortRequestDateAsc": "Request Date ▲",
"SortRequestDateDesc": "Request Date ▼",
"SortStatusAsc": "Status ▲",
"SortStatusDesc": "Status ▼"
},
"Issues": {
"Title": "Problem",
@ -154,6 +165,7 @@
"ClearFilter": "Clear Filter",
"FilterHeaderAvailability": "Availability",
"FilterHeaderRequestStatus": "Status",
"Approved": "Approved"
"Approved": "Approved",
"PendingApproval": "Pending Approval"
}
}
Loading…
Cancel
Save