mirror of
https://github.com/fergalmoran/podnoms.git
synced 2025-12-22 09:18:08 +00:00
Basic re-auth framework in place
This commit is contained in:
@@ -1,78 +1,79 @@
|
||||
{
|
||||
"name": "pod-noms.web",
|
||||
"version": "0.21.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --aot",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"ngrxGen": {
|
||||
"basePath": "./src/app",
|
||||
"seperateDirectory": true
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.2.10",
|
||||
"@angular/common": "^5.2.10",
|
||||
"@angular/compiler": "^5.2.10",
|
||||
"@angular/core": "^5.2.10",
|
||||
"@angular/forms": "^5.2.10",
|
||||
"@angular/http": "^5.2.10",
|
||||
"@angular/platform-browser": "^5.2.10",
|
||||
"@angular/platform-browser-dynamic": "^5.2.10",
|
||||
"@angular/router": "^5.2.10",
|
||||
"@aspnet/signalr": "1.0.0-rc1-30631",
|
||||
"@ngrx/effects": "^5.1.0",
|
||||
"@ngrx/store": "^5.1.0",
|
||||
"@ngrx/store-devtools": "^5.1.0",
|
||||
"@qontu/ngx-inline-editor": "^0.2.0-alpha.12",
|
||||
"angular2-jwt": "^0.2.3",
|
||||
"angular2-moment": "^1.8.0",
|
||||
"angularfire2": "^5.0.0-rc.6",
|
||||
"applicationinsights-js": "^1.0.15",
|
||||
"auth0": "^2.9.1",
|
||||
"auth0-lock": "^11.4.0",
|
||||
"bootstrap": "4.1.0",
|
||||
"core-js": "^2.5.3",
|
||||
"dropzone": "^5.3.0",
|
||||
"firebase": "^4.13.1",
|
||||
"font-awesome": "^4.7.0",
|
||||
"howler": "^2.0.9",
|
||||
"jquery": "^3.3.1",
|
||||
"lodash": "^4.17.5",
|
||||
"ng2-toasty": "^4.0.3",
|
||||
"ngx-bootstrap": "^2.0.4",
|
||||
"ngx-clipboard": "^10.0.0",
|
||||
"ngx-moment": "^2.0.0-rc.0",
|
||||
"popper.js": "^1.13.0",
|
||||
"rxjs": "5.5.6",
|
||||
"simple-line-icons": "^2.4.1",
|
||||
"tether": "^1.4.3",
|
||||
"uglify-es": "^3.3.10",
|
||||
"zone.js": "^0.8.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.7.4",
|
||||
"@angular/compiler-cli": "^5.2.6",
|
||||
"@angular/language-service": "^5.2.6",
|
||||
"@types/applicationinsights-js": "^1.0.5",
|
||||
"@types/jasmine": "^2.8.6",
|
||||
"@types/node": "~9.4.6",
|
||||
"codelyzer": "^4.2.1",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~2.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.4.1",
|
||||
"karma-jasmine": "^1.1.1",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.3.0",
|
||||
"ts-node": "^5.0.1",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.5.3"
|
||||
}
|
||||
"name": "pod-noms.web",
|
||||
"version": "0.21.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --aot",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"ngrxGen": {
|
||||
"basePath": "./src/app",
|
||||
"seperateDirectory": true
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.2.10",
|
||||
"@angular/common": "^5.2.10",
|
||||
"@angular/compiler": "^5.2.10",
|
||||
"@angular/core": "^5.2.10",
|
||||
"@angular/forms": "^5.2.10",
|
||||
"@angular/http": "^5.2.10",
|
||||
"@angular/platform-browser": "^5.2.10",
|
||||
"@angular/platform-browser-dynamic": "^5.2.10",
|
||||
"@angular/router": "^5.2.10",
|
||||
"@aspnet/signalr": "1.0.0-rc1-30631",
|
||||
"@ngrx/effects": "^5.1.0",
|
||||
"@ngrx/store": "^5.1.0",
|
||||
"@ngrx/store-devtools": "^5.1.0",
|
||||
"@qontu/ngx-inline-editor": "^0.2.0-alpha.12",
|
||||
"angular2-jwt": "^0.2.3",
|
||||
"angular2-moment": "^1.8.0",
|
||||
"angularfire2": "^5.0.0-rc.6",
|
||||
"angularx-social-login": "^1.1.8",
|
||||
"applicationinsights-js": "^1.0.15",
|
||||
"auth0": "^2.9.1",
|
||||
"auth0-lock": "^11.4.0",
|
||||
"bootstrap": "4.1.0",
|
||||
"core-js": "^2.5.3",
|
||||
"dropzone": "^5.3.0",
|
||||
"firebase": "^4.13.1",
|
||||
"font-awesome": "^4.7.0",
|
||||
"howler": "^2.0.9",
|
||||
"jquery": "^3.3.1",
|
||||
"lodash": "^4.17.5",
|
||||
"ng2-toasty": "^4.0.3",
|
||||
"ngx-bootstrap": "^2.0.4",
|
||||
"ngx-clipboard": "^10.0.0",
|
||||
"ngx-moment": "^2.0.0-rc.0",
|
||||
"popper.js": "^1.13.0",
|
||||
"rxjs": "5.5.6",
|
||||
"simple-line-icons": "^2.4.1",
|
||||
"tether": "^1.4.3",
|
||||
"uglify-es": "^3.3.10",
|
||||
"zone.js": "^0.8.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.7.4",
|
||||
"@angular/compiler-cli": "^5.2.6",
|
||||
"@angular/language-service": "^5.2.6",
|
||||
"@types/applicationinsights-js": "^1.0.5",
|
||||
"@types/jasmine": "^2.8.6",
|
||||
"@types/node": "~9.4.6",
|
||||
"codelyzer": "^4.2.1",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~2.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.4.1",
|
||||
"karma-jasmine": "^1.1.1",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.3.0",
|
||||
"ts-node": "^5.0.1",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { GlobalsService } from './services/globals.service';
|
||||
import { Component, HostBinding, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ToastyService } from 'ng2-toasty';
|
||||
import { AuthService } from 'app/services/auth.service';
|
||||
import { PodnomsAuthService } from 'app/services/podnoms-auth.service';
|
||||
import { AppInsightsService } from 'app/services/app-insights.service';
|
||||
import { SignalRService } from 'app/services/signalr.service';
|
||||
import { ProfileService } from './services/profile.service';
|
||||
@@ -15,15 +15,13 @@ import { MessagingService } from 'app/services/messaging.service';
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
private _authService: AuthService,
|
||||
private _authService: PodnomsAuthService,
|
||||
private _toastyService: ToastyService,
|
||||
private _signalrService: SignalRService,
|
||||
private _profileService: ProfileService,
|
||||
private _messagingService: MessagingService,
|
||||
_appInsights: AppInsightsService
|
||||
) {
|
||||
_authService.handleAuthentication();
|
||||
_authService.scheduleRenewal();
|
||||
}
|
||||
loggedIn() {
|
||||
return this._authService.isAuthenticated();
|
||||
|
||||
@@ -12,10 +12,14 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
|
||||
import { AngularFireDatabaseModule } from 'angularfire2/database';
|
||||
import { AngularFireAuthModule } from 'angularfire2/auth';
|
||||
import { AngularFireModule } from 'angularfire2';
|
||||
import { SocialLoginModule, AuthServiceConfig } from 'angularx-social-login';
|
||||
import {
|
||||
GoogleLoginProvider,
|
||||
FacebookLoginProvider
|
||||
} from 'angularx-social-login';
|
||||
|
||||
import { ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { AuthGuard } from './services/auth.guard';
|
||||
import { AuthConfig, AuthHttp } from 'angular2-jwt';
|
||||
import { ImageService } from './services/image.service';
|
||||
import { DebugService } from './services/debug.service';
|
||||
import { ChatterService } from './services/chatter.service';
|
||||
@@ -31,7 +35,7 @@ import { AppComponent } from './app.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { NavbarComponent } from './components/navbar/navbar.component';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { PodnomsAuthService } from './services/podnoms-auth.service';
|
||||
import { ProfileService } from './services/profile.service';
|
||||
import { MomentModule } from 'angular2-moment';
|
||||
import { FilterEntryPipe } from './pipes/filter-entry.pipe';
|
||||
@@ -61,17 +65,21 @@ import { environment } from 'environments/environment';
|
||||
import { FooterPlayerComponent } from 'app/components/footer-player/footer-player.component';
|
||||
import { AudioService } from 'app/services/audio.service';
|
||||
import { HumaniseTimePipe } from './pipes/humanise-time.pipe';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||
import { PodNomsApiInterceptor } from './interceptors/podnoms-api.interceptor';
|
||||
|
||||
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
|
||||
return new AuthHttp(
|
||||
new AuthConfig({
|
||||
noClientCheck: true,
|
||||
globalHeaders: [{ 'Content-Type': 'application/json' }],
|
||||
tokenGetter: () => localStorage.getItem('id_token')
|
||||
}),
|
||||
http,
|
||||
options
|
||||
);
|
||||
let config = new AuthServiceConfig([
|
||||
{
|
||||
id: GoogleLoginProvider.PROVIDER_ID,
|
||||
provider: new GoogleLoginProvider('Google-OAuth-Client-Id')
|
||||
},
|
||||
{
|
||||
id: FacebookLoginProvider.PROVIDER_ID,
|
||||
provider: new FacebookLoginProvider('117715354940616')
|
||||
}
|
||||
]);
|
||||
export function provideConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
@@ -112,7 +120,7 @@ export function authHttpServiceFactory(http: Http, options: RequestOptions) {
|
||||
}),
|
||||
AngularFireDatabaseModule,
|
||||
AngularFireAuthModule,
|
||||
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
HttpModule,
|
||||
FormsModule,
|
||||
@@ -123,6 +131,7 @@ export function authHttpServiceFactory(http: Http, options: RequestOptions) {
|
||||
ToastyModule.forRoot(),
|
||||
DropzoneModule,
|
||||
ClipboardModule,
|
||||
SocialLoginModule,
|
||||
|
||||
StoreModule.forRoot(reducers),
|
||||
|
||||
@@ -136,12 +145,16 @@ export function authHttpServiceFactory(http: Http, options: RequestOptions) {
|
||||
})
|
||||
],
|
||||
providers: [
|
||||
AuthService,
|
||||
PodnomsAuthService,
|
||||
AuthGuard,
|
||||
{
|
||||
provide: AuthHttp,
|
||||
useFactory: authHttpServiceFactory,
|
||||
deps: [Http, RequestOptions]
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: PodNomsApiInterceptor,
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: AuthServiceConfig,
|
||||
useFactory: provideConfig
|
||||
},
|
||||
SignalRService,
|
||||
ProfileService,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AuthService } from 'app/services/auth.service';
|
||||
import { PodnomsAuthService } from 'app/services/podnoms-auth.service';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
@@ -8,7 +8,7 @@ import { Router } from '@angular/router';
|
||||
styleUrls: ['./callback.component.css']
|
||||
})
|
||||
export class CallbackComponent implements OnInit {
|
||||
constructor(private _authService: AuthService, private _router: Router) {}
|
||||
constructor(private _authService: PodnomsAuthService, private _router: Router) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._router.navigate(['/podcasts']);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AuthService } from 'app/services/auth.service';
|
||||
import { PodnomsAuthService } from 'app/services/podnoms-auth.service';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Router } from '@angular/router';
|
||||
styleUrls: ['./home.component.css']
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
constructor(private _router: Router, private _authService: AuthService) {}
|
||||
constructor(private _router: Router, private _authService: PodnomsAuthService) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this._authService.isAuthenticated) {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.new-user-alert {
|
||||
padding-top: 2.5rem;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<div id="page-container"
|
||||
class="main-content-boxed">
|
||||
<div id="page-container" class="main-content-boxed">
|
||||
<main id="main-container">
|
||||
<div class="bg-image"
|
||||
style="background-image: url('/assets/img/robothand.jpg'); background-size: 100% 100%;">
|
||||
<div class="bg-image" style="background-image: url('/assets/img/robothand.jpg'); background-size: 100% 100%;">
|
||||
<div class="hero-static content content-full bg-white">
|
||||
<div class="text-center">
|
||||
<a class="link-effect font-w700">
|
||||
@@ -15,37 +13,26 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 mb-5">
|
||||
<button class="btn btn-facebook"
|
||||
(click)="login('facebook')"
|
||||
style="width: 100%"><i class="fa fa-facebook"></i> Facebook</button>
|
||||
<button class="btn btn-facebook" (click)="login('facebook')" style="width: 100%">
|
||||
<i class="fa fa-facebook"></i> Facebook</button>
|
||||
</div>
|
||||
<div class="col-sm-4 mb-5">
|
||||
<button class="btn btn-google-plus"
|
||||
(click)="login('google-oauth2')"
|
||||
style="width: 100%"><i class="fa fa-google"></i> Google</button>
|
||||
<button class="btn btn-google-plus" (click)="login('google-oauth2')" style="width: 100%">
|
||||
<i class="fa fa-google"></i> Google</button>
|
||||
</div>
|
||||
<div class="col-sm-4 mb-5">
|
||||
<button class="btn btn-twitter"
|
||||
(click)="login('twitter')"
|
||||
style="width: 100%"><i class="fa fa-twitter"></i> Twitter</button>
|
||||
<button class="btn btn-twitter" (click)="login('twitter')" style="width: 100%">
|
||||
<i class="fa fa-twitter"></i> Twitter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-sm-8 col-md-6 col-xl-4">
|
||||
<form class="js-validation-signin"
|
||||
action=""
|
||||
(ngSubmit)="login()"
|
||||
method="post">
|
||||
<form class="js-validation-signin" action="" (ngSubmit)="login()" method="post">
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<div class="form-material floating">
|
||||
<input type="text"
|
||||
autocomplete="username"
|
||||
class="form-control"
|
||||
id="login-username"
|
||||
name="login-username"
|
||||
[(ngModel)]="username">
|
||||
<input type="text" autocomplete="username" class="form-control" id="login-username" name="login-username" [(ngModel)]="username">
|
||||
<label for="login-username">Email Address</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,37 +40,32 @@
|
||||
<div class="form-group row">
|
||||
<div class="col-12">
|
||||
<div class="form-material floating">
|
||||
<input type="password"
|
||||
autocomplete="current-password"
|
||||
class="form-control"
|
||||
id="login-password"
|
||||
name="login-password"
|
||||
[(ngModel)]="password">
|
||||
<input type="password" autocomplete="current-password" class="form-control" id="login-password" name="login-password" [(ngModel)]="password">
|
||||
<label for="login-password">Password</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-danger"
|
||||
*ngIf="errorMessage"
|
||||
role="alert">
|
||||
<div class="alert alert-danger" *ngIf="errorMessage" role="alert">
|
||||
{{errorMessage}}
|
||||
</div>
|
||||
<div class="col-md-12 new-user-alert" *ngIf="brandNew">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong>Account created!</strong> Please login with your new details
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row gutters-tiny">
|
||||
<div class="col-12 mb-10">
|
||||
<button type="submit"
|
||||
class="btn btn-block btn-hero btn-noborder btn-rounded btn-alt-primary">
|
||||
<button type="submit" class="btn btn-block btn-hero btn-noborder btn-rounded btn-alt-primary">
|
||||
<i class="icon-login mr-10"></i> Sign In
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-6 mb-5">
|
||||
<a class="btn btn-block btn-noborder btn-rounded btn-alt-secondary"
|
||||
[routerLink]="['/register']">
|
||||
<a class="btn btn-block btn-noborder btn-rounded btn-alt-secondary" [routerLink]="['/register']">
|
||||
<i class="fa fa-plus text-muted mr-5"></i> New Account
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-6 mb-5">
|
||||
<a class="btn btn-block btn-noborder btn-rounded btn-alt-secondary"
|
||||
[routerLink]="['/reset']">
|
||||
<a class="btn btn-block btn-noborder btn-rounded btn-alt-secondary" [routerLink]="['/reset']">
|
||||
<i class="fa fa-warning text-muted mr-5"></i> Forgot password
|
||||
</a>
|
||||
</div>
|
||||
@@ -94,4 +76,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,65 @@
|
||||
import { AuthService } from './../../services/auth.service';
|
||||
import { PodnomsAuthService } from './../../services/podnoms-auth.service';
|
||||
|
||||
import { AuthService } from 'angularx-social-login';
|
||||
import {
|
||||
FacebookLoginProvider,
|
||||
GoogleLoginProvider,
|
||||
LinkedInLoginProvider
|
||||
} from 'angularx-social-login';
|
||||
|
||||
import { Component, NgZone, OnInit } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
@Component({
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.css']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
private _authWindow: Window;
|
||||
private _subscription: Subscription;
|
||||
|
||||
brandNew: boolean = false;
|
||||
user: any;
|
||||
username: string;
|
||||
password: string;
|
||||
|
||||
isRequesting: boolean = false;
|
||||
signIn;
|
||||
widget;
|
||||
errorMessage: string = '';
|
||||
constructor(private _authService: AuthService) {}
|
||||
constructor(
|
||||
private _authService: PodnomsAuthService,
|
||||
private _socialAuthService: AuthService,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
ngOnInit() {
|
||||
this._subscription = this._activatedRoute.queryParams.subscribe(
|
||||
(param: any) => {
|
||||
this.brandNew = param['brandNew'];
|
||||
this.username = param['email'];
|
||||
}
|
||||
);
|
||||
}
|
||||
login(provider?: string) {
|
||||
if (!provider) {
|
||||
this._authService.loginUsername(
|
||||
this.username,
|
||||
this.password,
|
||||
success => this.loginSuccess(success),
|
||||
error => this.loginError(error)
|
||||
);
|
||||
this.isRequesting = true;
|
||||
if (provider === 'facebook') {
|
||||
this._socialAuthService.signIn(FacebookLoginProvider.PROVIDER_ID);
|
||||
} else {
|
||||
this._authService.loginSocial(provider);
|
||||
this._authService
|
||||
.login(this.username, this.password)
|
||||
.finally(() => (this.isRequesting = false))
|
||||
.subscribe((result) => {
|
||||
if (result) {
|
||||
this._router.navigate(['/']);
|
||||
}
|
||||
}, (error) => (this.errorMessage = error));
|
||||
}
|
||||
|
||||
this._socialAuthService.authState.subscribe((user) => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
logout() {}
|
||||
loginSuccess(data) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ProfileModel } from 'app/models/profile.model';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { PodnomsAuthService } from '../../services/podnoms-auth.service';
|
||||
import { ProfileService } from '../../services/profile.service';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@@ -13,7 +13,7 @@ export class NavbarComponent implements OnInit {
|
||||
user$: Observable<ProfileModel>;
|
||||
|
||||
constructor(
|
||||
private _authService: AuthService,
|
||||
private _authService: PodnomsAuthService,
|
||||
private _profileService: ProfileService
|
||||
) {}
|
||||
|
||||
|
||||
@@ -40,16 +40,16 @@ export class PodcastAddUrlFormComponent implements AfterViewInit {
|
||||
this.isPosting = true;
|
||||
const entry = new PodcastEntryModel(this.podcast.id, urlToCheck);
|
||||
this._service.addEntry(entry).subscribe(
|
||||
e => {
|
||||
(e) => {
|
||||
if (e) {
|
||||
if (e.processingStatus == 6) {
|
||||
if (e.processingStatus == '6') {
|
||||
this.onUploadDeferred.emit(e);
|
||||
} else {
|
||||
this.onUrlAddComplete.emit(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
err => {
|
||||
(err) => {
|
||||
this.isPosting = false;
|
||||
this.errorText = 'This does not look like a valid URL';
|
||||
this.newEntrySourceUrl = urlToCheck;
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
|
||||
import { AuthService } from 'app/services/auth.service';
|
||||
import { PodnomsAuthService } from 'app/services/podnoms-auth.service';
|
||||
import { PodcastModel } from 'app/models/podcasts.models';
|
||||
import { environment } from 'environments/environment';
|
||||
|
||||
@@ -29,7 +29,7 @@ export class PodcastUploadFormComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private _toastyService: ToastyService,
|
||||
private _auth: AuthService
|
||||
private _auth: PodnomsAuthService
|
||||
) {}
|
||||
ngOnInit() {
|
||||
const config = {
|
||||
|
||||
@@ -25,7 +25,7 @@ export class PodcastComponent {
|
||||
selectedPodcast$: Observable<PodcastModel>;
|
||||
pendingEntry: PodcastEntryModel = null;
|
||||
entries$: Observable<PodcastEntryModel[]>;
|
||||
uploadMode = true;
|
||||
uploadMode = false;
|
||||
urlMode = false;
|
||||
firstRun = true;
|
||||
|
||||
|
||||
@@ -73,4 +73,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { AuthService } from './../../services/auth.service';
|
||||
import { PodnomsAuthService } from './../../services/podnoms-auth.service';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
@@ -12,21 +13,23 @@ export class RegisterComponent implements OnInit {
|
||||
password: string;
|
||||
passwordRepeat: string;
|
||||
sending = false;
|
||||
|
||||
_isRequesting: boolean = false;
|
||||
errorMessage: string;
|
||||
constructor(private _authService: AuthService) {}
|
||||
constructor(private _authService: PodnomsAuthService, private _router: Router) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
doRegister() {
|
||||
this._isRequesting = true;
|
||||
this._authService
|
||||
.signup(this.username, this.password)
|
||||
.catch(err => {
|
||||
if ((err.code = 'user_exists')) this.errorMessage = 'A user with this email address already exists';
|
||||
else this.errorMessage = err.description;
|
||||
|
||||
return Observable.of(`Error logging in: ${err.description}`);
|
||||
})
|
||||
.subscribe(r => console.log('Done'));
|
||||
.finally(() => (this._isRequesting = false))
|
||||
.subscribe((result) => {
|
||||
if (result) {
|
||||
this._router.navigate(['/login'], {
|
||||
queryParams: { brandNew: true, email: this.username }
|
||||
});
|
||||
}
|
||||
}, (errors) => (this.errorMessage = errors));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AuthService } from './../../services/auth.service';
|
||||
import { PodnomsAuthService } from './../../services/podnoms-auth.service';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
@@ -12,22 +12,22 @@ export class ResetComponent implements OnInit {
|
||||
username: string;
|
||||
errorMessage: string;
|
||||
successMessage: string;
|
||||
constructor(private _authService: AuthService) {}
|
||||
constructor(private _authService: PodnomsAuthService) {}
|
||||
|
||||
ngOnInit() {}
|
||||
resetPassword() {
|
||||
if (this.username) {
|
||||
this._authService
|
||||
.resetPassword(this.username)
|
||||
.catch(err => {
|
||||
this.errorMessage = err.description;
|
||||
return Observable.of(`Error resetting password: ${err.description}`);
|
||||
})
|
||||
.subscribe(result => {
|
||||
console.log('reset.component.ts', 'method', result);
|
||||
this.errorMessage = '';
|
||||
this.successMessage = `A password reset link has been sent to ${this.username}`;
|
||||
});
|
||||
.resetPassword(this.username);
|
||||
// .catch(err => {
|
||||
// this.errorMessage = err.description;
|
||||
// return Observable.of(`Error resetting password: ${err.description}`);
|
||||
// })
|
||||
// .subscribe(result => {
|
||||
// console.log('reset.component.ts', 'method', result);
|
||||
// this.errorMessage = '';
|
||||
// this.successMessage = `A password reset link has been sent to ${this.username}`;
|
||||
// });
|
||||
} else {
|
||||
this.errorMessage = 'Please enter your email address';
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ import { Injectable } from '@angular/core';
|
||||
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
|
||||
import { tokenNotExpired } from 'angular2-jwt';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { AuthService } from './auth.service';
|
||||
import { PodnomsAuthService } from './podnoms-auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private _auth: AuthService) {}
|
||||
constructor(private _auth: PodnomsAuthService) {}
|
||||
canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
if (this._auth.isAuthenticated()) {
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
import { environment } from 'environments/environment';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AUTH_CONFIG } from './../constants/auth0';
|
||||
import * as auth0 from 'auth0-js';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import 'rxjs/add/observable/throw';
|
||||
import 'rxjs/add/operator/filter';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
errorMessage: string;
|
||||
refreshSubscription: any;
|
||||
|
||||
auth0 = new auth0.WebAuth({
|
||||
domain: AUTH_CONFIG.AUTH0_DOMAIN,
|
||||
clientID: AUTH_CONFIG.AUTH0_CLIENT_ID,
|
||||
redirectUri: AUTH_CONFIG.AUTH0_CALLBACKURL,
|
||||
audience: `https://${AUTH_CONFIG.AUTH0_DOMAIN}/userinfo`,
|
||||
responseType: 'token id_token',
|
||||
prompt: 'select_account',
|
||||
scope: 'openid profile email'
|
||||
});
|
||||
constructor(private _router: Router) {}
|
||||
public loginUsername(username: string, password: string, success, error): void {
|
||||
this.auth0.client.login(
|
||||
{
|
||||
realm: 'podnoms-db-connection',
|
||||
username: username,
|
||||
password: password
|
||||
},
|
||||
(err, authResult) => {
|
||||
if (err) {
|
||||
error(err);
|
||||
console.log(err);
|
||||
return;
|
||||
} else if (authResult && authResult.accessToken && authResult.idToken) {
|
||||
this.setSession(authResult);
|
||||
success(authResult);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
public signup(email: string, password: string): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.auth0.redirect.signupAndLogin(
|
||||
{
|
||||
connection: 'podnoms-db-connection',
|
||||
email,
|
||||
password
|
||||
},
|
||||
err => {
|
||||
if (err) {
|
||||
observer.error(err);
|
||||
} else observer.next();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
public resetPassword(email: string): Observable<any> {
|
||||
return Observable.create(observer => {
|
||||
this.auth0.changePassword(
|
||||
{
|
||||
connection: 'podnoms-db-connection',
|
||||
email
|
||||
},
|
||||
(err, resp) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
Observable.throw(err);
|
||||
} else {
|
||||
observer.next('success');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
public loginSocial(provider: string): void {
|
||||
this.auth0.authorize({
|
||||
connection: provider
|
||||
});
|
||||
}
|
||||
public handleAuthentication(): void {
|
||||
this.auth0.parseHash((err, authResult) => {
|
||||
if (authResult && authResult.accessToken && authResult.idToken) {
|
||||
this.setSession(authResult);
|
||||
} else if (err) {
|
||||
this.logout();
|
||||
this._router.navigate(['/']).then(r => window.location.reload()); // TODO: Remove this for the love of baby Jesus!
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
public getToken(): string {
|
||||
if (this.isAuthenticated()) return localStorage.getItem('id_token');
|
||||
return '';
|
||||
}
|
||||
public renewToken() {
|
||||
this.auth0.renewAuth(
|
||||
{
|
||||
audience: 'https://podnoms/',
|
||||
redirectUri: `${environment.API_HOST}/silent`,
|
||||
usePostMessage: true,
|
||||
postMessageOrigin: environment.BASE_URL
|
||||
},
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
this.setSession(result);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
public scheduleRenewal() {
|
||||
if (!this.isAuthenticated()) return;
|
||||
this.unscheduleRenewal();
|
||||
|
||||
const expiresAt = JSON.parse(window.localStorage.getItem('expires_at'));
|
||||
const source = Observable.of(expiresAt).flatMap(e => {
|
||||
const now = Date.now();
|
||||
return Observable.timer(Math.max(1, e - now));
|
||||
});
|
||||
this.refreshSubscription = source.subscribe(() => {
|
||||
console.log('auth.service.ts', 'scheduleRenewal', 'Starting renewal and schedule');
|
||||
this.renewToken();
|
||||
this.scheduleRenewal();
|
||||
});
|
||||
}
|
||||
|
||||
public unscheduleRenewal() {
|
||||
if (!this.refreshSubscription) return;
|
||||
this.refreshSubscription.unsubscribe();
|
||||
}
|
||||
private setSession(authResult): void {
|
||||
const expiresAt = JSON.stringify(authResult.expiresIn * 1000 + new Date().getTime());
|
||||
localStorage.setItem('access_token', authResult.accessToken);
|
||||
localStorage.setItem('id_token', authResult.idToken);
|
||||
localStorage.setItem('expires_at', expiresAt);
|
||||
this.scheduleRenewal();
|
||||
this._router.navigate(['/']);
|
||||
}
|
||||
public logout(): void {
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('id_token');
|
||||
localStorage.removeItem('expires_at');
|
||||
|
||||
this._router.navigate(['/']);
|
||||
window.location.reload();
|
||||
}
|
||||
public isAuthenticated(): boolean {
|
||||
const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
|
||||
return new Date().getTime() < expiresAt;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'environments/environment';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class ChatterService {
|
||||
constructor(private _http: AuthHttp) {}
|
||||
constructor(private _http: HttpClient) {}
|
||||
|
||||
ping(message: string): any {
|
||||
return this._http.post(
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
import { environment } from 'environments/environment';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class DebugService {
|
||||
constructor(private _http: AuthHttp) {}
|
||||
constructor(private _http: HttpClient) {}
|
||||
|
||||
sendRealtime(message: string): any {
|
||||
return this._http.post(environment.API_HOST + '/debug/realtime', JSON.stringify(message));
|
||||
return this._http.post(
|
||||
environment.API_HOST + '/debug/realtime',
|
||||
JSON.stringify(message)
|
||||
);
|
||||
}
|
||||
|
||||
getDebugInfo(): Observable<string> {
|
||||
return this._http.get(environment.API_HOST + '/debug').map(r => r.json());
|
||||
return this._http.get<string>(environment.API_HOST + '/debug');
|
||||
}
|
||||
|
||||
ping(): Observable<string> {
|
||||
return this._http.get(environment.API_HOST + '/ping').map(r => r.text());
|
||||
return this._http.get<string>(environment.API_HOST + '/ping');
|
||||
}
|
||||
sendPush(): Observable<string>{
|
||||
return this._http.get(environment.API_HOST + '/debug/serverpush').map(r => r.text());
|
||||
sendPush(): Observable<string> {
|
||||
return this._http.get<string>(
|
||||
environment.API_HOST + '/debug/serverpush'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Http } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class EntriesService {
|
||||
constructor(private http: Http) {}
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
get(): Observable<any> {
|
||||
return this.http.get('https://api.com');
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {Http, Headers} from '@angular/http';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {AuthService} from './auth.service';
|
||||
import {PodnomsAuthService} from './podnoms-auth.service';
|
||||
import { environment } from 'environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class ImageService {
|
||||
|
||||
// TODO: Change this to use AuthHttp when I can figure out why formData is null
|
||||
constructor(private _http: Http, private _auth: AuthService) {
|
||||
constructor(private _http: Http, private _auth: PodnomsAuthService) {
|
||||
}
|
||||
|
||||
upload(podcastSlug: string, image) {
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Response } from '@angular/http';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { environment } from 'environments/environment';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class JobsService {
|
||||
constructor(private _http: AuthHttp) { }
|
||||
constructor(private _http: HttpClient) {}
|
||||
|
||||
processOrphans(): Observable<Response> {
|
||||
return this._http.get(environment.API_HOST + '/job/processorphans');
|
||||
return this._http.get<Response>(
|
||||
environment.API_HOST + '/job/processorphans'
|
||||
);
|
||||
}
|
||||
|
||||
processPlaylists(): Observable<Response> {
|
||||
return this._http.get(environment.API_HOST + '/job/processplaylists');
|
||||
return this._http.get<Response>(
|
||||
environment.API_HOST + '/job/processplaylists'
|
||||
);
|
||||
}
|
||||
updateYouTubeDl(): Observable<Response> {
|
||||
return this._http.get(environment.API_HOST + '/job/updateyoutubedl');
|
||||
return this._http.get<Response>(
|
||||
environment.API_HOST + '/job/updateyoutubedl'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { environment } from 'environments/environment';
|
||||
import { PodcastEntryModel } from 'app/models/podcasts.models';
|
||||
import { PodcastModel } from './../models/podcasts.models';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class PodcastService {
|
||||
@@ -13,24 +13,25 @@ export class PodcastService {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
constructor(private _http: AuthHttp) { }
|
||||
constructor(private _http: HttpClient) {}
|
||||
//#region Podcasts
|
||||
get(): Observable<PodcastModel[]> {
|
||||
return this._http
|
||||
.get(environment.API_HOST + '/podcast/')
|
||||
.map(res => res.json());
|
||||
return this._http.get<PodcastModel[]>(
|
||||
environment.API_HOST + '/podcast/'
|
||||
);
|
||||
}
|
||||
getPodcast(slug: string): Observable<PodcastModel> {
|
||||
return this._http
|
||||
.get(environment.API_HOST + '/podcast/' + slug)
|
||||
.map(res => res.json());
|
||||
return this._http.get<PodcastModel>(
|
||||
environment.API_HOST + '/podcast/' + slug
|
||||
);
|
||||
}
|
||||
addPodcast(podcast: PodcastModel): Observable<PodcastModel> {
|
||||
console.log('PodcastService', 'addPodcast', podcast);
|
||||
const data = JSON.stringify(podcast, PodcastService._replacer);
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/podcast', data)
|
||||
.map(res => res.json());
|
||||
return this._http.post<PodcastModel>(
|
||||
environment.API_HOST + '/podcast',
|
||||
data
|
||||
);
|
||||
}
|
||||
updatePodcast(podcast: PodcastModel) {
|
||||
return this._http.put(environment.API_HOST + '/podcast/', podcast);
|
||||
@@ -41,43 +42,48 @@ export class PodcastService {
|
||||
//#endregion
|
||||
//#region Entries
|
||||
getEntries(slug: string): any {
|
||||
return this._http
|
||||
.get(environment.API_HOST + '/entry/all/' + slug)
|
||||
.map(res => res.json());
|
||||
return this._http.get(environment.API_HOST + '/entry/all/' + slug);
|
||||
}
|
||||
addEntry(entry: PodcastEntryModel) {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/entry', JSON.stringify(entry))
|
||||
.map(res => res.json());
|
||||
addEntry(entry: PodcastEntryModel): Observable<PodcastEntryModel> {
|
||||
return this._http.post<PodcastEntryModel>(
|
||||
environment.API_HOST + '/entry',
|
||||
JSON.stringify(entry)
|
||||
);
|
||||
}
|
||||
updateEntry(entry: PodcastEntryModel) {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/entry', JSON.stringify(entry))
|
||||
.map(res => res.json());
|
||||
return this._http.post<PodcastEntryModel>(
|
||||
environment.API_HOST + '/entry',
|
||||
JSON.stringify(entry)
|
||||
);
|
||||
}
|
||||
deleteEntry(id: number) {
|
||||
return this._http.delete(environment.API_HOST + '/entry/' + id);
|
||||
}
|
||||
checkEntry(url: string): Observable<boolean> {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/entry/isvalid/', `"${url}"`)
|
||||
.map(r => (r.status == 200 ? true : false))
|
||||
.post<Response>(
|
||||
environment.API_HOST + '/entry/isvalid/',
|
||||
`"${url}"`
|
||||
)
|
||||
.map((r) => (r.status == 200 ? true : false))
|
||||
.catch((error: any) => {
|
||||
return Observable.throw(new Error(error.status));
|
||||
});
|
||||
}
|
||||
reSubmitEntry(entry: PodcastEntryModel): Observable<PodcastEntryModel> {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/entry/resubmit', entry)
|
||||
.map(res => res.json());
|
||||
return this._http.post<PodcastEntryModel>(
|
||||
environment.API_HOST + '/entry/resubmit',
|
||||
entry
|
||||
);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Playlists
|
||||
addPlaylist(entry: PodcastEntryModel) {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/playlist', JSON.stringify(entry))
|
||||
.map(res => res.json());
|
||||
return this._http.post<PodcastEntryModel>(
|
||||
environment.API_HOST + '/playlist',
|
||||
JSON.stringify(entry)
|
||||
);
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@ import { environment } from 'environments/environment';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { ProfileModel } from 'app/models/profile.model';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import 'rxjs/add/operator/map';
|
||||
import { Profile } from 'selenium-webdriver/firefox';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class ProfileService {
|
||||
constructor(private _http: AuthHttp) {}
|
||||
profile: ProfileModel;
|
||||
constructor(private _http: HttpClient) {}
|
||||
|
||||
getProfile(): Observable<ProfileModel> {
|
||||
if (!this.profile) {
|
||||
return this._http
|
||||
.get(environment.API_HOST + '/profile')
|
||||
.map(res => {
|
||||
this.profile = res.json();
|
||||
.get<ProfileModel>(environment.API_HOST + '/profile')
|
||||
.map((res) => {
|
||||
this.profile = res;
|
||||
return this.profile;
|
||||
});
|
||||
} else {
|
||||
@@ -26,20 +26,22 @@ export class ProfileService {
|
||||
|
||||
updateProfile(profile): Observable<ProfileModel> {
|
||||
console.log('ProfileService', 'updateProfile', profile);
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/profile', profile)
|
||||
.map(res => res.json());
|
||||
return this._http.post<ProfileModel>(
|
||||
environment.API_HOST + '/profile',
|
||||
profile
|
||||
);
|
||||
}
|
||||
|
||||
checkSlug(slug): Observable<string> {
|
||||
console.log('profile.service.ts', 'checkSlug', slug);
|
||||
return this._http
|
||||
.get(environment.API_HOST + '/profile/checkslug/' + slug)
|
||||
.map(res => res.text());
|
||||
return this._http.get<string>(
|
||||
environment.API_HOST + '/profile/checkslug/' + slug
|
||||
);
|
||||
}
|
||||
regenerateApiKey(): Observable<string> {
|
||||
return this._http
|
||||
.post(environment.API_HOST + '/profile/updateapikey', null)
|
||||
.map(res => res.text());
|
||||
return this._http.post<string>(
|
||||
environment.API_HOST + '/profile/updateapikey',
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AuthHttp } from 'angular2-jwt';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import 'rxjs/add/operator/catch';
|
||||
@@ -7,11 +6,12 @@ import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/observable/throw';
|
||||
|
||||
import { environment } from 'environments/environment';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class PushRegistrationService {
|
||||
private API_URL: string;
|
||||
constructor(private http: AuthHttp) {
|
||||
constructor(private _http: HttpClient) {
|
||||
this.API_URL = environment.API_HOST;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export class PushRegistrationService {
|
||||
|
||||
addSubscriber(subscription) {
|
||||
const url = `${this.API_URL}/webpush/subscribe`;
|
||||
return this.http.post(url, subscription).catch(this.handleError);
|
||||
return this._http.post(url, subscription).catch(this.handleError);
|
||||
}
|
||||
|
||||
deleteSubscriber(subscription) {
|
||||
@@ -40,7 +40,9 @@ export class PushRegistrationService {
|
||||
subscription: subscription
|
||||
};
|
||||
|
||||
return this.http.post(url, body).catch(this.handleError);
|
||||
return this._http
|
||||
.post(url, JSON.stringify(body))
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
private handleError(error: Response | any) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AuthService } from './auth.service';
|
||||
import { PodnomsAuthService } from './podnoms-auth.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HubConnection,
|
||||
@@ -12,7 +12,7 @@ import { environment } from 'environments/environment';
|
||||
export class SignalRService {
|
||||
public connection: HubConnection;
|
||||
|
||||
constructor(private _auth: AuthService) {}
|
||||
constructor(private _auth: PodnomsAuthService) {}
|
||||
public init(hub: string): Promise<void> {
|
||||
const url = `${environment.SIGNALR_HOST}/hubs/${hub}`;
|
||||
|
||||
|
||||
36
server/Controllers/AccountsController.cs
Normal file
36
server/Controllers/AccountsController.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PodNoms.Api.Models.ViewModels;
|
||||
using PodNoms.Api.Persistence;
|
||||
using PodNoms.Api.Services.Auth;
|
||||
|
||||
namespace PodNoms.Api.Controllers {
|
||||
|
||||
[Route("[controller]")]
|
||||
public class AccountsController : Controller {
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public AccountsController(IUserRepository userRepository, UserManager<ApplicationUser> userManager, IMapper mapper) {
|
||||
this._userRepository = userRepository;
|
||||
this._userManager = userManager;
|
||||
this._mapper = mapper;
|
||||
}
|
||||
// POST api/accounts
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Post([FromBody]RegistrationViewModel model) {
|
||||
if (!ModelState.IsValid) {
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var userIdentity = _mapper.Map<RegistrationViewModel, ApplicationUser>(model);
|
||||
var result = await _userManager.CreateAsync(userIdentity, model.Password);
|
||||
// var result = await _userRepository.AddOrUpdate(userIdentity, model.Password);
|
||||
|
||||
if (!result.Succeeded) return new BadRequestObjectResult(result);
|
||||
return new OkObjectResult(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,60 @@
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Persistence;
|
||||
using PodNoms.Api.Models.ViewModels;
|
||||
using PodNoms.Api.Services.Auth;
|
||||
using PodNoms.Api.Utils;
|
||||
|
||||
namespace PodNoms.Api.Controllers {
|
||||
[Authorize]
|
||||
[Route("[controller]")]
|
||||
public class AuthController : Controller {
|
||||
protected IUserRepository _userRepository { get; }
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly IJwtFactory _jwtFactory;
|
||||
private readonly JwtIssuerOptions _jwtOptions;
|
||||
|
||||
public AuthController(IUserRepository repository) {
|
||||
this._userRepository = repository;
|
||||
public AuthController(UserManager<ApplicationUser> userManager, IJwtFactory jwtFactory, IOptions<JwtIssuerOptions> jwtOptions) {
|
||||
_userManager = userManager;
|
||||
_jwtFactory = jwtFactory;
|
||||
_jwtOptions = jwtOptions.Value;
|
||||
}
|
||||
protected async Task<User> GetUserAsync() {
|
||||
var identifier = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
|
||||
var user = await this._userRepository.GetAsync(identifier);
|
||||
return user;
|
||||
|
||||
// POST api/auth/login
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Post([FromBody]CredentialsViewModel credentials) {
|
||||
if (!ModelState.IsValid) {
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password);
|
||||
if (identity == null) {
|
||||
return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState));
|
||||
}
|
||||
|
||||
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, credentials.UserName, _jwtOptions,
|
||||
new JsonSerializerSettings { Formatting = Formatting.Indented });
|
||||
return new OkObjectResult(jwt);
|
||||
}
|
||||
protected async Task<string> GetUserUidAsync() {
|
||||
var user = await GetUserAsync();
|
||||
return user.Uid;
|
||||
}
|
||||
protected async Task<int> GetUserIdAsync() {
|
||||
var user = await GetUserAsync();
|
||||
return user.Id;
|
||||
|
||||
private async Task<ClaimsIdentity> GetClaimsIdentity(string userName, string password) {
|
||||
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
|
||||
return await Task.FromResult<ClaimsIdentity>(null);
|
||||
|
||||
// get the user to verifty
|
||||
var userToVerify = await _userManager.FindByNameAsync(userName);
|
||||
|
||||
if (userToVerify == null) return await Task.FromResult<ClaimsIdentity>(null);
|
||||
|
||||
// check the credentials
|
||||
if (await _userManager.CheckPasswordAsync(userToVerify, password)) {
|
||||
return await Task.FromResult(_jwtFactory.GenerateClaimsIdentity(userName, userToVerify.Id));
|
||||
}
|
||||
|
||||
// Credentials are invalid, or account doesn't exist
|
||||
return await Task.FromResult<ClaimsIdentity>(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ using WebPush = Lib.Net.Http.WebPush;
|
||||
|
||||
namespace PodNoms.Api.Controllers {
|
||||
[Route("[controller]")]
|
||||
public class DebugController : AuthController {
|
||||
public class DebugController : UserController {
|
||||
private readonly StorageSettings _storageSettings;
|
||||
private readonly AudioFileStorageSettings _audioFileStorageSettings;
|
||||
private readonly ApplicationsSettings _applicationsSettings;
|
||||
|
||||
@@ -19,7 +19,7 @@ using PodNoms.Api.Services.Storage;
|
||||
namespace PodNoms.Api.Controllers {
|
||||
|
||||
[Route("[controller]")]
|
||||
public class EntryController : AuthController {
|
||||
public class EntryController : UserController {
|
||||
private readonly IPodcastRepository _podcastRepository;
|
||||
private readonly IEntryRepository _repository;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Models;
|
||||
@@ -24,10 +25,12 @@ namespace PodNoms.Api.Controllers {
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IOptions<AppSettings> _settings;
|
||||
private readonly IMapper _mapper;
|
||||
private ClaimsPrincipal _caller;
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public PodcastController(IPodcastRepository repository, IUserRepository userRepository,
|
||||
IOptions<AppSettings> options, IMapper mapper, IUnitOfWork unitOfWork) {
|
||||
IOptions<AppSettings> options, IMapper mapper, IUnitOfWork unitOfWork, IHttpContextAccessor httpContextAccessor) {
|
||||
_caller = httpContextAccessor.HttpContext.User;
|
||||
this._uow = unitOfWork;
|
||||
this._repository = repository;
|
||||
this._userRepository = userRepository;
|
||||
@@ -37,12 +40,10 @@ namespace PodNoms.Api.Controllers {
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<PodcastViewModel>> Get() {
|
||||
var email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
|
||||
if (!string.IsNullOrEmpty(email)) {
|
||||
var podcasts = await _repository.GetAllAsync(email);
|
||||
var ret = _mapper.Map<List<Podcast>, List<PodcastViewModel>>(podcasts.ToList());
|
||||
return ret;
|
||||
}
|
||||
var userId = _caller.Claims.Single(c => c.Type == "id");
|
||||
var podcasts = await _repository.GetAllAsync(userId.Value);
|
||||
var ret = _mapper.Map<List<Podcast>, List<PodcastViewModel>>(podcasts.ToList());
|
||||
return ret;
|
||||
throw new Exception("No local user stored!");
|
||||
}
|
||||
|
||||
@@ -60,9 +61,9 @@ namespace PodNoms.Api.Controllers {
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Post([FromBody] PodcastViewModel vm) {
|
||||
var email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
|
||||
var user = _userRepository.Get(email);
|
||||
if (string.IsNullOrEmpty(email) || user == null)
|
||||
var userId = _caller.Claims.Single(c => c.Type == "id");
|
||||
var user = _userRepository.Get(userId.Value);
|
||||
if (user == null)
|
||||
return new BadRequestObjectResult("Unable to look up user profile");
|
||||
|
||||
if (ModelState.IsValid) {
|
||||
|
||||
33
server/Controllers/UserController.cs
Normal file
33
server/Controllers/UserController.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Controllers {
|
||||
[Authorize]
|
||||
[Obsolete("This should be superceded by the new identity stuff")]
|
||||
public class UserController : Controller {
|
||||
protected IUserRepository _userRepository { get; }
|
||||
|
||||
public UserController(IUserRepository repository) {
|
||||
this._userRepository = repository;
|
||||
}
|
||||
protected async Task<User> GetUserAsync() {
|
||||
var identifier = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
|
||||
var user = await this._userRepository.GetAsync(identifier);
|
||||
return user;
|
||||
}
|
||||
protected async Task<string> GetUserUidAsync() {
|
||||
var user = await GetUserAsync();
|
||||
return user.Uid;
|
||||
}
|
||||
protected async Task<int> GetUserIdAsync() {
|
||||
var user = await GetUserAsync();
|
||||
return user.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace PodNoms.Api.Controllers {
|
||||
|
||||
// [Authorize]
|
||||
[Route("[controller]")]
|
||||
public class WebPushController : AuthController {
|
||||
public class WebPushController : UserController {
|
||||
private readonly IPushSubscriptionStore _subscriptionStore;
|
||||
public readonly IPushNotificationService _notificationService;
|
||||
|
||||
|
||||
194
server/Migrations/20180421161830_AddedAuthTables.Designer.cs
generated
Normal file
194
server/Migrations/20180421161830_AddedAuthTables.Designer.cs
generated
Normal file
@@ -0,0 +1,194 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180421161830_AddedAuthTables")]
|
||||
partial class AddedAuthTables
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsUnicode(true);
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApiKey")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("FullName")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("ProfileImage");
|
||||
|
||||
b.Property<string>("ProviderId")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("RefreshToken");
|
||||
|
||||
b.Property<string>("Sid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasFilter("[Slug] IS NOT NULL");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
19
server/Migrations/20180421161830_AddedAuthTables.cs
Normal file
19
server/Migrations/20180421161830_AddedAuthTables.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class AddedAuthTables : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
406
server/Migrations/20180421162833_ChangeContextType.Designer.cs
generated
Normal file
406
server/Migrations/20180421162833_ChangeContextType.Designer.cs
generated
Normal file
@@ -0,0 +1,406 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180421162833_ChangeContextType")]
|
||||
partial class ChangeContextType
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsUnicode(true);
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApiKey")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("FullName")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("ProfileImage");
|
||||
|
||||
b.Property<string>("ProviderId")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("RefreshToken");
|
||||
|
||||
b.Property<string>("Sid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasFilter("[Slug] IS NOT NULL");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
225
server/Migrations/20180421162833_ChangeContextType.cs
Normal file
225
server/Migrations/20180421162833_ChangeContextType.cs
Normal file
@@ -0,0 +1,225 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class ChangeContextType : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
Name = table.Column<string>(maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(nullable: false),
|
||||
UserName = table.Column<string>(maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(nullable: false),
|
||||
PasswordHash = table.Column<string>(nullable: true),
|
||||
SecurityStamp = table.Column<string>(nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(nullable: true),
|
||||
PhoneNumber = table.Column<string>(nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(nullable: false),
|
||||
AccessFailedCount = table.Column<int>(nullable: false),
|
||||
FirstName = table.Column<string>(nullable: true),
|
||||
LastName = table.Column<string>(nullable: true),
|
||||
FacebookId = table.Column<long>(nullable: true),
|
||||
PictureUrl = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
|
||||
RoleId = table.Column<string>(nullable: false),
|
||||
ClaimType = table.Column<string>(nullable: true),
|
||||
ClaimValue = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
|
||||
UserId = table.Column<string>(nullable: false),
|
||||
ClaimType = table.Column<string>(nullable: true),
|
||||
ClaimValue = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(nullable: false),
|
||||
ProviderKey = table.Column<string>(nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(nullable: true),
|
||||
UserId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(nullable: false),
|
||||
RoleId = table.Column<string>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<string>(nullable: false),
|
||||
LoginProvider = table.Column<string>(nullable: false),
|
||||
Name = table.Column<string>(nullable: false),
|
||||
Value = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true,
|
||||
filter: "[NormalizedName] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true,
|
||||
filter: "[NormalizedUserName] IS NOT NULL");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
||||
406
server/Migrations/20180421215724_RenameUserTable.Designer.cs
generated
Normal file
406
server/Migrations/20180421215724_RenameUserTable.Designer.cs
generated
Normal file
@@ -0,0 +1,406 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180421215724_RenameUserTable")]
|
||||
partial class RenameUserTable
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsUnicode(true);
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApiKey")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("FullName")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("ProfileImage");
|
||||
|
||||
b.Property<string>("ProviderId")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("RefreshToken");
|
||||
|
||||
b.Property<string>("Sid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasFilter("[Slug] IS NOT NULL");
|
||||
|
||||
b.ToTable("UserDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
75
server/Migrations/20180421215724_RenameUserTable.cs
Normal file
75
server/Migrations/20180421215724_RenameUserTable.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class RenameUserTable : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Podcasts_Users_UserId",
|
||||
table: "Podcasts");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Users",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "Users",
|
||||
newName: "UserDetails");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Users_Slug",
|
||||
table: "UserDetails",
|
||||
newName: "IX_UserDetails_Slug");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_UserDetails",
|
||||
table: "UserDetails",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Podcasts_UserDetails_UserId",
|
||||
table: "Podcasts",
|
||||
column: "UserId",
|
||||
principalTable: "UserDetails",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Podcasts_UserDetails_UserId",
|
||||
table: "Podcasts");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_UserDetails",
|
||||
table: "UserDetails");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "UserDetails",
|
||||
newName: "Users");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_UserDetails_Slug",
|
||||
table: "Users",
|
||||
newName: "IX_Users_Slug");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Users",
|
||||
table: "Users",
|
||||
column: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Podcasts_Users_UserId",
|
||||
table: "Podcasts",
|
||||
column: "UserId",
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
}
|
||||
}
|
||||
414
server/Migrations/20180422013049_JiggleUserModel.Designer.cs
generated
Normal file
414
server/Migrations/20180422013049_JiggleUserModel.Designer.cs
generated
Normal file
@@ -0,0 +1,414 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180422013049_JiggleUserModel")]
|
||||
partial class JiggleUserModel
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsUnicode(true);
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ApiKey")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("FullName")
|
||||
.HasMaxLength(100);
|
||||
|
||||
b.Property<string>("ProfileImage");
|
||||
|
||||
b.Property<string>("ProviderId")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("RefreshToken");
|
||||
|
||||
b.Property<string>("Sid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.HasMaxLength(50);
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Slug")
|
||||
.IsUnique()
|
||||
.HasFilter("[Slug] IS NOT NULL");
|
||||
|
||||
b.ToTable("UserDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AppUserId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
45
server/Migrations/20180422013049_JiggleUserModel.cs
Normal file
45
server/Migrations/20180422013049_JiggleUserModel.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class JiggleUserModel : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "AppUserId",
|
||||
table: "Podcasts",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Podcasts_AppUserId",
|
||||
table: "Podcasts",
|
||||
column: "AppUserId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Podcasts_AspNetUsers_AppUserId",
|
||||
table: "Podcasts",
|
||||
column: "AppUserId",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Podcasts_AspNetUsers_AppUserId",
|
||||
table: "Podcasts");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Podcasts_AppUserId",
|
||||
table: "Podcasts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "AppUserId",
|
||||
table: "Podcasts");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
@@ -19,9 +16,117 @@ namespace PodNoms.Api.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview1-28290")
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -47,6 +152,8 @@ namespace PodNoms.Api.Migrations
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
@@ -68,6 +175,8 @@ namespace PodNoms.Api.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
@@ -161,7 +270,111 @@ namespace PodNoms.Api.Migrations
|
||||
.IsUnique()
|
||||
.HasFilter("[Slug] IS NOT NULL");
|
||||
|
||||
b.ToTable("Users");
|
||||
b.ToTable("UserDetails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
@@ -174,6 +387,10 @@ namespace PodNoms.Api.Migrations
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AppUserId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
namespace PodNoms.Api.Models
|
||||
{
|
||||
public class AppSettings
|
||||
{
|
||||
namespace PodNoms.Api.Models {
|
||||
public class AppSettings {
|
||||
public string Version { get; set; }
|
||||
public string RssUrl { get; set; }
|
||||
}
|
||||
|
||||
public class StorageSettings
|
||||
{
|
||||
public class StorageSettings {
|
||||
public string ConnectionString { get; set; }
|
||||
public string CdnUrl { get; set; }
|
||||
|
||||
|
||||
56
server/Models/JwtIssuerOptions.cs
Normal file
56
server/Models/JwtIssuerOptions.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace PodNoms.Api.Models {
|
||||
public class JwtIssuerOptions {
|
||||
/// <summary>
|
||||
/// 4.1.1. "iss" (Issuer) Claim - The "iss" (issuer) claim identifies the principal that issued the JWT.
|
||||
/// </summary>
|
||||
public string Issuer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 4.1.2. "sub" (Subject) Claim - The "sub" (subject) claim identifies the principal that is the subject of the JWT.
|
||||
/// </summary>
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 4.1.3. "aud" (Audience) Claim - The "aud" (audience) claim identifies the recipients that the JWT is intended for.
|
||||
/// </summary>
|
||||
public string Audience { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 4.1.4. "exp" (Expiration Time) Claim - The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.
|
||||
/// </summary>
|
||||
public DateTime Expiration => IssuedAt.Add(ValidFor);
|
||||
|
||||
/// <summary>
|
||||
/// 4.1.5. "nbf" (Not Before) Claim - The "nbf" (not before) claim identifies the time before which the JWT MUST NOT be accepted for processing.
|
||||
/// </summary>
|
||||
public DateTime NotBefore => DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 4.1.6. "iat" (Issued At) Claim - The "iat" (issued at) claim identifies the time at which the JWT was issued.
|
||||
/// </summary>
|
||||
public DateTime IssuedAt => DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Set the timespan the token will be valid for (default is 120 min)
|
||||
/// </summary>
|
||||
public TimeSpan ValidFor { get; set; } = TimeSpan.FromMinutes(120);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// "jti" (JWT ID) Claim (default ID is a GUID)
|
||||
/// </summary>
|
||||
public Func<Task<string>> JtiGenerator =>
|
||||
() => Task.FromResult(Guid.NewGuid().ToString());
|
||||
|
||||
/// <summary>
|
||||
/// The signing key to use when generating tokens.
|
||||
/// </summary>
|
||||
public SigningCredentials SigningCredentials { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Services.Auth;
|
||||
|
||||
namespace PodNoms.Api.Models {
|
||||
public class Podcast : BaseModel {
|
||||
public int Id { get; set; }
|
||||
public string Uid { get; set; }
|
||||
public User User { get; set; }
|
||||
public ApplicationUser AppUser { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Slug { get; set; }
|
||||
|
||||
8
server/Models/ViewModels/CredentialsViewModel.cs
Normal file
8
server/Models/ViewModels/CredentialsViewModel.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using FluentValidation.Attributes;
|
||||
namespace PodNoms.Api.Models.ViewModels {
|
||||
[Validator(typeof(CredentialsViewModelValidator))]
|
||||
public class CredentialsViewModel {
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
11
server/Models/ViewModels/CredentialsViewModelValidator.cs
Normal file
11
server/Models/ViewModels/CredentialsViewModelValidator.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace PodNoms.Api.Models.ViewModels {
|
||||
public class CredentialsViewModelValidator : AbstractValidator<CredentialsViewModel> {
|
||||
public CredentialsViewModelValidator() {
|
||||
RuleFor(vm => vm.UserName).NotEmpty().WithMessage("Username cannot be empty");
|
||||
RuleFor(vm => vm.Password).NotEmpty().WithMessage("Password cannot be empty");
|
||||
RuleFor(vm => vm.Password).Length(6, 12).WithMessage("Password must be between 6 and 12 characters");
|
||||
}
|
||||
}
|
||||
}
|
||||
10
server/Models/ViewModels/RegistrationViewModel.cs
Normal file
10
server/Models/ViewModels/RegistrationViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PodNoms.Api.Models.ViewModels {
|
||||
public class RegistrationViewModel {
|
||||
public string Email { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Location { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,11 @@ using PodNoms.Api.Models;
|
||||
|
||||
namespace PodNoms.Api.Persistence {
|
||||
public interface IUserRepository {
|
||||
User Get(int id);
|
||||
User Get(string email);
|
||||
Task<User> GetAsync(string email);
|
||||
User Get(string id);
|
||||
Task<User> GetAsync(string id);
|
||||
Task<User> GetBySlugAsync(string slug);
|
||||
User UpdateRegistration(string email, string name, string sid, string providerId, string profileImage, string refreshToken);
|
||||
string UpdateApiKey(User email);
|
||||
string UpdateApiKey(User user);
|
||||
User AddOrUpdate(User user);
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,11 @@ namespace PodNoms.Api.Persistence {
|
||||
|
||||
return ret;
|
||||
}
|
||||
public async Task<IEnumerable<Podcast>> GetAllAsync(string emailAddress) {
|
||||
public async Task<IEnumerable<Podcast>> GetAllAsync(string userId) {
|
||||
var ret = _context.Podcasts
|
||||
.Where(u => u.User.EmailAddress == emailAddress)
|
||||
.Where(u => u.AppUser.Id == userId)
|
||||
.Include(p => p.User)
|
||||
.Include(p => p.AppUser)
|
||||
.OrderByDescending(p => p.Id);
|
||||
return await ret.ToListAsync();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Services.Auth;
|
||||
|
||||
namespace PodNoms.Api.Persistence {
|
||||
|
||||
public class PodnomsDbContext : DbContext {
|
||||
public class PodnomsDbContext : IdentityDbContext<ApplicationUser> {
|
||||
public PodnomsDbContext(DbContextOptions<PodnomsDbContext> options) : base(options) { }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
@@ -36,6 +38,6 @@ namespace PodNoms.Api.Persistence {
|
||||
public DbSet<Podcast> Podcasts { get; set; }
|
||||
public DbSet<PodcastEntry> PodcastEntries { get; set; }
|
||||
public DbSet<Playlist> Playlists { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<User> UserDetails { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,19 @@ namespace PodNoms.Api.Persistence {
|
||||
}
|
||||
|
||||
public User Get(int id) {
|
||||
return _context.Users.FirstOrDefault(u => u.Id == id);
|
||||
return _context.UserDetails.FirstOrDefault(u => u.Id == id);
|
||||
}
|
||||
|
||||
public User Get(string email) {
|
||||
return _context.Users.FirstOrDefault(u => u.EmailAddress == email);
|
||||
return _context.UserDetails.FirstOrDefault(u => u.EmailAddress == email);
|
||||
}
|
||||
public async Task<User> GetAsync(string email) {
|
||||
return await _context.Users
|
||||
return await _context.UserDetails
|
||||
.Where(u => u.EmailAddress == email)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
public async Task<User> GetBySlugAsync(string slug) {
|
||||
var user = await _context.Users
|
||||
var user = await _context.UserDetails
|
||||
.Where(u => u.Slug == slug)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace PodNoms.Api.Persistence {
|
||||
|
||||
public User AddOrUpdate(User user) {
|
||||
if (user.Id != 0) {
|
||||
_context.Users.Attach(user);
|
||||
_context.UserDetails.Attach(user);
|
||||
} else {
|
||||
_context.Users.Add(user);
|
||||
_context.UserDetails.Add(user);
|
||||
|
||||
}
|
||||
return user;
|
||||
@@ -46,7 +46,7 @@ namespace PodNoms.Api.Persistence {
|
||||
|
||||
public User UpdateRegistration(string email, string name, string sid, string providerId, string profileImage,
|
||||
string refreshToken) {
|
||||
var user = _context.Users.FirstOrDefault(u => u.EmailAddress == email);
|
||||
var user = _context.UserDetails.FirstOrDefault(u => u.EmailAddress == email);
|
||||
|
||||
if (user == null) {
|
||||
user = new User();
|
||||
@@ -57,7 +57,7 @@ namespace PodNoms.Api.Persistence {
|
||||
var c = user.FullName ?? email?.Split('@')[0] ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(c)) {
|
||||
user.Slug = c.Slugify(
|
||||
from u in _context.Users select u.Slug);
|
||||
from u in _context.UserDetails select u.Slug);
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(user.Uid)) {
|
||||
@@ -81,7 +81,7 @@ namespace PodNoms.Api.Persistence {
|
||||
if (user != null) {
|
||||
do {
|
||||
newKey = Randomisers.RandomString(16);
|
||||
} while (_context.Users.FirstOrDefault(u => u.ApiKey == newKey) != null);
|
||||
} while (_context.UserDetails.FirstOrDefault(u => u.ApiKey == newKey) != null);
|
||||
}
|
||||
user.ApiKey = newKey;
|
||||
return newKey;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<EmbeddedResource Include="Resources/*.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.2" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage" Version="1.5.2" />
|
||||
<PackageReference Include="Lib.Net.Http.WebPush" Version="1.3.0" />
|
||||
|
||||
@@ -9,23 +9,19 @@ using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace PodNoms.Api
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
namespace PodNoms.Api {
|
||||
public class Program {
|
||||
static bool isDevelopment =
|
||||
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == EnvironmentName.Development;
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
public static void Main(string[] args) {
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>()
|
||||
.UseUrls("http://0.0.0.0:5000")
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
.UseKestrel(options => {
|
||||
options.Limits.MaxRequestBodySize = 1073741824; //1Gb
|
||||
// if (isDevelopment)
|
||||
// {
|
||||
|
||||
@@ -3,15 +3,13 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Models.ViewModels;
|
||||
using PodNoms.Api.Services.Auth;
|
||||
|
||||
namespace PodNoms.Api.Providers
|
||||
{
|
||||
public class MappingProvider : Profile
|
||||
{
|
||||
namespace PodNoms.Api.Providers {
|
||||
public class MappingProvider : Profile {
|
||||
private readonly IConfiguration _options;
|
||||
public MappingProvider() { }
|
||||
public MappingProvider(IConfiguration options)
|
||||
{
|
||||
public MappingProvider(IConfiguration options) {
|
||||
this._options = options;
|
||||
|
||||
//Domain to API Resource
|
||||
@@ -29,7 +27,7 @@ namespace PodNoms.Api.Providers
|
||||
.ForMember(
|
||||
src => src.AudioUrl,
|
||||
e => e.MapFrom(m => $"{this._options.GetSection("Storage")["CdnUrl"]}{m.AudioUrl}"));
|
||||
|
||||
|
||||
CreateMap<User, ProfileViewModel>()
|
||||
.ForMember(
|
||||
src => src.Name,
|
||||
@@ -37,13 +35,17 @@ namespace PodNoms.Api.Providers
|
||||
|
||||
//API Resource to Domain
|
||||
CreateMap<PodcastViewModel, Podcast>()
|
||||
.ForMember(v => v.ImageUrl, opt => opt.Ignore())
|
||||
.ForMember(v => v.ImageUrl, map => map.Ignore())
|
||||
;
|
||||
CreateMap<PodcastEntryViewModel, PodcastEntry>()
|
||||
.ForMember(
|
||||
e => e.ImageUrl,
|
||||
opt => opt.MapFrom(m => m.ImageUrl))
|
||||
map => map.MapFrom(vm => vm.ImageUrl))
|
||||
;
|
||||
CreateMap<RegistrationViewModel, ApplicationUser>()
|
||||
.ForMember(
|
||||
e => e.UserName,
|
||||
map => map.MapFrom(vm => vm.Email));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
server/Services/Auth/ApplicationUser.cs
Normal file
11
server/Services/Auth/ApplicationUser.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public class ApplicationUser : IdentityUser {
|
||||
// Extended Properties
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public long? FacebookId { get; set; }
|
||||
public string PictureUrl { get; set; }
|
||||
}
|
||||
}
|
||||
13
server/Services/Auth/Constants.cs
Normal file
13
server/Services/Auth/Constants.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public static class Constants {
|
||||
public static class Strings {
|
||||
public static class JwtClaimIdentifiers {
|
||||
public const string Rol = "rol", Id = "id";
|
||||
}
|
||||
|
||||
public static class JwtClaims {
|
||||
public const string ApiAccess = "api_access";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
server/Services/Auth/IJwtFactory.cs
Normal file
9
server/Services/Auth/IJwtFactory.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public interface IJwtFactory {
|
||||
Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity);
|
||||
ClaimsIdentity GenerateClaimsIdentity(string userName, string id);
|
||||
}
|
||||
}
|
||||
73
server/Services/Auth/JwtFactory.cs
Normal file
73
server/Services/Auth/JwtFactory.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Models;
|
||||
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public class JwtFactory : IJwtFactory {
|
||||
private readonly JwtIssuerOptions _jwtOptions;
|
||||
|
||||
public JwtFactory(IOptions<JwtIssuerOptions> jwtOptions) {
|
||||
_jwtOptions = jwtOptions.Value;
|
||||
ThrowIfInvalidOptions(_jwtOptions);
|
||||
}
|
||||
|
||||
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity) {
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Sub, userName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
|
||||
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
|
||||
identity.FindFirst(Constants.Strings.JwtClaimIdentifiers.Rol),
|
||||
identity.FindFirst(Constants.Strings.JwtClaimIdentifiers.Id)
|
||||
};
|
||||
|
||||
// Create the JWT security token and encode it.
|
||||
var jwt = new JwtSecurityToken(
|
||||
issuer: _jwtOptions.Issuer,
|
||||
audience: _jwtOptions.Audience,
|
||||
claims: claims,
|
||||
notBefore: _jwtOptions.NotBefore,
|
||||
expires: _jwtOptions.Expiration,
|
||||
signingCredentials: _jwtOptions.SigningCredentials);
|
||||
|
||||
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
|
||||
|
||||
return encodedJwt;
|
||||
}
|
||||
|
||||
public ClaimsIdentity GenerateClaimsIdentity(string userName, string id) {
|
||||
return new ClaimsIdentity(new GenericIdentity(userName, "Token"), new[]
|
||||
{
|
||||
new Claim(Constants.Strings.JwtClaimIdentifiers.Id, id),
|
||||
new Claim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess)
|
||||
});
|
||||
}
|
||||
|
||||
/// <returns>Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).</returns>
|
||||
private static long ToUnixEpochDate(DateTime date)
|
||||
=> (long)Math.Round((date.ToUniversalTime() -
|
||||
new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
|
||||
.TotalSeconds);
|
||||
|
||||
private static void ThrowIfInvalidOptions(JwtIssuerOptions options) {
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
if (options.ValidFor <= TimeSpan.Zero) {
|
||||
throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor));
|
||||
}
|
||||
|
||||
if (options.SigningCredentials == null) {
|
||||
throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials));
|
||||
}
|
||||
|
||||
if (options.JtiGenerator == null) {
|
||||
throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
server/Services/Auth/Tokens.cs
Normal file
20
server/Services/Auth/Tokens.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using PodNoms.Api.Models;
|
||||
|
||||
namespace PodNoms.Api.Services.Auth {
|
||||
public class Tokens {
|
||||
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory, string userName,
|
||||
JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings) {
|
||||
var response = new {
|
||||
id = identity.Claims.Single(c => c.Type == "id").Value,
|
||||
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
|
||||
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
|
||||
};
|
||||
|
||||
return JsonConvert.SerializeObject(response, serializerSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using FluentValidation.AspNetCore;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
@@ -41,9 +42,14 @@ using PodNoms.Api.Services.Push.Extensions;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using PodNoms.Api.Services.Push.Formatters;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace PodNoms.Api {
|
||||
public class Startup {
|
||||
private const string SecretKey = "QGfaEMNASkNMGLKA3LjgPdkPfFEy3n40"; // todo: get this from somewhere secure
|
||||
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public Startup(IConfiguration configuration) {
|
||||
@@ -105,39 +111,65 @@ namespace PodNoms.Api {
|
||||
});
|
||||
|
||||
services.AddHttpClient();
|
||||
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
|
||||
|
||||
// Configure JwtIssuerOptions
|
||||
services.Configure<JwtIssuerOptions>(options => {
|
||||
//TODO: Remove this in production, only for testing
|
||||
options.ValidFor = TimeSpan.FromDays(28);
|
||||
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
|
||||
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
|
||||
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
|
||||
});
|
||||
var tokenValidationParameters = new TokenValidationParameters {
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
|
||||
|
||||
ValidateAudience = true,
|
||||
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
|
||||
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = _signingKey,
|
||||
|
||||
RequireExpirationTime = false,
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.Zero
|
||||
};
|
||||
services.AddAuthentication(options => {
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddJwtBearer(options => {
|
||||
options.Audience = Configuration["auth0:clientId"];
|
||||
options.Authority = $"https://{Configuration["auth0:domain"]}/";
|
||||
options.TokenValidationParameters = new TokenValidationParameters {
|
||||
NameClaimType = "name"
|
||||
}).AddJwtBearer(configureOptions => {
|
||||
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
|
||||
configureOptions.TokenValidationParameters = tokenValidationParameters;
|
||||
configureOptions.SaveToken = true;
|
||||
configureOptions.Events = new JwtBearerEvents() {
|
||||
//Don't need this now we've removed Auth0
|
||||
// OnTokenValidated = AuthenticationMiddleware.OnTokenValidated
|
||||
};
|
||||
options.Events = new JwtBearerEvents() {
|
||||
OnTokenValidated = AuthenticationMiddleware.OnTokenValidated
|
||||
};
|
||||
options.Events.OnMessageReceived = context => {
|
||||
configureOptions.Events.OnMessageReceived = context => {
|
||||
StringValues token;
|
||||
if (context.Request.Path.Value.StartsWith("/hubs/") && context.Request.Query.TryGetValue("token", out token)) {
|
||||
context.Token = token;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
var defaultPolicy =
|
||||
new AuthorizationPolicyBuilder()
|
||||
.AddAuthenticationSchemes("Bearer")
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
|
||||
services.AddAuthorization(j => {
|
||||
j.DefaultPolicy = defaultPolicy;
|
||||
j.AddPolicy("ApiUser", policy => policy.RequireClaim(
|
||||
Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
|
||||
});
|
||||
// add identity
|
||||
var identityBuilder = services.AddIdentityCore<ApplicationUser>(o => {
|
||||
// configure identity options
|
||||
o.Password.RequireDigit = false;
|
||||
o.Password.RequireLowercase = false;
|
||||
o.Password.RequireUppercase = false;
|
||||
o.Password.RequireNonAlphanumeric = false;
|
||||
o.Password.RequiredLength = 6;
|
||||
});
|
||||
identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(IdentityRole), identityBuilder.Services);
|
||||
identityBuilder.AddEntityFrameworkStores<PodnomsDbContext>().AddDefaultTokenProviders();
|
||||
|
||||
services.AddMvc(options => {
|
||||
options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
|
||||
@@ -150,7 +182,8 @@ namespace PodNoms.Api {
|
||||
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
|
||||
})
|
||||
.AddXmlSerializerFormatters();
|
||||
.AddXmlSerializerFormatters()
|
||||
.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
|
||||
|
||||
services.AddSwaggerGen(c => {
|
||||
c.SwaggerDoc("v1", new Info { Title = "Podnoms.API", Version = "v1" });
|
||||
@@ -174,6 +207,8 @@ namespace PodNoms.Api {
|
||||
|
||||
services.AddTransient<IFileUploader, AzureFileUploader>();
|
||||
services.AddTransient<IRealTimeUpdater, SignalRUpdater>();
|
||||
services.TryAddTransient<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddSingleton<IJwtFactory, JwtFactory>();
|
||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||
services.AddScoped<IPodcastRepository, PodcastRepository>();
|
||||
services.AddScoped<IEntryRepository, EntryRepository>();
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace PodNoms.Api.Utils
|
||||
{
|
||||
|
||||
public class DateUtils
|
||||
{
|
||||
public static DateTime ConvertFromUnixTimestamp(double timestamp)
|
||||
{
|
||||
namespace PodNoms.Api.Utils {
|
||||
public class DateUtils {
|
||||
public static DateTime ConvertFromUnixTimestamp(double timestamp) {
|
||||
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
return origin.AddSeconds(timestamp);
|
||||
}
|
||||
|
||||
public static double ConvertToUnixTimestamp(DateTime date)
|
||||
{
|
||||
public static double ConvertToUnixTimestamp(DateTime date) {
|
||||
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
TimeSpan diff = date.ToUniversalTime() - origin;
|
||||
return Math.Floor(diff.TotalSeconds);
|
||||
|
||||
19
server/Utils/Errors.cs
Normal file
19
server/Utils/Errors.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace PodNoms.Api.Utils {
|
||||
public static class Errors {
|
||||
public static ModelStateDictionary AddErrorsToModelState(IdentityResult identityResult, ModelStateDictionary modelState) {
|
||||
foreach (var e in identityResult.Errors) {
|
||||
modelState.TryAddModelError(e.Code, e.Description);
|
||||
}
|
||||
|
||||
return modelState;
|
||||
}
|
||||
|
||||
public static ModelStateDictionary AddErrorToModelState(string code, string description, ModelStateDictionary modelState) {
|
||||
modelState.TryAddModelError(code, description);
|
||||
return modelState;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user