mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-12 08:16:05 -07:00
!wip started on the Plex add user UI
This commit is contained in:
parent
51f5bbc6a8
commit
79fe8bb331
15 changed files with 379 additions and 14 deletions
|
@ -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);
|
||||
}
|
||||
}
|
84
src/Ombi.Api.Plex/Models/PlexAdd.cs
Normal file
84
src/Ombi.Api.Plex/Models/PlexAdd.cs
Normal file
|
@ -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">
|
||||
|
@ -128,3 +131,4 @@
|
|||
|
||||
<button type="button" class="btn btn-success-outline" (click)="bulkUpdate()">Update Users</button>
|
||||
</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,
|
||||
],
|
||||
|
||||
})
|
||||
|
|
94
src/Ombi/Controllers/External/PlexController.cs
vendored
94
src/Ombi/Controllers/External/PlexController.cs
vendored
|
@ -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>
|
||||
|
|
9
src/Ombi/Models/External/PlexServersAddUserModel.cs
vendored
Normal file
9
src/Ombi/Models/External/PlexServersAddUserModel.cs
vendored
Normal file
|
@ -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; }
|
||||
}
|
||||
}
|
9
src/Ombi/Models/External/PlexUserViewModel.cs
vendored
Normal file
9
src/Ombi/Models/External/PlexUserViewModel.cs
vendored
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue