diff --git a/client/package.json b/client/package.json
index e253528..8e2ca75 100644
--- a/client/package.json
+++ b/client/package.json
@@ -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"
+ }
}
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index 426ee21..d1c581d 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -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();
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index b6be60c..128b822 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -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,
diff --git a/client/src/app/components/callback/callback.component.ts b/client/src/app/components/callback/callback.component.ts
index 1633e54..d1ef023 100644
--- a/client/src/app/components/callback/callback.component.ts
+++ b/client/src/app/components/callback/callback.component.ts
@@ -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']);
diff --git a/client/src/app/components/home/home.component.ts b/client/src/app/components/home/home.component.ts
index d5cf050..c11f43c 100644
--- a/client/src/app/components/home/home.component.ts
+++ b/client/src/app/components/home/home.component.ts
@@ -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) {
diff --git a/client/src/app/components/login/login.component.css b/client/src/app/components/login/login.component.css
index e69de29..b2a10e5 100644
--- a/client/src/app/components/login/login.component.css
+++ b/client/src/app/components/login/login.component.css
@@ -0,0 +1,3 @@
+.new-user-alert {
+ padding-top: 2.5rem;
+}
diff --git a/client/src/app/components/login/login.component.html b/client/src/app/components/login/login.component.html
index ec9130d..7a817d8 100644
--- a/client/src/app/components/login/login.component.html
+++ b/client/src/app/components/login/login.component.html
@@ -1,8 +1,6 @@
-
+
-
+
@@ -15,37 +13,26 @@
-
+
-
+
-
+
diff --git a/client/src/app/components/login/login.component.ts b/client/src/app/components/login/login.component.ts
index 172a8c1..55377f9 100644
--- a/client/src/app/components/login/login.component.ts
+++ b/client/src/app/components/login/login.component.ts
@@ -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) {
diff --git a/client/src/app/components/navbar/navbar.component.ts b/client/src/app/components/navbar/navbar.component.ts
index ec78a43..8cba680 100644
--- a/client/src/app/components/navbar/navbar.component.ts
+++ b/client/src/app/components/navbar/navbar.component.ts
@@ -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
;
constructor(
- private _authService: AuthService,
+ private _authService: PodnomsAuthService,
private _profileService: ProfileService
) {}
diff --git a/client/src/app/components/podcast/podcast-add-url-form/podcast-add-url-form.component.ts b/client/src/app/components/podcast/podcast-add-url-form/podcast-add-url-form.component.ts
index 72da584..b61a164 100644
--- a/client/src/app/components/podcast/podcast-add-url-form/podcast-add-url-form.component.ts
+++ b/client/src/app/components/podcast/podcast-add-url-form/podcast-add-url-form.component.ts
@@ -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;
diff --git a/client/src/app/components/podcast/podcast-upload-form/podcast-upload-form.component.ts b/client/src/app/components/podcast/podcast-upload-form/podcast-upload-form.component.ts
index 7addf96..858ffa4 100644
--- a/client/src/app/components/podcast/podcast-upload-form/podcast-upload-form.component.ts
+++ b/client/src/app/components/podcast/podcast-upload-form/podcast-upload-form.component.ts
@@ -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 = {
diff --git a/client/src/app/components/podcast/podcast.component.ts b/client/src/app/components/podcast/podcast.component.ts
index bc6ffc8..6d192e5 100644
--- a/client/src/app/components/podcast/podcast.component.ts
+++ b/client/src/app/components/podcast/podcast.component.ts
@@ -25,7 +25,7 @@ export class PodcastComponent {
selectedPodcast$: Observable;
pendingEntry: PodcastEntryModel = null;
entries$: Observable;
- uploadMode = true;
+ uploadMode = false;
urlMode = false;
firstRun = true;
diff --git a/client/src/app/components/register/register.component.html b/client/src/app/components/register/register.component.html
index 9d0d261..defff8b 100644
--- a/client/src/app/components/register/register.component.html
+++ b/client/src/app/components/register/register.component.html
@@ -73,4 +73,4 @@
-
\ No newline at end of file
+
diff --git a/client/src/app/components/register/register.component.ts b/client/src/app/components/register/register.component.ts
index 6c99822..056bb4f 100644
--- a/client/src/app/components/register/register.component.ts
+++ b/client/src/app/components/register/register.component.ts
@@ -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));
}
}
diff --git a/client/src/app/components/reset/reset.component.ts b/client/src/app/components/reset/reset.component.ts
index af04795..e340353 100644
--- a/client/src/app/components/reset/reset.component.ts
+++ b/client/src/app/components/reset/reset.component.ts
@@ -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';
}
diff --git a/client/src/app/services/auth.guard.ts b/client/src/app/services/auth.guard.ts
index 97827eb..61beab1 100644
--- a/client/src/app/services/auth.guard.ts
+++ b/client/src/app/services/auth.guard.ts
@@ -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
{
return new Promise(resolve => {
if (this._auth.isAuthenticated()) {
diff --git a/client/src/app/services/auth.service.ts b/client/src/app/services/auth.service.ts
deleted file mode 100644
index 1e88b53..0000000
--- a/client/src/app/services/auth.service.ts
+++ /dev/null
@@ -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 {
- 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 {
- 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;
- }
-}
diff --git a/client/src/app/services/chatter.service.ts b/client/src/app/services/chatter.service.ts
index 81b3d1f..429c8e9 100644
--- a/client/src/app/services/chatter.service.ts
+++ b/client/src/app/services/chatter.service.ts
@@ -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(
diff --git a/client/src/app/services/debug.service.ts b/client/src/app/services/debug.service.ts
index 1f371c8..1d4a659 100644
--- a/client/src/app/services/debug.service.ts
+++ b/client/src/app/services/debug.service.ts
@@ -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 {
- return this._http.get(environment.API_HOST + '/debug').map(r => r.json());
+ return this._http.get(environment.API_HOST + '/debug');
}
ping(): Observable {
- return this._http.get(environment.API_HOST + '/ping').map(r => r.text());
+ return this._http.get(environment.API_HOST + '/ping');
}
- sendPush(): Observable{
- return this._http.get(environment.API_HOST + '/debug/serverpush').map(r => r.text());
+ sendPush(): Observable {
+ return this._http.get(
+ environment.API_HOST + '/debug/serverpush'
+ );
}
}
diff --git a/client/src/app/services/entries.service.ts b/client/src/app/services/entries.service.ts
index 332c671..5b1b84e 100644
--- a/client/src/app/services/entries.service.ts
+++ b/client/src/app/services/entries.service.ts
@@ -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 {
return this.http.get('https://api.com');
diff --git a/client/src/app/services/image.service.ts b/client/src/app/services/image.service.ts
index 263c2a7..68d7667 100644
--- a/client/src/app/services/image.service.ts
+++ b/client/src/app/services/image.service.ts
@@ -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) {
diff --git a/client/src/app/services/jobs.service.ts b/client/src/app/services/jobs.service.ts
index 0c6af1b..d1f27be 100644
--- a/client/src/app/services/jobs.service.ts
+++ b/client/src/app/services/jobs.service.ts
@@ -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 {
- return this._http.get(environment.API_HOST + '/job/processorphans');
+ return this._http.get(
+ environment.API_HOST + '/job/processorphans'
+ );
}
-
processPlaylists(): Observable {
- return this._http.get(environment.API_HOST + '/job/processplaylists');
+ return this._http.get(
+ environment.API_HOST + '/job/processplaylists'
+ );
}
updateYouTubeDl(): Observable {
- return this._http.get(environment.API_HOST + '/job/updateyoutubedl');
+ return this._http.get(
+ environment.API_HOST + '/job/updateyoutubedl'
+ );
}
}
diff --git a/client/src/app/services/podcast.service.ts b/client/src/app/services/podcast.service.ts
index a186a76..31988d9 100644
--- a/client/src/app/services/podcast.service.ts
+++ b/client/src/app/services/podcast.service.ts
@@ -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 {
- return this._http
- .get(environment.API_HOST + '/podcast/')
- .map(res => res.json());
+ return this._http.get(
+ environment.API_HOST + '/podcast/'
+ );
}
getPodcast(slug: string): Observable {
- return this._http
- .get(environment.API_HOST + '/podcast/' + slug)
- .map(res => res.json());
+ return this._http.get(
+ environment.API_HOST + '/podcast/' + slug
+ );
}
addPodcast(podcast: PodcastModel): Observable {
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(
+ 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 {
+ return this._http.post(
+ 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(
+ environment.API_HOST + '/entry',
+ JSON.stringify(entry)
+ );
}
deleteEntry(id: number) {
return this._http.delete(environment.API_HOST + '/entry/' + id);
}
checkEntry(url: string): Observable {
return this._http
- .post(environment.API_HOST + '/entry/isvalid/', `"${url}"`)
- .map(r => (r.status == 200 ? true : false))
+ .post(
+ 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 {
- return this._http
- .post(environment.API_HOST + '/entry/resubmit', entry)
- .map(res => res.json());
+ return this._http.post(
+ 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(
+ environment.API_HOST + '/playlist',
+ JSON.stringify(entry)
+ );
}
//#endregion
}
diff --git a/client/src/app/services/profile.service.ts b/client/src/app/services/profile.service.ts
index 4582255..b13d706 100644
--- a/client/src/app/services/profile.service.ts
+++ b/client/src/app/services/profile.service.ts
@@ -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 {
if (!this.profile) {
return this._http
- .get(environment.API_HOST + '/profile')
- .map(res => {
- this.profile = res.json();
+ .get(environment.API_HOST + '/profile')
+ .map((res) => {
+ this.profile = res;
return this.profile;
});
} else {
@@ -26,20 +26,22 @@ export class ProfileService {
updateProfile(profile): Observable {
console.log('ProfileService', 'updateProfile', profile);
- return this._http
- .post(environment.API_HOST + '/profile', profile)
- .map(res => res.json());
+ return this._http.post(
+ environment.API_HOST + '/profile',
+ profile
+ );
}
checkSlug(slug): Observable {
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(
+ environment.API_HOST + '/profile/checkslug/' + slug
+ );
}
regenerateApiKey(): Observable {
- return this._http
- .post(environment.API_HOST + '/profile/updateapikey', null)
- .map(res => res.text());
+ return this._http.post(
+ environment.API_HOST + '/profile/updateapikey',
+ null
+ );
}
}
diff --git a/client/src/app/services/push-registration.service.ts b/client/src/app/services/push-registration.service.ts
index 303bdfa..5c423af 100644
--- a/client/src/app/services/push-registration.service.ts
+++ b/client/src/app/services/push-registration.service.ts
@@ -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) {
diff --git a/client/src/app/services/signalr.service.ts b/client/src/app/services/signalr.service.ts
index a50fd77..5138d6e 100644
--- a/client/src/app/services/signalr.service.ts
+++ b/client/src/app/services/signalr.service.ts
@@ -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 {
const url = `${environment.SIGNALR_HOST}/hubs/${hub}`;
diff --git a/server/Controllers/AccountsController.cs b/server/Controllers/AccountsController.cs
new file mode 100644
index 0000000..6c1c222
--- /dev/null
+++ b/server/Controllers/AccountsController.cs
@@ -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 _userManager;
+ private readonly IMapper _mapper;
+
+ public AccountsController(IUserRepository userRepository, UserManager userManager, IMapper mapper) {
+ this._userRepository = userRepository;
+ this._userManager = userManager;
+ this._mapper = mapper;
+ }
+ // POST api/accounts
+ [HttpPost]
+ public async Task Post([FromBody]RegistrationViewModel model) {
+ if (!ModelState.IsValid) {
+ return BadRequest(ModelState);
+ }
+ var userIdentity = _mapper.Map(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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/Controllers/AuthController.cs b/server/Controllers/AuthController.cs
index 9c13f2d..bb9d5ba 100644
--- a/server/Controllers/AuthController.cs
+++ b/server/Controllers/AuthController.cs
@@ -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 _userManager;
+ private readonly IJwtFactory _jwtFactory;
+ private readonly JwtIssuerOptions _jwtOptions;
- public AuthController(IUserRepository repository) {
- this._userRepository = repository;
+ public AuthController(UserManager userManager, IJwtFactory jwtFactory, IOptions jwtOptions) {
+ _userManager = userManager;
+ _jwtFactory = jwtFactory;
+ _jwtOptions = jwtOptions.Value;
}
- protected async Task 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 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 GetUserUidAsync() {
- var user = await GetUserAsync();
- return user.Uid;
- }
- protected async Task GetUserIdAsync() {
- var user = await GetUserAsync();
- return user.Id;
+
+ private async Task GetClaimsIdentity(string userName, string password) {
+ if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
+ return await Task.FromResult(null);
+
+ // get the user to verifty
+ var userToVerify = await _userManager.FindByNameAsync(userName);
+
+ if (userToVerify == null) return await Task.FromResult(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(null);
}
}
-}
\ No newline at end of file
+}
diff --git a/server/Controllers/DebugController.cs b/server/Controllers/DebugController.cs
index b57fa2e..dffcc81 100644
--- a/server/Controllers/DebugController.cs
+++ b/server/Controllers/DebugController.cs
@@ -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;
diff --git a/server/Controllers/EntryController.cs b/server/Controllers/EntryController.cs
index 251adb6..a5b63b0 100644
--- a/server/Controllers/EntryController.cs
+++ b/server/Controllers/EntryController.cs
@@ -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;
diff --git a/server/Controllers/PodcastController.cs b/server/Controllers/PodcastController.cs
index 4000a5d..d1b0b4d 100644
--- a/server/Controllers/PodcastController.cs
+++ b/server/Controllers/PodcastController.cs
@@ -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 _settings;
private readonly IMapper _mapper;
+ private ClaimsPrincipal _caller;
private readonly IUnitOfWork _uow;
public PodcastController(IPodcastRepository repository, IUserRepository userRepository,
- IOptions options, IMapper mapper, IUnitOfWork unitOfWork) {
+ IOptions 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> 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>(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>(podcasts.ToList());
+ return ret;
throw new Exception("No local user stored!");
}
@@ -60,9 +61,9 @@ namespace PodNoms.Api.Controllers {
[HttpPost]
public async Task 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) {
diff --git a/server/Controllers/UserController.cs b/server/Controllers/UserController.cs
new file mode 100644
index 0000000..3505278
--- /dev/null
+++ b/server/Controllers/UserController.cs
@@ -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 GetUserAsync() {
+ var identifier = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
+ var user = await this._userRepository.GetAsync(identifier);
+ return user;
+ }
+ protected async Task GetUserUidAsync() {
+ var user = await GetUserAsync();
+ return user.Uid;
+ }
+ protected async Task GetUserIdAsync() {
+ var user = await GetUserAsync();
+ return user.Id;
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/Controllers/WebPushController.cs b/server/Controllers/WebPushController.cs
index de364b0..fc7c66c 100644
--- a/server/Controllers/WebPushController.cs
+++ b/server/Controllers/WebPushController.cs
@@ -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;
diff --git a/server/Migrations/20180421161830_AddedAuthTables.Designer.cs b/server/Migrations/20180421161830_AddedAuthTables.Designer.cs
new file mode 100644
index 0000000..8794cc7
--- /dev/null
+++ b/server/Migrations/20180421161830_AddedAuthTables.Designer.cs
@@ -0,0 +1,194 @@
+//
+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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreateDate");
+
+ b.Property("PodcastId");
+
+ b.Property("SourceUrl");
+
+ b.Property("UpdateDate");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PodcastId");
+
+ b.ToTable("Playlists");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreateDate")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValueSql("getdate()");
+
+ b.Property("Description");
+
+ b.Property("ImageUrl");
+
+ b.Property("Slug")
+ .IsUnicode(true);
+
+ b.Property("Title");
+
+ b.Property("Uid");
+
+ b.Property("UpdateDate");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Podcasts");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioFileSize");
+
+ b.Property("AudioLength");
+
+ b.Property("AudioUrl");
+
+ b.Property("Author");
+
+ b.Property("CreateDate")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValueSql("getdate()");
+
+ b.Property("Description");
+
+ b.Property("ImageUrl");
+
+ b.Property("PlaylistId");
+
+ b.Property("PodcastId");
+
+ b.Property("Processed");
+
+ b.Property("ProcessingPayload");
+
+ b.Property("ProcessingStatus");
+
+ b.Property("SourceUrl");
+
+ b.Property("Title");
+
+ b.Property("Uid");
+
+ b.Property("UpdateDate");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PlaylistId");
+
+ b.HasIndex("PodcastId");
+
+ b.ToTable("PodcastEntries");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApiKey")
+ .HasMaxLength(50);
+
+ b.Property("CreateDate");
+
+ b.Property("EmailAddress")
+ .HasMaxLength(100);
+
+ b.Property("FullName")
+ .HasMaxLength(100);
+
+ b.Property("ProfileImage");
+
+ b.Property("ProviderId")
+ .HasMaxLength(50);
+
+ b.Property("RefreshToken");
+
+ b.Property("Sid")
+ .HasMaxLength(50);
+
+ b.Property("Slug")
+ .HasMaxLength(50);
+
+ b.Property("Uid")
+ .HasMaxLength(50);
+
+ b.Property("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
+ }
+ }
+}
diff --git a/server/Migrations/20180421161830_AddedAuthTables.cs b/server/Migrations/20180421161830_AddedAuthTables.cs
new file mode 100644
index 0000000..de95779
--- /dev/null
+++ b/server/Migrations/20180421161830_AddedAuthTables.cs
@@ -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)
+ {
+
+ }
+ }
+}
diff --git a/server/Migrations/20180421162833_ChangeContextType.Designer.cs b/server/Migrations/20180421162833_ChangeContextType.Designer.cs
new file mode 100644
index 0000000..e3128ee
--- /dev/null
+++ b/server/Migrations/20180421162833_ChangeContextType.Designer.cs
@@ -0,0 +1,406 @@
+//
+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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Name")
+ .HasMaxLength(256);
+
+ b.Property("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", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("RoleId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider");
+
+ b.Property("ProviderKey");
+
+ b.Property("ProviderDisplayName");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider");
+
+ b.Property("Name");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreateDate");
+
+ b.Property("PodcastId");
+
+ b.Property("SourceUrl");
+
+ b.Property("UpdateDate");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PodcastId");
+
+ b.ToTable("Playlists");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreateDate")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValueSql("getdate()");
+
+ b.Property("Description");
+
+ b.Property("ImageUrl");
+
+ b.Property("Slug")
+ .IsUnicode(true);
+
+ b.Property("Title");
+
+ b.Property("Uid");
+
+ b.Property("UpdateDate");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Podcasts");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioFileSize");
+
+ b.Property("AudioLength");
+
+ b.Property("AudioUrl");
+
+ b.Property("Author");
+
+ b.Property("CreateDate")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValueSql("getdate()");
+
+ b.Property("Description");
+
+ b.Property("ImageUrl");
+
+ b.Property("PlaylistId");
+
+ b.Property("PodcastId");
+
+ b.Property("Processed");
+
+ b.Property("ProcessingPayload");
+
+ b.Property("ProcessingStatus");
+
+ b.Property("SourceUrl");
+
+ b.Property("Title");
+
+ b.Property("Uid");
+
+ b.Property("UpdateDate");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PlaylistId");
+
+ b.HasIndex("PodcastId");
+
+ b.ToTable("PodcastEntries");
+ });
+
+ modelBuilder.Entity("PodNoms.Api.Models.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApiKey")
+ .HasMaxLength(50);
+
+ b.Property("CreateDate");
+
+ b.Property("EmailAddress")
+ .HasMaxLength(100);
+
+ b.Property("FullName")
+ .HasMaxLength(100);
+
+ b.Property("ProfileImage");
+
+ b.Property("ProviderId")
+ .HasMaxLength(50);
+
+ b.Property("RefreshToken");
+
+ b.Property("Sid")
+ .HasMaxLength(50);
+
+ b.Property("Slug")
+ .HasMaxLength(50);
+
+ b.Property("Uid")
+ .HasMaxLength(50);
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("FacebookId");
+
+ b.Property("FirstName");
+
+ b.Property("LastName");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("PictureUrl");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("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", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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
+ }
+ }
+}
diff --git a/server/Migrations/20180421162833_ChangeContextType.cs b/server/Migrations/20180421162833_ChangeContextType.cs
new file mode 100644
index 0000000..63efaa1
--- /dev/null
+++ b/server/Migrations/20180421162833_ChangeContextType.cs
@@ -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(nullable: false),
+ Name = table.Column(maxLength: 256, nullable: true),
+ NormalizedName = table.Column(maxLength: 256, nullable: true),
+ ConcurrencyStamp = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetRoles", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetUsers",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ UserName = table.Column(maxLength: 256, nullable: true),
+ NormalizedUserName = table.Column(maxLength: 256, nullable: true),
+ Email = table.Column(maxLength: 256, nullable: true),
+ NormalizedEmail = table.Column(maxLength: 256, nullable: true),
+ EmailConfirmed = table.Column(nullable: false),
+ PasswordHash = table.Column(nullable: true),
+ SecurityStamp = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(nullable: true),
+ PhoneNumber = table.Column(nullable: true),
+ PhoneNumberConfirmed = table.Column(nullable: false),
+ TwoFactorEnabled = table.Column(nullable: false),
+ LockoutEnd = table.Column(nullable: true),
+ LockoutEnabled = table.Column(nullable: false),
+ AccessFailedCount = table.Column(nullable: false),
+ FirstName = table.Column(nullable: true),
+ LastName = table.Column(nullable: true),
+ FacebookId = table.Column(nullable: true),
+ PictureUrl = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AspNetUsers", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AspNetRoleClaims",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false)
+ .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
+ RoleId = table.Column(nullable: false),
+ ClaimType = table.Column(nullable: true),
+ ClaimValue = table.Column(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(nullable: false)
+ .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
+ UserId = table.Column(nullable: false),
+ ClaimType = table.Column(nullable: true),
+ ClaimValue = table.Column(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(nullable: false),
+ ProviderKey = table.Column(nullable: false),
+ ProviderDisplayName = table.Column(nullable: true),
+ UserId = table.Column(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(nullable: false),
+ RoleId = table.Column(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(nullable: false),
+ LoginProvider = table.Column(nullable: false),
+ Name = table.Column(nullable: false),
+ Value = table.Column(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");
+ }
+ }
+}
diff --git a/server/Migrations/20180421215724_RenameUserTable.Designer.cs b/server/Migrations/20180421215724_RenameUserTable.Designer.cs
new file mode 100644
index 0000000..f8d2283
--- /dev/null
+++ b/server/Migrations/20180421215724_RenameUserTable.Designer.cs
@@ -0,0 +1,406 @@
+//
+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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Name")
+ .HasMaxLength(256);
+
+ b.Property("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