From 143c619db0b4fa3b53ae7523e826fb8cd0ad7bfb Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 28 Sep 2017 21:24:31 +0100 Subject: [PATCH] Emby user importer is now therer! #1456 --- src/Ombi.DependencyInjection/IocExtensions.cs | 1 + src/Ombi.Helpers/LoggingEvents.cs | 1 + src/Ombi.Schedule/JobSetup.cs | 16 ++- .../Jobs/Emby/EmbyUserImporter.cs | 131 ++++++++++++++++++ .../Jobs/Emby/IEmbyUserImporter.cs | 9 ++ src/Ombi/ClientApp/app/interfaces/ICommon.ts | 5 + src/Ombi/ClientApp/app/interfaces/IPlex.ts | 5 - .../app/services/applications/emby.service.ts | 16 ++- .../app/services/applications/plex.service.ts | 4 +- .../app/settings/emby/emby.component.html | 2 +- .../usermanagement.component.html | 8 +- .../usermanagement.component.ts | 51 +++++-- .../Controllers/External/EmbyController.cs | 32 ++++- .../Controllers/External/PlexController.cs | 6 +- ...lexUsersViewModel.cs => UsersViewModel.cs} | 2 +- 15 files changed, 248 insertions(+), 41 deletions(-) create mode 100644 src/Ombi.Schedule/Jobs/Emby/EmbyUserImporter.cs create mode 100644 src/Ombi.Schedule/Jobs/Emby/IEmbyUserImporter.cs rename src/Ombi/Models/External/{PlexUsersViewModel.cs => UsersViewModel.cs} (78%) diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index b6f9f6108..1be7d1dc5 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -144,6 +144,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); } } diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 5a3947b3a..e4a349049 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -14,6 +14,7 @@ namespace Ombi.Helpers public static EventId PlexEpisodeCacher => new EventId(2001); public static EventId EmbyContentCacher => new EventId(2002); public static EventId PlexUserImporter => new EventId(2003); + public static EventId EmbyUserImporter => new EventId(2004); public static EventId MovieSender => new EventId(3000); diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index d00b9dbb5..6b13a10bb 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -10,13 +10,15 @@ namespace Ombi.Schedule public class JobSetup : IJobSetup { public JobSetup(IPlexContentCacher plexContentCacher, IRadarrCacher radarrCacher, - IOmbiAutomaticUpdater updater, IEmbyContentCacher embyCacher, IPlexUserImporter userImporter) + IOmbiAutomaticUpdater updater, IEmbyContentCacher embyCacher, IPlexUserImporter userImporter, + IEmbyUserImporter embyUserImporter) { PlexContentCacher = plexContentCacher; RadarrCacher = radarrCacher; Updater = updater; EmbyContentCacher = embyCacher; PlexUserImporter = userImporter; + EmbyUserImporter = embyUserImporter; } private IPlexContentCacher PlexContentCacher { get; } @@ -24,14 +26,16 @@ namespace Ombi.Schedule private IOmbiAutomaticUpdater Updater { get; } private IPlexUserImporter PlexUserImporter { get; } private IEmbyContentCacher EmbyContentCacher { get; } + private IEmbyUserImporter EmbyUserImporter { get; } public void Setup() { - RecurringJob.AddOrUpdate(() => PlexContentCacher.CacheContent(), Cron.Hourly); - RecurringJob.AddOrUpdate(() => EmbyContentCacher.Start(), Cron.Hourly); - RecurringJob.AddOrUpdate(() => RadarrCacher.CacheContent(), Cron.Hourly); - RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), Cron.Daily); - RecurringJob.AddOrUpdate(() => Updater.Update(null), Cron.Daily); + RecurringJob.AddOrUpdate(() => PlexContentCacher.CacheContent(), Cron.Hourly(20)); + RecurringJob.AddOrUpdate(() => EmbyContentCacher.Start(), Cron.Hourly(5)); + RecurringJob.AddOrUpdate(() => RadarrCacher.CacheContent(), Cron.Hourly(10)); + RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), Cron.Daily(1)); + RecurringJob.AddOrUpdate(() => EmbyUserImporter.Start(), Cron.Daily); + RecurringJob.AddOrUpdate(() => Updater.Update(null), Cron.Daily(3)); //BackgroundJob.Enqueue(() => PlexUserImporter.Start()); } diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyUserImporter.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyUserImporter.cs new file mode 100644 index 000000000..48bd3b293 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyUserImporter.cs @@ -0,0 +1,131 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: EmbyUserImporter.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.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Ombi.Api.Emby; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Helpers; +using Ombi.Settings.Settings.Models; +using Ombi.Store.Entities; + +namespace Ombi.Schedule.Jobs.Emby +{ + public class EmbyUserImporter : IEmbyUserImporter + { + public EmbyUserImporter(IEmbyApi api, UserManager um, ILogger log, + ISettingsService embySettings, ISettingsService ums) + { + _api = api; + _userManager = um; + _log = log; + _embySettings = embySettings; + _userManagementSettings = ums; + } + + private readonly IEmbyApi _api; + private readonly UserManager _userManager; + private readonly ILogger _log; + private readonly ISettingsService _embySettings; + private readonly ISettingsService _userManagementSettings; + + public async Task Start() + { + var userManagementSettings = await _userManagementSettings.GetSettingsAsync(); + if (!userManagementSettings.ImportEmbyUsers) + { + return; + } + var settings = await _embySettings.GetSettingsAsync(); + if (!settings.Enable) + { + return; + } + var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.EmbyUser).ToListAsync(); + foreach (var server in settings.Servers) + { + if (string.IsNullOrEmpty(server.ApiKey)) + { + continue; + } + + var embyUsers = await _api.GetUsers(server.FullUri, server.ApiKey); + foreach (var embyUser in embyUsers) + { + // Check if we should import this user + if (userManagementSettings.BannedEmbyUserIds.Contains(embyUser.Id)) + { + // Do not import these, they are not allowed into the country. + continue; + } + // Check if this Plex User already exists + // We are using the Plex USERNAME and Not the TITLE, the Title is for HOME USERS + var existingEmbyUser = allUsers.FirstOrDefault(x => x.ProviderUserId == embyUser.Id); + if (existingEmbyUser == null) + { + // Create this users + // We do not store a password against the user since they will authenticate via Plex + var newUser = new OmbiUser + { + UserType = UserType.EmbyUser, + UserName = embyUser.Name, + ProviderUserId = embyUser.Id, + Alias = string.Empty + }; + var result = await _userManager.CreateAsync(newUser); + if (!result.Succeeded) + { + foreach (var identityError in result.Errors) + { + _log.LogError(LoggingEvents.EmbyUserImporter, identityError.Description); + } + continue; + } + if (userManagementSettings.DefaultRoles.Any()) + { + foreach (var defaultRole in userManagementSettings.DefaultRoles) + { + await _userManager.AddToRoleAsync(newUser, defaultRole); + } + } + } + else + { + // Do we need to update this user? + existingEmbyUser.UserName = embyUser.Name; + + await _userManager.UpdateAsync(existingEmbyUser); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Emby/IEmbyUserImporter.cs b/src/Ombi.Schedule/Jobs/Emby/IEmbyUserImporter.cs new file mode 100644 index 000000000..595505f61 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Emby/IEmbyUserImporter.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Schedule.Jobs.Emby +{ + public interface IEmbyUserImporter + { + Task Start(); + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/interfaces/ICommon.ts b/src/Ombi/ClientApp/app/interfaces/ICommon.ts index 17a7f0546..c2e1e7e1d 100644 --- a/src/Ombi/ClientApp/app/interfaces/ICommon.ts +++ b/src/Ombi/ClientApp/app/interfaces/ICommon.ts @@ -21,3 +21,8 @@ export interface ICheckbox { value: string; enabled: boolean; } + +export interface IUsersModel { + id: string; + username: string; +} diff --git a/src/Ombi/ClientApp/app/interfaces/IPlex.ts b/src/Ombi/ClientApp/app/interfaces/IPlex.ts index 44bfc83d3..d8ce4ed06 100644 --- a/src/Ombi/ClientApp/app/interfaces/IPlex.ts +++ b/src/Ombi/ClientApp/app/interfaces/IPlex.ts @@ -20,11 +20,6 @@ export interface IPlexLibResponse { data: IPlexLibraries; } -export interface IPlexFriends { - id: string; - username: string; -} - export interface IMediaContainer { directory: IDirectory[]; } diff --git a/src/Ombi/ClientApp/app/services/applications/emby.service.ts b/src/Ombi/ClientApp/app/services/applications/emby.service.ts index 785352cc0..70d4cf5c7 100644 --- a/src/Ombi/ClientApp/app/services/applications/emby.service.ts +++ b/src/Ombi/ClientApp/app/services/applications/emby.service.ts @@ -1,19 +1,23 @@ import { Injectable } from "@angular/core"; -import { Http } from "@angular/http"; +import { Http } from "@angular/http"; +import { AuthHttp } from "angular2-jwt"; import { Observable } from "rxjs/Rx"; -import { ServiceHelpers } from "../service.helpers"; +import { ServiceAuthHelpers } from "../service.helpers"; -import { IEmbySettings } from "../../interfaces"; +import { IEmbySettings, IUsersModel } from "../../interfaces"; @Injectable() -export class EmbyService extends ServiceHelpers { - constructor(http: Http) { +export class EmbyService extends ServiceAuthHelpers { + constructor(http: AuthHttp, private regularHttp: Http) { super(http, "/api/v1/Emby/"); } public logIn(settings: IEmbySettings): Observable { - return this.http.post(`${this.url}`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + return this.regularHttp.post(`${this.url}`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + } + public getUsers(): Observable { + return this.http.get(`${this.url}users`, { headers: this.headers }).map(this.extractData); } } diff --git a/src/Ombi/ClientApp/app/services/applications/plex.service.ts b/src/Ombi/ClientApp/app/services/applications/plex.service.ts index 6711646f0..ea4e89230 100644 --- a/src/Ombi/ClientApp/app/services/applications/plex.service.ts +++ b/src/Ombi/ClientApp/app/services/applications/plex.service.ts @@ -6,7 +6,7 @@ import { Observable } from "rxjs/Rx"; import { ServiceAuthHelpers } from "../service.helpers"; -import { IPlexAuthentication, IPlexFriends, IPlexLibResponse, IPlexServer, IPlexServerViewModel } from "../../interfaces"; +import { IPlexAuthentication, IPlexLibResponse, IPlexServer, IPlexServerViewModel, IUsersModel } from "../../interfaces"; @Injectable() export class PlexService extends ServiceAuthHelpers { @@ -26,7 +26,7 @@ export class PlexService extends ServiceAuthHelpers { return this.http.post(`${this.url}Libraries`, JSON.stringify(plexSettings), { headers: this.headers }).map(this.extractData).catch(this.handleError); } - public getFriends(): Observable { + public getFriends(): Observable { return this.http.get(`${this.url}Friends`, { headers: this.headers }).map(this.extractData).catch(this.handleError); } } diff --git a/src/Ombi/ClientApp/app/settings/emby/emby.component.html b/src/Ombi/ClientApp/app/settings/emby/emby.component.html index 78b2fed02..00c641fd1 100644 --- a/src/Ombi/ClientApp/app/settings/emby/emby.component.html +++ b/src/Ombi/ClientApp/app/settings/emby/emby.component.html @@ -76,7 +76,7 @@
- +
diff --git a/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.html b/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.html index 0dc11ca92..4e99c0b4b 100644 --- a/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.html +++ b/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.html @@ -14,7 +14,7 @@

Plex Users exclude from Import

- +
@@ -27,6 +27,12 @@ + +
+

Emby Users exclude from Import

+ + +
diff --git a/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.ts b/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.ts index 4043b59b3..fda3fb4f9 100644 --- a/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.ts +++ b/src/Ombi/ClientApp/app/settings/usermanagement/usermanagement.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from "@angular/core"; import { ICheckbox, IUserManagementSettings } from "../../interfaces"; -import { IPlexFriends } from "../../interfaces/IPlex"; -import { IdentityService, JobService, NotificationService, PlexService, SettingsService } from "../../services"; +import { IUsersModel } from "../../interfaces"; +import { EmbyService, IdentityService, JobService, NotificationService, PlexService, SettingsService } from "../../services"; @Component({ templateUrl: "./usermanagement.component.html", @@ -14,31 +14,47 @@ export class UserManagementComponent implements OnInit { public settings: IUserManagementSettings; public claims: ICheckbox[]; - public plexUsers: IPlexFriends[]; - public filteredPlexUsers: IPlexFriends[]; - public bannedPlexUsers: IPlexFriends[] = []; + public plexUsers: IUsersModel[]; + public filteredPlexUsers: IUsersModel[]; + public bannedPlexUsers: IUsersModel[] = []; - constructor(private settingsService: SettingsService, - private notificationService: NotificationService, - private identityService: IdentityService, - private plexService: PlexService, - private jobService: JobService) { + public embyUsers: IUsersModel[]; + public filteredEmbyUsers: IUsersModel[]; + public bannedEmbyUsers: IUsersModel[] = []; + constructor(private readonly settingsService: SettingsService, + private readonly notificationService: NotificationService, + private readonly identityService: IdentityService, + private readonly plexService: PlexService, + private readonly jobService: JobService, + private readonly embyService: EmbyService) { } public ngOnInit(): void { this.settingsService.getUserManagementSettings().subscribe(x => { this.settings = x; - this.plexService.getFriends().subscribe(f => { + this.plexService.getFriends().subscribe(f => { this.plexUsers = f; this.plexUsers.forEach((plex) => { const isExcluded = this.settings.bannedPlexUserIds.some((val) => { return plex.id === val; }); if (isExcluded) { - this.bannedPlexUsers.push(plex); - } + this.bannedPlexUsers.push(plex); + } + }); + }); + + this.embyService.getUsers().subscribe(f => { + this.embyUsers = f; + this.embyUsers.forEach((emby) => { + const isExcluded = this.settings.bannedPlexUserIds.some((val) => { + return emby.id === val; + }); + if (isExcluded) { + this.bannedEmbyUsers.push(emby); + } }); }); @@ -65,6 +81,7 @@ export class UserManagementComponent implements OnInit { }); this.settings.defaultRoles = enabledClaims.map((claim) => claim.value); this.settings.bannedPlexUserIds = this.bannedPlexUsers.map((u) => u.id); + this.settings.bannedEmbyUserIds = this.bannedEmbyUsers.map((u) => u.id); this.settingsService.saveUserManagementSettings(this.settings).subscribe(x => { if (x === true) { @@ -75,15 +92,19 @@ export class UserManagementComponent implements OnInit { }); } - public filterUserList(event: any) { + public filterPlexList(event: any) { this.filteredPlexUsers = this.filter(event.query, this.plexUsers); } + public filterEmbyList(event: any) { + this.filteredEmbyUsers = this.filter(event.query, this.embyUsers); + } + public runImporter(): void { this.jobService.runPlexImporter().subscribe(); } - private filter(query: string, users: IPlexFriends[]): IPlexFriends[] { + private filter(query: string, users: IUsersModel[]): IUsersModel[] { return users.filter((val) => { return val.username.toLowerCase().indexOf(query.toLowerCase()) === 0; }); diff --git a/src/Ombi/Controllers/External/EmbyController.cs b/src/Ombi/Controllers/External/EmbyController.cs index 9723f3330..ff7a538fa 100644 --- a/src/Ombi/Controllers/External/EmbyController.cs +++ b/src/Ombi/Controllers/External/EmbyController.cs @@ -1,11 +1,15 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Ombi.Api.Emby; +using Ombi.Api.Plex; using Ombi.Attributes; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; +using Ombi.Helpers; +using Ombi.Models.External; namespace Ombi.Controllers.External { @@ -58,5 +62,31 @@ namespace Ombi.Controllers.External } return null; } + + /// + /// Gets the emby users. + /// + /// + [HttpGet("users")] + public async Task> EmbyUsers() + { + var vm = new List(); + var s = await EmbySettings.GetSettingsAsync(); + foreach (var server in s.Servers) + { + var users = await EmbyApi.GetUsers(server.FullUri, server.ApiKey); + if (users != null && users.Any()) + { + vm.AddRange(users.Select(u => new UsersViewModel + { + Username = u.Name, + Id = u.Id + })); + } + } + + // Filter out any dupes + return vm.DistinctBy(x => x.Id); + } } } diff --git a/src/Ombi/Controllers/External/PlexController.cs b/src/Ombi/Controllers/External/PlexController.cs index f5b5ee706..5980e0951 100644 --- a/src/Ombi/Controllers/External/PlexController.cs +++ b/src/Ombi/Controllers/External/PlexController.cs @@ -148,16 +148,16 @@ namespace Ombi.Controllers.External /// /// [HttpGet("friends")] - public async Task> GetFriends() + public async Task> GetFriends() { - var vm = new List(); + var vm = new List(); var s = await PlexSettings.GetSettingsAsync(); foreach (var server in s.Servers) { var users = await PlexApi.GetUsers(server.PlexAuthToken); if (users?.User != null && users.User.Any()) { - vm.AddRange(users.User.Select(u => new PlexUsersViewModel + vm.AddRange(users.User.Select(u => new UsersViewModel { Username = u.Username, Id = u.Id diff --git a/src/Ombi/Models/External/PlexUsersViewModel.cs b/src/Ombi/Models/External/UsersViewModel.cs similarity index 78% rename from src/Ombi/Models/External/PlexUsersViewModel.cs rename to src/Ombi/Models/External/UsersViewModel.cs index c2c5f1c77..155880b86 100644 --- a/src/Ombi/Models/External/PlexUsersViewModel.cs +++ b/src/Ombi/Models/External/UsersViewModel.cs @@ -1,6 +1,6 @@ namespace Ombi.Models.External { - public class PlexUsersViewModel + public class UsersViewModel { public string Username { get; set; } public string Id { get; set; }