mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
Got some nice improvements on the Wizard
This commit is contained in:
parent
541f50ffe1
commit
7f566f00dd
10 changed files with 78 additions and 40 deletions
|
@ -14,6 +14,8 @@ export interface IPlexOAuthViewModel {
|
||||||
|
|
||||||
export interface IPlexOAuthAccessToken {
|
export interface IPlexOAuthAccessToken {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
|
success: boolean;
|
||||||
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlexUser {
|
export interface IPlexUser {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<input type="password" matInput id="adminPassword" name="Password" [(ngModel)]="user.password" placeholder="Password">
|
<input type="password" matInput id="adminPassword" name="Password" [(ngModel)]="user.password" placeholder="Password">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<small class="important">You'll need to configure e-mail to recover any lost password!</small>
|
<small class="important">You'll need to configure e-mail to reset your password!</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,21 +4,22 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="right-container mediaserver">
|
<div class="right-container mediaserver">
|
||||||
<div class="right-container-content mediaserver">
|
<div class="right-container-content mediaserver">
|
||||||
<h1>Customize your Ombi</h1>
|
<h1 *ngIf="!config.applicationName">Customize your Ombi</h1>
|
||||||
|
<h1 *ngIf="config.applicationName">Customize your {{config.applicationName}}</h1>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input type="text" matInput id="applicationname" name="Application Name" placeholder="Application Name">
|
<input type="text" matInput id="applicationname" name="Application Name" [(ngModel)]="config.applicationName" placeholder="Application Name">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput type="text" id="applicationurl" name="Application URL" placeholder="Application URL">
|
<input matInput type="text" id="applicationurl" name="Application URL" [(ngModel)]="config.applicationUrl" placeholder="Application URL">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Custom Logo</mat-label>
|
<mat-label>Custom Logo</mat-label>
|
||||||
<input matInput type="url" id="customlogo" name="Custom Logo" placeholder="Input the URL of your custom logo">
|
<input matInput type="url" id="customlogo" name="Custom Logo" [(ngModel)]="config.logo" placeholder="Input the URL of your custom logo">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { Component, Input } from "@angular/core";
|
import { Component, Input } from "@angular/core";
|
||||||
|
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
|
||||||
|
import { WizardService } from "../services/wizard.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "wizard-ombi",
|
selector: "wizard-ombi",
|
||||||
|
@ -7,5 +9,5 @@
|
||||||
})
|
})
|
||||||
export class OmbiConfigComponent {
|
export class OmbiConfigComponent {
|
||||||
|
|
||||||
constructor() { }
|
@Input() public config: IOmbiConfigModel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput type="text" [(ngModel)]="login" id="username" placeholder="Username">
|
<input matInput type="text" [(ngModel)]="login" id="username" placeholder="Username" [disabled]="completed">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput type="password" [(ngModel)]="password" placeholder="Password">
|
<input matInput type="password" [(ngModel)]="password" placeholder="Password" [disabled]="completed">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,13 +21,15 @@
|
||||||
<div class="plex-buttons">
|
<div class="plex-buttons">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div style="text-align: center; margin-top: 20px">
|
<div style="text-align: center; margin-top: 20px">
|
||||||
<button (click)="requestAuthToken()" mat-raised-button color="primary" class="viewon-btn standard">Request Token <i class="fas fa-key"></i></button>
|
<button (click)="requestAuthToken()" mat-raised-button color="primary" class="viewon-btn standard" [disabled]="completed">Request Token <i class="fas fa-key"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-center space-or">OR</p>
|
<p class="text-center space-or">OR</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div style="text-align: center; margin-top: 20px">
|
<div style="text-align: center; margin-top: 20px">
|
||||||
<button (click)="oauth()" mat-raised-button color="accent" type="button" class="viewon-btn plex">Login With Plex</button>
|
<button (click)="oauth()" mat-raised-button color="accent" type="button" class="viewon-btn plex" [disabled]="completed">
|
||||||
|
<i *ngIf="oauthLoading" class="fas fa-circle-notch fa-spin fa-fw"></i>
|
||||||
|
Login With Plex</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,6 +16,8 @@ export class PlexComponent implements OnInit, OnDestroy {
|
||||||
public login: string;
|
public login: string;
|
||||||
public password: string;
|
public password: string;
|
||||||
public pinTimer: any;
|
public pinTimer: any;
|
||||||
|
public completed: boolean;
|
||||||
|
public oauthLoading: boolean;
|
||||||
|
|
||||||
private clientId: string;
|
private clientId: string;
|
||||||
|
|
||||||
|
@ -43,7 +45,7 @@ export class PlexComponent implements OnInit, OnDestroy {
|
||||||
usePlexAdminAccount: true,
|
usePlexAdminAccount: true,
|
||||||
}).subscribe(y => {
|
}).subscribe(y => {
|
||||||
if (y.result) {
|
if (y.result) {
|
||||||
this.router.navigate(["login"]);
|
this.notificationService.success("Created your Plex User!");
|
||||||
} else {
|
} else {
|
||||||
this.notificationService.error("Could not get the Plex Admin Information");
|
this.notificationService.error("Could not get the Plex Admin Information");
|
||||||
if (y.errors.length > 0) {
|
if (y.errors.length > 0) {
|
||||||
|
@ -57,6 +59,7 @@ export class PlexComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public oauth() {
|
public oauth() {
|
||||||
|
this.oauthLoading = true;
|
||||||
const oAuthWindow = window.open(window.location.toString(), "_blank", `toolbar=0,
|
const oAuthWindow = window.open(window.location.toString(), "_blank", `toolbar=0,
|
||||||
location=0,
|
location=0,
|
||||||
status=0,
|
status=0,
|
||||||
|
@ -69,20 +72,24 @@ export class PlexComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
|
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
|
||||||
oAuthWindow!.location.replace(x.url);
|
oAuthWindow!.location.replace(x.url);
|
||||||
|
|
||||||
this.pinTimer = setInterval(() => {
|
this.pinTimer = setInterval(() => {
|
||||||
// this.notify.info("Authenticating", "Loading... Please Wait");
|
// this.notify.info("Authenticating", "Loading... Please Wait");
|
||||||
this.getPinResult(x.pinId);
|
this.getPinResult(x.pinId);
|
||||||
}, 10000);
|
}, 3000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPinResult(pinId: number) {
|
public getPinResult(pinId: number) {
|
||||||
this.plexOauth.oAuth(pinId).subscribe(x => {
|
this.plexOauth.oAuth(pinId).subscribe(x => {
|
||||||
|
|
||||||
if (!x.accessToken) {
|
if (!x.accessToken) {
|
||||||
|
if(!x.success) {
|
||||||
|
this.oauthLoading = false;
|
||||||
|
clearInterval(this.pinTimer);
|
||||||
|
this.notificationService.error(`Error From Plex: ${x.error}`)
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
// RETURN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.identityService.createWizardUser({
|
this.identityService.createWizardUser({
|
||||||
|
@ -93,10 +100,14 @@ export class PlexComponent implements OnInit, OnDestroy {
|
||||||
if (u.result) {
|
if (u.result) {
|
||||||
this.authService.oAuth(pinId).subscribe(c => {
|
this.authService.oAuth(pinId).subscribe(c => {
|
||||||
this.store.save("id_token", c.access_token);
|
this.store.save("id_token", c.access_token);
|
||||||
this.router.navigate(["login"]);
|
this.completed = true;
|
||||||
|
this.notificationService.success("Created your Plex User!");
|
||||||
|
this.oauthLoading = false;
|
||||||
|
clearInterval(this.pinTimer);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
this.oauthLoading = false;
|
||||||
if (u.errors.length > 0) {
|
if (u.errors.length > 0) {
|
||||||
console.log(u.errors[0]);
|
console.log(u.errors[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { PlatformLocation, APP_BASE_HREF } from "@angular/common";
|
import { PlatformLocation, APP_BASE_HREF } from "@angular/common";
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { Injectable, Inject } from "@angular/core";
|
import { Injectable, Inject } from "@angular/core";
|
||||||
|
import { Observable } from "rxjs";
|
||||||
import { ICustomizationSettings } from "../../interfaces";
|
import { ICustomizationSettings } from "../../interfaces";
|
||||||
import { ServiceHelpers } from "../../services";
|
import { ServiceHelpers } from "../../services";
|
||||||
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
|
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
|
||||||
|
@ -12,7 +13,7 @@ export class WizardService extends ServiceHelpers {
|
||||||
super(http, "/api/v2/wizard/", href);
|
super(http, "/api/v2/wizard/", href);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async addOmbiConfig(config: IOmbiConfigModel): Promise<ICustomizationSettings> {
|
public addOmbiConfig(config: IOmbiConfigModel): Observable<ICustomizationSettings> {
|
||||||
return await this.http.post<ICustomizationSettings>(`${this.url}config`, config, {headers: this.headers}).toPromise();
|
return this.http.post<ICustomizationSettings>(`${this.url}config`, config, {headers: this.headers});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
<mat-step [optional]="true">
|
<mat-step [optional]="true">
|
||||||
<form >
|
<form >
|
||||||
<ng-template matStepLabel>Ombi config</ng-template>
|
<ng-template matStepLabel>Ombi config</ng-template>
|
||||||
<wizard-ombi></wizard-ombi>
|
<wizard-ombi [config]="config"></wizard-ombi>
|
||||||
<div>
|
<div>
|
||||||
<button mat-button matStepperPrevious class="mat-raised-button mat-error left">Back</button>
|
<button mat-button matStepperPrevious class="mat-raised-button mat-error left">Back</button>
|
||||||
<button mat-button matStepperNext class="mat-raised-button mat-accent right">Next</button>
|
<button mat-button matStepperNext class="mat-raised-button mat-accent right">Next</button>
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { AfterViewInit, Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
import { ICreateWizardUser } from "../../interfaces";
|
import { ICreateWizardUser } from "../../interfaces";
|
||||||
import { IdentityService, NotificationService } from "../../services";
|
import { IdentityService, NotificationService } from "../../services";
|
||||||
|
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
|
||||||
|
import { WizardService } from "../services/wizard.service";
|
||||||
|
import { MatHorizontalStepper } from'@angular/material/stepper';
|
||||||
|
import { StepperSelectionEvent } from "@angular/cdk/stepper";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./welcome.component.html",
|
templateUrl: "./welcome.component.html",
|
||||||
|
@ -10,10 +13,12 @@ import { IdentityService, NotificationService } from "../../services";
|
||||||
})
|
})
|
||||||
export class WelcomeComponent implements OnInit {
|
export class WelcomeComponent implements OnInit {
|
||||||
|
|
||||||
|
@ViewChild('stepper', {static: false}) public stepper: MatHorizontalStepper;
|
||||||
public localUser: ICreateWizardUser;
|
public localUser: ICreateWizardUser;
|
||||||
|
public config: IOmbiConfigModel;
|
||||||
|
|
||||||
constructor(private router: Router,
|
constructor(private router: Router, private identityService: IdentityService,
|
||||||
private identityService: IdentityService, private notificationService: NotificationService) { }
|
private notificationService: NotificationService, private WizardService: WizardService) { }
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.localUser = {
|
this.localUser = {
|
||||||
|
@ -21,17 +26,28 @@ export class WelcomeComponent implements OnInit {
|
||||||
username:"",
|
username:"",
|
||||||
usePlexAdminAccount:false
|
usePlexAdminAccount:false
|
||||||
}
|
}
|
||||||
|
this.config = {
|
||||||
|
applicationName: null,
|
||||||
|
applicationUrl: null,
|
||||||
|
logo: null
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public createUser() {
|
public createUser() {
|
||||||
|
this.WizardService.addOmbiConfig(this.config).subscribe(config => {
|
||||||
|
if(config != null) {
|
||||||
this.identityService.createWizardUser(this.localUser).subscribe(x => {
|
this.identityService.createWizardUser(this.localUser).subscribe(x => {
|
||||||
if (x.result) {
|
if (x.result) {
|
||||||
|
// save the config
|
||||||
this.router.navigate(["login"]);
|
this.router.navigate(["login"]);
|
||||||
} else {
|
} else {
|
||||||
if (x.errors.length > 0) {
|
if (x.errors.length > 0) {
|
||||||
this.notificationService.error(x.errors[0]);
|
this.notificationService.error(x.errors[0]);
|
||||||
|
this.stepper.previous();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}, configErr => this.notificationService.error(configErr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ namespace Ombi.Controllers.V1
|
||||||
public async Task<SaveWizardResult> CreateWizardUser([FromBody] CreateUserWizardModel user)
|
public async Task<SaveWizardResult> CreateWizardUser([FromBody] CreateUserWizardModel user)
|
||||||
{
|
{
|
||||||
var users = UserManager.Users;
|
var users = UserManager.Users;
|
||||||
if (users.Any(x => x.NormalizedUserName != "API"))
|
if (users.Any(x => x.UserType == UserType.LocalUser))
|
||||||
{
|
{
|
||||||
// No one should be calling this. Only the wizard
|
// No one should be calling this. Only the wizard
|
||||||
return new SaveWizardResult { Result = false, Errors = new List<string> { "Looks like there is an existing user!" } };
|
return new SaveWizardResult { Result = false, Errors = new List<string> { "Looks like there is an existing user!" } };
|
||||||
|
@ -169,7 +169,7 @@ namespace Ombi.Controllers.V1
|
||||||
ImportPlexAdmin = true
|
ImportPlexAdmin = true
|
||||||
});
|
});
|
||||||
|
|
||||||
return await SaveWizardUser(user, adminUser);
|
return await SaveWizardUser(user, adminUser, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userToCreate = new OmbiUser
|
var userToCreate = new OmbiUser
|
||||||
|
@ -179,10 +179,10 @@ namespace Ombi.Controllers.V1
|
||||||
StreamingCountry = "US"
|
StreamingCountry = "US"
|
||||||
};
|
};
|
||||||
|
|
||||||
return await SaveWizardUser(user, userToCreate);
|
return await SaveWizardUser(user, userToCreate, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<SaveWizardResult> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate)
|
private async Task<SaveWizardResult> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate, bool completeWizard)
|
||||||
{
|
{
|
||||||
IdentityResult result;
|
IdentityResult result;
|
||||||
var retVal = new SaveWizardResult();
|
var retVal = new SaveWizardResult();
|
||||||
|
@ -210,11 +210,14 @@ namespace Ombi.Controllers.V1
|
||||||
_log.LogInformation("Added the Admin role");
|
_log.LogInformation("Added the Admin role");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (completeWizard)
|
||||||
|
{
|
||||||
// Update the wizard flag
|
// Update the wizard flag
|
||||||
var settings = await OmbiSettings.GetSettingsAsync();
|
var settings = await OmbiSettings.GetSettingsAsync();
|
||||||
settings.Wizard = true;
|
settings.Wizard = true;
|
||||||
await OmbiSettings.SaveSettingsAsync(settings);
|
await OmbiSettings.SaveSettingsAsync(settings);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
LogErrors(result);
|
LogErrors(result);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue