Added the option to import the plex admin.

Fixed #1701
pull/1741/head
tidusjar 7 years ago
parent 1813b45fb3
commit 560072eba4

@ -18,5 +18,6 @@ namespace Ombi.Api.Plex
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey); Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, int ratingKey);
Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount); Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount);
Task<PlexFriends> GetUsers(string authToken); Task<PlexFriends> GetUsers(string authToken);
Task<PlexAccount> GetAccount(string authToken);
} }
} }

@ -2,13 +2,21 @@
namespace Ombi.Api.Plex.Models namespace Ombi.Api.Plex.Models
{ {
public class PlexAccount
{
public User user { get; set; }
}
public class User public class User
{ {
public string id { get; set; }
public string email { get; set; } public string email { get; set; }
public string uuid { get; set; } public string uuid { get; set; }
public string joined_at { get; set; } public string joined_at { get; set; }
public string username { get; set; } public string username { get; set; }
public string title { get; set; } public string title { get; set; }
public string thumb { get; set; }
public string hasPassword { get; set; }
public string authentication_token { get; set; } public string authentication_token { get; set; }
public Subscription subscription { get; set; } public Subscription subscription { get; set; }
public Roles roles { get; set; } public Roles roles { get; set; }

@ -18,7 +18,7 @@ namespace Ombi.Api.Plex
private const string SignInUri = "https://plex.tv/users/sign_in.json"; private const string SignInUri = "https://plex.tv/users/sign_in.json";
private const string FriendsUri = "https://plex.tv/pms/friends/all"; private const string FriendsUri = "https://plex.tv/pms/friends/all";
private const string GetAccountUri = "https://plex.tv/users/account"; private const string GetAccountUri = "https://plex.tv/users/account.json";
private const string ServerUri = "https://plex.tv/pms/servers.xml"; private const string ServerUri = "https://plex.tv/pms/servers.xml";
/// <summary> /// <summary>
@ -52,6 +52,13 @@ namespace Ombi.Api.Plex
return await Api.Request<PlexStatus>(request); return await Api.Request<PlexStatus>(request);
} }
public async Task<PlexAccount> GetAccount(string authToken)
{
var request = new Request(GetAccountUri, string.Empty, HttpMethod.Get);
AddHeaders(request, authToken);
return await Api.Request<PlexAccount>(request);
}
public async Task<PlexServer> GetServer(string authToken) public async Task<PlexServer> GetServer(string authToken)
{ {
var request = new Request(ServerUri, string.Empty, HttpMethod.Get, ContentType.Xml); var request = new Request(ServerUri, string.Empty, HttpMethod.Get, ContentType.Xml);

@ -1,10 +1,10 @@
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq; using Moq;
using Ombi.Core.Claims;
using Ombi.Core.Rule.Rules.Request; using Ombi.Core.Rule.Rules.Request;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Helpers;
namespace Ombi.Core.Tests.Rule.Request namespace Ombi.Core.Tests.Rule.Request
{ {

@ -2,8 +2,8 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Ombi.Core.Claims;
using Ombi.Core.Rule.Rules; using Ombi.Core.Rule.Rules;
using Ombi.Helpers;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Tests.Rule.Request namespace Ombi.Core.Tests.Rule.Request

@ -1,8 +1,8 @@
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Claims;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;

@ -1,8 +1,8 @@
using Ombi.Core.Claims; using Ombi.Store.Entities;
using Ombi.Store.Entities;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Rule.Rules namespace Ombi.Core.Rule.Rules

@ -1,7 +1,7 @@
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Claims;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
namespace Ombi.Core.Rule.Rules.Specific namespace Ombi.Core.Rule.Rules.Specific

@ -108,7 +108,7 @@ namespace Ombi.Core.Senders
// Get the root path from the rootfolder selected. // Get the root path from the rootfolder selected.
// For some reason, if we haven't got one use the first root folder in Sonarr // For some reason, if we haven't got one use the first root folder in Sonarr
// TODO make this overrideable via the UI // TODO make this overrideable via the UI
var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? 0, s); var rootFolderPath = await GetSonarrRootPath(model.ParentRequest.RootFolder ?? int.Parse(s.RootPath), s);
try try
{ {
// Does the series actually exist? // Does the series actually exist?

@ -1,4 +1,4 @@
namespace Ombi.Core.Claims namespace Ombi.Helpers
{ {
public static class OmbiRoles public static class OmbiRoles
{ {

@ -39,7 +39,7 @@ namespace Ombi.Notifications.Interfaces
public async Task NotifyAsync(NotificationOptions model) public async Task NotifyAsync(NotificationOptions model)
{ {
var configuration = GetConfiguration(); var configuration = await GetConfiguration();
await NotifyAsync(model, configuration); await NotifyAsync(model, configuration);
} }
@ -100,6 +100,12 @@ namespace Ombi.Notifications.Interfaces
} }
} }
/// <summary>
/// Loads the TV or Movie Request
/// </summary>
/// <param name="requestId"></param>
/// <param name="type"></param>
/// <returns></returns>
protected virtual async Task LoadRequest(int requestId, RequestType type) protected virtual async Task LoadRequest(int requestId, RequestType type)
{ {
if (type == RequestType.Movie) if (type == RequestType.Movie)
@ -112,12 +118,19 @@ namespace Ombi.Notifications.Interfaces
} }
} }
private T GetConfiguration() private async Task<T> GetConfiguration()
{ {
var settings = Settings.GetSettings(); var settings = await Settings.GetSettingsAsync();
return settings; return settings;
} }
/// <summary>
/// Loads the correct template from the DB
/// </summary>
/// <param name="agent"></param>
/// <param name="type"></param>
/// <param name="model"></param>
/// <returns></returns>
protected virtual async Task<NotificationMessageContent> LoadTemplate(NotificationAgent agent, NotificationType type, NotificationOptions model) protected virtual async Task<NotificationMessageContent> LoadTemplate(NotificationAgent agent, NotificationType type, NotificationOptions model)
{ {
var template = await TemplateRepository.GetTemplate(agent, type); var template = await TemplateRepository.GetTemplate(agent, type);

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
@ -44,6 +45,8 @@ namespace Ombi.Schedule.Jobs.Plex
{ {
return; return;
} }
var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.PlexUser).ToListAsync(); var allUsers = await _userManager.Users.Where(x => x.UserType == UserType.PlexUser).ToListAsync();
foreach (var server in settings.Servers) foreach (var server in settings.Servers)
{ {
@ -52,6 +55,8 @@ namespace Ombi.Schedule.Jobs.Plex
continue; continue;
} }
await ImportAdmin(userManagementSettings, server, allUsers);
var users = await _api.GetUsers(server.PlexAuthToken); var users = await _api.GetUsers(server.PlexAuthToken);
foreach (var plexUser in users.User) foreach (var plexUser in users.User)
@ -80,12 +85,8 @@ namespace Ombi.Schedule.Jobs.Plex
}; };
_log.LogInformation("Creating Plex user {0}", newUser.UserName); _log.LogInformation("Creating Plex user {0}", newUser.UserName);
var result = await _userManager.CreateAsync(newUser); var result = await _userManager.CreateAsync(newUser);
if (!result.Succeeded) if (!LogResult(result))
{ {
foreach (var identityError in result.Errors)
{
_log.LogError(LoggingEvents.PlexUserImporter, identityError.Description);
}
continue; continue;
} }
if (userManagementSettings.DefaultRoles.Any()) if (userManagementSettings.DefaultRoles.Any())
@ -107,5 +108,59 @@ namespace Ombi.Schedule.Jobs.Plex
} }
} }
} }
private async Task ImportAdmin(UserManagementSettings settings, PlexServers server, List<OmbiUser> allUsers)
{
if (!settings.ImportPlexAdmin)
{
return;
}
var plexAdmin = (await _api.GetAccount(server.PlexAuthToken)).user;
// Check if the admin is already in the DB
var adminUserFromDb = allUsers.FirstOrDefault(x =>
x.ProviderUserId.Equals(plexAdmin.id, StringComparison.CurrentCultureIgnoreCase));
if (adminUserFromDb != null)
{
// Let's update the user
adminUserFromDb.Email = plexAdmin.email;
adminUserFromDb.UserName = plexAdmin.username;
adminUserFromDb.ProviderUserId = plexAdmin.id;
await _userManager.UpdateAsync(adminUserFromDb);
return;
}
var newUser = new OmbiUser
{
UserType = UserType.PlexUser,
UserName = plexAdmin.username ?? plexAdmin.id,
ProviderUserId = plexAdmin.id,
Email = plexAdmin.email ?? string.Empty,
Alias = string.Empty
};
var result = await _userManager.CreateAsync(newUser);
if (!LogResult(result))
{
return;
}
var roleResult = await _userManager.AddToRoleAsync(newUser, OmbiRoles.Admin);
LogResult(roleResult);
}
private bool LogResult(IdentityResult result)
{
if (!result.Succeeded)
{
foreach (var identityError in result.Errors)
{
_log.LogError(LoggingEvents.PlexUserImporter, identityError.Description);
}
}
return result.Succeeded;
}
} }
} }

@ -13,8 +13,6 @@ namespace Ombi.Core.Settings.Models.External
public class PlexServers : ExternalSettings public class PlexServers : ExternalSettings
{ {
public string Name { get; set; } public string Name { get; set; }
public bool EnableEpisodeSearching { get; set; }
public string PlexAuthToken { get; set; } public string PlexAuthToken { get; set; }
public string MachineIdentifier { get; set; } public string MachineIdentifier { get; set; }

@ -4,6 +4,7 @@ namespace Ombi.Settings.Settings.Models
{ {
public class UserManagementSettings : Settings public class UserManagementSettings : Settings
{ {
public bool ImportPlexAdmin { get; set; }
public bool ImportPlexUsers { get; set; } public bool ImportPlexUsers { get; set; }
public bool ImportEmbyUsers { get; set; } public bool ImportEmbyUsers { get; set; }
public List<string> DefaultRoles { get; set; } = new List<string>(); public List<string> DefaultRoles { get; set; } = new List<string>();

@ -1,5 +1,5 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Ombi.Core.Claims; using Ombi.Helpers;
namespace Ombi.Attributes namespace Ombi.Attributes
{ {

@ -1,5 +1,7 @@
<p-growl [value]="notificationService.messages" [life]="3000"></p-growl> <p-growl [value]="notificationService.messages" [life]="3000"></p-growl>
<div *ngIf="user.name">
<div *ngIf="hasRole('Admin') || hasRole('PowerUser')" class="adminUser"></div>
</div>
<nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top"> <nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">

@ -121,7 +121,8 @@ export interface IAuthenticationSettings extends ISettings {
} }
export interface IUserManagementSettings extends ISettings { export interface IUserManagementSettings extends ISettings {
importPlexUsers: boolean; importPlexUsers: boolean;
importPlexAdmin: boolean;
importEmbyUsers: boolean; importEmbyUsers: boolean;
defaultRoles: string[]; defaultRoles: string[];
bannedPlexUserIds: string[]; bannedPlexUserIds: string[];

@ -14,6 +14,12 @@ export interface IUser {
checked: boolean; checked: boolean;
} }
export interface ICreateWizardUser {
username: string;
password: string;
usePlexAdminAccount: boolean;
}
export enum UserType { export enum UserType {
LocalUser = 1, LocalUser = 1,
PlexUser = 2, PlexUser = 2,

@ -28,7 +28,7 @@ export class MovieSearchComponent implements OnInit {
private readonly translate: TranslateService, private sanitizer: DomSanitizer) { private readonly translate: TranslateService, private sanitizer: DomSanitizer) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms after the last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
@ -40,9 +40,9 @@ export class MovieSearchComponent implements OnInit {
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.searchApplied = true; this.searchApplied = true;
// Now let's load some exta info including IMDBId // Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results. // This way the search is fast at displaying results.
this.getExtaInfo(); this.getExtraInfo();
}); });
}); });
} }
@ -103,7 +103,7 @@ export class MovieSearchComponent implements OnInit {
this.searchService.popularMovies() this.searchService.popularMovies()
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtraInfo();
}); });
} }
public nowPlayingMovies() { public nowPlayingMovies() {
@ -111,7 +111,7 @@ export class MovieSearchComponent implements OnInit {
this.searchService.nowPlayingMovies() this.searchService.nowPlayingMovies()
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtraInfo();
}); });
} }
public topRatedMovies() { public topRatedMovies() {
@ -119,19 +119,19 @@ export class MovieSearchComponent implements OnInit {
this.searchService.topRatedMovies() this.searchService.topRatedMovies()
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtraInfo();
}); });
} }
public upcomingMovies() { public upcomingMovies() {
this.clearResults(); this.clearResults();
this.searchService.upcomignMovies() this.searchService.upcomingMovies()
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtraInfo();
}); });
} }
private getExtaInfo() { private getExtraInfo() {
this.movieResults.forEach((val, index) => { this.movieResults.forEach((val, index) => {

@ -122,7 +122,7 @@ export class MovieSearchGridComponent implements OnInit {
} }
public upcomingMovies() { public upcomingMovies() {
this.clearResults(); this.clearResults();
this.searchService.upcomignMovies() this.searchService.upcomingMovies()
.subscribe(x => { .subscribe(x => {
this.movieResults = x; this.movieResults = x;
this.getExtaInfo(); this.getExtaInfo();
@ -130,7 +130,7 @@ export class MovieSearchGridComponent implements OnInit {
} }
private getExtaInfo() { private getExtaInfo() {
this.movieResults.forEach((val, index) => { this.movieResults.forEach((val) => {
this.searchService.getMovieInformation(val.id) this.searchService.getMovieInformation(val.id)
.subscribe(m => this.updateItem(val, m)); .subscribe(m => this.updateItem(val, m));
}); });

@ -4,7 +4,7 @@ import { Http } from "@angular/http";
import { AuthHttp } from "angular2-jwt"; import { AuthHttp } from "angular2-jwt";
import { Observable } from "rxjs/Rx"; import { Observable } from "rxjs/Rx";
import { ICheckbox, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser } from "../interfaces"; import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser } from "../interfaces";
import { ServiceAuthHelpers } from "./service.helpers"; import { ServiceAuthHelpers } from "./service.helpers";
@Injectable() @Injectable()
@ -12,8 +12,8 @@ export class IdentityService extends ServiceAuthHelpers {
constructor(http: AuthHttp, private regularHttp: Http, public platformLocation: PlatformLocation) { constructor(http: AuthHttp, private regularHttp: Http, public platformLocation: PlatformLocation) {
super(http, "/api/v1/Identity/", platformLocation); super(http, "/api/v1/Identity/", platformLocation);
} }
public createWizardUser(username: string, password: string): Observable<boolean> { public createWizardUser(user: ICreateWizardUser): Observable<boolean> {
return this.regularHttp.post(`${this.url}Wizard/`, JSON.stringify({ username, password }), { headers: this.headers }).map(this.extractData); return this.regularHttp.post(`${this.url}Wizard/`, JSON.stringify(user), { headers: this.headers }).map(this.extractData);
} }
public getUser(): Observable<IUser> { public getUser(): Observable<IUser> {

@ -22,7 +22,7 @@ export class SearchService extends ServiceAuthHelpers {
public popularMovies(): Observable<ISearchMovieResult[]> { public popularMovies(): Observable<ISearchMovieResult[]> {
return this.http.get(`${this.url}/Movie/Popular`).map(this.extractData); return this.http.get(`${this.url}/Movie/Popular`).map(this.extractData);
} }
public upcomignMovies(): Observable<ISearchMovieResult[]> { public upcomingMovies(): Observable<ISearchMovieResult[]> {
return this.http.get(`${this.url}/Movie/upcoming`).map(this.extractData); return this.http.get(`${this.url}/Movie/upcoming`).map(this.extractData);
} }
public nowPlayingMovies(): Observable<ISearchMovieResult[]> { public nowPlayingMovies(): Observable<ISearchMovieResult[]> {

@ -13,6 +13,13 @@
<label for="importPlex">Import Plex Users</label> <label for="importPlex">Import Plex Users</label>
</div> </div>
</div> </div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="importAdmin" [(ngModel)]="settings.importPlexAdmin">
<label for="importAdmin">Import Plex Admin</label>
</div>
</div>
<div *ngIf="plexUsers"> <div *ngIf="plexUsers">
<p>Plex Users exclude from Import</p> <p>Plex Users exclude from Import</p>

@ -1,21 +1,6 @@
<h1>User Management</h1> <h1>User Management</h1>
<!--Search-->
<div class="row">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon left-radius">
<i class="fa fa-search"></i>
</div>
<input type="text" class="form-control" id="search" placeholder="Search" [(ngModel)]="searchTerm">
</div>
</div>
</div>
<button type="button" class="btn btn-success-outline" [routerLink]="['/usermanagement/add']">Add User</button> <button type="button" class="btn btn-success-outline" [routerLink]="['/usermanagement/add']">Add User</button>
<!-- Table --> <!-- Table -->

@ -18,7 +18,7 @@ export class CreateAdminComponent {
private router: Router, private auth: AuthService, private settings: SettingsService) { } private router: Router, private auth: AuthService, private settings: SettingsService) { }
public createUser() { public createUser() {
this.identityService.createWizardUser(this.username, this.password).subscribe(x => { this.identityService.createWizardUser({username: this.username, password: this.password, usePlexAdminAccount: false}).subscribe(x => {
if (x) { if (x) {
// Log me in. // Log me in.
this.auth.login({ username: this.username, password: this.password, rememberMe:false }).subscribe(c => { this.auth.login({ username: this.username, password: this.password, rememberMe:false }).subscribe(c => {

@ -22,4 +22,6 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<p-confirmDialog></p-confirmDialog>

@ -1,8 +1,11 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { ConfirmationService } from "primeng/primeng";
import { PlexService } from "../../services"; import { PlexService } from "../../services";
import { NotificationService } from "../../services"; import { IdentityService, NotificationService, SettingsService } from "../../services";
import { AuthService } from "./../../auth/auth.service";
@Component({ @Component({
templateUrl: "./plex.component.html", templateUrl: "./plex.component.html",
@ -12,7 +15,12 @@ export class PlexComponent {
public login: string; public login: string;
public password: string; public password: string;
constructor(private plexService: PlexService, private router: Router, private notificationService: NotificationService) { } constructor(private plexService: PlexService, private router: Router,
private notificationService: NotificationService,
private confirmationService: ConfirmationService,
private identityService: IdentityService,
private settings: SettingsService,
private auth: AuthService) { }
public requestAuthToken() { public requestAuthToken() {
this.plexService.logIn(this.login, this.password).subscribe(x => { this.plexService.logIn(this.login, this.password).subscribe(x => {
@ -20,7 +28,46 @@ export class PlexComponent {
this.notificationService.error("Username or password was incorrect. Could not authenticate with Plex."); this.notificationService.error("Username or password was incorrect. Could not authenticate with Plex.");
return; return;
} }
this.router.navigate(["Wizard/CreateAdmin"]); this.confirmationService.confirm({
message: "Do you want your Plex user to be the main admin account on Ombi?",
header: "Use Plex Account",
icon: "fa fa-check",
accept: () => {
this.identityService.createWizardUser({
username: "",
password: "",
usePlexAdminAccount: true,
}).subscribe(x => {
if (x) {
this.auth.login({ username: this.login, password: this.password, rememberMe:false }).subscribe(c => {
localStorage.setItem("id_token", c.access_token);
// Mark that we have done the settings now
this.settings.getOmbi().subscribe(ombi => {
ombi.wizard = true;
this.settings.saveOmbi(ombi).subscribe(x => {
this.settings.getUserManagementSettings().subscribe(usr => {
usr.importPlexAdmin = true;
this.settings.saveUserManagementSettings(usr).subscribe(saved => {
this.router.navigate(["login"]);
});
});
});
});
});
} else {
this.notificationService.error("Could not get the Plex Admin Information");
return;
}
});
},
reject: () => {
this.router.navigate(["Wizard/CreateAdmin"]);
},
});
}); });
} }
} }

@ -3,6 +3,8 @@ import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms"; import { FormsModule } from "@angular/forms";
import { RouterModule, Routes } from "@angular/router"; import { RouterModule, Routes } from "@angular/router";
import {ConfirmationService, ConfirmDialogModule } from "primeng/primeng";
import { CreateAdminComponent } from "./createadmin/createadmin.component"; import { CreateAdminComponent } from "./createadmin/createadmin.component";
import { EmbyComponent } from "./emby/emby.component"; import { EmbyComponent } from "./emby/emby.component";
import { MediaServerComponent } from "./mediaserver/mediaserver.component"; import { MediaServerComponent } from "./mediaserver/mediaserver.component";
@ -25,6 +27,7 @@ const routes: Routes = [
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,
ConfirmDialogModule,
RouterModule.forChild(routes), RouterModule.forChild(routes),
], ],
declarations: [ declarations: [
@ -41,6 +44,7 @@ const routes: Routes = [
PlexService, PlexService,
IdentityService, IdentityService,
EmbyService, EmbyService,
ConfirmationService,
], ],
}) })

@ -43,32 +43,30 @@ namespace Ombi.Controllers.External
{ {
try try
{ {
// Do we already have settings?
_log.LogDebug("OK, signing into Plex");
var settings = await PlexSettings.GetSettingsAsync();
if (!settings.Servers?.Any() ?? false) return null;
_log.LogDebug("This is our first time, good to go!");
// Do we already have settings?
_log.LogDebug("OK, signing into Plex");
var settings = await PlexSettings.GetSettingsAsync();
if (!settings.Servers?.Any() ?? false) return null;
_log.LogDebug("This is our first time, good to go!"); var result = await PlexApi.SignIn(request);
var result = await PlexApi.SignIn(request); _log.LogDebug("Attempting to sign in to Plex.Tv");
if (!string.IsNullOrEmpty(result.user?.authentication_token))
_log.LogDebug("Attempting to sign in to Plex.Tv");
if (!string.IsNullOrEmpty(result.user?.authentication_token))
{
_log.LogDebug("Sign in successful");
_log.LogDebug("Getting servers");
var server = await PlexApi.GetServer(result.user.authentication_token);
var servers = server.Server.FirstOrDefault();
if (servers == null)
{ {
_log.LogWarning("Looks like we can't find any Plex Servers"); _log.LogDebug("Sign in successful");
} _log.LogDebug("Getting servers");
_log.LogDebug("Adding first server"); var server = await PlexApi.GetServer(result.user.authentication_token);
var servers = server.Server.FirstOrDefault();
if (servers == null)
{
_log.LogWarning("Looks like we can't find any Plex Servers");
}
_log.LogDebug("Adding first server");
settings.Enable = true; settings.Enable = true;
settings.Servers = new List<PlexServers> { settings.Servers = new List<PlexServers> {
new PlexServers new PlexServers
{ {
PlexAuthToken = result.user.authentication_token, PlexAuthToken = result.user.authentication_token,
@ -81,11 +79,11 @@ namespace Ombi.Controllers.External
} }
}; };
await PlexSettings.SaveSettingsAsync(settings); await PlexSettings.SaveSettingsAsync(settings);
} }
_log.LogDebug("Finished"); _log.LogDebug("Finished");
return result; return result;
} }
catch (Exception e) catch (Exception e)
{ {

@ -12,14 +12,15 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Ombi.Api.Plex;
using Ombi.Attributes; using Ombi.Attributes;
using Ombi.Config; using Ombi.Config;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Claims;
using Ombi.Core.Helpers; using Ombi.Core.Helpers;
using Ombi.Core.Models.UI; using Ombi.Core.Models.UI;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Models; using Ombi.Models;
using Ombi.Models.Identity; using Ombi.Models.Identity;
using Ombi.Notifications; using Ombi.Notifications;
@ -35,6 +36,7 @@ using OmbiIdentityResult = Ombi.Models.Identity.IdentityResult;
namespace Ombi.Controllers namespace Ombi.Controllers
{ {
/// <inheritdoc />
/// <summary> /// <summary>
/// The Identity Controller, the API for everything Identity/User related /// The Identity Controller, the API for everything Identity/User related
/// </summary> /// </summary>
@ -48,7 +50,9 @@ namespace Ombi.Controllers
IWelcomeEmail welcome, IWelcomeEmail welcome,
IMovieRequestRepository m, IMovieRequestRepository m,
ITvRequestRepository t, ITvRequestRepository t,
ILogger<IdentityController> l) ILogger<IdentityController> l,
IPlexApi plexApi,
ISettingsService<PlexSettings> settings)
{ {
UserManager = user; UserManager = user;
Mapper = mapper; Mapper = mapper;
@ -60,6 +64,8 @@ namespace Ombi.Controllers
MovieRepo = m; MovieRepo = m;
TvRepo = t; TvRepo = t;
_log = l; _log = l;
_plexApi = plexApi;
_plexSettings = settings;
} }
private OmbiUserManager UserManager { get; } private OmbiUserManager UserManager { get; }
@ -71,7 +77,9 @@ namespace Ombi.Controllers
private IWelcomeEmail WelcomeEmail { get; } private IWelcomeEmail WelcomeEmail { get; }
private IMovieRequestRepository MovieRepo { get; } private IMovieRequestRepository MovieRepo { get; }
private ITvRequestRepository TvRepo { get; } private ITvRequestRepository TvRepo { get; }
private ILogger<IdentityController> _log; private readonly ILogger<IdentityController> _log;
private readonly IPlexApi _plexApi;
private readonly ISettingsService<PlexSettings> _plexSettings;
/// <summary> /// <summary>
/// This is what the Wizard will call when creating the user for the very first time. /// This is what the Wizard will call when creating the user for the very first time.
@ -85,7 +93,7 @@ namespace Ombi.Controllers
[HttpPost("Wizard")] [HttpPost("Wizard")]
[ApiExplorerSettings(IgnoreApi = true)] [ApiExplorerSettings(IgnoreApi = true)]
[AllowAnonymous] [AllowAnonymous]
public async Task<bool> CreateWizardUser([FromBody] UserAuthModel user) public async Task<bool> CreateWizardUser([FromBody] CreateUserWizardModel user)
{ {
var users = UserManager.Users; var users = UserManager.Users;
if (users.Any()) if (users.Any())
@ -94,13 +102,48 @@ namespace Ombi.Controllers
return false; return false;
} }
if (user.UsePlexAdminAccount)
{
var settings = await _plexSettings.GetSettingsAsync();
var authToken = settings.Servers.FirstOrDefault()?.PlexAuthToken ?? string.Empty;
if (authToken.IsNullOrEmpty())
{
_log.LogWarning("Could not find an auth token to create the plex user with");
return false;
}
var plexUser = await _plexApi.GetAccount(authToken);
var adminUser = new OmbiUser
{
UserName = plexUser.user.username,
UserType = UserType.PlexUser,
Email = plexUser.user.email,
ProviderUserId = plexUser.user.id
};
return await SaveWizardUser(user, adminUser);
}
var userToCreate = new OmbiUser var userToCreate = new OmbiUser
{ {
UserName = user.Username, UserName = user.Username,
UserType = UserType.LocalUser UserType = UserType.LocalUser
}; };
var result = await UserManager.CreateAsync(userToCreate, user.Password); return await SaveWizardUser(user, userToCreate);
}
private async Task<bool> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate)
{
IdentityResult result;
// When creating the admin as the plex user, we do not pass in the password.
if (user.Password.HasValue())
{
result = await UserManager.CreateAsync(userToCreate, user.Password);
}
else
{
result = await UserManager.CreateAsync(userToCreate);
}
if (result.Succeeded) if (result.Succeeded)
{ {
_log.LogInformation("Created User {0}", userToCreate.UserName); _log.LogInformation("Created User {0}", userToCreate.UserName);
@ -319,7 +362,7 @@ namespace Ombi.Controllers
{ {
return Error("You need to provide your current password to make any changes"); return Error("You need to provide your current password to make any changes");
} }
var changingPass = !string.IsNullOrEmpty(ui.Password) || !string.IsNullOrEmpty(ui.ConfirmNewPassword); var changingPass = !string.IsNullOrEmpty(ui.Password) || !string.IsNullOrEmpty(ui.ConfirmNewPassword);
if (changingPass) if (changingPass)
@ -457,7 +500,7 @@ namespace Ombi.Controllers
{ {
return Error("You do not have the correct permissions to delete this user"); return Error("You do not have the correct permissions to delete this user");
} }
// We need to delete all the requests first // We need to delete all the requests first
var moviesUserRequested = MovieRepo.GetAll().Where(x => x.RequestedUserId == userId); var moviesUserRequested = MovieRepo.GetAll().Where(x => x.RequestedUserId == userId);
var tvUserRequested = TvRepo.GetChild().Where(x => x.RequestedUserId == userId); var tvUserRequested = TvRepo.GetChild().Where(x => x.RequestedUserId == userId);

@ -10,7 +10,7 @@ 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.Authentication;
using Ombi.Core.Claims; using Ombi.Helpers;
using Ombi.Models; using Ombi.Models;
using Ombi.Models.Identity; using Ombi.Models.Identity;
using Ombi.Store.Entities; using Ombi.Store.Entities;

@ -0,0 +1,9 @@
namespace Ombi.Models
{
public class CreateUserWizardModel
{
public string Username { get; set; }
public string Password { get; set; }
public bool UsePlexAdminAccount { get; set; }
}
}

@ -5,5 +5,6 @@
public string Username { get; set; } public string Username { get; set; }
public string Password { get; set; } public string Password { get; set; }
public bool RememberMe { get; set; } public bool RememberMe { get; set; }
public bool UsePlexAdminAccount { get; set; }
} }
} }
Loading…
Cancel
Save