BAEL-797 changing the UI to make requests without passing credentials. Updating serurity config to always use the default redirect url. Adding a super simple landing page also forcing all 404s to land on the angular app.

This commit is contained in:
tschiman 2017-05-10 15:48:38 -06:00
parent cf99183473
commit 6d710e245a
12 changed files with 116 additions and 165 deletions

View File

@ -6,20 +6,7 @@
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
</ul>
<div *ngIf="!principal.authenticated; then loginForm else loginMessage"></div>
<ng-template #loginForm>
<form (ngSubmit)="onLogin(f)" class="form-inline mt-2 mt-md-0" #f="ngForm">
<input name="username" [(ngModel)]="credentials.username" required class="form-control mr-sm-2" type="text" placeholder="Username">
<input name="password" [(ngModel)]="credentials.password" required class="form-control mr-sm-2" type="password" placeholder="Password">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" [disabled]="!f.valid">Login</button>
</form>
</ng-template>
<ng-template #loginMessage>
<button type="button" class="btn btn-link" (click)="onLogout()">Logout</button>
</ng-template>
<div *ngIf="loginFailed">
<div class="alert alert-warning">Login Failed</div>
</div>
<button *ngIf="principal.authenticated" type="button" class="btn btn-link" (click)="onLogout()">Logout</button>
</div>
</nav>

View File

@ -1,7 +1,6 @@
import {Component} from "@angular/core";
import {Principal} from "./principal";
import {Response} from "@angular/http";
import {NgForm} from "@angular/forms";
import {Book} from "./book";
import {HttpService} from "./http.service";
@ -11,38 +10,29 @@ import {HttpService} from "./http.service";
styleUrls: ['./app.component.css']
})
export class AppComponent {
credentials = {
username: '',
password: ''
};
selectedBook: Book = null;
principal: Principal = new Principal(false, [], null);
principal: Principal = new Principal(false, []);
loginFailed: boolean = false;
constructor(private httpService: HttpService){}
ngOnInit(): void {}
onLogin(form: NgForm) {
this.loginFailed = false;
this.credentials = {username: form.value.username, password: form.value.password};
this.httpService.login(this.credentials)
ngOnInit(): void {
this.httpService.me()
.subscribe((response: Response) => {
let principalJson = response.json();
this.principal = new Principal(principalJson.authenticated, principalJson.authorities, this.credentials);
this.principal = new Principal(principalJson.authenticated, principalJson.authorities);
}, (error) => {
console.log(error);
});
}
onLogout() {
this.httpService.logout(this.principal.credentials)
this.httpService.logout()
.subscribe((response: Response) => {
if (response.status === 204) {
if (response.status === 200) {
this.loginFailed = false;
this.credentials.username = '';
this.credentials.password = '';
this.principal = new Principal(false, [], null);
this.principal = new Principal(false, []);
window.location.replace(response.url);
}
}, (error) => {
console.log(error);

View File

@ -56,7 +56,7 @@ export class BookListComponent implements OnInit {
saveBook(bookIndex: number, newBook: Book) {
console.log(newBook);
//save the book to the database
this.httpService.updateBook(newBook, this.principal.credentials)
this.httpService.updateBook(newBook)
.subscribe((response: Response) => {
let bookJson = response.json();
let book: Book = new Book(bookJson.id, bookJson.author, bookJson.title);
@ -74,7 +74,7 @@ export class BookListComponent implements OnInit {
delete(bookIndex: number) {
let book: Book = this.books[bookIndex];
this.httpService.deleteBook(book, this.principal.credentials)
this.httpService.deleteBook(book)
.subscribe(() => {
if (this.selectedBook !== null && this.books[bookIndex].id === this.selectedBook.id) {
this.selectedBook = null;
@ -95,7 +95,7 @@ export class BookListComponent implements OnInit {
addNewBook(newBook: Book, element: any) {
//write new book to db
this.httpService.createBook(newBook, this.principal.credentials)
this.httpService.createBook(newBook)
.subscribe((response: Response) => {
let bookJson = response.json();
let book: Book = new Book(bookJson.id, bookJson.author, bookJson.title);

View File

@ -9,61 +9,48 @@ export class HttpService {
constructor(private http: Http) { }
login(user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.get("/me", options)
me(): Observable<Response> {
return this.http.get("/me", this.makeOptions())
}
logout(user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.post("/logout", '', options)
logout(): Observable<Response> {
return this.http.post("/logout", '', this.makeOptions())
}
getBooks(): Observable<Response> {
return this.http.get("/book-service/books", this.makeOptions())
}
updateBook(newBook: Book): Observable<Response> {
return this.http.put("/book-service/books/" + newBook.id, newBook, this.makeOptions())
}
deleteBook(book: Book): Observable<Response> {
return this.http.delete("/book-service/books/" + book.id, this.makeOptions())
}
createBook(newBook: Book): Observable<Response> {
return this.http.post("/book-service/books", newBook, this.makeOptions())
}
getRatings(bookId: number): Observable<Response> {
return this.http.get("/rating-service/ratings?bookId=" + bookId, this.makeOptions())
}
createRating(rating: Rating): Observable<Response> {
return this.http.post("/rating-service/ratings", rating, this.makeOptions())
}
deleteRating(ratingId: number) {
return this.http.delete("/rating-service/ratings/" + ratingId, this.makeOptions())
}
updateRating(rating: Rating) {
return this.http.put("/rating-service/ratings/" + rating.id, rating, this.makeOptions())
}
private makeOptions(): RequestOptions {
let headers = new Headers({'Content-Type': 'application/json'});
let options = new RequestOptions({headers: headers});
return this.http.get("/book-service/books", options)
}
updateBook(newBook: Book, user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.put("/book-service/books/" + newBook.id, newBook, options)
}
deleteBook(book: Book, user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.delete("/book-service/books/" + book.id, options)
}
createBook(newBook: Book, user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.post("/book-service/books", newBook, options)
}
getRatings(bookId: number, user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.get("/rating-service/ratings?bookId=" + bookId, options)
}
createRating(rating: Rating, user: any): Observable<Response> {
let options = this.makeAuthOptions(user);
return this.http.post("/rating-service/ratings", rating, options)
}
deleteRating(ratingId: number, user: any) {
let options = this.makeAuthOptions(user);
return this.http.delete("/rating-service/ratings/" + ratingId, options)
}
updateRating(rating: Rating, user: any) {
let options = this.makeAuthOptions(user);
return this.http.put("/rating-service/ratings/" + rating.id, rating, options)
}
private makeAuthOptions(user: any): RequestOptions {
let headers = new Headers({'Content-Type': 'application/json'});
headers.append('Authorization','Basic ' + btoa(user.username + ':' + user.password));
headers.append('X-Requested-With','XMLHttpRequest');
return new RequestOptions({headers: headers});;
return new RequestOptions({headers: headers});
}
}

View File

@ -1,12 +1,10 @@
export class Principal {
public authenticated: boolean;
public authorities: Authority[] = [];
public credentials: any;
constructor(authenticated: boolean, authorities: any[], credentials: any) {
constructor(authenticated: boolean, authorities: any[]) {
this.authenticated = authenticated;
authorities.map(auth => this.authorities.push(new Authority(auth.authority)))
this.credentials = credentials;
}
isAdmin() {

View File

@ -33,7 +33,7 @@ export class RatingComponent implements OnInit, OnChanges {
}
private loadRatings() {
this.httpService.getRatings(this.bookId, this.principal.credentials)
this.httpService.getRatings(this.bookId)
.subscribe((response: Response) => {
let responseJson: any[] = response.json();
responseJson.forEach(rating => this.ratings.push(new Rating(rating.id, rating.bookId, rating.stars)))
@ -45,7 +45,7 @@ export class RatingComponent implements OnInit, OnChanges {
onSaveRating() {
console.log(this.newRating);
let ratingCopy: Rating = Object.assign({}, this.newRating);
this.httpService.createRating(ratingCopy, this.principal.credentials)
this.httpService.createRating(ratingCopy)
.subscribe((response: Response) => {
let ratingJson = response.json()
this.ratings.push(new Rating(ratingJson.id, ratingJson.bookId, ratingJson.stars))
@ -55,7 +55,7 @@ export class RatingComponent implements OnInit, OnChanges {
}
updateRating() {
this.httpService.updateRating(this.newRating, this.principal.credentials)
this.httpService.updateRating(this.newRating)
.subscribe(() => {
this.newRating = new Rating(null, this.bookId, 1);
}, (error) => {
@ -75,7 +75,7 @@ export class RatingComponent implements OnInit, OnChanges {
deleteRating(index: number) {
let rating = this.ratings[index];
this.httpService.deleteRating(rating.id, this.principal.credentials)
this.httpService.deleteRating(rating.id)
.subscribe(() => {
if (this.ratings[index] === this.newRating) {
this.newRating = new Rating(null, this.bookId, 1);

View File

@ -10,7 +10,7 @@ import org.springframework.stereotype.Component;
public class ErrorPageConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/home/index.html"));
}
}

View File

@ -29,10 +29,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/home/index.html")
.defaultSuccessUrl("/home/index.html", true)
.and()
.authorizeRequests()
.antMatchers("/book-service/**", "/rating-service/**", "/login*").permitAll()
.antMatchers("/book-service/**", "/rating-service/**", "/login*", "/").permitAll()
.antMatchers("/eureka/**").hasRole("ADMIN")
.antMatchers("/home/*").authenticated()
.anyRequest().authenticated()

View File

@ -75,7 +75,7 @@ module.exports = module.exports.toString();
/***/ 149:
/***/ (function(module, exports) {
module.exports = "<nav class=\"navbar navbar-toggleable-md navbar-inverse fixed-top bg-inverse\">\r\n <button class=\"navbar-toggler navbar-toggler-right\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarCollapse\" aria-controls=\"navbarCollapse\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <a class=\"navbar-brand\" href=\"#\">Book Rater <span *ngIf=\"principal.isAdmin()\">Admin</span></a>\r\n <div class=\"collapse navbar-collapse\" id=\"navbarCollapse\">\r\n <ul class=\"navbar-nav mr-auto\">\r\n </ul>\r\n <div *ngIf=\"!principal.authenticated; then loginForm else loginMessage\"></div>\r\n <ng-template #loginForm>\r\n <form (ngSubmit)=\"onLogin(f)\" class=\"form-inline mt-2 mt-md-0\" #f=\"ngForm\">\r\n <input name=\"username\" [(ngModel)]=\"credentials.username\" required class=\"form-control mr-sm-2\" type=\"text\" placeholder=\"Username\">\r\n <input name=\"password\" [(ngModel)]=\"credentials.password\" required class=\"form-control mr-sm-2\" type=\"password\" placeholder=\"Password\">\r\n <button class=\"btn btn-outline-success my-2 my-sm-0\" type=\"submit\" [disabled]=\"!f.valid\">Login</button>\r\n </form>\r\n </ng-template>\r\n <ng-template #loginMessage>\r\n <button type=\"button\" class=\"btn btn-link\" (click)=\"onLogout()\">Logout</button>\r\n </ng-template>\r\n <div *ngIf=\"loginFailed\">\r\n <div class=\"alert alert-warning\">Login Failed</div>\r\n </div>\r\n </div>\r\n</nav>\r\n\r\n<div class=\"jumbotron\">\r\n <div class=\"container\">\r\n <h1>Book Rater App</h1>\r\n <p *ngIf=\"!principal.authenticated\" class=\"lead\">Anyone can view the books.</p>\r\n <p *ngIf=\"principal.authenticated && !principal.isAdmin()\" class=\"lead\">Users can view and create ratings</p>\r\n <p *ngIf=\"principal.isAdmin()\" class=\"lead\">Admins can do anything!</p>\r\n </div>\r\n</div>\r\n\r\n<section class=\"books\">\r\n <div class=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col-md\">\r\n <div class=\"row\">\r\n <div class=\"col-md-12\">\r\n <app-book-list [principal]=\"principal\" (onBookSelected)=\"selectBook($event)\"></app-book-list>\r\n </div>\r\n </div>\r\n </div>\r\n <div *ngIf=\"selectedBook != null\" class=\"col-md-3\">\r\n <app-book-detail [selectedBook]=\"selectedBook\" [principal]=\"principal\" (closeBook)=\"closeBookDetail()\"></app-book-detail>\r\n </div>\r\n </div>\r\n </div>\r\n</section>\r\n"
module.exports = "<nav class=\"navbar navbar-toggleable-md navbar-inverse fixed-top bg-inverse\">\r\n <button class=\"navbar-toggler navbar-toggler-right\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarCollapse\" aria-controls=\"navbarCollapse\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n <a class=\"navbar-brand\" href=\"#\">Book Rater <span *ngIf=\"principal.isAdmin()\">Admin</span></a>\r\n <div class=\"collapse navbar-collapse\" id=\"navbarCollapse\">\r\n <ul class=\"navbar-nav mr-auto\">\r\n </ul>\r\n <button *ngIf=\"principal.authenticated\" type=\"button\" class=\"btn btn-link\" (click)=\"onLogout()\">Logout</button>\r\n </div>\r\n</nav>\r\n\r\n<div class=\"jumbotron\">\r\n <div class=\"container\">\r\n <h1>Book Rater App</h1>\r\n <p *ngIf=\"!principal.authenticated\" class=\"lead\">Anyone can view the books.</p>\r\n <p *ngIf=\"principal.authenticated && !principal.isAdmin()\" class=\"lead\">Users can view and create ratings</p>\r\n <p *ngIf=\"principal.isAdmin()\" class=\"lead\">Admins can do anything!</p>\r\n </div>\r\n</div>\r\n\r\n<section class=\"books\">\r\n <div class=\"container\">\r\n <div class=\"row\">\r\n <div class=\"col-md\">\r\n <div class=\"row\">\r\n <div class=\"col-md-12\">\r\n <app-book-list [principal]=\"principal\" (onBookSelected)=\"selectBook($event)\"></app-book-list>\r\n </div>\r\n </div>\r\n </div>\r\n <div *ngIf=\"selectedBook != null\" class=\"col-md-3\">\r\n <app-book-detail [selectedBook]=\"selectedBook\" [principal]=\"principal\" (closeBook)=\"closeBookDetail()\"></app-book-detail>\r\n </div>\r\n </div>\r\n </div>\r\n</section>\r\n"
/***/ }),
@ -130,53 +130,39 @@ var HttpService = (function () {
function HttpService(http) {
this.http = http;
}
HttpService.prototype.login = function (user) {
var options = this.makeAuthOptions(user);
return this.http.get("/me", options);
HttpService.prototype.me = function () {
return this.http.get("/me", this.makeOptions());
};
HttpService.prototype.logout = function (user) {
var options = this.makeAuthOptions(user);
return this.http.post("/logout", '', options);
HttpService.prototype.logout = function () {
return this.http.post("/logout", '', this.makeOptions());
};
HttpService.prototype.getBooks = function () {
return this.http.get("/book-service/books", this.makeOptions());
};
HttpService.prototype.updateBook = function (newBook) {
return this.http.put("/book-service/books/" + newBook.id, newBook, this.makeOptions());
};
HttpService.prototype.deleteBook = function (book) {
return this.http.delete("/book-service/books/" + book.id, this.makeOptions());
};
HttpService.prototype.createBook = function (newBook) {
return this.http.post("/book-service/books", newBook, this.makeOptions());
};
HttpService.prototype.getRatings = function (bookId) {
return this.http.get("/rating-service/ratings?bookId=" + bookId, this.makeOptions());
};
HttpService.prototype.createRating = function (rating) {
return this.http.post("/rating-service/ratings", rating, this.makeOptions());
};
HttpService.prototype.deleteRating = function (ratingId) {
return this.http.delete("/rating-service/ratings/" + ratingId, this.makeOptions());
};
HttpService.prototype.updateRating = function (rating) {
return this.http.put("/rating-service/ratings/" + rating.id, rating, this.makeOptions());
};
HttpService.prototype.makeOptions = function () {
var headers = new __WEBPACK_IMPORTED_MODULE_1__angular_http__["b" /* Headers */]({ 'Content-Type': 'application/json' });
var options = new __WEBPACK_IMPORTED_MODULE_1__angular_http__["c" /* RequestOptions */]({ headers: headers });
return this.http.get("/book-service/books", options);
};
HttpService.prototype.updateBook = function (newBook, user) {
var options = this.makeAuthOptions(user);
return this.http.put("/book-service/books/" + newBook.id, newBook, options);
};
HttpService.prototype.deleteBook = function (book, user) {
var options = this.makeAuthOptions(user);
return this.http.delete("/book-service/books/" + book.id, options);
};
HttpService.prototype.createBook = function (newBook, user) {
var options = this.makeAuthOptions(user);
return this.http.post("/book-service/books", newBook, options);
};
HttpService.prototype.getRatings = function (bookId, user) {
var options = this.makeAuthOptions(user);
return this.http.get("/rating-service/ratings?bookId=" + bookId, options);
};
HttpService.prototype.createRating = function (rating, user) {
var options = this.makeAuthOptions(user);
return this.http.post("/rating-service/ratings", rating, options);
};
HttpService.prototype.deleteRating = function (ratingId, user) {
var options = this.makeAuthOptions(user);
return this.http.delete("/rating-service/ratings/" + ratingId, options);
};
HttpService.prototype.updateRating = function (rating, user) {
var options = this.makeAuthOptions(user);
return this.http.put("/rating-service/ratings/" + rating.id, rating, options);
};
HttpService.prototype.makeAuthOptions = function (user) {
var headers = new __WEBPACK_IMPORTED_MODULE_1__angular_http__["b" /* Headers */]({ 'Content-Type': 'application/json' });
headers.append('Authorization', 'Basic ' + btoa(user.username + ':' + user.password));
headers.append('X-Requested-With', 'XMLHttpRequest');
return new __WEBPACK_IMPORTED_MODULE_1__angular_http__["c" /* RequestOptions */]({ headers: headers });
;
};
return HttpService;
}());
@ -197,12 +183,11 @@ var _a;
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Principal; });
/* unused harmony export Authority */
var Principal = (function () {
function Principal(authenticated, authorities, credentials) {
function Principal(authenticated, authorities) {
var _this = this;
this.authorities = [];
this.authenticated = authenticated;
authorities.map(function (auth) { return _this.authorities.push(new Authority(auth.authority)); });
this.credentials = credentials;
}
Principal.prototype.isAdmin = function () {
return this.authorities.some(function (auth) { return auth.authority.indexOf('ADMIN') > -1; });
@ -297,36 +282,28 @@ var __metadata = (this && this.__metadata) || function (k, v) {
var AppComponent = (function () {
function AppComponent(httpService) {
this.httpService = httpService;
this.credentials = {
username: '',
password: ''
};
this.selectedBook = null;
this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, [], null);
this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, []);
this.loginFailed = false;
}
AppComponent.prototype.ngOnInit = function () { };
AppComponent.prototype.onLogin = function (form) {
AppComponent.prototype.ngOnInit = function () {
var _this = this;
this.loginFailed = false;
this.credentials = { username: form.value.username, password: form.value.password };
this.httpService.login(this.credentials)
this.httpService.me()
.subscribe(function (response) {
var principalJson = response.json();
_this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](principalJson.authenticated, principalJson.authorities, _this.credentials);
_this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](principalJson.authenticated, principalJson.authorities);
}, function (error) {
console.log(error);
});
};
AppComponent.prototype.onLogout = function () {
var _this = this;
this.httpService.logout(this.principal.credentials)
this.httpService.logout()
.subscribe(function (response) {
if (response.status === 204) {
if (response.status === 200) {
_this.loginFailed = false;
_this.credentials.username = '';
_this.credentials.password = '';
_this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, [], null);
_this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, []);
window.location.replace(response.url);
}
}, function (error) {
console.log(error);
@ -537,7 +514,7 @@ var BookListComponent = (function () {
var _this = this;
console.log(newBook);
//save the book to the database
this.httpService.updateBook(newBook, this.principal.credentials)
this.httpService.updateBook(newBook)
.subscribe(function (response) {
var bookJson = response.json();
var book = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](bookJson.id, bookJson.author, bookJson.title);
@ -553,7 +530,7 @@ var BookListComponent = (function () {
BookListComponent.prototype.delete = function (bookIndex) {
var _this = this;
var book = this.books[bookIndex];
this.httpService.deleteBook(book, this.principal.credentials)
this.httpService.deleteBook(book)
.subscribe(function () {
if (_this.selectedBook !== null && _this.books[bookIndex].id === _this.selectedBook.id) {
_this.selectedBook = null;
@ -572,7 +549,7 @@ var BookListComponent = (function () {
BookListComponent.prototype.addNewBook = function (newBook, element) {
var _this = this;
//write new book to db
this.httpService.createBook(newBook, this.principal.credentials)
this.httpService.createBook(newBook)
.subscribe(function (response) {
var bookJson = response.json();
var book = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](bookJson.id, bookJson.author, bookJson.title);
@ -716,7 +693,7 @@ var RatingComponent = (function () {
};
RatingComponent.prototype.loadRatings = function () {
var _this = this;
this.httpService.getRatings(this.bookId, this.principal.credentials)
this.httpService.getRatings(this.bookId)
.subscribe(function (response) {
var responseJson = response.json();
responseJson.forEach(function (rating) { return _this.ratings.push(new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](rating.id, rating.bookId, rating.stars)); });
@ -728,7 +705,7 @@ var RatingComponent = (function () {
var _this = this;
console.log(this.newRating);
var ratingCopy = Object.assign({}, this.newRating);
this.httpService.createRating(ratingCopy, this.principal.credentials)
this.httpService.createRating(ratingCopy)
.subscribe(function (response) {
var ratingJson = response.json();
_this.ratings.push(new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](ratingJson.id, ratingJson.bookId, ratingJson.stars));
@ -738,7 +715,7 @@ var RatingComponent = (function () {
};
RatingComponent.prototype.updateRating = function () {
var _this = this;
this.httpService.updateRating(this.newRating, this.principal.credentials)
this.httpService.updateRating(this.newRating)
.subscribe(function () {
_this.newRating = new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](null, _this.bookId, 1);
}, function (error) {
@ -756,7 +733,7 @@ var RatingComponent = (function () {
RatingComponent.prototype.deleteRating = function (index) {
var _this = this;
var rating = this.ratings[index];
this.httpService.deleteRating(rating.id, this.principal.credentials)
this.httpService.deleteRating(rating.id)
.subscribe(function () {
if (_this.ratings[index] === _this.newRating) {
_this.newRating = new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](null, _this.bookId, 1);

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Book Rater Landing</title>
</head>
<body>
<h1>Book Rater</h1>
<p>So many great things about the books</p>
<a href="/login.html">Login</a>
</body>
</html>