!wip started on the Plex add user UI

pull/2452/head
Jamie 6 years ago
parent 51f5bbc6a8
commit 79fe8bb331

@ -24,5 +24,6 @@ namespace Ombi.Api.Plex
Task<PlexMetadata> GetRecentlyAdded(string authToken, string uri, string sectionId);
Task<OAuthPin> GetPin(int pinId);
Task<Uri> GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard);
Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs);
}
}

@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Ombi.Api.Plex.Models
{
[XmlRoot(ElementName = "Section")]
public class Section
{
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlAttribute(AttributeName = "key")]
public string Key { get; set; }
[XmlAttribute(AttributeName = "title")]
public string Title { get; set; }
[XmlAttribute(AttributeName = "type")]
public string Type { get; set; }
[XmlAttribute(AttributeName = "shared")]
public string Shared { get; set; }
}
[XmlRoot(ElementName = "SharedServer")]
public class SharedServer
{
[XmlElement(ElementName = "Section")]
public List<Section> Section { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
[XmlAttribute(AttributeName = "username")]
public string Username { get; set; }
[XmlAttribute(AttributeName = "email")]
public string Email { get; set; }
[XmlAttribute(AttributeName = "userID")]
public string UserID { get; set; }
[XmlAttribute(AttributeName = "accessToken")]
public string AccessToken { get; set; }
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "acceptedAt")]
public string AcceptedAt { get; set; }
[XmlAttribute(AttributeName = "invitedAt")]
public string InvitedAt { get; set; }
[XmlAttribute(AttributeName = "allowSync")]
public string AllowSync { get; set; }
[XmlAttribute(AttributeName = "allowCameraUpload")]
public string AllowCameraUpload { get; set; }
[XmlAttribute(AttributeName = "allowChannels")]
public string AllowChannels { get; set; }
[XmlAttribute(AttributeName = "allowTuners")]
public string AllowTuners { get; set; }
[XmlAttribute(AttributeName = "owned")]
public string Owned { get; set; }
}
[XmlRoot(ElementName = "MediaContainer")]
public class PlexAdd
{
[XmlElement(ElementName = "SharedServer")]
public SharedServer SharedServer { get; set; }
[XmlAttribute(AttributeName = "friendlyName")]
public string FriendlyName { get; set; }
[XmlAttribute(AttributeName = "identifier")]
public string Identifier { get; set; }
[XmlAttribute(AttributeName = "machineIdentifier")]
public string MachineIdentifier { get; set; }
[XmlAttribute(AttributeName = "size")]
public string Size { get; set; }
}
[XmlRoot(ElementName = "Response")]
public class AddUserError
{
[XmlAttribute(AttributeName = "code")]
public string Code { get; set; }
[XmlAttribute(AttributeName = "status")]
public string Status { get; set; }
}
public class PlexAddWrapper
{
public PlexAdd Add { get; set; }
public AddUserError Error { get; set; }
public bool HasError => Error != null;
}
}

@ -243,6 +243,34 @@ namespace Ombi.Api.Plex
return request.FullUri;
}
public async Task<PlexAddWrapper> AddUser(string emailAddress, string serverId, string authToken, int[] libs)
{
var request = new Request(string.Empty, $"https://plex.tv/api/servers/{serverId}/shared_servers", HttpMethod.Post, ContentType.Xml);
await AddHeaders(request, authToken);
request.AddJsonBody(new
{
server_id = serverId,
shared_server = new
{
library_section_ids = libs.Length > 0 ? libs : new int[]{},
invited_email = emailAddress
},
sharing_settings = new { }
});
var result = await Api.RequestContent(request);
try
{
var add = Api.DeserializeXml<PlexAdd>(result);
return new PlexAddWrapper{Add = add};
}
catch (InvalidOperationException)
{
var error = Api.DeserializeXml<AddUserError>(result);
return new PlexAddWrapper{Error = error};
}
}
/// <summary>
/// Adds the required headers and also the authorization header
/// </summary>

@ -80,15 +80,20 @@ namespace Ombi.Api
else
{
// XML
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(receivedString);
var value = (T)serializer.Deserialize(reader);
return value;
return DeserializeXml<T>(receivedString);
}
}
}
public T DeserializeXml<T>(string receivedString)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(receivedString);
var value = (T) serializer.Deserialize(reader);
return value;
}
public async Task<string> RequestContent(Request request)
{
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))

@ -7,5 +7,6 @@ namespace Ombi.Api
Task Request(Request request);
Task<T> Request<T>(Request request);
Task<string> RequestContent(Request request);
T DeserializeXml<T>(string receivedString);
}
}

@ -6,7 +6,7 @@ namespace Ombi.Store.Entities
{
public enum RequestType
{
TvShow,
Movie
TvShow = 0,
Movie = 1
}
}

@ -49,6 +49,28 @@ export interface IPlexServerViewModel {
servers: IPlexServerResult;
}
export interface IPlexServerAddViewModel {
success: boolean;
servers: IPlexServersAdd[];
}
export interface IPlexServersAdd {
serverId: number;
machineId: string;
serverName: string;
}
export interface IPlexUserViewModel {
username: string;
machineIdentifier: string;
libsSelected: number[];
}
export interface IPlexUserAddResponse {
success: boolean;
error: string;
}
export interface IPlexServerResult {
friendlyName: string;
machineIdentifier: string;

@ -6,7 +6,7 @@ import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";
import { IPlexAuthentication, IPlexLibResponse, IPlexOAuthViewModel, IPlexServer, IPlexServerViewModel, IUsersModel } from "../../interfaces";
import { IPlexAuthentication, IPlexLibResponse, IPlexOAuthViewModel, IPlexServer, IPlexServerAddViewModel, IPlexServerViewModel, IPlexUserAddResponse, IPlexUserViewModel, IUsersModel } from "../../interfaces";
@Injectable()
export class PlexService extends ServiceHelpers {
@ -22,10 +22,22 @@ export class PlexService extends ServiceHelpers {
return this.http.post<IPlexServerViewModel>(`${this.url}servers`, JSON.stringify({ login, password }), {headers: this.headers});
}
public getServersFromSettings(): Observable<IPlexServerAddViewModel> {
return this.http.get<IPlexServerAddViewModel>(`${this.url}servers`, {headers: this.headers});
}
public getLibraries(plexSettings: IPlexServer): Observable<IPlexLibResponse> {
return this.http.post<IPlexLibResponse>(`${this.url}Libraries`, JSON.stringify(plexSettings), {headers: this.headers});
}
public getLibrariesFromSettings(machineId: string): Observable<IPlexLibResponse> {
return this.http.get<IPlexLibResponse>(`${this.url}Libraries/${machineId}`, {headers: this.headers});
}
public addUserToServer(user: IPlexUserViewModel): Observable<IPlexUserAddResponse> {
return this.http.post<IPlexUserAddResponse>(`${this.url}user`,JSON.stringify(user), {headers: this.headers});
}
public getFriends(): Observable<IUsersModel[]> {
return this.http.get<IUsersModel[]>(`${this.url}Friends`, {headers: this.headers});
}

@ -0,0 +1,25 @@
import { Component, Input } from "@angular/core";
import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
@Component({
selector: "ngbd-modal-content",
template: `
<div class="modal-header">
</div>
<div class="modal-body">
<p>Hello, {{name}}!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger-outline" (click)="activeModal.close('Close click')">Close</button>
</div>
`,
})
export class AddPlexUserComponent {
@Input() public name: string;
constructor(public activeModal: NgbActiveModal) {
console.log("called");
}
}

@ -1,8 +1,11 @@
<h1>User Management</h1>
<button type="button" class="btn btn-success-outline" [routerLink]="['/usermanagement/add']">Add User</button>
<div *ngIf="plexEnabled">
<button type="button" class="btn btn-success-outline" (click)="open()">Add User To Plex</button>
<hr>
</div>
<button type="button" class="btn btn-success-outline" [routerLink]="['/usermanagement/add']">Add User To Ombi</button>
<button type="button" style="float:right;" class="btn btn-primary-outline"(click)="showBulkEdit = !showBulkEdit" [disabled]="!hasChecked()">Bulk Edit</button>
<!-- Table -->
<table class="table table-striped table-hover table-responsive table-condensed table-usermanagement">
@ -127,4 +130,5 @@
</div>
<button type="button" class="btn btn-success-outline" (click)="bulkUpdate()">Update Users</button>
</p-sidebar>
</p-sidebar>

@ -1,10 +1,28 @@
import { Component, OnInit } from "@angular/core";
import { ICheckbox, ICustomizationSettings, IEmailNotificationSettings, IUser } from "../interfaces";
import { IdentityService, NotificationService, SettingsService } from "../services";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ICheckbox, ICustomizationSettings, IEmailNotificationSettings, IPlexLibraries, IPlexServersAdd, IUser } from "../interfaces";
import { IdentityService, NotificationService, PlexService, SettingsService } from "../services";
import { AddPlexUserComponent } from "./addplexuser.component";
@Component({
templateUrl: "./usermanagement.component.html",
styles:[`.modal-backdrop.fade{opacity:0.5}
.fade {
opacity:1 !important;
}
.modal {
display: none;
overflow: hidden;
position: fixed;
top: 100px;
right: 0;
bottom: 0;
left: 0;
z-index: 1050;
-webkit-overflow-scrolling: touch;
outline: 0;
}`],
})
export class UserManagementComponent implements OnInit {
@ -20,10 +38,20 @@ export class UserManagementComponent implements OnInit {
public availableClaims: ICheckbox[];
public bulkMovieLimit?: number;
public bulkEpisodeLimit?: number;
public plexEnabled: boolean;
public plexServers: IPlexServersAdd[];
public plexLibs: IPlexLibraries;
public plexUsername: string;
public libsSelected: number[];
public machineId: string;
constructor(private identityService: IdentityService,
private settingsService: SettingsService,
private notificationService: NotificationService) { }
private notificationService: NotificationService,
private plexSettings: SettingsService,
private plexService: PlexService,
private modalService: NgbModal) { }
public ngOnInit() {
this.users = [];
@ -31,11 +59,18 @@ export class UserManagementComponent implements OnInit {
this.users = x;
});
this.plexSettings.getPlex().subscribe(x => this.plexEnabled = x.enable);
this.identityService.getAllAvailableClaims().subscribe(x => this.availableClaims = x);
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
this.settingsService.getEmailNotificationSettings().subscribe(x => this.emailSettings = x);
}
public open() {
const modalRef = this.modalService.open(AddPlexUserComponent, {container:"ombi"});
modalRef.componentInstance.name = "World";
}
public welcomeEmail(user: IUser) {
if (!user.emailAddress) {
this.notificationService.error("The user needs an email address.");
@ -118,4 +153,34 @@ export class UserManagementComponent implements OnInit {
this.order = value;
}
public getServers() {
if(!this.plexEnabled) {
return this.notificationService.error("Plex is not enabled");
}
this.plexService.getServersFromSettings().subscribe(x => {
if(x.success) {
this.plexServers = x.servers;
}
});
}
public getPlexLibs(machineId: string) {
this.plexService.getLibrariesFromSettings(machineId).subscribe(x => {
if(x.successful) {
this.plexLibs = x.data;
}
});
}
public addUser() {
this.plexService.addUserToServer({ username: this.plexUsername, machineIdentifier: this.machineId, libsSelected: this.libsSelected}).subscribe(x => {
if(x.success) {
this.notificationService.success("User added to Plex");
} else {
this.notificationService.error(x.error);
}
});
}
}

@ -12,11 +12,12 @@ import { UserManagementEditComponent } from "./usermanagement-edit.component";
import { UserManagementComponent } from "./usermanagement.component";
import { PipeModule } from "../pipes/pipe.module";
import { IdentityService } from "../services";
import { IdentityService, PlexService } from "../services";
import { AuthGuard } from "../auth/auth.guard";
import { OrderModule } from "ngx-order-pipe";
import { AddPlexUserComponent } from "./addplexuser.component";
const routes: Routes = [
{ path: "", component: UserManagementComponent, canActivate: [AuthGuard] },
@ -44,6 +45,10 @@ const routes: Routes = [
UserManagementAddComponent,
UserManagementEditComponent,
UpdateDetailsComponent,
AddPlexUserComponent,
],
entryComponents:[
AddPlexUserComponent,
],
exports: [
RouterModule,
@ -51,6 +56,7 @@ const routes: Routes = [
providers: [
IdentityService,
ConfirmationService,
PlexService,
],
})

@ -127,6 +127,100 @@ namespace Ombi.Controllers.External
}
}
[HttpGet("Libraries/{machineId}")]
[PowerUser]
public async Task<PlexLibrariesResponse> GetPlexLibraries(string machineId)
{
try
{
var s = await PlexSettings.GetSettingsAsync();
var settings = s.Servers.FirstOrDefault(x => x.MachineIdentifier == machineId);
var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
return new PlexLibrariesResponse
{
Successful = true,
Data = libs
};
}
catch (Exception e)
{
_log.LogWarning(e, "Error thrown when attempting to obtain the plex libs");
var message = e.InnerException != null ? $"{e.Message} - {e.InnerException.Message}" : e.Message;
return new PlexLibrariesResponse
{
Successful = false,
Message = message
};
}
}
[HttpPost("user")]
[PowerUser]
public async Task<IActionResult> AddUser([FromBody] PlexUserViewModel user)
{
var s = await PlexSettings.GetSettingsAsync();
var server = s.Servers.FirstOrDefault(x => x.MachineIdentifier == user.MachineIdentifier);
var result = await PlexApi.AddUser(user.Username, user.MachineIdentifier, server.PlexAuthToken,
user.LibsSelected);
if (result.HasError)
{
return Json(new
{
Success = false,
Error = result.Error.Status
});
}
else
{
return Json(new
{
Success = true
});
}
}
/// <summary>
/// Gets the plex servers.
/// </summary>
/// <param name="u">The u.</param>
/// <returns></returns>
[HttpGet("servers")]
[PowerUser]
public async Task<IActionResult> GetServers()
{
try
{
var s = await PlexSettings.GetSettingsAsync();
var servers = new List<PlexServersAddUserModel>();
foreach (var plexServer in s.Servers)
{
servers.Add(new PlexServersAddUserModel
{
ServerId = plexServer.Id,
MachineId = plexServer.MachineIdentifier,
ServerName = plexServer.Name
});
}
return Json(new
{
Success = true,
Servers = servers
});
}
catch (Exception e)
{
_log.LogWarning(e, "Error thrown when attempting to obtain the GetServers for Add User VM");
return Json(new PlexServersViewModel
{
Success = false,
});
}
}
/// <summary>
/// Gets the plex servers.
/// </summary>

@ -0,0 +1,9 @@
namespace Ombi.Models.External
{
public class PlexServersAddUserModel
{
public string ServerName { get; set; }
public int ServerId { get; set; }
public string MachineId { get; set; }
}
}

@ -0,0 +1,9 @@
namespace Ombi.Models.External
{
public class PlexUserViewModel
{
public string Username { get; set; }
public string MachineIdentifier { get; set; }
public int[] LibsSelected { get; set; }
}
}
Loading…
Cancel
Save