mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-07 21:51:13 -07:00
Fixed the issue of it showing as not requested when we find it in Radarr.
Made the tv shows match a bit more to the movie requests Added the ability for plex and emby users to login Improved the welcome email, will only show for users that have not logged in Fixed discord notifications the about screen now checks if there is an update ready #1513
This commit is contained in:
parent
9556ed1b34
commit
057683d97a
32 changed files with 1039 additions and 108 deletions
|
@ -11,12 +11,12 @@ namespace Ombi.Api.Discord
|
||||||
Api = api;
|
Api = api;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string Endpoint => "https://discordapp.com/api/";
|
private const string BaseUrl = "https://discordapp.com/api/";
|
||||||
private IApi Api { get; }
|
private IApi Api { get; }
|
||||||
|
|
||||||
public async Task SendMessage(DiscordWebhookBody body, string webhookId, string webhookToken)
|
public async Task SendMessage(DiscordWebhookBody body, string webhookId, string webhookToken)
|
||||||
{
|
{
|
||||||
var request = new Request(Endpoint, $"webhooks/{webhookId}/{webhookToken}", HttpMethod.Post);
|
var request = new Request($"webhooks/{webhookId}/{webhookToken}", BaseUrl, HttpMethod.Post);
|
||||||
|
|
||||||
request.AddJsonBody(body);
|
request.AddJsonBody(body);
|
||||||
|
|
||||||
|
|
124
src/Ombi.Core/Authentication/OmbiUserManager.cs
Normal file
124
src/Ombi.Core/Authentication/OmbiUserManager.cs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: OmbiUserManager.cs
|
||||||
|
// Created By: Jamie Rees
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
// ************************************************************************/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Ombi.Api.Emby;
|
||||||
|
using Ombi.Api.Plex;
|
||||||
|
using Ombi.Api.Plex.Models;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Core.Settings.Models.External;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
|
||||||
|
namespace Ombi.Core.Authentication
|
||||||
|
{
|
||||||
|
public class OmbiUserManager : UserManager<OmbiUser>
|
||||||
|
{
|
||||||
|
public OmbiUserManager(IUserStore<OmbiUser> store, IOptions<IdentityOptions> optionsAccessor,
|
||||||
|
IPasswordHasher<OmbiUser> passwordHasher, IEnumerable<IUserValidator<OmbiUser>> userValidators,
|
||||||
|
IEnumerable<IPasswordValidator<OmbiUser>> passwordValidators, ILookupNormalizer keyNormalizer,
|
||||||
|
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<OmbiUser>> logger, IPlexApi plexApi,
|
||||||
|
IEmbyApi embyApi, ISettingsService<EmbySettings> embySettings)
|
||||||
|
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
|
||||||
|
{
|
||||||
|
_plexApi = plexApi;
|
||||||
|
_embyApi = embyApi;
|
||||||
|
_embySettings = embySettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IPlexApi _plexApi;
|
||||||
|
private readonly IEmbyApi _embyApi;
|
||||||
|
private readonly ISettingsService<EmbySettings> _embySettings;
|
||||||
|
|
||||||
|
public override async Task<bool> CheckPasswordAsync(OmbiUser user, string password)
|
||||||
|
{
|
||||||
|
if (user.UserType == UserType.LocalUser)
|
||||||
|
{
|
||||||
|
return await base.CheckPasswordAsync(user, password);
|
||||||
|
}
|
||||||
|
if (user.UserType == UserType.PlexUser)
|
||||||
|
{
|
||||||
|
return await CheckPlexPasswordAsync(user, password);
|
||||||
|
}
|
||||||
|
if (user.UserType == UserType.EmbyUser)
|
||||||
|
{
|
||||||
|
return await CheckEmbyPasswordAsync(user, password);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sign the user into plex and make sure we can get the authentication token.
|
||||||
|
/// <remarks>We do not check if the user is in the owners "friends" since they must have a local user account to get this far</remarks>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="password"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> CheckPlexPasswordAsync(OmbiUser user, string password)
|
||||||
|
{
|
||||||
|
var result = await _plexApi.SignIn(new UserRequest { password = password, login = user.UserName });
|
||||||
|
if (result.user?.authentication_token != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sign the user into Emby
|
||||||
|
/// <remarks>We do not check if the user is in the owners "friends" since they must have a local user account to get this far.
|
||||||
|
/// We also have to try and authenticate them with every server, the first server that work we just say it was a success</remarks>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="password"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> CheckEmbyPasswordAsync(OmbiUser user, string password)
|
||||||
|
{
|
||||||
|
var embySettings = await _embySettings.GetSettingsAsync();
|
||||||
|
foreach (var server in embySettings.Servers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _embyApi.LogIn(user.UserName, password, server.ApiKey, server.FullUri);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(e, "Emby Login Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ using Ombi.Store.Repository;
|
||||||
using Ombi.Store.Repository.Requests;
|
using Ombi.Store.Repository.Requests;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ namespace Ombi.Core.Engine
|
||||||
private Dictionary<int, TvRequests> _dbTv;
|
private Dictionary<int, TvRequests> _dbTv;
|
||||||
|
|
||||||
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
|
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
|
||||||
IRuleEvaluator rules, UserManager<OmbiUser> um) : base(identity, um, rules)
|
IRuleEvaluator rules, OmbiUserManager um) : base(identity, um, rules)
|
||||||
{
|
{
|
||||||
RequestService = requestService;
|
RequestService = requestService;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,13 @@ using Ombi.Store.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.Interfaces
|
namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
public abstract class BaseEngine
|
public abstract class BaseEngine
|
||||||
{
|
{
|
||||||
protected BaseEngine(IPrincipal user, UserManager<OmbiUser> um, IRuleEvaluator rules)
|
protected BaseEngine(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules)
|
||||||
{
|
{
|
||||||
UserPrinciple = user;
|
UserPrinciple = user;
|
||||||
Rules = rules;
|
Rules = rules;
|
||||||
|
@ -23,7 +24,7 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
|
|
||||||
protected IPrincipal UserPrinciple { get; }
|
protected IPrincipal UserPrinciple { get; }
|
||||||
protected IRuleEvaluator Rules { get; }
|
protected IRuleEvaluator Rules { get; }
|
||||||
protected UserManager<OmbiUser> UserManager { get; }
|
protected OmbiUserManager UserManager { get; }
|
||||||
protected string Username => UserPrinciple.Identity.Name;
|
protected string Username => UserPrinciple.Identity.Name;
|
||||||
|
|
||||||
private OmbiUser _user;
|
private OmbiUser _user;
|
||||||
|
|
|
@ -12,6 +12,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Engine.Interfaces;
|
using Ombi.Core.Engine.Interfaces;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
|
@ -22,7 +23,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
|
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
|
||||||
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
|
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
|
||||||
UserManager<OmbiUser> manager) : base(user, requestService, r, manager)
|
OmbiUserManager manager) : base(user, requestService, r, manager)
|
||||||
{
|
{
|
||||||
MovieApi = movieApi;
|
MovieApi = movieApi;
|
||||||
NotificationHelper = helper;
|
NotificationHelper = helper;
|
||||||
|
|
|
@ -15,13 +15,14 @@ using Ombi.Core.Rule.Interfaces;
|
||||||
using StackExchange.Profiling;
|
using StackExchange.Profiling;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
|
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
|
||||||
{
|
{
|
||||||
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
||||||
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, UserManager<OmbiUser> um)
|
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um)
|
||||||
: base(identity, service, r, um)
|
: base(identity, service, r, um)
|
||||||
{
|
{
|
||||||
MovieApi = movApi;
|
MovieApi = movApi;
|
||||||
|
|
|
@ -11,6 +11,7 @@ using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Engine.Interfaces;
|
using Ombi.Core.Engine.Interfaces;
|
||||||
using Ombi.Core.Helpers;
|
using Ombi.Core.Helpers;
|
||||||
using Ombi.Core.Rule;
|
using Ombi.Core.Rule;
|
||||||
|
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
|
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
|
||||||
INotificationHelper helper, IMapper map,
|
INotificationHelper helper, IMapper map,
|
||||||
IRuleEvaluator rule, UserManager<OmbiUser> manager,
|
IRuleEvaluator rule, OmbiUserManager manager,
|
||||||
ITvSender sender, IAuditRepository audit) : base(user, requestService, rule, manager)
|
ITvSender sender, IAuditRepository audit) : base(user, requestService, rule, manager)
|
||||||
{
|
{
|
||||||
TvApi = tvApi;
|
TvApi = tvApi;
|
||||||
|
|
|
@ -20,13 +20,14 @@ using Ombi.Store.Repository.Requests;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine
|
public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine
|
||||||
{
|
{
|
||||||
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
|
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
|
||||||
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, UserManager<OmbiUser> um)
|
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um)
|
||||||
: base(identity, service, r, um)
|
: base(identity, service, r, um)
|
||||||
{
|
{
|
||||||
TvMazeApi = tvMaze;
|
TvMazeApi = tvMaze;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ombi.Core.Models.UI
|
namespace Ombi.Core.Models.UI
|
||||||
{
|
{
|
||||||
|
@ -10,7 +11,8 @@ namespace Ombi.Core.Models.UI
|
||||||
public List<ClaimCheckboxes> Claims { get; set; }
|
public List<ClaimCheckboxes> Claims { get; set; }
|
||||||
public string EmailAddress { get; set; }
|
public string EmailAddress { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
public bool IsSetup { get; set; }
|
public DateTime? LastLoggedIn { get; set; }
|
||||||
|
public bool HasLoggedIn { get; set; }
|
||||||
public UserType UserType { get; set; }
|
public UserType UserType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -53,10 +54,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
var users = await _api.GetUsers(server.PlexAuthToken);
|
var users = await _api.GetUsers(server.PlexAuthToken);
|
||||||
|
|
||||||
foreach (var plexUsers in users.User)
|
foreach (var plexUser in users.User)
|
||||||
{
|
{
|
||||||
// Check if we should import this user
|
// Check if we should import this user
|
||||||
if (userManagementSettings.BannedPlexUserIds.Contains(plexUsers.Id))
|
if (userManagementSettings.BannedPlexUserIds.Contains(plexUser.Id))
|
||||||
{
|
{
|
||||||
// Do not import these, they are not allowed into the country.
|
// Do not import these, they are not allowed into the country.
|
||||||
continue;
|
continue;
|
||||||
|
@ -64,7 +65,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
|
|
||||||
// Check if this Plex User already exists
|
// Check if this Plex User already exists
|
||||||
// We are using the Plex USERNAME and Not the TITLE, the Title is for HOME USERS
|
// We are using the Plex USERNAME and Not the TITLE, the Title is for HOME USERS
|
||||||
var existingPlexUser = allUsers.FirstOrDefault(x => x.ProviderUserId == plexUsers.Id);
|
var existingPlexUser = allUsers.FirstOrDefault(x => x.ProviderUserId == plexUser.Id);
|
||||||
if (existingPlexUser == null)
|
if (existingPlexUser == null)
|
||||||
{
|
{
|
||||||
// Create this users
|
// Create this users
|
||||||
|
@ -72,9 +73,9 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
var newUser = new OmbiUser
|
var newUser = new OmbiUser
|
||||||
{
|
{
|
||||||
UserType = UserType.PlexUser,
|
UserType = UserType.PlexUser,
|
||||||
UserName = plexUsers.Username,
|
UserName = plexUser.Username,
|
||||||
ProviderUserId = plexUsers.Id,
|
ProviderUserId = plexUser.Id,
|
||||||
Email = plexUsers.Email,
|
Email = plexUser.Email,
|
||||||
Alias = string.Empty
|
Alias = string.Empty
|
||||||
};
|
};
|
||||||
var result = await _userManager.CreateAsync(newUser);
|
var result = await _userManager.CreateAsync(newUser);
|
||||||
|
@ -97,6 +98,10 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Do we need to update this user?
|
// Do we need to update this user?
|
||||||
|
existingPlexUser.Email = plexUser.Email;
|
||||||
|
existingPlexUser.UserName = plexUser.Username;
|
||||||
|
|
||||||
|
await _userManager.UpdateAsync(existingPlexUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,13 +100,13 @@ namespace Ombi.Store.Context
|
||||||
|
|
||||||
foreach (var agent in allAgents)
|
foreach (var agent in allAgents)
|
||||||
{
|
{
|
||||||
if (templates.Any(x => x.Agent == agent))
|
|
||||||
{
|
|
||||||
// We have all the templates for this notification agent
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (var notificationType in allTypes)
|
foreach (var notificationType in allTypes)
|
||||||
{
|
{
|
||||||
|
if (templates.Any(x => x.Agent == agent && x.NotificationType == notificationType))
|
||||||
|
{
|
||||||
|
// We already have this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
NotificationTemplates notificationToAdd;
|
NotificationTemplates notificationToAdd;
|
||||||
switch (notificationType)
|
switch (notificationType)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace Ombi.Store.Entities
|
namespace Ombi.Store.Entities
|
||||||
|
@ -7,11 +8,14 @@ namespace Ombi.Store.Entities
|
||||||
{
|
{
|
||||||
public string Alias { get; set; }
|
public string Alias { get; set; }
|
||||||
public UserType UserType { get; set; }
|
public UserType UserType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This will be the unique Plex/Emby user id reference
|
/// This will be the unique Plex/Emby user id reference
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ProviderUserId { get; set; }
|
public string ProviderUserId { get; set; }
|
||||||
|
|
||||||
|
public DateTime? LastLoggedIn { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string UserAlias => string.IsNullOrEmpty(Alias) ? UserName : Alias;
|
public string UserAlias => string.IsNullOrEmpty(Alias) ? UserName : Alias;
|
||||||
}
|
}
|
||||||
|
|
731
src/Ombi.Store/Migrations/20170928150420_LastLoggedIn.Designer.cs
generated
Normal file
731
src/Ombi.Store/Migrations/20170928150420_LastLoggedIn.Designer.cs
generated
Normal file
|
@ -0,0 +1,731 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Store.Context;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(OmbiContext))]
|
||||||
|
[Migration("20170928150420_LastLoggedIn")]
|
||||||
|
partial class LastLoggedIn
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<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.EmbyContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
|
b.Property<string>("EmbyId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
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>("ParentId");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
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.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<DateTime?>("LastLoggedIn");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
||||||
|
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>("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.PlexContent", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime>("AddedAt");
|
||||||
|
|
||||||
|
b.Property<int>("Key");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderId");
|
||||||
|
|
||||||
|
b.Property<string>("Quality");
|
||||||
|
|
||||||
|
b.Property<string>("ReleaseYear");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<string>("Url");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("PlexContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
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>("SeasonKey");
|
||||||
|
|
||||||
|
b.Property<int>("SeasonNumber");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PlexContentId");
|
||||||
|
|
||||||
|
b.ToTable("PlexSeasonsContent");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("TheMovieDbId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RadarrCache");
|
||||||
|
});
|
||||||
|
|
||||||
|
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<int>("ParentRequestId");
|
||||||
|
|
||||||
|
b.Property<int>("RequestType");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RequestedDate");
|
||||||
|
|
||||||
|
b.Property<string>("RequestedUserId");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ParentRequestId");
|
||||||
|
|
||||||
|
b.HasIndex("RequestedUserId");
|
||||||
|
|
||||||
|
b.ToTable("ChildRequests");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Description");
|
||||||
|
|
||||||
|
b.Property<int?>("IssueId");
|
||||||
|
|
||||||
|
b.Property<int>("MovieId");
|
||||||
|
|
||||||
|
b.Property<string>("Subect");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IssueId");
|
||||||
|
|
||||||
|
b.HasIndex("MovieId");
|
||||||
|
|
||||||
|
b.ToTable("MovieIssues");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Approved");
|
||||||
|
|
||||||
|
b.Property<bool>("Available");
|
||||||
|
|
||||||
|
b.Property<bool?>("Denied");
|
||||||
|
|
||||||
|
b.Property<string>("DeniedReason");
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId");
|
||||||
|
|
||||||
|
b.Property<int?>("IssueId");
|
||||||
|
|
||||||
|
b.Property<string>("Overview");
|
||||||
|
|
||||||
|
b.Property<string>("PosterPath");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReleaseDate");
|
||||||
|
|
||||||
|
b.Property<int>("RequestType");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RequestedDate");
|
||||||
|
|
||||||
|
b.Property<string>("RequestedUserId");
|
||||||
|
|
||||||
|
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.TvIssues", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Description");
|
||||||
|
|
||||||
|
b.Property<int?>("IssueId");
|
||||||
|
|
||||||
|
b.Property<string>("Subect");
|
||||||
|
|
||||||
|
b.Property<int>("TvId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IssueId");
|
||||||
|
|
||||||
|
b.HasIndex("TvId");
|
||||||
|
|
||||||
|
b.ToTable("TvIssues");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("ImdbId");
|
||||||
|
|
||||||
|
b.Property<string>("Overview");
|
||||||
|
|
||||||
|
b.Property<string>("PosterPath");
|
||||||
|
|
||||||
|
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.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.PlexEpisode", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexContent", "Series")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("GrandparentKey")
|
||||||
|
.HasPrincipalKey("Key")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.PlexContent")
|
||||||
|
.WithMany("Seasons")
|
||||||
|
.HasForeignKey("PlexContentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||||
|
.WithMany("ChildRequests")
|
||||||
|
.HasForeignKey("ParentRequestId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RequestedUserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||||
|
.WithMany("Issues")
|
||||||
|
.HasForeignKey("IssueId");
|
||||||
|
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests", "Movie")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("MovieId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RequestedUserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||||
|
.WithMany("Issues")
|
||||||
|
.HasForeignKey("IssueId");
|
||||||
|
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "Child")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TvId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||||
|
.WithMany("Episodes")
|
||||||
|
.HasForeignKey("SeasonId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||||
|
.WithMany("SeasonRequests")
|
||||||
|
.HasForeignKey("ChildRequestId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/Ombi.Store/Migrations/20170928150420_LastLoggedIn.cs
Normal file
25
src/Ombi.Store/Migrations/20170928150420_LastLoggedIn.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ombi.Store.Migrations
|
||||||
|
{
|
||||||
|
public partial class LastLoggedIn : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastLoggedIn",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastLoggedIn",
|
||||||
|
table: "AspNetUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -260,6 +260,8 @@ namespace Ombi.Store.Migrations
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed");
|
b.Property<bool>("EmailConfirmed");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastLoggedIn");
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled");
|
b.Property<bool>("LockoutEnabled");
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||||
|
|
|
@ -8,7 +8,8 @@ export interface IUser {
|
||||||
emailAddress: string;
|
emailAddress: string;
|
||||||
password: string;
|
password: string;
|
||||||
userType: UserType;
|
userType: UserType;
|
||||||
isSetup: boolean;
|
lastLoggedIn: Date;
|
||||||
|
hasLoggedIn: boolean;
|
||||||
// FOR UI
|
// FOR UI
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
<ng-template [ngIf]="result.available"><span class="label label-success">Available</span></ng-template>
|
<ng-template [ngIf]="result.available"><span class="label label-success">Available</span></ng-template>
|
||||||
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info">Processing Request</span></ng-template>
|
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info">Processing Request</span></ng-template>
|
||||||
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning">Pending Approval</span></ng-template>
|
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning">Pending Approval</span></ng-template>
|
||||||
<ng-template [ngIf]="!result.requested && !result.available"><span class="label label-danger">Not Requested</span></ng-template>
|
<ng-template [ngIf]="!result.requested && !result.available && !result.approved"><span class="label label-danger">Not Requested</span></ng-template>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<span>Version</span>
|
<span>Version</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span>{{about.version}}</span>
|
<span>{{about.version}} <a [routerLink]="['/Settings/Update']" *ngIf="newUpdate" style="color:#df691a"><b>(New Update Available)</b></a></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { IAbout } from "../../interfaces/ISettings";
|
import { IAbout } from "../../interfaces/ISettings";
|
||||||
import { SettingsService } from "../../services";
|
import { JobService, SettingsService } from "../../services";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./about.component.html",
|
templateUrl: "./about.component.html",
|
||||||
|
@ -8,10 +8,18 @@ import { SettingsService } from "../../services";
|
||||||
export class AboutComponent implements OnInit {
|
export class AboutComponent implements OnInit {
|
||||||
|
|
||||||
public about: IAbout;
|
public about: IAbout;
|
||||||
|
public newUpdate: boolean;
|
||||||
|
|
||||||
constructor(private settingsService: SettingsService) { }
|
constructor(private readonly settingsService: SettingsService,
|
||||||
|
private readonly jobService: JobService) { }
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {
|
||||||
this.settingsService.about().subscribe(x => this.about = x);
|
this.settingsService.about().subscribe(x => this.about = x);
|
||||||
|
this.jobService.checkForNewUpdate().subscribe(x => {
|
||||||
|
if (x === true) {
|
||||||
|
this.newUpdate = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ export class RadarrComponent implements OnInit {
|
||||||
}
|
}
|
||||||
const settings = <IRadarrSettings>form.value;
|
const settings = <IRadarrSettings>form.value;
|
||||||
this.testerService.radarrTest(settings).subscribe(x => {
|
this.testerService.radarrTest(settings).subscribe(x => {
|
||||||
if (x) {
|
if (x === true) {
|
||||||
this.notificationService.success("Connected", "Successfully connected to Radarr!");
|
this.notificationService.success("Connected", "Successfully connected to Radarr!");
|
||||||
} else {
|
} else {
|
||||||
this.notificationService.error("Connected", "We could not connect to Radarr!");
|
this.notificationService.error("Connected", "We could not connect to Radarr!");
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<input type="checkbox" id="importEmbyUsers" [(ngModel)]="settings.importPlexUsers">
|
<input type="checkbox" id="importEmbyUsers" [(ngModel)]="settings.importEmbyUsers">
|
||||||
<label for="importEmbyUsers">Import Emby Users</label>
|
<label for="importEmbyUsers">Import Emby Users</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,8 @@ export class UserManagementAddComponent implements OnInit {
|
||||||
username: "",
|
username: "",
|
||||||
userType: UserType.LocalUser,
|
userType: UserType.LocalUser,
|
||||||
checked:false,
|
checked:false,
|
||||||
isSetup:false,
|
hasLoggedIn: false,
|
||||||
|
lastLoggedIn:new Date(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="alias" class="control-label">Email Address</label>
|
<label for="alias" class="control-label">Email Address</label>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}">
|
<input type="text" [(ngModel)]="user.emailAddress" class="form-control form-control-custom " id="emailAddress" name="emailAddress" value="{{user?.emailAddress}}" [disabled]="user?.userType != 1">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class UserManagementEditComponent {
|
||||||
private notificationSerivce: NotificationService,
|
private notificationSerivce: NotificationService,
|
||||||
private router: Router) {
|
private router: Router) {
|
||||||
this.route.params
|
this.route.params
|
||||||
.subscribe(params => {
|
.subscribe((params: any) => {
|
||||||
this.userId = params.id;
|
this.userId = params.id;
|
||||||
|
|
||||||
this.identityService.getUserById(this.userId).subscribe(x => {
|
this.identityService.getUserById(this.userId).subscribe(x => {
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
<th>
|
<th>
|
||||||
Roles
|
Roles
|
||||||
</th>
|
</th>
|
||||||
|
<th>
|
||||||
|
Last Logged In
|
||||||
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<a>
|
<a>
|
||||||
User Type
|
User Type
|
||||||
|
@ -74,6 +77,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{u.lastLoggedIn | date: 'short'}}
|
||||||
|
</td>
|
||||||
<td ng-hide="hideColumns">
|
<td ng-hide="hideColumns">
|
||||||
<span *ngIf="u.userType === 1">Local User</span>
|
<span *ngIf="u.userType === 1">Local User</span>
|
||||||
<span *ngIf="u.userType === 2">Plex User</span>
|
<span *ngIf="u.userType === 2">Plex User</span>
|
||||||
|
@ -83,7 +89,7 @@
|
||||||
<a [routerLink]="['/usermanagement/edit/' + u.id]" class="btn btn-sm btn-info-outline">Details/Edit</a>
|
<a [routerLink]="['/usermanagement/edit/' + u.id]" class="btn btn-sm btn-info-outline">Details/Edit</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a *ngIf="!u.isSetup" (click)="welcomeEmail(u)" class="btn btn-sm btn-info-outline">Send Welcome Email</a>
|
<button *ngIf="!u.hasLoggedIn" (click)="welcomeEmail(u)" [disabled]="!customizationSettings.applicationUrl" class="btn btn-sm btn-info-outline">Send Welcome Email</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
|
||||||
import { IEmailNotificationSettings, IUser } from "../interfaces";
|
import { ICustomizationSettings, IEmailNotificationSettings, IUser } from "../interfaces";
|
||||||
import { IdentityService, NotificationService, SettingsService } from "../services";
|
import { IdentityService, NotificationService, SettingsService } from "../services";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -11,10 +11,11 @@ export class UserManagementComponent implements OnInit {
|
||||||
public users: IUser[];
|
public users: IUser[];
|
||||||
public checkAll = false;
|
public checkAll = false;
|
||||||
public emailSettings: IEmailNotificationSettings;
|
public emailSettings: IEmailNotificationSettings;
|
||||||
|
public customizationSettings: ICustomizationSettings;
|
||||||
|
|
||||||
constructor(private identityService: IdentityService,
|
constructor(private readonly identityService: IdentityService,
|
||||||
private settingsService: SettingsService,
|
private readonly settingsService: SettingsService,
|
||||||
private notificationService: NotificationService) { }
|
private readonly notificationService: NotificationService) { }
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {
|
||||||
this.users = [];
|
this.users = [];
|
||||||
|
@ -22,6 +23,7 @@ export class UserManagementComponent implements OnInit {
|
||||||
this.users = x;
|
this.users = x;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||||
this.settingsService.getEmailNotificationSettings().subscribe(x => this.emailSettings = x);
|
this.settingsService.getEmailNotificationSettings().subscribe(x => this.emailSettings = x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,20 +97,20 @@ label {
|
||||||
margin-bottom: .5rem $i;
|
margin-bottom: .5rem $i;
|
||||||
font-size: 16px $i;
|
font-size: 16px $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-label {
|
.small-label {
|
||||||
display: inline-block $i;
|
display: inline-block $i;
|
||||||
margin-bottom: .5rem $i;
|
margin-bottom: .5rem $i;
|
||||||
font-size: 11px $i;
|
font-size: 11px $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-checkbox{
|
.small-checkbox {
|
||||||
min-height:0 $i;
|
min-height: 0 $i;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.round-checkbox {
|
.round-checkbox {
|
||||||
border-radius:8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs > li {
|
.nav-tabs > li {
|
||||||
|
@ -428,7 +428,7 @@ $border-radius: 10px;
|
||||||
bottom: 1px;
|
bottom: 1px;
|
||||||
border: 2px solid #eee;
|
border: 2px solid #eee;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
min-height:0px $i;
|
min-height: 0px $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-checkbox input[type=checkbox] {
|
.small-checkbox input[type=checkbox] {
|
||||||
|
@ -444,11 +444,11 @@ $border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-checkbox label {
|
.small-checkbox label {
|
||||||
min-height: 0 $i;
|
min-height: 0 $i;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group-sm {
|
.input-group-sm {
|
||||||
|
@ -517,6 +517,7 @@ $border-radius: 10px;
|
||||||
-webkit-box-shadow: 3px 3px 5px 6px #191919;
|
-webkit-box-shadow: 3px 3px 5px 6px #191919;
|
||||||
box-shadow: 3px 3px 5px 6px #191919;
|
box-shadow: 3px 3px 5px 6px #191919;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-circle {
|
.img-circle {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +543,7 @@ $border-radius: 10px;
|
||||||
margin-right: -250px;
|
margin-right: -250px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: #4e5d6c;
|
background: #4e5d6c;
|
||||||
padding-left:0;
|
padding-left: 0;
|
||||||
-webkit-transition: all 0.5s ease;
|
-webkit-transition: all 0.5s ease;
|
||||||
-moz-transition: all 0.5s ease;
|
-moz-transition: all 0.5s ease;
|
||||||
-o-transition: all 0.5s ease;
|
-o-transition: all 0.5s ease;
|
||||||
|
@ -641,61 +642,60 @@ $border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lightbox {
|
#lightbox {
|
||||||
|
|
||||||
background-color: grey;
|
background-color: grey;
|
||||||
filter:alpha(opacity=50); /* IE */
|
filter: alpha(opacity=50); /* IE */
|
||||||
opacity: 0.5; /* Safari, Opera */
|
opacity: 0.5; /* Safari, Opera */
|
||||||
-moz-opacity:0.50; /* FireFox */
|
-moz-opacity: 0.50; /* FireFox */
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-repeat:no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position:center;
|
background-position: center;
|
||||||
position:absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.list-group-item-dropdown {
|
.list-group-item-dropdown {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
background-color: #3e3e3e;
|
background-color: #3e3e3e;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wizard-heading{
|
.wizard-heading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.wizard-img{
|
|
||||||
|
.wizard-img {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
display: block $i;
|
display: block $i;
|
||||||
margin: 0 auto $i;
|
margin: 0 auto $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pace {
|
.pace {
|
||||||
-webkit-pointer-events: none;
|
-webkit-pointer-events: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
-webkit-user-select: none;
|
-moz-user-select: none;
|
||||||
-moz-user-select: none;
|
user-select: none;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pace-inactive {
|
.pace-inactive {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pace .pace-progress {
|
.pace .pace-progress {
|
||||||
background: $primary-colour;
|
background: $primary-colour;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 100%;
|
right: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-brand {
|
.navbar-brand {
|
||||||
|
@ -705,8 +705,8 @@ $border-radius: 10px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gravatar{
|
.gravatar {
|
||||||
border-radius:1em;
|
border-radius: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -716,6 +716,7 @@ html {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -727,6 +728,7 @@ body {
|
||||||
.ui-datatable-odd {
|
.ui-datatable-odd {
|
||||||
background-color: $form-color $i;
|
background-color: $form-color $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-datatable-even {
|
.ui-datatable-even {
|
||||||
background-color: $form-color-lighter $i;
|
background-color: $form-color-lighter $i;
|
||||||
}
|
}
|
||||||
|
@ -742,8 +744,9 @@ body {
|
||||||
border-bottom: 1px solid transparent;
|
border-bottom: 1px solid transparent;
|
||||||
background: $form-color;
|
background: $form-color;
|
||||||
}
|
}
|
||||||
.card-header > a{
|
|
||||||
color:white;
|
.card-header > a {
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -776,9 +779,10 @@ textarea {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-state-default.ui-unselectable-text{
|
.ui-state-default.ui-unselectable-text {
|
||||||
display:none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-treetable-toggler.fa.fa-fw.ui-clickable.fa-caret-right,
|
.ui-treetable-toggler.fa.fa-fw.ui-clickable.fa-caret-right,
|
||||||
.ui-treetable-toggler.fa.fa-fw.ui-clickable.fa-caret-down {
|
.ui-treetable-toggler.fa.fa-fw.ui-clickable.fa-caret-down {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -795,6 +799,20 @@ textarea {
|
||||||
.ui-state-default {
|
.ui-state-default {
|
||||||
border: 1px solid $form-color-lighter;
|
border: 1px solid $form-color-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-treetable tbody td {
|
.ui-treetable tbody td {
|
||||||
white-space:inherit;
|
white-space: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
table a:not(.btn) {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a > h4 {
|
||||||
|
color: #df691a;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a > h4:hover {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
using Ombi.Attributes;
|
using Ombi.Attributes;
|
||||||
using Ombi.Config;
|
using Ombi.Config;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Claims;
|
using Ombi.Core.Claims;
|
||||||
using Ombi.Core.Helpers;
|
using Ombi.Core.Helpers;
|
||||||
using Ombi.Core.Models.UI;
|
using Ombi.Core.Models.UI;
|
||||||
|
@ -41,7 +42,7 @@ namespace Ombi.Controllers
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
public class IdentityController : Controller
|
public class IdentityController : Controller
|
||||||
{
|
{
|
||||||
public IdentityController(UserManager<OmbiUser> user, IMapper mapper, RoleManager<IdentityRole> rm, IEmailProvider prov,
|
public IdentityController(OmbiUserManager user, IMapper mapper, RoleManager<IdentityRole> rm, IEmailProvider prov,
|
||||||
ISettingsService<EmailNotificationSettings> s,
|
ISettingsService<EmailNotificationSettings> s,
|
||||||
ISettingsService<CustomizationSettings> c,
|
ISettingsService<CustomizationSettings> c,
|
||||||
IOptions<UserSettings> userSettings,
|
IOptions<UserSettings> userSettings,
|
||||||
|
@ -57,7 +58,7 @@ namespace Ombi.Controllers
|
||||||
WelcomeEmail = welcome;
|
WelcomeEmail = welcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserManager<OmbiUser> UserManager { get; }
|
private OmbiUserManager UserManager { get; }
|
||||||
private RoleManager<IdentityRole> RoleManager { get; }
|
private RoleManager<IdentityRole> RoleManager { get; }
|
||||||
private IMapper Mapper { get; }
|
private IMapper Mapper { get; }
|
||||||
private IEmailProvider EmailProvider { get; }
|
private IEmailProvider EmailProvider { get; }
|
||||||
|
@ -178,7 +179,8 @@ namespace Ombi.Controllers
|
||||||
EmailAddress = user.Email,
|
EmailAddress = user.Email,
|
||||||
UserType = (Core.Models.UserType)(int)user.UserType,
|
UserType = (Core.Models.UserType)(int)user.UserType,
|
||||||
Claims = new List<ClaimCheckboxes>(),
|
Claims = new List<ClaimCheckboxes>(),
|
||||||
IsSetup = !string.IsNullOrEmpty(user.PasswordHash)
|
LastLoggedIn = user.LastLoggedIn,
|
||||||
|
HasLoggedIn = user.LastLoggedIn.HasValue
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var role in userRoles)
|
foreach (var role in userRoles)
|
||||||
|
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Claims;
|
using Ombi.Core.Claims;
|
||||||
using Ombi.Models;
|
using Ombi.Models;
|
||||||
using Ombi.Models.Identity;
|
using Ombi.Models.Identity;
|
||||||
|
@ -21,7 +22,7 @@ namespace Ombi.Controllers
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
public class TokenController
|
public class TokenController
|
||||||
{
|
{
|
||||||
public TokenController(UserManager<OmbiUser> um, IOptions<TokenAuthentication> ta,
|
public TokenController(OmbiUserManager um, IOptions<TokenAuthentication> ta,
|
||||||
IApplicationConfigRepository config, IAuditRepository audit, ITokenRepository token)
|
IApplicationConfigRepository config, IAuditRepository audit, ITokenRepository token)
|
||||||
{
|
{
|
||||||
_userManager = um;
|
_userManager = um;
|
||||||
|
@ -35,7 +36,7 @@ namespace Ombi.Controllers
|
||||||
private IApplicationConfigRepository _config;
|
private IApplicationConfigRepository _config;
|
||||||
private readonly IAuditRepository _audit;
|
private readonly IAuditRepository _audit;
|
||||||
private readonly ITokenRepository _token;
|
private readonly ITokenRepository _token;
|
||||||
private readonly UserManager<OmbiUser> _userManager;
|
private readonly OmbiUserManager _userManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the token.
|
/// Gets the token.
|
||||||
|
@ -65,6 +66,9 @@ namespace Ombi.Controllers
|
||||||
return new UnauthorizedResult();
|
return new UnauthorizedResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user.LastLoggedIn = DateTime.UtcNow;
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
|
||||||
var claims = new List<Claim>
|
var claims = new List<Claim>
|
||||||
{
|
{
|
||||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||||
|
|
|
@ -15,7 +15,6 @@ namespace Ombi
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
private static string UrlArgs { get; set; }
|
private static string UrlArgs { get; set; }
|
||||||
private static string WebRoot { get; set; }
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Console.Title = "Ombi";
|
Console.Title = "Ombi";
|
||||||
|
@ -26,16 +25,11 @@ namespace Ombi
|
||||||
.WithParsed(o =>
|
.WithParsed(o =>
|
||||||
{
|
{
|
||||||
host = o.Host;
|
host = o.Host;
|
||||||
WebRoot = Path.Combine(o.WebRoot, "wwwroot");
|
|
||||||
storagePath = o.StoragePath;
|
storagePath = o.StoragePath;
|
||||||
});
|
});
|
||||||
|
|
||||||
Console.WriteLine(HelpOutput(result));
|
Console.WriteLine(HelpOutput(result));
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(WebRoot))
|
|
||||||
{
|
|
||||||
WebRoot = Path.Combine(WebHost.CreateDefaultBuilder().GetSetting("contentRoot"), "wwwroot");
|
|
||||||
}
|
|
||||||
UrlArgs = host;
|
UrlArgs = host;
|
||||||
|
|
||||||
var urlValue = string.Empty;
|
var urlValue = string.Empty;
|
||||||
|
@ -73,7 +67,6 @@ namespace Ombi
|
||||||
.UseStartup<Startup>()
|
.UseStartup<Startup>()
|
||||||
.UseUrls(UrlArgs)
|
.UseUrls(UrlArgs)
|
||||||
.PreferHostingUrls(true)
|
.PreferHostingUrls(true)
|
||||||
.UseWebRoot(WebRoot)
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
private static string HelpOutput(ParserResult<Options> args)
|
private static string HelpOutput(ParserResult<Options> args)
|
||||||
|
@ -101,10 +94,5 @@ namespace Ombi
|
||||||
[Option('s', "storage", Required = false, HelpText = "Storage path, where we save the logs and database")]
|
[Option('s', "storage", Required = false, HelpText = "Storage path, where we save the logs and database")]
|
||||||
public string StoragePath { get; set; }
|
public string StoragePath { get; set; }
|
||||||
|
|
||||||
[Option('w', "webroot", Required = false,
|
|
||||||
HelpText = "(Root Path for Reverse Proxies) If not specified, the default is \"(Working Directory)\", if the path exists. If the path doesn\'t exist, then a no-op file provider is used."
|
|
||||||
,Default = "")]
|
|
||||||
public string WebRoot { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Ombi.Config;
|
using Ombi.Config;
|
||||||
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Claims;
|
using Ombi.Core.Claims;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.DependencyInjection;
|
using Ombi.DependencyInjection;
|
||||||
|
@ -85,7 +86,8 @@ namespace Ombi
|
||||||
|
|
||||||
services.AddIdentity<OmbiUser, IdentityRole>()
|
services.AddIdentity<OmbiUser, IdentityRole>()
|
||||||
.AddEntityFrameworkStores<OmbiContext>()
|
.AddEntityFrameworkStores<OmbiContext>()
|
||||||
.AddDefaultTokenProviders();
|
.AddDefaultTokenProviders()
|
||||||
|
.AddUserManager<OmbiUserManager>();
|
||||||
|
|
||||||
services.Configure<IdentityOptions>(options =>
|
services.Configure<IdentityOptions>(options =>
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue