mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-15 01:32:55 -07:00
Finished the wizard #865 (For Plex Anyway)
This commit is contained in:
parent
fa0e167650
commit
7294f942d9
13 changed files with 248 additions and 17 deletions
34
Ombi/Ombi.Core/Claims/OmbiClaims.cs
Normal file
34
Ombi/Ombi.Core/Claims/OmbiClaims.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: OmbiClaims.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
|
||||
namespace Ombi.Core.Claims
|
||||
{
|
||||
public static class OmbiClaims
|
||||
{
|
||||
public const string Admin = nameof(Admin);
|
||||
|
||||
}
|
||||
}
|
|
@ -51,6 +51,8 @@ namespace Ombi.Core.IdentityResolver
|
|||
public async Task<bool> CredentialsValid(string username, string password)
|
||||
{
|
||||
var user = await UserRepository.GetUser(username);
|
||||
if (user == null) return false;
|
||||
|
||||
var hash = HashPassword(password, user.Salt);
|
||||
|
||||
return hash.HashedPass.Equals(user.Password);
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ombi.Core.Claims;
|
||||
using Ombi.Core.IdentityResolver;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Models;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
|
@ -21,6 +26,37 @@ namespace Ombi.Controllers
|
|||
{
|
||||
return await IdentityManager.GetUser(this.HttpContext.User.Identity.Name);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is what the Wizard will call when creating the user for the very first time.
|
||||
/// This should never be called after this.
|
||||
/// The reason why we return false if users exists is that this method doesn't have any
|
||||
/// authorization and could be called from anywhere.
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("Wizard")]
|
||||
[AllowAnonymous]
|
||||
public async Task<bool> CreateWizardUser([FromBody] UserAuthModel user)
|
||||
{
|
||||
var users = await IdentityManager.GetUsers();
|
||||
if (users.Any())
|
||||
{
|
||||
// No one should be calling this. Only the wizard
|
||||
return false;
|
||||
}
|
||||
|
||||
await IdentityManager.CreateUser(new UserDto
|
||||
{
|
||||
Username = user.Username,
|
||||
UserType = UserType.LocalUser,
|
||||
Claims = new List<Claim>() {new Claim(ClaimTypes.Role, OmbiClaims.Admin)},
|
||||
Password = user.Password,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
65
Ombi/Ombi/Controllers/StatusController.cs
Normal file
65
Ombi/Ombi/Controllers/StatusController.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2017 Jamie Rees
|
||||
// File: StatusController.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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
|
||||
public class StatusController : BaseV1ApiController
|
||||
{
|
||||
public StatusController(ISettingsService<OmbiSettings> ombi)
|
||||
{
|
||||
Ombi = ombi;
|
||||
}
|
||||
|
||||
private ISettingsService<OmbiSettings> Ombi { get; }
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet]
|
||||
public HttpStatusCode GetStatus()
|
||||
{
|
||||
return HttpStatusCode.OK;
|
||||
}
|
||||
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("Wizard")]
|
||||
public async Task<object> WizardStatus()
|
||||
{
|
||||
var settings = await Ombi.GetSettingsAsync();
|
||||
|
||||
return new { Result = settings?.Wizard ?? false};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -20,6 +20,20 @@
|
|||
<Content Include="wwwroot\app\auth\IUserLogin.ts" />
|
||||
<Content Include="wwwroot\app\login\login.component.html" />
|
||||
<Content Include="wwwroot\app\login\login.component.ts" />
|
||||
<Content Include="wwwroot\app\services\identity - Copy.service.js">
|
||||
<DependentUpon>identity - Copy.service.ts</DependentUpon>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="wwwroot\app\services\identity - Copy.service.js.map">
|
||||
<DependentUpon>identity - Copy.service.js</DependentUpon>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="wwwroot\app\services\identity - Copy.service.ts">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="wwwroot\app\services\identity.service.js" />
|
||||
<Content Include="wwwroot\app\services\identity.service.js.map" />
|
||||
<Content Include="wwwroot\app\services\identity.service.ts" />
|
||||
<Content Include="wwwroot\app\services\plex.service.js" />
|
||||
<Content Include="wwwroot\app\services\plex.service.js.map" />
|
||||
<Content Include="wwwroot\app\services\plex.service.ts">
|
||||
|
@ -28,6 +42,10 @@
|
|||
<Content Include="wwwroot\app\services\settings.service.js" />
|
||||
<Content Include="wwwroot\app\services\settings.service.js.map" />
|
||||
<Content Include="wwwroot\app\services\settings.service.ts" />
|
||||
<Content Include="wwwroot\app\services\status.service.js" />
|
||||
<Content Include="wwwroot\app\services\status.service.js.map" />
|
||||
<Content Include="wwwroot\app\services\status.service.ts" />
|
||||
<Content Include="wwwroot\app\services\useridentity.service.ts" />
|
||||
<Content Include="wwwroot\app\settings\emby\emby.component.html" />
|
||||
<Content Include="wwwroot\app\settings\emby\emby.component.js" />
|
||||
<Content Include="wwwroot\app\settings\emby\emby.component.js.map" />
|
||||
|
@ -59,11 +77,6 @@
|
|||
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js" />
|
||||
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.js.map" />
|
||||
<Content Include="wwwroot\app\wizard\createadmin\createadmin.component.ts" />
|
||||
<Content Include="wwwroot\app\wizard\createadmin\plex.component.js">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="wwwroot\app\wizard\createadmin\plex.component.js.map" />
|
||||
<Content Include="wwwroot\app\wizard\createadmin\plex.component.ts" />
|
||||
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.html">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p-growl [value]="notificationService.messages" [life]="500000"></p-growl>
|
||||
|
||||
<nav class="navbar navbar-default navbar-fixed-top">
|
||||
<nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
|
|
|
@ -9,5 +9,13 @@ import { AuthService } from './auth/auth.service';
|
|||
})
|
||||
export class AppComponent {
|
||||
|
||||
constructor(public notificationService: NotificationService, public authService : AuthService) { };
|
||||
constructor(public notificationService: NotificationService, public authService: AuthService) {
|
||||
this.showNav = true;
|
||||
//console.log(this.route);
|
||||
//if (this.route.("/Wizard/*") !== -1) {
|
||||
// this.showNav = false;
|
||||
//}
|
||||
}
|
||||
|
||||
showNav :boolean;
|
||||
}
|
|
@ -23,6 +23,9 @@ import { SettingsService } from './services/settings.service';
|
|||
import { AuthService } from './auth/auth.service';
|
||||
import { AuthGuard } from './auth/auth.guard';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { IdentityService } from './services/identity.service';
|
||||
import { StatusService } from './services/status.service';
|
||||
|
||||
|
||||
// Modules
|
||||
import { SettingsModule } from './settings/settings.module';
|
||||
|
@ -69,7 +72,9 @@ const routes: Routes = [
|
|||
NotificationService,
|
||||
AuthService,
|
||||
AuthGuard,
|
||||
SettingsService
|
||||
SettingsService,
|
||||
IdentityService,
|
||||
StatusService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { StatusService } from '../services/status.service';
|
||||
import { NotificationService } from '../services/notification.service';
|
||||
|
||||
@Component({
|
||||
|
@ -11,7 +11,13 @@ import { NotificationService } from '../services/notification.service';
|
|||
templateUrl: './login.component.html',
|
||||
})
|
||||
export class LoginComponent {
|
||||
constructor(private authService: AuthService, private router: Router, private notify: NotificationService) { }
|
||||
constructor(private authService: AuthService, private router: Router, private notify: NotificationService, private status: StatusService) {
|
||||
this.status.getWizardStatus().subscribe(x => {
|
||||
if (!x.result) {
|
||||
this.router.navigate(['Wizard']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
username: string;
|
||||
|
|
17
Ombi/Ombi/wwwroot/app/services/identity.service.ts
Normal file
17
Ombi/Ombi/wwwroot/app/services/identity.service.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ServiceAuthHelpers } from './service.helpers';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class IdentityService extends ServiceAuthHelpers {
|
||||
constructor(http: AuthHttp, private regularHttp : Http) {
|
||||
super(http, '/api/v1/Identity/');
|
||||
}
|
||||
createUser(username:string,password:string): Observable<boolean> {
|
||||
return this.regularHttp.post(`${this.url}/Wizard/`, JSON.stringify({username:username, password:password}), { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
}
|
16
Ombi/Ombi/wwwroot/app/services/status.service.ts
Normal file
16
Ombi/Ombi/wwwroot/app/services/status.service.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ServiceHelpers } from './service.helpers';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class StatusService extends ServiceHelpers {
|
||||
constructor(http : Http) {
|
||||
super(http, '/api/v1/status/');
|
||||
}
|
||||
getWizardStatus(): Observable<any> {
|
||||
return this.http.get(`${this.url}/Wizard/`, { headers: this.headers }).map(this.extractData);
|
||||
}
|
||||
}
|
|
@ -1,23 +1,47 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { IdentityService } from '../../services/identity.service';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import { AuthService } from '../../auth/auth.service';
|
||||
import { NotificationService } from '../../services/notification.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ombi',
|
||||
moduleId: module.id,
|
||||
templateUrl: './plex.component.html',
|
||||
templateUrl: './createadmin.component.html',
|
||||
})
|
||||
export class PlexComponent {
|
||||
export class CreateAdminComponent {
|
||||
|
||||
constructor(private identityService: IdentityService, private notificationService: NotificationService,
|
||||
private router: Router, private auth: AuthService, private settings: SettingsService) { }
|
||||
|
||||
constructor(private authService: AuthService, private notificationService: NotificationService) { }
|
||||
|
||||
|
||||
username: string;
|
||||
password: string;
|
||||
|
||||
createUser() {
|
||||
this.identityService.createUser(this.username, this.password).subscribe(x => {
|
||||
if (x) {
|
||||
// Log me in.
|
||||
this.auth.login({ username: this.username, password: this.password }).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();
|
||||
|
||||
this.router.navigate(['search']);
|
||||
});
|
||||
|
||||
});
|
||||
} else {
|
||||
this.notificationService.error("Error in creating user",
|
||||
"There was an error... You might want to put this on Github...");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,13 +6,16 @@ import { RouterModule, Routes } from '@angular/router';
|
|||
import { WelcomeComponent } from './welcome/welcome.component';
|
||||
import { MediaServerComponent } from './mediaserver/mediaserver.component';
|
||||
import { PlexComponent } from './plex/plex.component';
|
||||
import { CreateAdminComponent } from './createadmin/createadmin.component';
|
||||
|
||||
import { PlexService } from '../services/plex.service';
|
||||
import { IdentityService } from '../services/identity.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'Wizard', component: WelcomeComponent},
|
||||
{ path: 'Wizard/MediaServer', component: MediaServerComponent},
|
||||
{ path: 'Wizard/Plex', component: PlexComponent},
|
||||
{ path: 'Wizard/CreateAdmin', component: CreateAdminComponent},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -24,13 +27,15 @@ const routes: Routes = [
|
|||
declarations: [
|
||||
WelcomeComponent,
|
||||
MediaServerComponent,
|
||||
PlexComponent
|
||||
PlexComponent,
|
||||
CreateAdminComponent
|
||||
],
|
||||
exports: [
|
||||
RouterModule
|
||||
],
|
||||
providers: [
|
||||
PlexService
|
||||
PlexService,
|
||||
IdentityService
|
||||
],
|
||||
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue