Emby user importer is now therer! #1456

pull/1529/head
tidusjar 7 years ago
parent 28abc214b7
commit 143c619db0

@ -144,6 +144,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<IRadarrCacher, RadarrCacher>();
services.AddTransient<IOmbiAutomaticUpdater, OmbiAutomaticUpdater>();
services.AddTransient<IPlexUserImporter, PlexUserImporter>();
services.AddTransient<IEmbyUserImporter, EmbyUserImporter>();
services.AddTransient<IWelcomeEmail, WelcomeEmail>();
}
}

@ -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);

@ -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());
}

@ -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<OmbiUser> um, ILogger<EmbyUserImporter> log,
ISettingsService<EmbySettings> embySettings, ISettingsService<UserManagementSettings> ums)
{
_api = api;
_userManager = um;
_log = log;
_embySettings = embySettings;
_userManagementSettings = ums;
}
private readonly IEmbyApi _api;
private readonly UserManager<OmbiUser> _userManager;
private readonly ILogger<EmbyUserImporter> _log;
private readonly ISettingsService<EmbySettings> _embySettings;
private readonly ISettingsService<UserManagementSettings> _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);
}
}
}
}
}
}

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Ombi.Schedule.Jobs.Emby
{
public interface IEmbyUserImporter
{
Task Start();
}
}

@ -21,3 +21,8 @@ export interface ICheckbox {
value: string;
enabled: boolean;
}
export interface IUsersModel {
id: string;
username: string;
}

@ -20,11 +20,6 @@ export interface IPlexLibResponse {
data: IPlexLibraries;
}
export interface IPlexFriends {
id: string;
username: string;
}
export interface IMediaContainer {
directory: IDirectory[];
}

@ -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<IEmbySettings> {
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<IUsersModel[]> {
return this.http.get(`${this.url}users`, { headers: this.headers }).map(this.extractData);
}
}

@ -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<IPlexFriends[]> {
public getFriends(): Observable<IUsersModel[]> {
return this.http.get(`${this.url}Friends`, { headers: this.headers }).map(this.extractData).catch(this.handleError);
}
}

@ -76,7 +76,7 @@
</div>
<div class="form-group">
<div>
<button id="testEmby" type="submit" (click)="test()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
<button id="testEmby" type="submit" (click)="test(server)" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
</div>
</div>
</div>

@ -14,7 +14,7 @@
<div *ngIf="plexUsers">
<p>Plex Users exclude from Import</p>
<p-autoComplete [(ngModel)]="bannedPlexUsers" [suggestions]="filteredPlexUsers" [multiple]="true" field="username" (completeMethod)="filterUserList($event)"></p-autoComplete>
<p-autoComplete [(ngModel)]="bannedPlexUsers" [suggestions]="filteredPlexUsers" [multiple]="true" field="username" (completeMethod)="filterPlexList($event)"></p-autoComplete>
</div>
</div>
@ -27,6 +27,12 @@
<label for="importEmbyUsers">Import Emby Users</label>
</div>
</div>
<div *ngIf="embyUsers">
<p>Emby Users exclude from Import</p>
<p-autoComplete [(ngModel)]="bannedEmbyUsers" [suggestions]="filteredEmbyUsers" [multiple]="true" field="username" (completeMethod)="filterEmbyList($event)"></p-autoComplete>
</div>
</div>
</div>

@ -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;
});

@ -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;
}
/// <summary>
/// Gets the emby users.
/// </summary>
/// <returns></returns>
[HttpGet("users")]
public async Task<IEnumerable<UsersViewModel>> EmbyUsers()
{
var vm = new List<UsersViewModel>();
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);
}
}
}

@ -148,16 +148,16 @@ namespace Ombi.Controllers.External
/// </summary>
/// <returns></returns>
[HttpGet("friends")]
public async Task<IEnumerable<PlexUsersViewModel>> GetFriends()
public async Task<IEnumerable<UsersViewModel>> GetFriends()
{
var vm = new List<PlexUsersViewModel>();
var vm = new List<UsersViewModel>();
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

@ -1,6 +1,6 @@
namespace Ombi.Models.External
{
public class PlexUsersViewModel
public class UsersViewModel
{
public string Username { get; set; }
public string Id { get; set; }
Loading…
Cancel
Save