Merge pull request #1741 from tschiman/master
BAEL-797 Angular App For Cloud Series
This commit is contained in:
commit
dacc694f02
|
@ -59,6 +59,56 @@
|
|||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*LiveTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<exec executable="cmd" osfamily="windows" dir="${project.basedir}/src/main/angular/ui">
|
||||
<arg value="/c"/>
|
||||
<arg value="ng"/>
|
||||
<arg value="build"/>
|
||||
</exec>
|
||||
<exec executable="/bin/sh" osfamily="mac" dir="${project.basedir}/src/main/angular/ui">
|
||||
<arg value="-c"/>
|
||||
<arg value="ng build"/>
|
||||
</exec>
|
||||
</tasks>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>Brixton.SR7</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "ui"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "../../resources/static/home",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"styles.css",
|
||||
"../node_modules/bootstrap/dist/css/bootstrap.min.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
|
@ -0,0 +1,42 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -0,0 +1,28 @@
|
|||
# Ui
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
Before running the tests make sure you are serving the app via `ng serve`.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
|
@ -0,0 +1,14 @@
|
|||
import {UiPage} from "./app.po";
|
||||
|
||||
describe('ui App', () => {
|
||||
let page: UiPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new UiPage();
|
||||
});
|
||||
|
||||
it('should display message saying app works', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('app works!');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
import {browser, element, by} from "protractor";
|
||||
|
||||
export class UiPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types":[
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
files: [
|
||||
{ pattern: './src/test.ts', watched: false }
|
||||
],
|
||||
preprocessors: {
|
||||
'./src/test.ts': ['@angular/cli']
|
||||
},
|
||||
mime: {
|
||||
'text/x-typescript': ['ts','tsx']
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: config.angularCli && config.angularCli.codeCoverage
|
||||
? ['progress', 'coverage-istanbul']
|
||||
: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "ui",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^4.0.0",
|
||||
"@angular/compiler": "^4.0.0",
|
||||
"@angular/core": "^4.0.0",
|
||||
"@angular/forms": "^4.0.0",
|
||||
"@angular/http": "^4.0.0",
|
||||
"@angular/platform-browser": "^4.0.0",
|
||||
"@angular/platform-browser-dynamic": "^4.0.0",
|
||||
"@angular/router": "^4.0.0",
|
||||
"bootstrap": "^4.0.0-alpha.6",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.1.0",
|
||||
"zone.js": "^0.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.0.0",
|
||||
"@angular/compiler-cli": "^4.0.0",
|
||||
"@types/jasmine": "2.5.38",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "~2.0.0",
|
||||
"jasmine-core": "~2.5.2",
|
||||
"jasmine-spec-reporter": "~3.2.0",
|
||||
"karma": "~1.4.1",
|
||||
"karma-chrome-launcher": "~2.0.0",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"karma-coverage-istanbul-reporter": "^0.2.0",
|
||||
"protractor": "~5.1.0",
|
||||
"ts-node": "~2.0.0",
|
||||
"tslint": "~4.5.0",
|
||||
"typescript": "~2.2.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
beforeLaunch: function() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
},
|
||||
onPrepare() {
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
.custom-close {
|
||||
float:right;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<nav class="navbar navbar-toggleable-md navbar-inverse fixed-top bg-inverse">
|
||||
<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">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#">Book Rater <span *ngIf="principal.isAdmin()">Admin</span></a>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
</ul>
|
||||
<button *ngIf="principal.authenticated" type="button" class="btn btn-link" (click)="onLogout()">Logout</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<h1>Book Rater App</h1>
|
||||
<p *ngIf="!principal.authenticated" class="lead">Anyone can view the books.</p>
|
||||
<p *ngIf="principal.authenticated && !principal.isAdmin()" class="lead">Users can view and create ratings</p>
|
||||
<p *ngIf="principal.isAdmin()" class="lead">Admins can do anything!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="books">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<app-book-list [principal]="principal" (onBookSelected)="selectBook($event)"></app-book-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="selectedBook != null" class="col-md-3">
|
||||
<app-book-detail [selectedBook]="selectedBook" [principal]="principal" (closeBook)="closeBookDetail()"></app-book-detail>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -0,0 +1,50 @@
|
|||
import {Component} from "@angular/core";
|
||||
import {Principal} from "./principal";
|
||||
import {Response} from "@angular/http";
|
||||
import {Book} from "./book";
|
||||
import {HttpService} from "./http.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
selectedBook: Book = null;
|
||||
principal: Principal = new Principal(false, []);
|
||||
loginFailed: boolean = false;
|
||||
|
||||
constructor(private httpService: HttpService){}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.httpService.me()
|
||||
.subscribe((response: Response) => {
|
||||
let principalJson = response.json();
|
||||
this.principal = new Principal(principalJson.authenticated, principalJson.authorities);
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
onLogout() {
|
||||
this.httpService.logout()
|
||||
.subscribe((response: Response) => {
|
||||
if (response.status === 200) {
|
||||
this.loginFailed = false;
|
||||
this.principal = new Principal(false, []);
|
||||
window.location.replace(response.url);
|
||||
}
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
closeBookDetail() {
|
||||
this.selectedBook = null;
|
||||
}
|
||||
|
||||
selectBook(book: Book) {
|
||||
this.selectedBook = book;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import {BrowserModule} from "@angular/platform-browser";
|
||||
import {NgModule} from "@angular/core";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {HttpModule} from "@angular/http";
|
||||
import {AppComponent} from "./app.component";
|
||||
import {RatingComponent} from "./rating/rating.component";
|
||||
import {ClickStopPropagationDirective} from "./click-stop-propagation.directive";
|
||||
import {BookDetailComponent} from "./book/book-detail/book-detail.component";
|
||||
import {BookListComponent} from "./book/book-list/book-list.component";
|
||||
import {HttpService} from "./http.service";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
RatingComponent,
|
||||
ClickStopPropagationDirective,
|
||||
BookDetailComponent,
|
||||
BookListComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule
|
||||
],
|
||||
providers: [HttpService],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -0,0 +1,10 @@
|
|||
export class Book {
|
||||
id: number;
|
||||
author: String;
|
||||
title: String;
|
||||
constructor(id: number, author: String, title: String){
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<div class="card">
|
||||
<div class="card-block">
|
||||
<button type="button" class="close" aria-label="Close" (click)="closeBookDetail()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="card-title">Title: {{selectedBook.title}}</h4>
|
||||
<h6 class="card-subtitle mb-2 text-muted">Author: {{selectedBook.author}}</h6>
|
||||
<p class="card-text">A quick summary of the book</p>
|
||||
<app-rating *ngIf="principal.authenticated" [bookId]="selectedBook.id" [principal]="principal"></app-rating>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
import {Component, OnInit, Input, Output, EventEmitter} from "@angular/core";
|
||||
import {Book} from "../../book";
|
||||
import {Principal} from "../../principal";
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-detail',
|
||||
templateUrl: './book-detail.component.html',
|
||||
styleUrls: ['./book-detail.component.css']
|
||||
})
|
||||
export class BookDetailComponent implements OnInit {
|
||||
|
||||
@Input() selectedBook: Book = null;
|
||||
@Input() principal: Principal = null;
|
||||
@Output() closeBook: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
closeBookDetail() {
|
||||
this.closeBook.emit(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
.custom-close {
|
||||
float:right;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<div class="col-md-12" *ngFor="let book of books; let i = index;" (click)="selectBook(book)">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div *ngIf="booksToEdit.indexOf(i) === -1 ; then bookView else bookEdit"></div>
|
||||
<ng-template #bookView>
|
||||
<button appClickStopPropagation *ngIf="principal.isAdmin()" type="button" class="btn btn-danger custom-close" (click)="delete(i)">Delete</button>
|
||||
<button appClickStopPropagation *ngIf="principal.isAdmin()" type="button" class="btn btn-warning custom-close" (click)="editBook(i)">Edit</button>
|
||||
<h4 class="card-title">Title: {{book.title}}</h4>
|
||||
<h6 class="card-subtitle mb-2 text-muted">Author: {{book.author}}</h6>
|
||||
</ng-template>
|
||||
<ng-template #bookEdit>
|
||||
<button appClickStopPropagation type="button" class="btn btn-secondary custom-close" (click)="cancelEditBook(i)">Cancel</button>
|
||||
<form appClickStopPropagation (ngSubmit)="saveBook(i, newBooks[i])" class="mt-2 mt-md-0" #f1="ngForm">
|
||||
<div class="form-group">
|
||||
<label for="title">Title:</label>
|
||||
<input id="title" name="title" [(ngModel)]="newBooks[i].title" required class="form-control mr-sm-2" type="text">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="author">Author:</label>
|
||||
<input id="author" name="author" [(ngModel)]="newBooks[i].author" required class="form-control mr-sm-2" type="text">
|
||||
</div>
|
||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" [disabled]="!f1.valid">Save</button>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="principal.isAdmin()" class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div *ngIf="!isAddNewBook; then bookPlaceHolder else bookAdd"></div>
|
||||
<ng-template #bookPlaceHolder>
|
||||
<h4 (click)="activateAddNewBook()" class="card-title center-block">Add New Book</h4>
|
||||
</ng-template>
|
||||
<ng-template #bookAdd>
|
||||
<button appClickStopPropagation type="button" class="btn btn-secondary custom-close" (click)="cancelAddBook()">Cancel</button>
|
||||
<form appClickStopPropagation (ngSubmit)="addNewBook(newBook, titleNewBook)" class="mt-2 mt-md-0" #f2="ngForm">
|
||||
<div class="form-group">
|
||||
<label for="titleNewBook">Title:</label>
|
||||
<input id="titleNewBook" name="title" [(ngModel)]="newBook.title" required class="form-control mr-sm-2" type="text" #titleNewBook>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="authorNewBook">Author:</label>
|
||||
<input id="authorNewBook" name="author" [(ngModel)]="newBook.author" required class="form-control mr-sm-2" type="text">
|
||||
</div>
|
||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" [disabled]="!f2.valid">Save</button>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,122 @@
|
|||
import {Component, OnInit, Input, Output, EventEmitter} from "@angular/core";
|
||||
import {Principal} from "../../principal";
|
||||
import {Book} from "../../book";
|
||||
import {Response} from "@angular/http";
|
||||
import {HttpService} from "../../http.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-list',
|
||||
templateUrl: './book-list.component.html',
|
||||
styleUrls: ['./book-list.component.css']
|
||||
})
|
||||
export class BookListComponent implements OnInit {
|
||||
|
||||
@Input() principal: Principal = null;
|
||||
@Output() onBookSelected: EventEmitter<Book> = new EventEmitter<Book>();
|
||||
|
||||
books: Book[] = [];
|
||||
newBooks: Book[] = [];
|
||||
newBook: Book = new Book(Math.floor(Math.random() * 1000), '', '');
|
||||
booksToEdit: number[] = [];
|
||||
isAddNewBook: boolean = false;
|
||||
selectedBook: Book = null;
|
||||
|
||||
constructor(private httpService: HttpService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.loadBooks();
|
||||
}
|
||||
|
||||
loadBooks() {
|
||||
this.httpService.getBooks()
|
||||
.subscribe((response: Response) => {
|
||||
let booksJson: any[] = response.json()
|
||||
booksJson.forEach(book => {
|
||||
this.books.push(new Book(book.id, book.author, book.title));
|
||||
this.newBooks.push(new Book(book.id, book.author, book.title));
|
||||
})
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
cancelEditBook(bookIndex: number) {
|
||||
if (this.booksToEdit.indexOf(bookIndex) !== -1) {
|
||||
this.booksToEdit.splice(this.booksToEdit.indexOf(bookIndex), 1); //remove the index of the book to edit
|
||||
//get the original book
|
||||
let bookCopy: Book = new Book(this.books[bookIndex].id, this.books[bookIndex].author, this.books[bookIndex].title);
|
||||
this.newBooks.splice(bookIndex,1,bookCopy); //replace the edited book with the old book
|
||||
}
|
||||
}
|
||||
|
||||
editBook(bookIndex: number) {
|
||||
this.booksToEdit.push(bookIndex);
|
||||
}
|
||||
|
||||
saveBook(bookIndex: number, newBook: Book) {
|
||||
console.log(newBook);
|
||||
//save the book to the database
|
||||
this.httpService.updateBook(newBook)
|
||||
.subscribe((response: Response) => {
|
||||
let bookJson = response.json();
|
||||
let book: Book = new Book(bookJson.id, bookJson.author, bookJson.title);
|
||||
//update the current array of books
|
||||
let bookArr: Book = this.books.find(b => b.id === book.id);
|
||||
bookArr.title = book.title;
|
||||
bookArr.author = book.author;
|
||||
this.booksToEdit.splice(this.booksToEdit.indexOf(bookIndex), 1); //remove the index of the book to edit
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
delete(bookIndex: number) {
|
||||
let book: Book = this.books[bookIndex];
|
||||
this.httpService.deleteBook(book)
|
||||
.subscribe(() => {
|
||||
if (this.selectedBook !== null && this.books[bookIndex].id === this.selectedBook.id) {
|
||||
this.selectedBook = null;
|
||||
this.onBookSelected.emit(this.selectedBook);
|
||||
}
|
||||
|
||||
this.books.splice(bookIndex, 1); //remove the book at this index;
|
||||
this.newBooks.splice(bookIndex, 1); //remove the editing book at this index
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
activateAddNewBook() {
|
||||
this.isAddNewBook = true;
|
||||
this.newBook = new Book(null, '', '');
|
||||
}
|
||||
|
||||
addNewBook(newBook: Book, element: any) {
|
||||
//write new book to db
|
||||
this.httpService.createBook(newBook)
|
||||
.subscribe((response: Response) => {
|
||||
let bookJson = response.json();
|
||||
let book: Book = new Book(bookJson.id, bookJson.author, bookJson.title);
|
||||
console.log(book);
|
||||
this.books.push(book);
|
||||
this.newBooks.push(book);
|
||||
this.newBook = new Book(Math.floor(Math.random() * 1000), '', '');
|
||||
element.focus();
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
cancelAddBook() {
|
||||
this.isAddNewBook = false;
|
||||
}
|
||||
|
||||
|
||||
selectBook(book: Book) {
|
||||
this.selectedBook = book;
|
||||
this.onBookSelected.emit(book);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import {Directive, HostListener} from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: '[appClickStopPropagation]'
|
||||
})
|
||||
export class ClickStopPropagationDirective
|
||||
{
|
||||
@HostListener("click", ["$event"])
|
||||
public onClick(event: any): void
|
||||
{
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {Observable} from "rxjs";
|
||||
import {Response, Http, Headers, RequestOptions} from "@angular/http";
|
||||
import {Book} from "./book";
|
||||
import {Rating} from "./rating";
|
||||
|
||||
@Injectable()
|
||||
export class HttpService {
|
||||
|
||||
constructor(private http: Http) { }
|
||||
|
||||
me(): Observable<Response> {
|
||||
return this.http.get("/me", this.makeOptions())
|
||||
}
|
||||
|
||||
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'});
|
||||
return new RequestOptions({headers: headers});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
export class Principal {
|
||||
public authenticated: boolean;
|
||||
public authorities: Authority[] = [];
|
||||
|
||||
constructor(authenticated: boolean, authorities: any[]) {
|
||||
this.authenticated = authenticated;
|
||||
authorities.map(auth => this.authorities.push(new Authority(auth.authority)))
|
||||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.authorities.some((auth: Authority) => auth.authority.indexOf('ADMIN') > -1)
|
||||
}
|
||||
}
|
||||
|
||||
export class Authority {
|
||||
public authority: String;
|
||||
|
||||
constructor(authority: String) {
|
||||
this.authority = authority;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
export class Rating{
|
||||
id: number;
|
||||
bookId: number;
|
||||
stars: number;
|
||||
|
||||
constructor(id: number, bookId: number, stars: number) {
|
||||
this.id = id;
|
||||
this.bookId = bookId;
|
||||
this.stars = stars;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
div.progress {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.rating:hover {
|
||||
border: solid blue;
|
||||
}
|
||||
|
||||
.selected {
|
||||
border: solid blue;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
Ratings:
|
||||
<div *ngFor="let rating of ratings; let i = index;" class="row">
|
||||
<div class="col-md-10">
|
||||
<div class="progress" [ngClass]="{'selected': principal.isAdmin() && rating === newRating, 'rating': principal.isAdmin()}" (click)="selectRating(rating)">
|
||||
<div class="progress-bar bg-success" role="progressbar" [style.width]="findWidth(rating)" [attr.aria-valuenow]="rating.stars" aria-valuemin="0" aria-valuemax="5"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button *ngIf="principal?.isAdmin()" type="button" class="close" aria-label="Close" (click)="deleteRating(i)">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form (ngSubmit)="onSaveRating(f)" #f="ngForm">
|
||||
<div class="form-check form-check-inline" *ngFor="let star of stars; let i = index;">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="radio" name="star" [(ngModel)]="newRating.stars" [value]="star">{{star}}
|
||||
</label>
|
||||
</div>
|
||||
<button *ngIf="newRating.id === null" type="submit" class="btn btn-secondary" [disabled]="!f.valid">Add Rating</button>
|
||||
<button *ngIf="principal.isAdmin() && newRating.id !== null" type="button" class="btn btn-secondary" (click)="updateRating()">Save</button>
|
||||
<button *ngIf="principal.isAdmin() && newRating.id !== null" type="button" class="btn btn-secondary" (click)="cancelSelection()">Cancel</button>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import {Component, OnInit, Input, OnChanges} from "@angular/core";
|
||||
import {Rating} from "../rating";
|
||||
import {Principal} from "../principal";
|
||||
import {HttpService} from "../http.service";
|
||||
import {Response} from "@angular/http";
|
||||
|
||||
@Component({
|
||||
selector: 'app-rating',
|
||||
templateUrl: './rating.component.html',
|
||||
styleUrls: ['./rating.component.css']
|
||||
})
|
||||
export class RatingComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() bookId: number;
|
||||
@Input() principal: Principal = null;
|
||||
ratings: Rating[] = [];
|
||||
stars: number[] = [1,2,3,4,5];
|
||||
newRating: Rating = null;
|
||||
|
||||
constructor(private httpService: HttpService) { }
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngOnChanges() {
|
||||
this.newRating = new Rating(null, this.bookId, 1);
|
||||
this.ratings = [];
|
||||
this.loadRatings();
|
||||
}
|
||||
|
||||
findWidth(rating: Rating): String {
|
||||
let percent: number = (rating.stars/5)*100;
|
||||
return percent.toString() + '%';
|
||||
}
|
||||
|
||||
private loadRatings() {
|
||||
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)))
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
onSaveRating() {
|
||||
console.log(this.newRating);
|
||||
let ratingCopy: Rating = Object.assign({}, this.newRating);
|
||||
this.httpService.createRating(ratingCopy)
|
||||
.subscribe((response: Response) => {
|
||||
let ratingJson = response.json()
|
||||
this.ratings.push(new Rating(ratingJson.id, ratingJson.bookId, ratingJson.stars))
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
updateRating() {
|
||||
this.httpService.updateRating(this.newRating)
|
||||
.subscribe(() => {
|
||||
this.newRating = new Rating(null, this.bookId, 1);
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
selectRating(rating: Rating) {
|
||||
if (this.principal.isAdmin()) {
|
||||
this.newRating = rating;
|
||||
}
|
||||
}
|
||||
|
||||
cancelSelection() {
|
||||
this.newRating = new Rating(null, this.bookId, 1);
|
||||
}
|
||||
|
||||
deleteRating(index: number) {
|
||||
let rating = this.ratings[index];
|
||||
this.httpService.deleteRating(rating.id)
|
||||
.subscribe(() => {
|
||||
if (this.ratings[index] === this.newRating) {
|
||||
this.newRating = new Rating(null, this.bookId, 1);
|
||||
}
|
||||
this.ratings.splice(index, 1);
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export const environment = {
|
||||
production: true
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Ui</title>
|
||||
<base href="/home/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
import {enableProdMode} from "@angular/core";
|
||||
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
|
||||
import {AppModule} from "./app/app.module";
|
||||
import {environment} from "./environments/environment";
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -0,0 +1,15 @@
|
|||
import "core-js/es6/reflect";
|
||||
import "core-js/es7/reflect";
|
||||
import "zone.js/dist/zone";
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date, currency, decimal and percent pipes.
|
||||
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
*/
|
||||
// import 'intl'; // Run `npm install --save intl`.
|
|
@ -0,0 +1 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
|
@ -0,0 +1,27 @@
|
|||
import "zone.js/dist/long-stack-trace-zone";
|
||||
import "zone.js/dist/proxy.js";
|
||||
import "zone.js/dist/sync-test";
|
||||
import "zone.js/dist/jasmine-patch";
|
||||
import "zone.js/dist/async-test";
|
||||
import "zone.js/dist/fake-async-test";
|
||||
import {getTestBed} from "@angular/core/testing";
|
||||
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from "@angular/platform-browser-dynamic/testing";
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare var __karma__: any;
|
||||
declare var require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
// Finally, start Karma to run the tests.
|
||||
__karma__.start();
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "es2015",
|
||||
"baseUrl": "",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"baseUrl": "",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
5
spring-cloud/spring-cloud-bootstrap/gateway/src/main/angular/ui/src/typings.d.ts
vendored
Normal file
5
spring-cloud/spring-cloud-bootstrap/gateway/src/main/angular/ui/src/typings.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* SystemJS module definition */
|
||||
declare var module: NodeModule;
|
||||
interface NodeModule {
|
||||
id: string;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"baseUrl": "src",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2016",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [true, "rxjs"],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
"static-before-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [true, "ignore-params"],
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"typeof-compare": true,
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
|
||||
"directive-selector": [true, "attribute", "app", "camelCase"],
|
||||
"component-selector": [true, "element", "app", "kebab-case"],
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true,
|
||||
"no-access-missing-member": true,
|
||||
"templates-use-public": true,
|
||||
"invoke-injectable": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
@RestController
|
||||
public class AuthenticationController {
|
||||
@GetMapping("/me")
|
||||
public Principal getMyUser(Principal principal) {
|
||||
return principal;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.springframework.boot.web.servlet.ErrorPage;
|
||||
import org.springframework.boot.web.servlet.ErrorPageRegistrar;
|
||||
import org.springframework.boot.web.servlet.ErrorPageRegistry;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ErrorPageConfig implements ErrorPageRegistrar {
|
||||
@Override
|
||||
public void registerErrorPages(ErrorPageRegistry registry) {
|
||||
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/home/index.html"));
|
||||
}
|
||||
|
||||
}
|
|
@ -21,18 +21,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/book-service/books").permitAll()
|
||||
.antMatchers("/zipkin/**").permitAll()
|
||||
http
|
||||
.formLogin()
|
||||
.defaultSuccessUrl("/home/index.html", true)
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/book-service/**", "/rating-service/**", "/login*", "/").permitAll()
|
||||
.antMatchers("/eureka/**").hasRole("ADMIN")
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.logout()
|
||||
.and()
|
||||
.logout().permitAll()
|
||||
.logoutSuccessUrl("/book-service/books").permitAll()
|
||||
.and()
|
||||
.csrf()
|
||||
.disable();
|
||||
.csrf().disable();
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Ui</title>
|
||||
<base href="/home/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
<script type="text/javascript" src="inline.bundle.js"></script><script type="text/javascript" src="polyfills.bundle.js"></script><script type="text/javascript" src="styles.bundle.js"></script><script type="text/javascript" src="vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body>
|
||||
</html>
|
|
@ -0,0 +1,146 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // install a JSONP callback for chunk loading
|
||||
/******/ var parentJsonpFunction = window["webpackJsonp"];
|
||||
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
|
||||
/******/ // add "moreModules" to the modules object,
|
||||
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||||
/******/ var moduleId, chunkId, i = 0, resolves = [], result;
|
||||
/******/ for(;i < chunkIds.length; i++) {
|
||||
/******/ chunkId = chunkIds[i];
|
||||
/******/ if(installedChunks[chunkId])
|
||||
/******/ resolves.push(installedChunks[chunkId][0]);
|
||||
/******/ installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ for(moduleId in moreModules) {
|
||||
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
|
||||
/******/ modules[moduleId] = moreModules[moduleId];
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
|
||||
/******/ while(resolves.length)
|
||||
/******/ resolves.shift()();
|
||||
/******/ if(executeModules) {
|
||||
/******/ for(i=0; i < executeModules.length; i++) {
|
||||
/******/ result = __webpack_require__(__webpack_require__.s = executeModules[i]);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ return result;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // objects to store loaded and loading chunks
|
||||
/******/ var installedChunks = {
|
||||
/******/ 4: 0
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ // This file contains only the entry chunk.
|
||||
/******/ // The chunk loading function for additional chunks
|
||||
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
|
||||
/******/ if(installedChunks[chunkId] === 0)
|
||||
/******/ return Promise.resolve();
|
||||
/******/
|
||||
/******/ // an Promise means "currently loading".
|
||||
/******/ if(installedChunks[chunkId]) {
|
||||
/******/ return installedChunks[chunkId][2];
|
||||
/******/ }
|
||||
/******/ // start chunk loading
|
||||
/******/ var head = document.getElementsByTagName('head')[0];
|
||||
/******/ var script = document.createElement('script');
|
||||
/******/ script.type = 'text/javascript';
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.async = true;
|
||||
/******/ script.timeout = 120000;
|
||||
/******/
|
||||
/******/ if (__webpack_require__.nc) {
|
||||
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||
/******/ }
|
||||
/******/ script.src = __webpack_require__.p + "" + chunkId + ".chunk.js";
|
||||
/******/ var timeout = setTimeout(onScriptComplete, 120000);
|
||||
/******/ script.onerror = script.onload = onScriptComplete;
|
||||
/******/ function onScriptComplete() {
|
||||
/******/ // avoid mem leaks in IE.
|
||||
/******/ script.onerror = script.onload = null;
|
||||
/******/ clearTimeout(timeout);
|
||||
/******/ var chunk = installedChunks[chunkId];
|
||||
/******/ if(chunk !== 0) {
|
||||
/******/ if(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
|
||||
/******/ installedChunks[chunkId] = undefined;
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ var promise = new Promise(function(resolve, reject) {
|
||||
/******/ installedChunks[chunkId] = [resolve, reject];
|
||||
/******/ });
|
||||
/******/ installedChunks[chunkId][2] = promise;
|
||||
/******/
|
||||
/******/ head.appendChild(script);
|
||||
/******/ return promise;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // identity function for calling harmony imports with the correct context
|
||||
/******/ __webpack_require__.i = function(value) { return value; };
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // on error function for async loading
|
||||
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([]);
|
||||
//# sourceMappingURL=inline.bundle.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,788 @@
|
|||
webpackJsonp([1,4],{
|
||||
|
||||
/***/ 144:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
exports = module.exports = __webpack_require__(13)();
|
||||
// imports
|
||||
|
||||
|
||||
// module
|
||||
exports.push([module.i, ".custom-close {\r\n float:right;\r\n}\r\n", ""]);
|
||||
|
||||
// exports
|
||||
|
||||
|
||||
/*** EXPORTS FROM exports-loader ***/
|
||||
module.exports = module.exports.toString();
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 145:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
exports = module.exports = __webpack_require__(13)();
|
||||
// imports
|
||||
|
||||
|
||||
// module
|
||||
exports.push([module.i, "", ""]);
|
||||
|
||||
// exports
|
||||
|
||||
|
||||
/*** EXPORTS FROM exports-loader ***/
|
||||
module.exports = module.exports.toString();
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 146:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
exports = module.exports = __webpack_require__(13)();
|
||||
// imports
|
||||
|
||||
|
||||
// module
|
||||
exports.push([module.i, ".custom-close {\r\n float:right;\r\n}\r\n", ""]);
|
||||
|
||||
// exports
|
||||
|
||||
|
||||
/*** EXPORTS FROM exports-loader ***/
|
||||
module.exports = module.exports.toString();
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 147:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
exports = module.exports = __webpack_require__(13)();
|
||||
// imports
|
||||
|
||||
|
||||
// module
|
||||
exports.push([module.i, "div.progress {\r\n margin-top: 5px;\r\n}\r\n\r\n.rating:hover {\r\n border: solid blue;\r\n}\r\n\r\n.selected {\r\n border: solid blue;\r\n}\r\n", ""]);
|
||||
|
||||
// exports
|
||||
|
||||
|
||||
/*** EXPORTS FROM exports-loader ***/
|
||||
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 <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"
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 150:
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = "<div class=\"card\">\r\n <div class=\"card-block\">\r\n <button type=\"button\" class=\"close\" aria-label=\"Close\" (click)=\"closeBookDetail()\">\r\n <span aria-hidden=\"true\">×</span>\r\n </button>\r\n <h4 class=\"card-title\">Title: {{selectedBook.title}}</h4>\r\n <h6 class=\"card-subtitle mb-2 text-muted\">Author: {{selectedBook.author}}</h6>\r\n <p class=\"card-text\">A quick summary of the book</p>\r\n <app-rating *ngIf=\"principal.authenticated\" [bookId]=\"selectedBook.id\" [principal]=\"principal\"></app-rating>\r\n </div>\r\n</div>\r\n"
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 151:
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = "<div class=\"col-md-12\" *ngFor=\"let book of books; let i = index;\" (click)=\"selectBook(book)\">\r\n <div class=\"card\">\r\n <div class=\"card-block\">\r\n <div *ngIf=\"booksToEdit.indexOf(i) === -1 ; then bookView else bookEdit\"></div>\r\n <ng-template #bookView>\r\n <button appClickStopPropagation *ngIf=\"principal.isAdmin()\" type=\"button\" class=\"btn btn-danger custom-close\" (click)=\"delete(i)\">Delete</button>\r\n <button appClickStopPropagation *ngIf=\"principal.isAdmin()\" type=\"button\" class=\"btn btn-warning custom-close\" (click)=\"editBook(i)\">Edit</button>\r\n <h4 class=\"card-title\">Title: {{book.title}}</h4>\r\n <h6 class=\"card-subtitle mb-2 text-muted\">Author: {{book.author}}</h6>\r\n </ng-template>\r\n <ng-template #bookEdit>\r\n <button appClickStopPropagation type=\"button\" class=\"btn btn-secondary custom-close\" (click)=\"cancelEditBook(i)\">Cancel</button>\r\n <form appClickStopPropagation (ngSubmit)=\"saveBook(i, newBooks[i])\" class=\"mt-2 mt-md-0\" #f1=\"ngForm\">\r\n <div class=\"form-group\">\r\n <label for=\"title\">Title:</label>\r\n <input id=\"title\" name=\"title\" [(ngModel)]=\"newBooks[i].title\" required class=\"form-control mr-sm-2\" type=\"text\">\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"author\">Author:</label>\r\n <input id=\"author\" name=\"author\" [(ngModel)]=\"newBooks[i].author\" required class=\"form-control mr-sm-2\" type=\"text\">\r\n </div>\r\n <button class=\"btn btn-outline-success my-2 my-sm-0\" type=\"submit\" [disabled]=\"!f1.valid\">Save</button>\r\n </form>\r\n </ng-template>\r\n\r\n </div>\r\n </div>\r\n</div>\r\n<div *ngIf=\"principal.isAdmin()\" class=\"col-md-12\">\r\n <div class=\"card\">\r\n <div class=\"card-block\">\r\n <div *ngIf=\"!isAddNewBook; then bookPlaceHolder else bookAdd\"></div>\r\n <ng-template #bookPlaceHolder>\r\n <h4 (click)=\"activateAddNewBook()\" class=\"card-title center-block\">Add New Book</h4>\r\n </ng-template>\r\n <ng-template #bookAdd>\r\n <button appClickStopPropagation type=\"button\" class=\"btn btn-secondary custom-close\" (click)=\"cancelAddBook()\">Cancel</button>\r\n <form appClickStopPropagation (ngSubmit)=\"addNewBook(newBook, titleNewBook)\" class=\"mt-2 mt-md-0\" #f2=\"ngForm\">\r\n <div class=\"form-group\">\r\n <label for=\"titleNewBook\">Title:</label>\r\n <input id=\"titleNewBook\" name=\"title\" [(ngModel)]=\"newBook.title\" required class=\"form-control mr-sm-2\" type=\"text\" #titleNewBook>\r\n </div>\r\n <div class=\"form-group\">\r\n <label for=\"authorNewBook\">Author:</label>\r\n <input id=\"authorNewBook\" name=\"author\" [(ngModel)]=\"newBook.author\" required class=\"form-control mr-sm-2\" type=\"text\">\r\n </div>\r\n <button class=\"btn btn-outline-success my-2 my-sm-0\" type=\"submit\" [disabled]=\"!f2.valid\">Save</button>\r\n </form>\r\n </ng-template>\r\n\r\n </div>\r\n </div>\r\n\r\n</div>\r\n"
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 152:
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = "Ratings:\r\n<div *ngFor=\"let rating of ratings; let i = index;\" class=\"row\">\r\n <div class=\"col-md-10\">\r\n <div class=\"progress\" [ngClass]=\"{'selected': principal.isAdmin() && rating === newRating, 'rating': principal.isAdmin()}\" (click)=\"selectRating(rating)\">\r\n <div class=\"progress-bar bg-success\" role=\"progressbar\" [style.width]=\"findWidth(rating)\" [attr.aria-valuenow]=\"rating.stars\" aria-valuemin=\"0\" aria-valuemax=\"5\"></div>\r\n </div>\r\n </div>\r\n <div class=\"col-md-1\">\r\n <button *ngIf=\"principal?.isAdmin()\" type=\"button\" class=\"close\" aria-label=\"Close\" (click)=\"deleteRating(i)\">\r\n <span aria-hidden=\"true\">×</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<form (ngSubmit)=\"onSaveRating(f)\" #f=\"ngForm\">\r\n <div class=\"form-check form-check-inline\" *ngFor=\"let star of stars; let i = index;\">\r\n <label class=\"form-check-label\">\r\n <input class=\"form-check-input\" type=\"radio\" name=\"star\" [(ngModel)]=\"newRating.stars\" [value]=\"star\">{{star}}\r\n </label>\r\n </div>\r\n <button *ngIf=\"newRating.id === null\" type=\"submit\" class=\"btn btn-secondary\" [disabled]=\"!f.valid\">Add Rating</button>\r\n <button *ngIf=\"principal.isAdmin() && newRating.id !== null\" type=\"button\" class=\"btn btn-secondary\" (click)=\"updateRating()\">Save</button>\r\n <button *ngIf=\"principal.isAdmin() && newRating.id !== null\" type=\"button\" class=\"btn btn-secondary\" (click)=\"cancelSelection()\">Cancel</button>\r\n</form>\r\n\r\n"
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 176:
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
module.exports = __webpack_require__(75);
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 22:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__angular_http__ = __webpack_require__(50);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return HttpService; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
|
||||
var HttpService = (function () {
|
||||
function HttpService(http) {
|
||||
this.http = http;
|
||||
}
|
||||
HttpService.prototype.me = function () {
|
||||
return this.http.get("/me", this.makeOptions());
|
||||
};
|
||||
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' });
|
||||
return new __WEBPACK_IMPORTED_MODULE_1__angular_http__["c" /* RequestOptions */]({ headers: headers });
|
||||
};
|
||||
return HttpService;
|
||||
}());
|
||||
HttpService = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["c" /* Injectable */])(),
|
||||
__metadata("design:paramtypes", [typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_1__angular_http__["d" /* Http */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_1__angular_http__["d" /* Http */]) === "function" && _a || Object])
|
||||
], HttpService);
|
||||
|
||||
var _a;
|
||||
//# sourceMappingURL=http.service.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 23:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Principal; });
|
||||
/* unused harmony export Authority */
|
||||
var Principal = (function () {
|
||||
function Principal(authenticated, authorities) {
|
||||
var _this = this;
|
||||
this.authorities = [];
|
||||
this.authenticated = authenticated;
|
||||
authorities.map(function (auth) { return _this.authorities.push(new Authority(auth.authority)); });
|
||||
}
|
||||
Principal.prototype.isAdmin = function () {
|
||||
return this.authorities.some(function (auth) { return auth.authority.indexOf('ADMIN') > -1; });
|
||||
};
|
||||
return Principal;
|
||||
}());
|
||||
|
||||
var Authority = (function () {
|
||||
function Authority(authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
return Authority;
|
||||
}());
|
||||
|
||||
//# sourceMappingURL=principal.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 51:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Book; });
|
||||
var Book = (function () {
|
||||
function Book(id, author, title) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
return Book;
|
||||
}());
|
||||
|
||||
//# sourceMappingURL=book.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 74:
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
function webpackEmptyContext(req) {
|
||||
throw new Error("Cannot find module '" + req + "'.");
|
||||
}
|
||||
webpackEmptyContext.keys = function() { return []; };
|
||||
webpackEmptyContext.resolve = webpackEmptyContext;
|
||||
module.exports = webpackEmptyContext;
|
||||
webpackEmptyContext.id = 74;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 75:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__angular_platform_browser_dynamic__ = __webpack_require__(81);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__app_app_module__ = __webpack_require__(83);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__environments_environment__ = __webpack_require__(89);
|
||||
|
||||
|
||||
|
||||
|
||||
if (__WEBPACK_IMPORTED_MODULE_3__environments_environment__["a" /* environment */].production) {
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["a" /* enableProdMode */])();
|
||||
}
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__angular_platform_browser_dynamic__["a" /* platformBrowserDynamic */])().bootstrapModule(__WEBPACK_IMPORTED_MODULE_2__app_app_module__["a" /* AppModule */]);
|
||||
//# sourceMappingURL=main.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 82:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__principal__ = __webpack_require__(23);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__http_service__ = __webpack_require__(22);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return AppComponent; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
|
||||
|
||||
var AppComponent = (function () {
|
||||
function AppComponent(httpService) {
|
||||
this.httpService = httpService;
|
||||
this.selectedBook = null;
|
||||
this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, []);
|
||||
this.loginFailed = false;
|
||||
}
|
||||
AppComponent.prototype.ngOnInit = function () {
|
||||
var _this = this;
|
||||
this.httpService.me()
|
||||
.subscribe(function (response) {
|
||||
var principalJson = response.json();
|
||||
_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()
|
||||
.subscribe(function (response) {
|
||||
if (response.status === 200) {
|
||||
_this.loginFailed = false;
|
||||
_this.principal = new __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */](false, []);
|
||||
window.location.replace(response.url);
|
||||
}
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
AppComponent.prototype.closeBookDetail = function () {
|
||||
this.selectedBook = null;
|
||||
};
|
||||
AppComponent.prototype.selectBook = function (book) {
|
||||
this.selectedBook = book;
|
||||
};
|
||||
return AppComponent;
|
||||
}());
|
||||
AppComponent = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_3" /* Component */])({
|
||||
selector: 'app-root',
|
||||
template: __webpack_require__(149),
|
||||
styles: [__webpack_require__(144)]
|
||||
}),
|
||||
__metadata("design:paramtypes", [typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_2__http_service__["a" /* HttpService */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_2__http_service__["a" /* HttpService */]) === "function" && _a || Object])
|
||||
], AppComponent);
|
||||
|
||||
var _a;
|
||||
//# sourceMappingURL=app.component.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 83:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_platform_browser__ = __webpack_require__(21);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__angular_forms__ = __webpack_require__(80);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__angular_http__ = __webpack_require__(50);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__app_component__ = __webpack_require__(82);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__rating_rating_component__ = __webpack_require__(88);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__click_stop_propagation_directive__ = __webpack_require__(86);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__book_book_detail_book_detail_component__ = __webpack_require__(84);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__book_book_list_book_list_component__ = __webpack_require__(85);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__http_service__ = __webpack_require__(22);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return AppModule; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var AppModule = (function () {
|
||||
function AppModule() {
|
||||
}
|
||||
return AppModule;
|
||||
}());
|
||||
AppModule = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__angular_core__["b" /* NgModule */])({
|
||||
declarations: [
|
||||
__WEBPACK_IMPORTED_MODULE_4__app_component__["a" /* AppComponent */],
|
||||
__WEBPACK_IMPORTED_MODULE_5__rating_rating_component__["a" /* RatingComponent */],
|
||||
__WEBPACK_IMPORTED_MODULE_6__click_stop_propagation_directive__["a" /* ClickStopPropagationDirective */],
|
||||
__WEBPACK_IMPORTED_MODULE_7__book_book_detail_book_detail_component__["a" /* BookDetailComponent */],
|
||||
__WEBPACK_IMPORTED_MODULE_8__book_book_list_book_list_component__["a" /* BookListComponent */]
|
||||
],
|
||||
imports: [
|
||||
__WEBPACK_IMPORTED_MODULE_0__angular_platform_browser__["a" /* BrowserModule */],
|
||||
__WEBPACK_IMPORTED_MODULE_2__angular_forms__["a" /* FormsModule */],
|
||||
__WEBPACK_IMPORTED_MODULE_3__angular_http__["a" /* HttpModule */]
|
||||
],
|
||||
providers: [__WEBPACK_IMPORTED_MODULE_9__http_service__["a" /* HttpService */]],
|
||||
bootstrap: [__WEBPACK_IMPORTED_MODULE_4__app_component__["a" /* AppComponent */]]
|
||||
})
|
||||
], AppModule);
|
||||
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 84:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__book__ = __webpack_require__(51);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__principal__ = __webpack_require__(23);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return BookDetailComponent; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
|
||||
|
||||
var BookDetailComponent = (function () {
|
||||
function BookDetailComponent() {
|
||||
this.selectedBook = null;
|
||||
this.principal = null;
|
||||
this.closeBook = new __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */]();
|
||||
}
|
||||
BookDetailComponent.prototype.ngOnInit = function () {
|
||||
};
|
||||
BookDetailComponent.prototype.closeBookDetail = function () {
|
||||
this.closeBook.emit(null);
|
||||
};
|
||||
return BookDetailComponent;
|
||||
}());
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["M" /* Input */])(),
|
||||
__metadata("design:type", typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_1__book__["a" /* Book */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_1__book__["a" /* Book */]) === "function" && _a || Object)
|
||||
], BookDetailComponent.prototype, "selectedBook", void 0);
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["M" /* Input */])(),
|
||||
__metadata("design:type", typeof (_b = typeof __WEBPACK_IMPORTED_MODULE_2__principal__["a" /* Principal */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_2__principal__["a" /* Principal */]) === "function" && _b || Object)
|
||||
], BookDetailComponent.prototype, "principal", void 0);
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_2" /* Output */])(),
|
||||
__metadata("design:type", typeof (_c = typeof __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */]) === "function" && _c || Object)
|
||||
], BookDetailComponent.prototype, "closeBook", void 0);
|
||||
BookDetailComponent = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_3" /* Component */])({
|
||||
selector: 'app-book-detail',
|
||||
template: __webpack_require__(150),
|
||||
styles: [__webpack_require__(145)]
|
||||
}),
|
||||
__metadata("design:paramtypes", [])
|
||||
], BookDetailComponent);
|
||||
|
||||
var _a, _b, _c;
|
||||
//# sourceMappingURL=book-detail.component.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 85:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__principal__ = __webpack_require__(23);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__book__ = __webpack_require__(51);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__http_service__ = __webpack_require__(22);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return BookListComponent; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var BookListComponent = (function () {
|
||||
function BookListComponent(httpService) {
|
||||
this.httpService = httpService;
|
||||
this.principal = null;
|
||||
this.onBookSelected = new __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */]();
|
||||
this.books = [];
|
||||
this.newBooks = [];
|
||||
this.newBook = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](Math.floor(Math.random() * 1000), '', '');
|
||||
this.booksToEdit = [];
|
||||
this.isAddNewBook = false;
|
||||
this.selectedBook = null;
|
||||
}
|
||||
BookListComponent.prototype.ngOnInit = function () {
|
||||
this.loadBooks();
|
||||
};
|
||||
BookListComponent.prototype.loadBooks = function () {
|
||||
var _this = this;
|
||||
this.httpService.getBooks()
|
||||
.subscribe(function (response) {
|
||||
var booksJson = response.json();
|
||||
booksJson.forEach(function (book) {
|
||||
_this.books.push(new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](book.id, book.author, book.title));
|
||||
_this.newBooks.push(new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](book.id, book.author, book.title));
|
||||
});
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
BookListComponent.prototype.cancelEditBook = function (bookIndex) {
|
||||
if (this.booksToEdit.indexOf(bookIndex) !== -1) {
|
||||
this.booksToEdit.splice(this.booksToEdit.indexOf(bookIndex), 1); //remove the index of the book to edit
|
||||
//get the original book
|
||||
var bookCopy = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](this.books[bookIndex].id, this.books[bookIndex].author, this.books[bookIndex].title);
|
||||
this.newBooks.splice(bookIndex, 1, bookCopy); //replace the edited book with the old book
|
||||
}
|
||||
};
|
||||
BookListComponent.prototype.editBook = function (bookIndex) {
|
||||
this.booksToEdit.push(bookIndex);
|
||||
};
|
||||
BookListComponent.prototype.saveBook = function (bookIndex, newBook) {
|
||||
var _this = this;
|
||||
console.log(newBook);
|
||||
//save the book to the database
|
||||
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);
|
||||
//update the current array of books
|
||||
var bookArr = _this.books.find(function (b) { return b.id === book.id; });
|
||||
bookArr.title = book.title;
|
||||
bookArr.author = book.author;
|
||||
_this.booksToEdit.splice(_this.booksToEdit.indexOf(bookIndex), 1); //remove the index of the book to edit
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
BookListComponent.prototype.delete = function (bookIndex) {
|
||||
var _this = this;
|
||||
var book = this.books[bookIndex];
|
||||
this.httpService.deleteBook(book)
|
||||
.subscribe(function () {
|
||||
if (_this.selectedBook !== null && _this.books[bookIndex].id === _this.selectedBook.id) {
|
||||
_this.selectedBook = null;
|
||||
_this.onBookSelected.emit(_this.selectedBook);
|
||||
}
|
||||
_this.books.splice(bookIndex, 1); //remove the book at this index;
|
||||
_this.newBooks.splice(bookIndex, 1); //remove the editing book at this index
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
BookListComponent.prototype.activateAddNewBook = function () {
|
||||
this.isAddNewBook = true;
|
||||
this.newBook = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](null, '', '');
|
||||
};
|
||||
BookListComponent.prototype.addNewBook = function (newBook, element) {
|
||||
var _this = this;
|
||||
//write new book to db
|
||||
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);
|
||||
console.log(book);
|
||||
_this.books.push(book);
|
||||
_this.newBooks.push(book);
|
||||
_this.newBook = new __WEBPACK_IMPORTED_MODULE_2__book__["a" /* Book */](Math.floor(Math.random() * 1000), '', '');
|
||||
element.focus();
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
BookListComponent.prototype.cancelAddBook = function () {
|
||||
this.isAddNewBook = false;
|
||||
};
|
||||
BookListComponent.prototype.selectBook = function (book) {
|
||||
this.selectedBook = book;
|
||||
this.onBookSelected.emit(book);
|
||||
};
|
||||
return BookListComponent;
|
||||
}());
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["M" /* Input */])(),
|
||||
__metadata("design:type", typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_1__principal__["a" /* Principal */]) === "function" && _a || Object)
|
||||
], BookListComponent.prototype, "principal", void 0);
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_2" /* Output */])(),
|
||||
__metadata("design:type", typeof (_b = typeof __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_0__angular_core__["D" /* EventEmitter */]) === "function" && _b || Object)
|
||||
], BookListComponent.prototype, "onBookSelected", void 0);
|
||||
BookListComponent = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_3" /* Component */])({
|
||||
selector: 'app-book-list',
|
||||
template: __webpack_require__(151),
|
||||
styles: [__webpack_require__(146)]
|
||||
}),
|
||||
__metadata("design:paramtypes", [typeof (_c = typeof __WEBPACK_IMPORTED_MODULE_3__http_service__["a" /* HttpService */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_3__http_service__["a" /* HttpService */]) === "function" && _c || Object])
|
||||
], BookListComponent);
|
||||
|
||||
var _a, _b, _c;
|
||||
//# sourceMappingURL=book-list.component.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 86:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ClickStopPropagationDirective; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
var ClickStopPropagationDirective = (function () {
|
||||
function ClickStopPropagationDirective() {
|
||||
}
|
||||
ClickStopPropagationDirective.prototype.onClick = function (event) {
|
||||
event.stopPropagation();
|
||||
};
|
||||
return ClickStopPropagationDirective;
|
||||
}());
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_4" /* HostListener */])("click", ["$event"]),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], ClickStopPropagationDirective.prototype, "onClick", null);
|
||||
ClickStopPropagationDirective = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["H" /* Directive */])({
|
||||
selector: '[appClickStopPropagation]'
|
||||
})
|
||||
], ClickStopPropagationDirective);
|
||||
|
||||
//# sourceMappingURL=click-stop-propagation.directive.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 87:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Rating; });
|
||||
var Rating = (function () {
|
||||
function Rating(id, bookId, stars) {
|
||||
this.id = id;
|
||||
this.bookId = bookId;
|
||||
this.stars = stars;
|
||||
}
|
||||
return Rating;
|
||||
}());
|
||||
|
||||
//# sourceMappingURL=rating.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 88:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__angular_core__ = __webpack_require__(2);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__rating__ = __webpack_require__(87);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__principal__ = __webpack_require__(23);
|
||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__http_service__ = __webpack_require__(22);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RatingComponent; });
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var RatingComponent = (function () {
|
||||
function RatingComponent(httpService) {
|
||||
this.httpService = httpService;
|
||||
this.principal = null;
|
||||
this.ratings = [];
|
||||
this.stars = [1, 2, 3, 4, 5];
|
||||
this.newRating = null;
|
||||
}
|
||||
RatingComponent.prototype.ngOnInit = function () { };
|
||||
RatingComponent.prototype.ngOnChanges = function () {
|
||||
this.newRating = new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](null, this.bookId, 1);
|
||||
this.ratings = [];
|
||||
this.loadRatings();
|
||||
};
|
||||
RatingComponent.prototype.findWidth = function (rating) {
|
||||
var percent = (rating.stars / 5) * 100;
|
||||
return percent.toString() + '%';
|
||||
};
|
||||
RatingComponent.prototype.loadRatings = function () {
|
||||
var _this = this;
|
||||
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)); });
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
RatingComponent.prototype.onSaveRating = function () {
|
||||
var _this = this;
|
||||
console.log(this.newRating);
|
||||
var ratingCopy = Object.assign({}, this.newRating);
|
||||
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));
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
RatingComponent.prototype.updateRating = function () {
|
||||
var _this = this;
|
||||
this.httpService.updateRating(this.newRating)
|
||||
.subscribe(function () {
|
||||
_this.newRating = new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](null, _this.bookId, 1);
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
RatingComponent.prototype.selectRating = function (rating) {
|
||||
if (this.principal.isAdmin()) {
|
||||
this.newRating = rating;
|
||||
}
|
||||
};
|
||||
RatingComponent.prototype.cancelSelection = function () {
|
||||
this.newRating = new __WEBPACK_IMPORTED_MODULE_1__rating__["a" /* Rating */](null, this.bookId, 1);
|
||||
};
|
||||
RatingComponent.prototype.deleteRating = function (index) {
|
||||
var _this = this;
|
||||
var rating = this.ratings[index];
|
||||
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);
|
||||
}
|
||||
_this.ratings.splice(index, 1);
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
return RatingComponent;
|
||||
}());
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["M" /* Input */])(),
|
||||
__metadata("design:type", Number)
|
||||
], RatingComponent.prototype, "bookId", void 0);
|
||||
__decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["M" /* Input */])(),
|
||||
__metadata("design:type", typeof (_a = typeof __WEBPACK_IMPORTED_MODULE_2__principal__["a" /* Principal */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_2__principal__["a" /* Principal */]) === "function" && _a || Object)
|
||||
], RatingComponent.prototype, "principal", void 0);
|
||||
RatingComponent = __decorate([
|
||||
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__angular_core__["_3" /* Component */])({
|
||||
selector: 'app-rating',
|
||||
template: __webpack_require__(152),
|
||||
styles: [__webpack_require__(147)]
|
||||
}),
|
||||
__metadata("design:paramtypes", [typeof (_b = typeof __WEBPACK_IMPORTED_MODULE_3__http_service__["a" /* HttpService */] !== "undefined" && __WEBPACK_IMPORTED_MODULE_3__http_service__["a" /* HttpService */]) === "function" && _b || Object])
|
||||
], RatingComponent);
|
||||
|
||||
var _a, _b;
|
||||
//# sourceMappingURL=rating.component.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 89:
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return environment; });
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
var environment = {
|
||||
production: false
|
||||
};
|
||||
//# sourceMappingURL=environment.js.map
|
||||
|
||||
/***/ })
|
||||
|
||||
},[176]);
|
||||
//# sourceMappingURL=main.bundle.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -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">Login</a>
|
||||
</body>
|
||||
</html>
|
|
@ -1,201 +0,0 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
public class IntegrationLiveTest {
|
||||
|
||||
private TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||
private String testUrl = "http://localhost:8080";
|
||||
|
||||
@Test
|
||||
public void testAccess() throws Exception {
|
||||
ResponseEntity<String> response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//try the protected resource and confirm the redirect to login
|
||||
response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class);
|
||||
Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode());
|
||||
Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0));
|
||||
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "user");
|
||||
form.add("password", "password");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
addBook();
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
addRatings();
|
||||
|
||||
//request the admin protected resource to determine it is still protected
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
|
||||
|
||||
//login as the admin
|
||||
form.clear();
|
||||
form.add("username", "admin");
|
||||
form.add("password", "admin");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//request the discovery resources as the admin
|
||||
response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
}
|
||||
|
||||
private void addRatings() {
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "user");
|
||||
form.add("password", "password");
|
||||
ResponseEntity<String> response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType());
|
||||
Rating rating = new Rating(1L, 4);
|
||||
|
||||
HttpEntity<Rating> httpEntity = new HttpEntity<>(rating, headers);
|
||||
|
||||
//request the protected resource
|
||||
ResponseEntity<Rating> bookResponse = testRestTemplate.postForEntity(testUrl + "/rating-service/ratings", httpEntity, Rating.class);
|
||||
Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode());
|
||||
Assert.assertEquals(rating.getBookId(), bookResponse.getBody().getBookId());
|
||||
Assert.assertEquals(rating.getStars(), bookResponse.getBody().getStars());
|
||||
}
|
||||
|
||||
private void addBook(){
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "admin");
|
||||
form.add("password", "admin");
|
||||
ResponseEntity<String> response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType());
|
||||
Book book = new Book("Baeldung", "How to spring cloud");
|
||||
|
||||
HttpEntity<Book> httpEntity = new HttpEntity<>(book, headers);
|
||||
|
||||
//request the protected resource
|
||||
ResponseEntity<Book> bookResponse = testRestTemplate.postForEntity(testUrl + "/book-service/books", httpEntity, Book.class);
|
||||
Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode());
|
||||
Assert.assertEquals(book.getAuthor(), bookResponse.getBody().getAuthor());
|
||||
Assert.assertEquals(book.getTitle(), bookResponse.getBody().getTitle());
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Book {
|
||||
|
||||
private Long id;
|
||||
private String author;
|
||||
private String title;
|
||||
|
||||
public Book() {
|
||||
}
|
||||
|
||||
public Book(String author, String title) {
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Rating {
|
||||
private Long id;
|
||||
private Long bookId;
|
||||
private int stars;
|
||||
|
||||
public Rating() {
|
||||
}
|
||||
|
||||
public Rating(Long bookId, int stars) {
|
||||
this.bookId = bookId;
|
||||
this.stars = stars;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(Long bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public int getStars() {
|
||||
return stars;
|
||||
}
|
||||
|
||||
public void setStars(int stars) {
|
||||
this.stars = stars;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import static io.restassured.RestAssured.config;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.authentication.FormAuthConfig;
|
||||
import io.restassured.config.RedirectConfig;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.response.Response;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import static io.restassured.RestAssured.config;
|
||||
|
||||
public class LiveTest {
|
||||
|
||||
|
@ -34,7 +33,7 @@ public class LiveTest {
|
|||
|
||||
@Test
|
||||
public void whenAccessProtectedResourceWithoutLogin_thenRedirectToLogin() {
|
||||
final Response response = RestAssured.get(ROOT_URI + "/book-service/books/1");
|
||||
final Response response = RestAssured.get(ROOT_URI + "/home/index.html");
|
||||
Assert.assertEquals(HttpStatus.FOUND.value(), response.getStatusCode());
|
||||
Assert.assertEquals("http://localhost:8080/login", response.getHeader("Location"));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcbook;
|
||||
|
||||
import com.baeldung.spring.cloud.bootstrap.svcbook.book.Book;
|
||||
import com.baeldung.spring.cloud.bootstrap.svcbook.book.BookService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DataLoader implements ApplicationRunner {
|
||||
|
||||
private BookService bookService;
|
||||
|
||||
@Autowired
|
||||
public DataLoader(BookService bookService) {
|
||||
this.bookService = bookService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments applicationArguments) throws Exception {
|
||||
this.bookService.createBook(new Book("Aldous Huxley", "Brave new world"));
|
||||
this.bookService.createBook(new Book("George Orwell", "Animal Farm"));
|
||||
}
|
||||
}
|
|
@ -19,6 +19,11 @@ public class Book {
|
|||
public Book() {
|
||||
}
|
||||
|
||||
public Book(String author, String title) {
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating;
|
||||
|
||||
import com.baeldung.spring.cloud.bootstrap.svcrating.rating.Rating;
|
||||
import com.baeldung.spring.cloud.bootstrap.svcrating.rating.RatingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DataLoader implements ApplicationRunner {
|
||||
|
||||
private RatingService ratingService;
|
||||
|
||||
@Autowired
|
||||
public DataLoader(RatingService ratingService) {
|
||||
this.ratingService = ratingService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments applicationArguments) throws Exception {
|
||||
this.ratingService.createRating(new Rating(1L, 1));
|
||||
this.ratingService.createRating(new Rating(1L, 2));
|
||||
this.ratingService.createRating(new Rating(2L, 3));
|
||||
this.ratingService.createRating(new Rating(2L, 4));
|
||||
this.ratingService.createRating(new Rating(2L, 5));
|
||||
}
|
||||
}
|
|
@ -26,6 +26,11 @@ public class Rating {
|
|||
this.stars = stars;
|
||||
}
|
||||
|
||||
public Rating(Long bookId, int stars) {
|
||||
this.bookId = bookId;
|
||||
this.stars = stars;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Transactional(readOnly = true)
|
||||
|
@ -58,6 +57,7 @@ public class RatingService {
|
|||
return ratingRepository.save(rating);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public Rating updateRating(Rating rating, Long ratingId) {
|
||||
Preconditions.checkNotNull(rating);
|
||||
Preconditions.checkState(rating.getId() == ratingId);
|
||||
|
|
Loading…
Reference in New Issue