├── .gitignore
├── .travis.yml
├── Jenkinsfile
├── LICENSE
├── README.md
├── Vagrantfile
├── angular-spring-boot-webapp
├── .bowerrc
├── .jshintrc
├── Gruntfile.js
├── bower.json
├── karma.conf.ci.js
├── karma.conf.js
├── lombok.config
├── package.json
├── pom.xml
├── serenity.properties
└── src
│ ├── main
│ ├── docker
│ │ ├── mysql
│ │ │ ├── .dockerignore
│ │ │ ├── Dockerfile
│ │ │ └── conf.yml
│ │ └── ngspring
│ │ │ ├── .dockerignore
│ │ │ ├── Dockerfile
│ │ │ ├── bootstrap.sh
│ │ │ ├── conf.yml
│ │ │ └── run.sh
│ ├── frontend
│ │ ├── .buildignore
│ │ ├── .htaccess
│ │ ├── 404.html
│ │ ├── images
│ │ │ └── angularjs-logo.png
│ │ ├── index.html
│ │ ├── robots.txt
│ │ ├── scripts
│ │ │ ├── app.js
│ │ │ ├── controllers
│ │ │ │ ├── ctrl.about.js
│ │ │ │ ├── ctrl.event.js
│ │ │ │ ├── ctrl.main.js
│ │ │ │ └── ctrl.nav.js
│ │ │ ├── services
│ │ │ │ ├── srv.auth.js
│ │ │ │ ├── srv.domain.js
│ │ │ │ ├── srv.errorHandling.js
│ │ │ │ ├── srv.event.js
│ │ │ │ ├── srv.redirect.js
│ │ │ │ └── srv.user.js
│ │ │ └── util
│ │ │ │ └── proto.string.js
│ │ ├── styles
│ │ │ ├── _mixins.scss
│ │ │ ├── _theme.scss
│ │ │ ├── font-awesome.min.css
│ │ │ └── main.scss
│ │ ├── templates
│ │ │ └── user-management.html
│ │ └── views
│ │ │ ├── about.html
│ │ │ ├── event.html
│ │ │ └── main.html
│ ├── java
│ │ └── ngSpring
│ │ │ └── demo
│ │ │ ├── AngularSpringApplication.java
│ │ │ ├── controllers
│ │ │ ├── EventController.java
│ │ │ ├── LoginController.java
│ │ │ └── UserController.java
│ │ │ ├── domain
│ │ │ ├── AbstractBaseEntity.java
│ │ │ ├── DTO.java
│ │ │ ├── dto
│ │ │ │ ├── EventDTO.java
│ │ │ │ ├── UserDTO.java
│ │ │ │ ├── UserProfileDTO.java
│ │ │ │ └── UserRoleDTO.java
│ │ │ └── entities
│ │ │ │ ├── Event.java
│ │ │ │ └── User.java
│ │ │ ├── errorhandling
│ │ │ ├── GlobalControllerExceptionHandler.java
│ │ │ └── ValidationMessage.java
│ │ │ ├── exceptions
│ │ │ ├── BusinessException.java
│ │ │ ├── EntityNotFoundException.java
│ │ │ └── ValidationException.java
│ │ │ ├── mvc
│ │ │ └── MvcConfig.java
│ │ │ ├── repositories
│ │ │ ├── EventRepository.java
│ │ │ └── UserRepository.java
│ │ │ ├── security
│ │ │ ├── AngularSpringAuthenticationProvider.java
│ │ │ ├── AppSecurityConfiguration.java
│ │ │ └── AuthenticationSecurity.java
│ │ │ ├── services
│ │ │ └── impl
│ │ │ │ └── UserDetailsServiceImpl.java
│ │ │ ├── transformer
│ │ │ ├── GenericTransformer.java
│ │ │ ├── Transformer.java
│ │ │ └── impl
│ │ │ │ ├── EventTransformer.java
│ │ │ │ ├── UserProfileTransformer.java
│ │ │ │ └── UserTransformer.java
│ │ │ ├── util
│ │ │ └── Message.java
│ │ │ └── validation
│ │ │ ├── AbstractBeanValidator.java
│ │ │ ├── DateRangeValidator.java
│ │ │ ├── TimeRangeValidator.java
│ │ │ ├── ValidateDateRange.java
│ │ │ └── ValidateTimeRange.java
│ └── resources
│ │ ├── ValidationMessages_de.properties
│ │ ├── application-heroku.properties
│ │ ├── application-test.properties
│ │ ├── application.properties
│ │ ├── db
│ │ └── migration
│ │ │ └── V1_0_01__Initial_db_version.sql
│ │ └── templates
│ │ └── login.html
│ └── test
│ ├── frontend
│ ├── .jshintrc
│ ├── mocks
│ │ ├── mock.app.js
│ │ ├── mock.srv.auth.js
│ │ ├── mock.srv.event.js
│ │ ├── mock.srv.redirect.js
│ │ └── mock.srv.user.js
│ └── spec
│ │ ├── controllers
│ │ ├── ctrl.eventSpec.js
│ │ ├── ctrl.mainSpec.js
│ │ └── ctrl.navSpec.js
│ │ └── services
│ │ ├── srv.authSpec.js
│ │ ├── srv.domainEventSpec.js
│ │ ├── srv.domainValidationSpec.js
│ │ ├── srv.errorHandlingSpec.js
│ │ └── srv.eventSpec.js
│ ├── java
│ └── ngSpring
│ │ └── demo
│ │ ├── AngularSpringApplicationTest.java
│ │ ├── domain
│ │ ├── EventDomainTest.java
│ │ ├── UserDomainTest.java
│ │ ├── fixtures
│ │ │ ├── EventFixture.java
│ │ │ └── UserFixture.java
│ │ └── validation
│ │ │ ├── EventValidationTest.java
│ │ │ └── UserValidationTest.java
│ │ ├── errorhandling
│ │ └── ControllerErrorHandlingTestBase.java
│ │ ├── integration
│ │ ├── rest
│ │ │ └── EventControllerIT.java
│ │ └── ui
│ │ │ ├── LoginSerenityIT.java
│ │ │ ├── pages
│ │ │ ├── CmsPage.java
│ │ │ └── LoginPage.java
│ │ │ ├── steps
│ │ │ └── LoginSteps.java
│ │ │ └── util
│ │ │ └── AbstractSerenityITTestBase.java
│ │ ├── transformer
│ │ ├── EventTransformerTest.java
│ │ └── UserTransformerTest.java
│ │ └── util
│ │ ├── MockedMvcTestBase.java
│ │ ├── RestITBase.java
│ │ └── ValidationTestBase.java
│ └── resources
│ ├── setup
│ └── test.sql
│ └── testdata
│ └── login.csv
├── install.sh
├── pom.xml
└── sample.png
/.gitignore:
--------------------------------------------------------------------------------
1 | angular-spring-boot-webapp/tmp/
2 | angular-spring-boot-webapp/.tmp/
3 | angular-spring-boot-webapp/.sass-cache/
4 | angular-spring-boot-webapp/bower_components/
5 | angular-spring-boot-webapp/node/
6 | angular-spring-boot-webapp/node_modules/
7 | angular-spring-boot-webapp/src/main/resources/static/*
8 |
9 | # Eclipse files
10 | **/.project
11 | **/.settings/
12 | **/.classpath
13 | *.class
14 | **/target
15 | **/bin
16 | **/.springBeans
17 | Procfile
18 |
19 | # IDEA files
20 | .idea/*
21 | *.iml
22 | *.ipr
23 | *.iws
24 | *.log
25 |
26 | # Vagrant
27 | .vagrant/*
28 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 |
4 | services:
5 | - docker
6 |
7 | language: java
8 | jdk:
9 | - oraclejdk8
10 |
11 | install:
12 | - export MAVEN_SKIP_RC=true
13 | - export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=512m"
14 | - "export PATH=`pwd`/bin:$PATH"
15 | - echo $HOME
16 | - "export DISPLAY=:99.0"
17 | - "sh -e /etc/init.d/xvfb start"
18 |
19 | script:
20 | - export DISPLAY=:99.0 && mvn clean test
21 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | node {
2 | env.JAVA_HOME = tool 'jdk-8-oracle'
3 | def mvnHome = tool 'Maven 3.3.1'
4 | env.PATH="${env.JAVA_HOME}/bin:${mvnHome}/bin:${env.PATH}"
5 |
6 | stage 'Checkout'
7 | git url: 'https://github.com/hypery2k/angular-spring-boot-sample.git'
8 |
9 | stage 'Build'
10 | sh "${mvnHome}/bin/mvn clean package"
11 |
12 | stage 'Unit-Tests'
13 | sh "${mvnHome}/bin/mvn test"
14 |
15 | stage 'Integration-Tests'
16 | wrap([$class: 'Xvfb']) {
17 | sh "${mvnHome}/bin/mvn -Pdocker clean verify"
18 | }
19 |
20 | step([
21 | $class: 'ArtifactArchiver',
22 | artifacts: '**/target/*.jar',
23 | fingerprint: true
24 | ])
25 | step([
26 | $class: 'JUnitResultArchiver',
27 | testResults: 'angular-spring-boot-webapp/target/surefire-reports/TEST*.xml,target/failsafe-reports/TEST*.xml'
28 | ])
29 | publishHTML(target: [
30 | reportDir:'angular-spring-boot-webapp/target/site/serenity/',
31 | reportFiles:'index.html',
32 | reportName:'Serenity Test Report',
33 | keepAll:true,
34 | alwaysLinkToLastBuild:true,
35 | allowMissing: false
36 | ])
37 |
38 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Martin Reinhardt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Spring Demo Application
2 | [](https://travis-ci.org/hypery2k/angular-spring-boot-sample)
3 |
4 | ## Development-Setup
5 |
6 | ### Setup
7 |
8 | * Install JDK 8+ and Maven 3.3+
9 | * Install MySQL5.5+ Server
10 | * Install NodeJS and npm (http://nodejs.org/download/)
11 | * Install Build Tools
12 | ```bash
13 | $ sudo npm install -g bower grunt-cli karma
14 | ```
15 | * Install [docker](http://docs.docker.com) (optional)
16 |
17 |
18 | #### local setup
19 |
20 | Install MySQL and run the following SQL:
21 | ```
22 | CREATE USER 'ngspring'@'localhost' IDENTIFIED BY 'password';
23 | GRANT ALL PRIVILEGES ON * . * TO 'ngspring'@'localhost';
24 | CREATE DATABASE NGSPRING;
25 | ```
26 |
27 | Run maven
28 |
29 | ```bash
30 | $ mvn clean install idea:idea eclipse:eclipse
31 | ```
32 |
33 | Projects can now imported in your favourite IDE
34 |
35 | ### Development
36 |
37 |
38 | 1. start the backend:
39 |
40 | ```bash
41 | $ vagrant up
42 | $ cd angular-spring-boot-webapp
43 | $ mvn spring-boot:run
44 | ```
45 |
46 | 2. start the frontend:
47 |
48 | ```bash
49 | $ cd angular-spring-boot-webapp
50 | $ npm start
51 | ```
52 |
53 | Browser now opens [localhost:9000](http://localhost:9000) and you can add some events ;)
54 | 
55 |
56 |
57 | >Note:
58 | Any changes in the frontend will be lead to a reload in the browser
59 |
60 | Backend is available at [](http://localhost:9080) with user/password
61 |
62 | API is available at [](http://localhost:9080/swagger-ui.html)
63 |
64 | ### Docker
65 |
66 | #### Run
67 |
68 | ```bash
69 | $ mvn -Pdocker spring-boot:run
70 | ```
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8 | config.vm.box = "precise64"
9 | config.vm.box_url = "http://files.vagrantup.com/precise64.box"
10 | config.vm.network :forwarded_port, guest: 3306, host: 33060
11 | config.vm.provision :shell, :path => "install.sh"
12 | config.vm.synced_folder "./angular-spring-boot-webapp/src/test/resources/setup", "/setup", :mount_options => ["dmode=777", "fmode=666"]
13 | config.vm.synced_folder ".", "/vagrant", :mount_options => ["dmode=777", "fmode=666"]
14 | config.vm.network "private_network", ip: "33.33.33.10"
15 | end
16 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "undef": true,
16 | "unused": true,
17 | "strict": true,
18 | "trailing": true,
19 | "smarttabs": true,
20 | "globals": {
21 | "app": false,
22 | "angular": false
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngSpring",
3 | "version": "0.2.0",
4 | "description": "ngSpring app",
5 | "dependencies": {
6 | "angular": "1.4.9",
7 | "angular-animate": "1.4.9",
8 | "angular-block-ui": "0.2.0",
9 | "angular-bootstrap": "0.13.0",
10 | "angular-cookies": "1.4.9",
11 | "angular-invocation-handler": "1.3.2",
12 | "angular-resource": "1.4.9",
13 | "angular-route": "1.4.9",
14 | "angular-sanitize": "1.4.9",
15 | "angular-touch": "1.4.9",
16 | "angular-translate": "2.7.2",
17 | "bootstrap-sass-official": "3.2.0",
18 | "compass-mixins": "1.0.2",
19 | "ng-table": "0.8.3"
20 | },
21 | "devDependencies": {
22 | "angular-mocks": "1.4.9"
23 | },
24 | "resolutions": {
25 | "angular": "1.4.9",
26 | "angular-sanitize": "1.4.9",
27 | "angular-animate": "1.4.9"
28 | },
29 | "appPath": "src/main/frontend",
30 | "bowerPath": "bower_components",
31 | "testPath": "src/test/frontend",
32 | "resPath": "src/main/resources",
33 | "distPath": "target/dist",
34 | "docPath": "target/docs"
35 | }
36 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/karma.conf.ci.js:
--------------------------------------------------------------------------------
1 | var baseConfig = require('./karma.conf.js');
2 |
3 | module.exports = function (config) {
4 | // Load base config
5 | baseConfig(config);
6 |
7 | // Override base config
8 | config.set({
9 | junitReporter: {
10 | outputDir: 'target/surefire-reports', // results will be saved as $outputDir/$browserName.xml
11 | suite: 'ng-spring-boot'
12 | },
13 | singleRun: true,
14 | autoWatch: false
15 | });
16 | };
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // http://karma-runner.github.io/0.12/config/configuration-file.html
3 | // Generated on 2015-06-18 using
4 | // generator-karma 1.0.0
5 |
6 | module.exports = function (config) {
7 | 'use strict';
8 |
9 | config.set({
10 | // enable / disable watching file and executing tests whenever any file changes
11 | autoWatch: true,
12 |
13 | // base path, that will be used to resolve files and exclude
14 | basePath: '.',
15 |
16 | // testing framework to use (jasmine/mocha/qunit/...)
17 | // as well as any additional frameworks (requirejs/chai/sinon/...)
18 | frameworks: [
19 | "jasmine"
20 | ],
21 |
22 | // list of files / patterns to load in the browser
23 | files: [
24 | // bower:js
25 | 'bower_components/jquery/dist/jquery.js',
26 | 'bower_components/es5-shim/es5-shim.js',
27 | 'bower_components/angular/angular.js',
28 | 'bower_components/angular-animate/angular-animate.js',
29 | 'bower_components/angular-block-ui/dist/angular-block-ui.js',
30 | 'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
31 | 'bower_components/angular-cookies/angular-cookies.js',
32 | 'bower_components/angular-invocation-handler/dist/angular-invocation-handler.js',
33 | 'bower_components/angular-resource/angular-resource.js',
34 | 'bower_components/angular-route/angular-route.js',
35 | 'bower_components/angular-sanitize/angular-sanitize.js',
36 | 'bower_components/angular-touch/angular-touch.js',
37 | 'bower_components/angular-translate/angular-translate.js',
38 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/affix.js',
39 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/alert.js',
40 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/button.js',
41 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/carousel.js',
42 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/collapse.js',
43 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/dropdown.js',
44 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/tab.js',
45 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/transition.js',
46 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/scrollspy.js',
47 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/modal.js',
48 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/tooltip.js',
49 | 'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap/popover.js',
50 | 'bower_components/ng-table/dist/ng-table.min.js',
51 | 'bower_components/angular-mocks/angular-mocks.js',
52 | // endbower
53 | "src/main/frontend/scripts/**/*.js",
54 | "src/test/frontend/mocks/**/*.js",
55 | "src/test/frontend/spec/**/*.js"
56 | ],
57 |
58 | // list of files / patterns to exclude
59 | exclude: [],
60 |
61 | // web server port
62 | port: 9080,
63 |
64 | // Start these browsers, currently available:
65 | // - Chrome
66 | // - ChromeCanary
67 | // - Firefox
68 | // - Opera
69 | // - Safari (only Mac)
70 | // - PhantomJS
71 | // - IE (only Windows)
72 | browsers: [
73 | "PhantomJS"
74 | ],
75 |
76 | // Which plugins to enable
77 | plugins: [
78 | "karma-phantomjs-launcher",
79 | "karma-jasmine",
80 | "karma-junit-reporter"
81 | ],
82 |
83 | reporters: [
84 | "progress",
85 | "junit"
86 | ],
87 |
88 | junitReporter: {
89 | outputDir: 'target', // results will be saved as $outputDir/$browserName.xml
90 | suite: 'ng-spring-boot'
91 | },
92 |
93 | // Continuous Integration mode
94 | // if true, it capture browsers, run tests and exit
95 | singleRun: false,
96 |
97 | colors: true,
98 |
99 | // level of logging
100 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
101 | logLevel: config.LOG_INFO,
102 |
103 | // Uncomment the following lines if you are using grunt's server to run the tests
104 | // proxies: {
105 | // '/': 'http://localhost:9000/'
106 | // },
107 | // URL root prevent conflicts with the site root
108 | // urlRoot: '_karma_'
109 | });
110 | };
111 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/lombok.config:
--------------------------------------------------------------------------------
1 | lombok.nonNull.exceptionType = IllegalArgumentException
2 | lombok.log.fieldName = LOG
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngSpring",
3 | "version": "0.2.0",
4 | "description": "ngSpring app",
5 | "license": "MIT",
6 | "repository": {},
7 | "dependencies": {},
8 | "devDependencies": {
9 | "bower": "1.7.2",
10 | "findup-sync": "0.3.0",
11 | "grunt": "0.4.5",
12 | "grunt-autoprefixer": "3.0.3",
13 | "grunt-banner": "0.6.0",
14 | "grunt-cli": "0.1.13",
15 | "grunt-concurrent": "2.1.0",
16 | "grunt-connect-proxy": "*",
17 | "grunt-contrib-clean": "0.7.0",
18 | "grunt-contrib-compass": "1.0.4",
19 | "grunt-contrib-concat": "0.5.1",
20 | "grunt-contrib-connect": "0.11.2",
21 | "grunt-contrib-copy": "0.8.2",
22 | "grunt-contrib-cssmin": "0.14.0",
23 | "grunt-contrib-htmlmin": "0.6.0",
24 | "grunt-contrib-imagemin": "1.0.0",
25 | "grunt-contrib-jshint": "0.11.3",
26 | "grunt-contrib-uglify": "0.11.0",
27 | "grunt-contrib-watch": "0.6.1",
28 | "grunt-filerev": "2.3.1",
29 | "grunt-google-cdn": "0.4.3",
30 | "grunt-karma": "0.12.1",
31 | "grunt-newer": "1.1.1",
32 | "grunt-ng-annotate": "1.0.1",
33 | "grunt-ngdocs": "0.2.9",
34 | "grunt-open": "0.2.3",
35 | "grunt-raml2html": "0.3.2",
36 | "grunt-sass": "1.1.0",
37 | "grunt-svgmin": "3.1.2",
38 | "grunt-text-replace": "0.4.0",
39 | "grunt-usemin": "3.1.1",
40 | "grunt-wiredep": "2.0.0",
41 | "imagemin": "4.0.0",
42 | "jasmine-core": "2.3.4",
43 | "jshint-stylish": "1.0.0",
44 | "karma": "0.13.3",
45 | "karma-jasmine": "*",
46 | "karma-junit-reporter": "0.3.1",
47 | "karma-phantomjs-launcher": "*",
48 | "load-grunt-tasks": "3.1.0",
49 | "phantomjs": "1.9.17",
50 | "node-sass": "2.1.1",
51 | "serve-static": "1.10.0",
52 | "time-grunt": "1.0.0",
53 | "vinyl-fs": "2.4.2"
54 | },
55 | "engines": {
56 | "node": ">=0.10.0"
57 | },
58 | "scripts": {
59 | "postinstall": "bower install && npm rebuild node-sass && grunt build",
60 | "start": "npm install && grunt serve",
61 | "test": "grunt check && grunt test"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/serenity.properties:
--------------------------------------------------------------------------------
1 | # more details on http://thucydides.info/docs/serenity-staging/#_running_serenity_tests_from_the_command_line
2 | serenity.browser.width = 1280
3 | serenity.browser.height = 1024
4 | serenity.verbose.steps = true
5 | serenity.timeout=3000
6 | serenity.step.delay = 800
7 | serenity.store.html.source = true
8 | serenity.reports.show.step.detail=true
9 | serenity.report.show.manual.tests=false
10 | serenity.report.show.releases=false
11 | serenity.take.screenshots = FOR_EACH_ACTION
12 | webdriver.timeouts.implicitlywait = 5000
13 | webdriver.driver = firefox
14 | webdriver.base.url = http://localhost:9000
15 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/mysql/.dockerignore:
--------------------------------------------------------------------------------
1 | # SPIN
2 | *.trail
3 | */pan
4 |
5 | # Generated by T4
6 | */StonTest.cs
7 |
8 | # MonoDevelop
9 | *.userprefs
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 |
18 | [Dd]ebug/
19 | [Rr]elease/
20 | x64/
21 | build/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | *_i.c
30 | *_p.c
31 | *.ilk
32 | *.meta
33 | *.obj
34 | *.pch
35 | *.pdb
36 | *.pgc
37 | *.pgd
38 | *.rsp
39 | *.sbr
40 | *.tlb
41 | *.tli
42 | *.tlh
43 | *.tmp
44 | *.tmp_proj
45 | *.log
46 | *.vspscc
47 | *.vssscc
48 | .builds
49 | *.pidb
50 | *.log
51 | *.scc
52 |
53 | # Visual C++ cache files
54 | ipch/
55 | *.aps
56 | *.ncb
57 | *.opensdf
58 | *.sdf
59 | *.cachefile
60 |
61 | # Visual Studio profiler
62 | *.psess
63 | *.vsp
64 | *.vspx
65 |
66 | # Guidance Automation Toolkit
67 | *.gpState
68 |
69 | # ReSharper is a .NET coding add-in
70 | _ReSharper*/
71 | *.[Rr]e[Ss]harper
72 |
73 | # TeamCity is a build add-in
74 | _TeamCity*
75 |
76 | # DotCover is a Code Coverage Tool
77 | *.dotCover
78 |
79 | # NCrunch
80 | *.ncrunch*
81 | .*crunch*.local.xml
82 |
83 | # Installshield output folder
84 | [Ee]xpress/
85 |
86 | # DocProject is a documentation generator add-in
87 | DocProject/buildhelp/
88 | DocProject/Help/*.HxT
89 | DocProject/Help/*.HxC
90 | DocProject/Help/*.hhc
91 | DocProject/Help/*.hhk
92 | DocProject/Help/*.hhp
93 | DocProject/Help/Html2
94 | DocProject/Help/html
95 |
96 | # Click-Once directory
97 | publish/
98 |
99 | # Publish Web Output
100 | *.Publish.xml
101 | *.pubxml
102 |
103 | # NuGet Packages Directory
104 | packages/*
105 |
106 | # Windows Azure Build Output
107 | csx
108 | *.build.csdef
109 |
110 | # Windows Store app package directory
111 | AppPackages/
112 |
113 | # Others
114 | sql/
115 | *.Cache
116 | ClientBin/
117 | [Ss]tyle[Cc]op.*
118 | ~$*
119 | *~
120 | *.dbmdl
121 | *.[Pp]ublish.xml
122 | *.pfx
123 | *.publishsettings
124 | */bin/*
125 | */obj/*
126 |
127 | # RIA/Silverlight projects
128 | Generated_Code/
129 |
130 | # Backup & report files from converting an old project file to a newer
131 | # Visual Studio version. Backup files are not needed, because we have git ;-)
132 | _UpgradeReport_Files/
133 | Backup*/
134 | UpgradeLog*.XML
135 | UpgradeLog*.htm
136 |
137 | # SQL Server files
138 | App_Data/*.mdf
139 | App_Data/*.ldf
140 |
141 | # =========================
142 | # Windows detritus
143 | # =========================
144 |
145 | # Windows image file caches
146 | Thumbs.db
147 | ehthumbs.db
148 |
149 | # Folder config file
150 | Desktop.ini
151 |
152 | # Recycle Bin used on file shares
153 | $RECYCLE.BIN/
154 |
155 | # Mac crap
156 | .DS_Store
157 |
158 | # Xcode Generated Files
159 | *.xcodeproj/*
160 | DerivedData/*
161 | xcuserdata
162 | *~.nib
163 | *.pbxuser
164 | *.perspective
165 | *.perspectivev2
166 | #!xcuserdata/
167 | #*.xcuserstate
168 | UserInterfaceState.xcuserstate
169 | *xcshareddata*
170 |
171 | # Vim & Sublime Text
172 | *~
173 | *.sublime-workspace
174 | *.sublime-project
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/mysql/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.6
2 |
3 | ENV MYSQL_ROOT_PASSWORD Passw0rd!
4 | ENV MYSQL_USER ngspring
5 | ENV MYSQL_PASSWORD password
6 | ENV MYSQL_DATABASE NGSPRING
7 |
8 | EXPOSE ${mysql.port}
9 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/mysql/conf.yml:
--------------------------------------------------------------------------------
1 | ports:
2 | - ${mysql.port} 3306
3 | healthChecks:
4 | logPatterns:
5 | - "ready for connections"
6 | tag: ngspring/db:${project.version}
7 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/ngspring/.dockerignore:
--------------------------------------------------------------------------------
1 | # SPIN
2 | *.trail
3 | */pan
4 |
5 | # Generated by T4
6 | */StonTest.cs
7 |
8 | # MonoDevelop
9 | *.userprefs
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 |
18 | [Dd]ebug/
19 | [Rr]elease/
20 | x64/
21 | build/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | *_i.c
30 | *_p.c
31 | *.ilk
32 | *.meta
33 | *.obj
34 | *.pch
35 | *.pdb
36 | *.pgc
37 | *.pgd
38 | *.rsp
39 | *.sbr
40 | *.tlb
41 | *.tli
42 | *.tlh
43 | *.tmp
44 | *.tmp_proj
45 | *.log
46 | *.vspscc
47 | *.vssscc
48 | .builds
49 | *.pidb
50 | *.log
51 | *.scc
52 |
53 | # Visual C++ cache files
54 | ipch/
55 | *.aps
56 | *.ncb
57 | *.opensdf
58 | *.sdf
59 | *.cachefile
60 |
61 | # Visual Studio profiler
62 | *.psess
63 | *.vsp
64 | *.vspx
65 |
66 | # Guidance Automation Toolkit
67 | *.gpState
68 |
69 | # ReSharper is a .NET coding add-in
70 | _ReSharper*/
71 | *.[Rr]e[Ss]harper
72 |
73 | # TeamCity is a build add-in
74 | _TeamCity*
75 |
76 | # DotCover is a Code Coverage Tool
77 | *.dotCover
78 |
79 | # NCrunch
80 | *.ncrunch*
81 | .*crunch*.local.xml
82 |
83 | # Installshield output folder
84 | [Ee]xpress/
85 |
86 | # DocProject is a documentation generator add-in
87 | DocProject/buildhelp/
88 | DocProject/Help/*.HxT
89 | DocProject/Help/*.HxC
90 | DocProject/Help/*.hhc
91 | DocProject/Help/*.hhk
92 | DocProject/Help/*.hhp
93 | DocProject/Help/Html2
94 | DocProject/Help/html
95 |
96 | # Click-Once directory
97 | publish/
98 |
99 | # Publish Web Output
100 | *.Publish.xml
101 | *.pubxml
102 |
103 | # NuGet Packages Directory
104 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
105 | packages/*
106 |
107 | # Windows Azure Build Output
108 | csx
109 | *.build.csdef
110 |
111 | # Windows Store app package directory
112 | AppPackages/
113 |
114 | # Others
115 | sql/
116 | *.Cache
117 | ClientBin/
118 | [Ss]tyle[Cc]op.*
119 | ~$*
120 | *~
121 | *.dbmdl
122 | *.[Pp]ublish.xml
123 | *.pfx
124 | *.publishsettings
125 | */bin/*
126 | */obj/*
127 |
128 | # RIA/Silverlight projects
129 | Generated_Code/
130 |
131 | # Backup & report files from converting an old project file to a newer
132 | # Visual Studio version. Backup files are not needed, because we have git ;-)
133 | _UpgradeReport_Files/
134 | Backup*/
135 | UpgradeLog*.XML
136 | UpgradeLog*.htm
137 |
138 | # SQL Server files
139 | App_Data/*.mdf
140 | App_Data/*.ldf
141 |
142 | # =========================
143 | # Windows detritus
144 | # =========================
145 |
146 | # Windows image file caches
147 | Thumbs.db
148 | ehthumbs.db
149 |
150 | # Folder config file
151 | Desktop.ini
152 |
153 | # Recycle Bin used on file shares
154 | $RECYCLE.BIN/
155 |
156 | # Mac crap
157 | .DS_Store
158 |
159 | # Xcode Generated Files
160 | *.xcodeproj/*
161 | DerivedData/*
162 | xcuserdata
163 | *~.nib
164 | *.pbxuser
165 | *.perspective
166 | *.perspectivev2
167 | #!xcuserdata/
168 | #*.xcuserstate
169 | UserInterfaceState.xcuserstate
170 | *xcshareddata*
171 |
172 | # Vim & Sublime Text
173 | *~
174 | *.sublime-workspace
175 | *.sublime-project
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/ngspring/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM java:8
2 |
3 | WORKDIR /
4 |
5 | RUN apt-get update && apt-get install -y mysql-client
6 |
7 | ADD ${project.build.finalName}.jar /
8 | ADD run.sh /
9 |
10 | RUN chmod +x run.sh
11 |
12 | ENTRYPOINT /run.sh ${project.build.finalName}
13 |
14 | EXPOSE ${server.port}
15 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/ngspring/bootstrap.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # restart mysql
4 | /etc/init.d/mysql restart
5 |
6 | # run spring boot
7 |
8 | java -jar /tmp/ng-spring-boot.jar --server.port=40080 2> boot-error.log 1> boot-info.log
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/ngspring/conf.yml:
--------------------------------------------------------------------------------
1 | # additional data require to create the Docker image
2 | packaging:
3 | # files to add to the build, usually used with ADD in the Dockerfile
4 | add:
5 | - target/${project.build.finalName}.jar
6 | # optional list of port to expose on the host
7 | ports:
8 | - ${server.port}
9 | healthChecks:
10 | pings:
11 | - url: http://localhost:${server.port}/
12 | timeout: 60000
13 | links:
14 | - mysql:db
15 | # how long in milliseconds to sleep after start-up (default 0)
16 | sleep: 5000
17 | # tag to use for images
18 | tag: ngspring/app:${project.version}
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/docker/ngspring/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -version
3 |
4 | serverPort=${server.port}
5 | dbUrl="jdbc:mysql://"$DB_PORT_${mysql.port}_TCP_ADDR"/NGSPRING?useUnicode=true&characterEncoding=utf8"
6 |
7 |
8 | echo "App name: "$1
9 | echo "Server Port: "$serverPort
10 | echo "DB URL: "$dbUrl
11 |
12 | echo "starting app"
13 | java -Djava.security.egd=file:/dev/./urandom -jar /$1.jar --flyway.url=${dbUrl} --spring.datasource.url=${dbUrl} --server.port=${serverPort} 2> /boot-error.log 1> /boot-info.log
14 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/.buildignore:
--------------------------------------------------------------------------------
1 | *.coffee
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found :(
6 |
141 |
142 |
143 |
144 |
Not found :(
145 |
Sorry, but the page you were trying to view does not exist.
146 |
It looks like this was the result of either:
147 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
151 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/images/angularjs-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hypery2k/angular-spring-boot-sample/02073c15169a5344722878efc781aed7dd75a327/angular-spring-boot-webapp/src/main/frontend/images/angularjs-logo.png
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ 'GENERAL_TITLE' | translate }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
53 |
54 |
59 |
60 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc overview
3 | * @name ngSpringBootApp
4 | * @description
5 | *
6 | * Main module of the application.
7 | */
8 |
9 | /*global app: true*/
10 | var app = angular.module('ngSpringBootApp', [
11 | 'ngAnimate',
12 | 'ngCookies',
13 | 'ngResource',
14 | 'ngRoute',
15 | 'ngSanitize',
16 | 'ui.bootstrap',
17 | 'blockUI',
18 | 'pascalprecht.translate',
19 | 'ngTouch',
20 | 'ngTable',
21 | 'ngIH.core',
22 | 'ngIH.ui'
23 | ]);
24 |
25 |
26 | app.config(function ($provide, ngIHServiceProvider, ngIHConfig) {
27 | 'use strict';
28 |
29 | // enable UI feedback attach
30 | ngIHConfig.feedbackAttach = true;
31 | ngIHConfig.customErrorHandler = 'ErrorHandlingService';
32 | // decorate the mentioned [services] with automatic error handling.
33 | ngIHServiceProvider.decorate($provide, ['EventService']);
34 | ngIHServiceProvider.decorate($provide, ['UserService']);
35 | });
36 |
37 |
38 | app.config(function ($routeProvider) {
39 | 'use strict';
40 |
41 | $routeProvider
42 | .when('/home', {
43 | templateUrl: 'views/main.html',
44 | controller: 'MainCtrl'
45 | })
46 | .when('/event', {
47 | templateUrl: 'views/event.html',
48 | controller: 'EventCtrl'
49 | })
50 | .otherwise({
51 | redirectTo: '/event'
52 | });
53 | });
54 |
55 | app.config(function ($translateProvider) {
56 | 'use strict';
57 |
58 | $translateProvider.translations('de_DE', {
59 | GENERAL_LOADING: 'Lade',
60 | GENERAL_TITLE: 'ngSpringBoot',
61 | GENERAL_EDIT: 'Bearbeiten',
62 | GENERAL_DELETE: 'Löschen',
63 | GENERAL_ALL: 'Alle',
64 | GENERAL_NEW: 'Neu',
65 | GENERAL_SAVE: 'Speichern',
66 | GENERAL_CANCEL: 'Abbrechen',
67 | GENERAL_CLOSE: 'Schließen',
68 | GENERAL_TODAY: 'Heute',
69 | GENERAL_BEGIN: 'Beginn',
70 | GENERAL_END: 'Ende',
71 | GENERAL_YES: 'Ja',
72 | GENERAL_NO: 'Nein',
73 | GENERAL_CHOOSE: 'Bitte auswählen',
74 | GENERAL_ADD: 'Neuer Eintrag',
75 | GENERAL_UPLOAD: 'Hochladen',
76 |
77 | MAIN_HEADLINE: 'AngularJS Spring Boot Demo',
78 | MAIN_GREETING: 'Demo Anwendung die die Verwendung von AngularJS und SpringBoot zeigt',
79 | MAIN_FIRST_HEADLINE: 'AngularJS',
80 | MAIN_FIRST_TEXT: 'AngularJS – oft einfach als Angular bezeichnet – ist ein Open-Source-Framework des US-amerikanischen Unternehmens Google Inc. Mit AngularJS kann man in HTML und JavaScript Single-page-Webanwendungen nach einem Model View ViewModel-Muster erstellen. Die Softwareentwicklung und das Komponententesten können damit vereinfacht werden.',
81 | MAIN_SECOND_HEADLINE: 'SpringBoot',
82 | MAIN_SECOND_TEXT: 'Spring Boot heißt das neue Projekt der Entwickler des Spring Frameworks für die Java-Plattform. Spring Boot soll also eine Art Einstiegspunkt für Entwickler bieten, von dem aus sie auf die Funktionen von Spring zugreifen können, um damit Anwendungen und Dienste zu erstellen.',
83 | MAIN_THIRD_HEADLINE: 'Swagger',
84 | MAIN_THIRD_TEXT: 'm Funktionalität und Möglichkeiten einer API zu überschauen, ist die Qualität der API-Dokumentation ausschlaggebend. Mit Swagger UI behalten wir immer den Überblick, können andere Personen die API bereitstellen oder häufig genutzte Schnittstellen dokumentieren.',
85 |
86 | EVENT_HEADLINE: 'Eventdaten',
87 | EVENT_SELECTION_HEADING: 'Eventdaten auswählen',
88 | EVENT_CREATION_DATE: 'Eintragung',
89 | EVENT_DESCRIPTION: 'Ereignis',
90 | EVENT_DESCRIPTION_REQUIRED: 'Die Ereignisbezeichnung ist erforderlich',
91 | EVENT_START_DATE: 'Beginn',
92 | EVENT_END_DATE: 'Ende',
93 | EVENT_EDIT_HEADING: 'Eventdaten bearbeiten',
94 | EVENT_DELETE_SUCCESS: 'Event wurde gelöscht.',
95 | EVENT_SAVE_SUCCESS: 'Event wurde erfolgreich gespeichert.',
96 |
97 | LOGIN_HEADLINE: 'Willkommen zur Angular SpringBoot Demo',
98 | LOGIN_GREETING: 'Melden Sie sich an um das Portal zu nutzen.',
99 | LOGIN_FORM_USERNAME: 'Nutzer',
100 | LOGIN_FORM_PASSWORD: 'Passwort',
101 | LOGIN_FORM_SUBMIT: 'Anmelden',
102 | LOGIN_ERROR: 'Anmeldefehler. Bitte versuchen Sie erneut sich anzumelden.',
103 | LOGIN_DENIED: 'Anmeldefehler. Der angebene Nutzer ist nicht berechtigt für die Oberfläche.',
104 | NAV_EVENTS: 'Events',
105 | NAV_LOGOUT: 'Abmelden',
106 |
107 | LOGOUT_ERROR: 'Fehler beim Abmelden',
108 |
109 | HTTP_STATUS_CODE_0: 'Der Server antwortet nicht.',
110 | HTTP_STATUS_CODE_400: 'Validierungsfehler.',
111 | HTTP_STATUS_CODE_403: 'Zugriff verweigert.',
112 | HTTP_STATUS_CODE_404: 'Dieser Datensatz existiert nicht.',
113 | HTTP_STATUS_CODE_405: 'Ungültige Anfrage.',
114 | HTTP_STATUS_CODE_409: 'Es besteht ein Datenkonflikt.',
115 | HTTP_STATUS_CODE_500: 'Unbekannter Serverfehler.',
116 |
117 | // bean validation messages
118 | 'VALIDATION_ERROR_validation.jpa.unique': 'Ein ähnlicher Datensatz existiert bereits',
119 | 'VALIDATION_ERROR_validation.jpa.unknown': 'Prüfen Sie ihre Daten',
120 | 'VALIDATION_ERROR_validation.passwords_not_match': 'Die Passwordbestätigung ist nicht korrekt',
121 | 'VALIDATION_ERROR_validation.date.range_error': 'Das Startdatum liegt nicht vor dem Enddatum.',
122 | 'VALIDATION_ERROR_validation.time.range_error': 'Der Beginn der Uhrzeit liegt nicht vor dem Ende.',
123 | 'VALIDATION_ERROR_javax.validation.constraints.NotNull.message': 'Bitte füllen Sie alle Pflichtfelder aus. ',
124 | 'VALIDATION_ERROR_javax.validation.constraints.Size.message': 'Die maximale Länge wurde überschritten.',
125 | });
126 |
127 | $translateProvider.preferredLanguage('de_DE');
128 | $translateProvider.useSanitizeValueStrategy('escape');
129 | });
130 |
131 | app.config(function (blockUIConfig) {
132 | 'use strict';
133 |
134 | // Change the default overlay message
135 | blockUIConfig.message = 'Lade ...';
136 |
137 | // Change the default delay to 100ms before the blocking is visible
138 | blockUIConfig.delay = 10;
139 | });
140 |
141 | app.run(function ($rootScope, AuthenticationService) {
142 | 'use strict';
143 |
144 | // register listener to watch route changes
145 | $rootScope.$on('$routeChangeStart', function (event, next, current) {
146 | AuthenticationService.validateUser(event, next, current);
147 | });
148 | });
149 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/controllers/ctrl.about.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc function
3 | * @name ngSpringBootApp.controller:AboutCtrl
4 | * @description
5 | * About controller of the normalizerBaseDateHours
6 | */
7 | app.controller('AboutCtrl', function ($scope) {
8 | 'use strict';
9 |
10 | $scope.awesomeThings = [
11 | 'HTML5 Boilerplate',
12 | 'AngularJS',
13 | 'Karma'
14 | ];
15 | });
16 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/controllers/ctrl.event.js:
--------------------------------------------------------------------------------
1 | app.controller('EventCtrl', function ($scope, $log, $translate, ngTableParams, feedbackUI, EventService, Domain) {
2 | 'use strict';
3 |
4 | // internal functions
5 |
6 | function init() {
7 | $scope.currentEvent = false;
8 | loadEvents();
9 | }
10 |
11 | function loadEvents() {
12 | EventService.listAllEvents(function (events) {
13 | $scope.allEvents = [];
14 | if (events) {
15 | for (var i = 0; i < events.length; i++) {
16 |
17 | $scope.allEvents.push(events[i]);
18 | }
19 | }
20 | // init pagination
21 | $scope.tableParams = new ngTableParams({ // jshint ignore:line
22 | page: 1, // show first page
23 | count: 10 // count per page
24 | }, {
25 | total: $scope.allEvents.length, // length of data
26 | getData: function ($defer, params) {
27 | $defer.resolve($scope.allEvents.slice((params.page() - 1) * params.count(), params.page() * params.count()));
28 | }
29 | });
30 | });
31 | }
32 |
33 | // init the controller
34 | init();
35 |
36 | // view API
37 |
38 | // datepicker ui bootstrap
39 | $scope.openStartDate = function ($event) {
40 | $event.preventDefault();
41 | $event.stopPropagation();
42 | $scope.startDateOpened = true;
43 | };
44 | $scope.openEndDate = function ($event) {
45 | $event.preventDefault();
46 | $event.stopPropagation();
47 | $scope.endDateOpened = true;
48 | };
49 |
50 | $scope.getEvent = function (eventId) {
51 | EventService.getEvent(eventId, function (event) {
52 | $scope.currentEvent = event;
53 | });
54 | };
55 | $scope.deleteEvent = function (event) {
56 | EventService.deleteEvent(event, function () {
57 | // success
58 | init();
59 | $translate('EVENT_DELETE_SUCCESS').then(function (translatedValue) {
60 | feedbackUI.appendInfoMsg(translatedValue);
61 | });
62 | });
63 | };
64 |
65 | $scope.reset = function () {
66 | init();
67 | };
68 |
69 | $scope.createEvent = function () {
70 | $scope.currentEvent = Domain.Event.build();
71 | };
72 |
73 | $scope.saveEvent = function (form) {
74 | // only submit valid from
75 | if (form.$valid) {
76 | EventService.saveEvent($scope.currentEvent, function () {
77 | // success
78 | init();
79 | $translate('EVENT_SAVE_SUCCESS').then(function (translatedValue) {
80 | feedbackUI.appendInfoMsg(translatedValue);
81 | });
82 | });
83 | }
84 | };
85 | }
86 | );
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/controllers/ctrl.main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc function
3 | * @name ngSpringBootApp.controller:MainCtrl
4 | * @description
5 | * Main controller of the ngSpringBootApp
6 | */
7 | app.controller('MainCtrl', function ($scope) {
8 | 'use strict';
9 |
10 | $scope.awesomeThings = [
11 | 'HTML5 Boilerplate',
12 | 'AngularJS',
13 | 'Karma'
14 | ];
15 | });
16 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/controllers/ctrl.nav.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc function
3 | * @name ngSpringBootApp.controller:NavCtrl
4 | * @description
5 | * Login Controller of the navigation bar
6 | */
7 | app.controller('NavCtrl', function ($rootScope, $scope, $log, $translate, $location, feedbackUI, AuthenticationService) {
8 | 'use strict';
9 |
10 | $scope.isActive = function (path) {
11 | if ($rootScope.user) {
12 | if ($location.path().substr(0, path.length) === path) {
13 | return true;
14 | }
15 | // add user check here
16 | } else {
17 | return false;
18 | }
19 | return false;
20 | };
21 | $scope.logout = function () {
22 | AuthenticationService.logout(function (response) {
23 | $rootScope.user = response;
24 | $log.info('Logout complete.');
25 | }, function () {
26 | $log.error('Logout failure for user.');
27 | $translate('LOGOUT_ERROR').then(function (translatedValue) {
28 | feedbackUI.appendErrorMsg(translatedValue);
29 | });
30 | });
31 | };
32 | });
33 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.auth.js:
--------------------------------------------------------------------------------
1 | app.factory('AuthenticationService', function ($rootScope, $log, $location, RedirectService, $resource, $http, Domain) {
2 | 'use strict';
3 |
4 | var currentUser,
5 | whiteListedUrls = [],
6 | resource = $resource('./api/login/user'),
7 | loginHandlerSpring = './login',
8 | logoutHandlerSpring = './logout';
9 |
10 | function redirectToLoginPage(event, next, current) {
11 | if (event && next && current) {
12 | // already logged in, no redirect needed
13 | } else {
14 | // fallback
15 | RedirectService.redirect(loginHandlerSpring);
16 | }
17 | }
18 |
19 | function validateUser(event, next, current) {
20 | getUserDetails(function (user) {
21 | currentUser = user;
22 | $rootScope.user = user;
23 | if (user.isValid()) {
24 | $log.info('Login revalidation was sucessfull for user ' + user.username);
25 | $rootScope.$broadcast('userUpdate', user);
26 | } else {
27 | // check white listed URLs
28 | if (whiteListedUrls.indexOf(next.loadedTemplateUrl) === -1) {
29 | redirectToLoginPage(event, next, current);
30 | }
31 | }
32 | }, function (user) {
33 | $rootScope.user = user;
34 | redirectToLoginPage(event, next, current);
35 | });
36 | }
37 |
38 | function getUserDetails(callback, errorCallback) {
39 | return resource.get({},
40 | function (response) {
41 | $log.info('Got a valid user response');
42 | callback(Domain.User.build(response.username, response.userId, response.permissions, response.customers));
43 | },
44 | function () {
45 | $log.error('Could not read user details.');
46 | errorCallback(Domain.User.build());
47 | });
48 | }
49 |
50 | return {
51 | login: function (credentials, callback, errorCallback) {
52 | $http({
53 | method: 'POST',
54 | url: loginHandlerSpring,
55 | data: credentials,
56 | transformRequest: function (obj) {
57 | var str = [];
58 | for (var p in obj) {
59 | str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
60 | }
61 | return str.join('&');
62 | },
63 | headers: {'Content-Type': 'application/x-www-form-urlencoded'}
64 | }).success(function () {
65 | getUserDetails(callback, errorCallback);
66 | }).error(function () {
67 | $log.error('Got a login error');
68 | errorCallback(Domain.User.build());
69 | });
70 | },
71 | checkUser: function (callback, errorCallback) {
72 | getUserDetails(callback, errorCallback);
73 | },
74 | getCurrentUser: function () {
75 | if (!currentUser || !currentUser.customers) {
76 | validateUser();
77 | }
78 | if (!currentUser.isValid()) {
79 | redirectToLoginPage();
80 | }
81 | return currentUser;
82 | },
83 | validateUser: validateUser,
84 | logout: function (callback, errorCallback) {
85 | $http.post(logoutHandlerSpring).
86 | success(function () {
87 | callback(Domain.User.build());
88 | }).
89 | error(function () {
90 | $log.error('Got a logout error');
91 | errorCallback(Domain.User.build());
92 | });
93 | redirectToLoginPage();
94 | }
95 | };
96 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.domain.js:
--------------------------------------------------------------------------------
1 | app.factory('Domain', function () {
2 | 'use strict';
3 |
4 | // reference for base
5 | var referenceBaseDateHours = new Date(1970, 1, 2, 0, 0, 0, 0),
6 | // use for date DTO normalization
7 | normalizerBaseDateHours = new Date(1970, 1, 2, 12, 0, 0, 0);
8 |
9 | // HELPER functions
10 |
11 | function convertDateStringToDate(time) {
12 | if (time) {
13 | var date = new Date(referenceBaseDateHours.getTime()),
14 | res = time.split('-');
15 | date.setYear(res[0]);
16 | date.setMonth(res[1]);
17 | date.setDate(res[2]);
18 | return date;
19 | } else {
20 | return null;
21 | }
22 | }
23 |
24 | /**
25 | * User Object
26 | */
27 | function User(username, userId, permissions, customers) {
28 | this.username = username;
29 | this.userId = userId;
30 | this.permissions = permissions;
31 | this.customers = customers;
32 | }
33 |
34 |
35 | //Public object methods, assigned to prototype
36 |
37 |
38 | User.prototype.isValid = function () {
39 | if (this.username && this.username !== 'anonymousUser') {
40 | return true;
41 | } else {
42 | return false;
43 | }
44 | };
45 | // Static method, assigned to class, e.g. builders
46 | // Instance ('this') is not available in static context
47 | User.build = function (username, userId, permissions, customers) {
48 | return new User(username, userId, permissions, customers);
49 |
50 | };
51 |
52 | /**
53 | * Event Object
54 | */
55 | function Event() {
56 | this.eventId = null;
57 | this.eventDescription = null;
58 | this.insertDate = null;
59 | this.startDate = null;
60 | this.endDate = null;
61 | }
62 |
63 |
64 | Event.prototype.convertToDTO = function () {
65 | var date = new Date(normalizerBaseDateHours.getTime());
66 | this.startDate.setHours(date.getHours());
67 | this.startDate.setMinutes(date.getMinutes());
68 | if (this.endDate) {
69 | this.endDate.setHours(date.getHours());
70 | this.endDate.setMinutes(date.getMinutes());
71 | }
72 | return this;
73 | };
74 |
75 | Event.prototype.convertFromDTO = function () {
76 | // easy way to get a clean copy
77 | var copy = Event.build(this);
78 | // convert times
79 | if (copy.startDate) {
80 | copy.startDate = convertDateStringToDate(this.startDate);
81 | }
82 | if (copy.endDate) {
83 | copy.endDate = convertDateStringToDate(this.endDate);
84 | }
85 | return copy;
86 | };
87 |
88 | function UserProfile(){
89 | this.userName = null;
90 | this.password = null;
91 | this.passwordConfirmation = null;
92 | this.customerName = null;
93 | this.customerId = null;
94 | this.branchNumber = null;
95 | }
96 |
97 | UserProfile.prototype.isValid = function () {
98 | if(this.userName && this.password && this.passwordConfirmation && this.customerName && this.password === this.passwordConfirmation){
99 | return true;
100 | }
101 | return false;
102 | };
103 |
104 | UserProfile.build = function(data){
105 | if(!data) {
106 | return new UserProfile();
107 | }else{
108 | var userProfile = new UserProfile();
109 | for(var key in data){
110 | if (key.charAt(0) !== '$' && data.hasOwnProperty(key)) {
111 | userProfile[key] = data[key];
112 | }
113 | }
114 | return userProfile;
115 | }
116 | };
117 |
118 | // Static method, assigned to class, e.g. builders
119 | // Instance ('this') is not available in static context
120 | Event.build = function (data) {
121 | if (!data) {
122 | return new Event();
123 | } else {
124 | var event = new Event();
125 | for (var key in data) {
126 | if (key.charAt(0) !== '$' && data.hasOwnProperty(key)) {
127 | event[key] = data[key];
128 | }
129 | }
130 | return event;
131 | }
132 | };
133 |
134 |
135 |
136 | return {
137 | User: User,
138 | Event: Event,
139 | UserProfile: UserProfile
140 | };
141 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.errorHandling.js:
--------------------------------------------------------------------------------
1 | app.factory('ErrorHandlingService', function ($log, $translate, blockUI) {
2 | 'use strict';
3 |
4 | function buildValidationMessages(error, status, msg, callback, i) {
5 | var errorDetails = error.data[i];
6 | $translate('VALIDATION_ERROR_' + errorDetails.messageTemplate).then(function (translatedValue) {
7 | msg = msg + ' ' + translatedValue;
8 |
9 | // replace placeholder if set
10 | if (errorDetails.propertyList) {
11 | msg = msg.format(errorDetails.propertyList);
12 | }
13 |
14 | // callback when complete
15 | if (i === error.data.length - 1) {
16 | $log.debug(status + '=>' + msg);
17 | callback(msg);
18 | }
19 | }, function (err) {
20 | $log.error(err);
21 | callback(msg);
22 | });
23 | }
24 |
25 | return {
26 | resolve: function (details, callback) {
27 | if (details.error) {
28 | var error = details.error;
29 | var status = details.status;
30 | // read by http code
31 | $translate('HTTP_STATUS_CODE_' + status).then(function (translatedValue) {
32 | var msg = translatedValue;
33 | // handle violation errors
34 | if (status === 400 && error.data && error.data.length) {
35 | for (var i = 0; i < error.data.length; i++) {
36 | blockUI.stop();
37 | buildValidationMessages(error, status, msg, callback, i);
38 | }
39 | } else {
40 | blockUI.stop();
41 | $log.debug('Got unkown error status ' + status + ':' + msg);
42 | callback(msg);
43 | }
44 | });
45 | }
46 | }
47 | };
48 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.event.js:
--------------------------------------------------------------------------------
1 | app.factory('EventService', function ($resource, Domain) {
2 | 'use strict';
3 |
4 | var eventResource = $resource('/api/events/:eventId', {eventId: '@eventId'}, {update: {method: 'PUT'}});
5 |
6 | return {
7 | listAllEvents: function (callback, errorCallback) {
8 | return eventResource.query({}, function (events) {
9 | var result = [];
10 | if (events && events.length > 0) {
11 | for (var i = 0; i < events.length; i++) {
12 | result.push(Domain.Event.build(events[i]).convertFromDTO());
13 | }
14 | }
15 | callback(result);
16 | }, errorCallback);
17 | },
18 | getEvent: function (eventId, callback, errorCallback) {
19 | return eventResource.get({eventId: eventId}, function (event) {
20 | var result = null;
21 | if (event) {
22 | result = Domain.Event.build(event).convertFromDTO();
23 | }
24 | callback(result);
25 | }, errorCallback);
26 | },
27 | saveEvent: function (event, callback, errorCallback) {
28 | if (event.eventId) {
29 | return eventResource.update({eventId: event.eventId}, event.convertToDTO(), callback, errorCallback);
30 | } else {
31 | return eventResource.save({}, event.convertToDTO(), callback, errorCallback);
32 | }
33 | },
34 | deleteEvent: function (event, callback, errorCallback) {
35 | return eventResource.delete({eventId: event.eventId}, event.convertToDTO(), callback, errorCallback);
36 | }
37 | };
38 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.redirect.js:
--------------------------------------------------------------------------------
1 | app.factory('RedirectService', function ($window) {
2 | 'use strict';
3 |
4 | return {
5 | redirect: function (path) {
6 | $window.location.href = path;
7 | }
8 | };
9 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/services/srv.user.js:
--------------------------------------------------------------------------------
1 | app.factory('UserService', function ($resource) {
2 | 'use strict';
3 |
4 | var userResource = $resource('/api/user/:userId', {userId: '@userId',}, {update: {method: 'PUT'}});
5 |
6 | return {
7 | saveUser: function (user, callback, errorCallback) {
8 | if (user.userId) {
9 | return userResource.update({userId: user.userId}, user, callback, errorCallback);
10 | } else {
11 | return userResource.save({}, user, callback, errorCallback);
12 | }
13 | },
14 | deleteUser: function(userId, callback, errorCallback){
15 | return userResource.delete({userId: userId}, callback, errorCallback);
16 | }
17 | };
18 | });
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/scripts/util/proto.string.js:
--------------------------------------------------------------------------------
1 | String.prototype.format = function (args) {
2 | 'use strict';
3 | var str = this;
4 | return str.replace(String.prototype.format.regex, function (item) {
5 | var intVal = parseInt(item.substring(1, item.length - 1));
6 | var replace;
7 | if (intVal >= 0) {
8 | replace = args[intVal];
9 | } else if (intVal === -1) {
10 | replace = '{';
11 | } else if (intVal === -2) {
12 | replace = '}';
13 | } else {
14 | replace = '';
15 | }
16 | return replace;
17 | });
18 | };
19 | String.prototype.format.regex = new RegExp('{-?[0-9]+}', 'g');
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/styles/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin vertical-align {
2 | position: relative;
3 | top: 50%;
4 | -webkit-transform: translateY(-50%);
5 | -ms-transform: translateY(-50%);
6 | transform: translateY(-50%);
7 | }
8 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/styles/_theme.scss:
--------------------------------------------------------------------------------
1 | //=== Shared nav styles
2 | $nav-link-padding: 10px 10px !default;
3 | $panel-heading-padding: 10px 10px !default;
4 |
5 | /* Custom page header */
6 | .navbar {
7 | .navbar-nav > li > a.active {
8 | color: #555555;
9 | background-color: #fff;
10 | border: 1px solid #ddd;
11 | border-bottom-color: transparent;
12 | cursor: default;
13 | margin: 0px;
14 | }
15 |
16 | .navbar-brand {
17 | padding-top: 5px;
18 | padding-bottom: 5px;
19 |
20 | .logo {
21 | width: 35px;
22 | margin-top: 5px;
23 | margin-left: 10px;
24 |
25 | @media screen and (min-width: 767px) {
26 | width: 50px;
27 | margin-top: 0px;
28 | margin-left: 0;
29 | padding-left: 0;
30 | height: 50px;
31 | }
32 | }
33 | }
34 |
35 | }
36 |
37 | .container-fluid {
38 | .container {
39 | .table-responsive {
40 | width: 100%;
41 | border: 0;
42 | margin-left: 2px;
43 |
44 | // pagination
45 | .ng-table-pagination,
46 | .ng-table-counts {
47 | margin: 0px 0px 20px 0px;;
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/styles/main.scss:
--------------------------------------------------------------------------------
1 | $icon-font-path: "../fonts/";
2 |
3 | // bower:scss
4 | @import "bootstrap";
5 | // endbower
6 |
7 | @import "./font-awesome.min";
8 | @import "./theme";
9 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/templates/user-management.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/views/about.html:
--------------------------------------------------------------------------------
1 | This is the about view.
2 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/views/event.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
65 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/frontend/views/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/AngularSpringApplication.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo;
2 |
3 | import com.google.common.base.Predicate;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.boot.context.web.SpringBootServletInitializer;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.ComponentScan;
10 | import springfox.documentation.builders.ApiInfoBuilder;
11 | import springfox.documentation.service.ApiInfo;
12 | import springfox.documentation.spi.DocumentationType;
13 | import springfox.documentation.spring.web.plugins.Docket;
14 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
15 |
16 | import static com.google.common.base.Predicates.or;
17 | import static springfox.documentation.builders.PathSelectors.regex;
18 |
19 | //tag::spring-app[]
20 | @SpringBootApplication
21 | @ComponentScan
22 | @EnableAutoConfiguration
23 | //end::spring-app[]
24 | //tag::swagger-docs[]
25 | @EnableSwagger2
26 | //tag::spring-app[]
27 | public class AngularSpringApplication extends SpringBootServletInitializer {
28 | //end::spring-app[]
29 |
30 | @Bean
31 | public Docket ngSpringApi() {
32 | return new Docket(DocumentationType.SWAGGER_2)
33 | .groupName("ng-spring-boot-api")
34 | .apiInfo(apiInfo())
35 | .select()
36 | .paths(apiPaths())
37 | .build();
38 | }
39 |
40 | private Predicate apiPaths() {
41 | return or(
42 | regex("/api/event.*"),
43 | regex("/api/login.*"),
44 | regex("/api/user.*")
45 | );
46 | }
47 |
48 | private ApiInfo apiInfo() {
49 | return new ApiInfoBuilder()
50 | .title("Angular SpringBoot Demo API")
51 | .description("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum " +
52 | "has been the industry's standard dummy text ever since the 1500s, when an unknown printer "
53 | + "took a " +
54 | "galley of type and scrambled it to make a type specimen book. It has survived not only five " +
55 | "centuries, but also the leap into electronic typesetting, remaining essentially unchanged. " +
56 | "It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum " +
57 | "passages, and more recently with desktop publishing software like Aldus PageMaker including " +
58 | "versions of Lorem Ipsum.")
59 | .termsOfServiceUrl("https://github.com/hypery2k/angular-spring-boot-sample")
60 | .contact("contact@martinreinhardt-online.de")
61 | .license("MIT")
62 | .licenseUrl("https://raw.githubusercontent.com/hypery2k/angular-spring-boot-sample/master/LICENSE")
63 | .version("0.2.0")
64 | .build();
65 | } //end::swagger-docs[]
66 |
67 | //tag::spring-app[]
68 | public static void main(String[] args) {
69 | SpringApplication.run(AngularSpringApplication.class, args);
70 | }
71 | //end::spring-app[]
72 | }
73 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/controllers/EventController.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.controllers;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import io.swagger.annotations.ApiResponse;
6 | import io.swagger.annotations.ApiResponses;
7 | import ngSpring.demo.domain.dto.EventDTO;
8 | import ngSpring.demo.domain.entities.Event;
9 | import ngSpring.demo.exceptions.BusinessException;
10 | import ngSpring.demo.exceptions.EntityNotFoundException;
11 | import ngSpring.demo.exceptions.ValidationException;
12 | import ngSpring.demo.repositories.EventRepository;
13 | import ngSpring.demo.transformer.impl.EventTransformer;
14 | import ngSpring.demo.util.Message;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.data.domain.Sort;
17 | import org.springframework.data.domain.Sort.Order;
18 | import org.springframework.http.HttpStatus;
19 | import org.springframework.http.ResponseEntity;
20 | import org.springframework.web.bind.annotation.*;
21 |
22 | import java.util.ArrayList;
23 | import java.util.Iterator;
24 | import java.util.List;
25 |
26 |
27 | //tag::swagger-docs[]
28 | @Api(basePath = "/api/events", value = "Events", description = "Operations with Events", produces = "application/json")
29 | //end::swagger-docs[]
30 | //tag::events-rest-api[]
31 | @RestController
32 | @RequestMapping(value = "/api/events")
33 | @ResponseStatus(HttpStatus.OK)
34 | public class EventController {
35 | //end::events-rest-api[]
36 |
37 | @Autowired
38 | private EventTransformer eventTransformer;
39 |
40 | @Autowired
41 | private EventRepository eventRepository;
42 |
43 | private Sort sort = new Sort(new Order(Sort.Direction.ASC, "startDate"));
44 |
45 | @RequestMapping(method = RequestMethod.GET)
46 | public List getEvents(@RequestParam(required = false) boolean includeDeleted) {
47 | Iterator iterator = eventRepository.findAll().iterator();
48 | List events = new ArrayList<>();
49 | while (iterator.hasNext()) {
50 | events.add(iterator.next());
51 | }
52 | return eventTransformer.transformToDTOs(events);
53 | }
54 |
55 | //tag::events-rest-api[]
56 | @ApiOperation(value = "Update an event", notes = "Updates an existing event dataset")
57 | @ApiResponses(value = {@ApiResponse(code = 400, message = "Fields are with validation errors")})
58 | @RequestMapping(method = RequestMethod.POST)
59 | public ResponseEntity setEvent(@RequestBody EventDTO dto) throws EntityNotFoundException {
60 | save(dto);
61 | return new ResponseEntity(new Message("The event has been properly entered"), HttpStatus.OK);
62 | }
63 | //end::events-rest-api[]
64 |
65 | @ApiOperation(value = "Get event", notes = "Read event dataset")
66 | @RequestMapping(value = "/{eventId}", method = RequestMethod.GET)
67 | public EventDTO getEventByEventId(@PathVariable String eventId) throws EntityNotFoundException {
68 | Event event = loadEvent(eventId);
69 | return eventTransformer.transformToDTO(event);
70 | }
71 |
72 | @ApiOperation(value = "Create new event", notes = "Creates new event dataset")
73 | @ApiResponses(value = {@ApiResponse(code = 400, message = "Fields are with validation errors")})
74 | @RequestMapping(value = "/{eventId}", method = RequestMethod.PUT)
75 | public ResponseEntity updateEventByEventId(@PathVariable String eventId,
76 | @RequestBody EventDTO event) throws BusinessException {
77 | validateEventId(eventId, event);
78 | save(event);
79 | return new ResponseEntity(new Message("The event has been properly updated"), HttpStatus.OK);
80 | }
81 |
82 | @ApiOperation(value = "Delete anevent", notes = "Delete an event dataset")
83 | @RequestMapping(value = "/{eventId}", method = RequestMethod.DELETE)
84 | public ResponseEntity deleteEventByEventId(@PathVariable String eventId) throws EntityNotFoundException {
85 | Event event = loadEvent(eventId);
86 | event.setDeleted(true);
87 | eventRepository.save(event);
88 | return new ResponseEntity(new Message("The event has been properly deleted"), HttpStatus.OK);
89 | }
90 |
91 | private Event loadEvent(String eventId) throws EntityNotFoundException {
92 | Event event = eventRepository.findByEventIdAndDeleted(eventId, false, sort);
93 | if (event == null) {
94 | throw new EntityNotFoundException(eventId);
95 | }
96 | return event;
97 | }
98 |
99 | private void validateEventId(String eventId, EventDTO event) throws ValidationException {
100 | if (!event.getEventId().equals(eventId)) {
101 | throw new ValidationException("The eventId does not match the given event in body");
102 | }
103 | }
104 |
105 | private Event save(EventDTO dto) throws EntityNotFoundException {
106 | return eventRepository.save(eventTransformer.transformToEntity(dto));
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/controllers/LoginController.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.controllers;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import io.swagger.annotations.ApiResponse;
6 | import io.swagger.annotations.ApiResponses;
7 | import ngSpring.demo.domain.dto.UserDTO;
8 | import ngSpring.demo.domain.entities.User;
9 | import ngSpring.demo.transformer.impl.UserTransformer;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.security.core.context.SecurityContextHolder;
12 | import org.springframework.security.core.userdetails.UserDetailsService;
13 | import org.springframework.web.bind.annotation.RequestMapping;
14 | import org.springframework.web.bind.annotation.RequestMethod;
15 | import org.springframework.web.bind.annotation.RestController;
16 |
17 | import javax.security.auth.login.LoginException;
18 | import java.security.Principal;
19 |
20 | @Api(basePath = "/api/login", value = "Login", description = "Login operations", produces = "application/json")
21 | @RestController
22 | @RequestMapping(value = "/api/login")
23 | public class LoginController {
24 |
25 | @Autowired
26 | UserTransformer userTransformer;
27 |
28 | @Autowired
29 | UserDetailsService userDetailsService;
30 |
31 | @ApiOperation(value = "Get user details", notes = "Get existing user dataset")
32 | @ApiResponses(value = {@ApiResponse(code = 401, message = "Login errors")})
33 | @RequestMapping(value = "/user", method = RequestMethod.GET)
34 | public UserDTO getUserDetails() throws LoginException {
35 | Principal principal = SecurityContextHolder.getContext().getAuthentication();
36 | if (principal != null) {
37 | User user = (User) userDetailsService.loadUserByUsername(principal.getName());
38 | UserDTO userDTO = userTransformer.transformToDTO(user);
39 | return userDTO;
40 | } else {
41 | throw new LoginException();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/controllers/UserController.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.controllers;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import io.swagger.annotations.ApiResponse;
6 | import io.swagger.annotations.ApiResponses;
7 | import ngSpring.demo.domain.dto.UserProfileDTO;
8 | import ngSpring.demo.domain.entities.User;
9 | import ngSpring.demo.errorhandling.ValidationMessage;
10 | import ngSpring.demo.exceptions.EntityNotFoundException;
11 | import ngSpring.demo.exceptions.ValidationException;
12 | import ngSpring.demo.repositories.UserRepository;
13 | import ngSpring.demo.transformer.impl.UserProfileTransformer;
14 | import ngSpring.demo.util.Message;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.http.HttpStatus;
17 | import org.springframework.http.ResponseEntity;
18 | import org.springframework.security.access.AccessDeniedException;
19 | import org.springframework.security.core.context.SecurityContextHolder;
20 | import org.springframework.util.StringUtils;
21 | import org.springframework.web.bind.annotation.*;
22 |
23 | import java.security.Principal;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | @Api(basePath = "/api/user", value = "User", description = "User operations", produces = "application/json")
28 | @RestController
29 | @RequestMapping(value = "/api/user")
30 | public class UserController {
31 |
32 | @Autowired
33 | UserRepository userRepository;
34 |
35 | @Autowired
36 | UserProfileTransformer userProfileTransformer;
37 |
38 |
39 | @ApiOperation(value = "Update user details", notes = "Update existing user dataset")
40 | @ApiResponses(value = {@ApiResponse(code = 400, message = "Validation errors")})
41 | @RequestMapping(method = RequestMethod.POST)
42 | public ResponseEntity postUser(@RequestBody UserProfileDTO userProfileDTO) throws ValidationException {
43 |
44 | User loggedInUser = checkUser();
45 | validateUserProfileDto(userProfileDTO);
46 | User newUser = this.userProfileTransformer.transformToEntity(userProfileDTO);
47 |
48 | newUser.setEnabled(true);
49 | this.userRepository.save(newUser);
50 | return new ResponseEntity(new Message("The user has been properly created."), HttpStatus.OK);
51 | }
52 |
53 | @RequestMapping(value = "/{userId}", method = RequestMethod.PUT)
54 | public ResponseEntity putUser(@PathVariable String userId, @RequestBody UserProfileDTO userProfileDTO) throws ValidationException, EntityNotFoundException {
55 |
56 | User loggedInUser = checkUser();
57 | validateUserProfileDto(userProfileDTO);
58 | User currentUser = this.userRepository.findByUserIdAndDeletedFalse(userId);
59 | if (currentUser == null) {
60 | throw new EntityNotFoundException();
61 | }
62 | User updatedUser = this.userProfileTransformer.transformToEntity(userProfileDTO);
63 | updatedUser.setEnabled(currentUser.isEnabled());
64 | updatedUser.setInsertDate(currentUser.getInsertDate());
65 | this.userRepository.save(updatedUser);
66 | return new ResponseEntity(new Message("The user has been properly updated."), HttpStatus.OK);
67 | }
68 |
69 | @RequestMapping(value = "/{userId}", method = RequestMethod.DELETE)
70 | public ResponseEntity deleteUser(@PathVariable String userId) throws EntityNotFoundException {
71 | User loggedInUser = checkUser();
72 | User toBeDeleted = this.userRepository.findByUserIdAndDeletedFalse(userId);
73 |
74 | if (toBeDeleted == null) {
75 | throw new EntityNotFoundException();
76 | }
77 |
78 | this.userRepository.save(toBeDeleted);
79 | return new ResponseEntity(new Message("The user has been properly deleted."), HttpStatus.OK);
80 | }
81 |
82 | @RequestMapping(value = "/changePassword", method = RequestMethod.PUT)
83 | public ResponseEntity changePassword(@RequestBody UserProfileDTO dto) throws ValidationException {
84 | User loggedInUser = checkUser();
85 | validateUserProfileDto(dto);
86 | if (loggedInUser.getUserId() == dto.getUserId()) {
87 | User updatedUser = this.userProfileTransformer.transformToEntity(dto);
88 | this.userRepository.save(updatedUser);
89 | } else {
90 | throw new AccessDeniedException("Not allowed");
91 | }
92 | return new ResponseEntity(new Message("The password has been properly changed."), HttpStatus.OK);
93 | }
94 |
95 | @RequestMapping(value = "/controller/{customerId}", method = RequestMethod.GET)
96 | public ResponseEntity getControllerByCustomerId(@PathVariable String customerId) throws EntityNotFoundException {
97 | String userName = this.userRepository.findControllerUserNameByCustomerId(customerId);
98 | User user = this.userRepository.findByUsernameAndDeletedFalse(userName);
99 | if (user == null) {
100 | throw new EntityNotFoundException();
101 | }
102 | UserProfileDTO userProfileDTO = this.userProfileTransformer.transformToDTO(user);
103 | return new ResponseEntity(userProfileDTO, HttpStatus.OK);
104 | }
105 |
106 | @RequestMapping(value = "/planer/{branchId}", method = RequestMethod.GET)
107 | public ResponseEntity getPlanerByBranchId(@PathVariable String branchId) throws EntityNotFoundException {
108 | String userName = this.userRepository.findPlanerUserNameByBranchId(branchId);
109 | User user = this.userRepository.findByUsernameAndDeletedFalse(userName);
110 | if (user == null) {
111 | throw new EntityNotFoundException();
112 | }
113 | UserProfileDTO userProfileDTO = this.userProfileTransformer.transformToDTO(user);
114 | return new ResponseEntity(userProfileDTO, HttpStatus.OK);
115 | }
116 |
117 | private User checkUser() {
118 | Principal principal = SecurityContextHolder.getContext().getAuthentication();
119 | if (principal != null) {
120 | return userRepository.findByUsernameAndDeletedFalse(principal.getName());
121 | } else {
122 | throw new AccessDeniedException("Not logged in.");
123 | }
124 | }
125 |
126 |
127 | private void validateUserProfileDto(UserProfileDTO dto) throws ValidationException {
128 | // check password
129 | if (dto.getUserId() == null && !StringUtils.pathEquals(dto.getPassword(), dto.getPasswordConfirmation())) {
130 | List validationMessages = new ArrayList<>();
131 | validationMessages.add(ValidationMessage.builder()
132 | .entity(dto.getUsername())
133 | .messageTemplate("validation.passwords_not_match")
134 | .build());
135 | throw new ValidationException("", validationMessages);
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/AbstractBaseEntity.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 |
5 | import javax.persistence.MappedSuperclass;
6 | import java.util.Date;
7 |
8 | @MappedSuperclass
9 | public abstract class AbstractBaseEntity {
10 |
11 | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "CET")
12 | protected Date insertDate;
13 |
14 | protected boolean deleted;
15 |
16 | public Date getInsertDate() {
17 | return insertDate;
18 | }
19 |
20 | public void setInsertDate(Date insertDate) {
21 | this.insertDate = insertDate;
22 | }
23 |
24 | public boolean isDeleted() {
25 | return deleted;
26 | }
27 |
28 | public void setDeleted(boolean deleted) {
29 | this.deleted = deleted;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/DTO.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain;
2 |
3 | /**
4 | * Commont DTO API
5 | *
6 | * @author hypery2k
7 | */
8 | public class DTO {
9 | }
10 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/dto/EventDTO.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.dto;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.*;
5 |
6 | import javax.validation.constraints.NotNull;
7 | import javax.validation.constraints.Size;
8 | import java.util.Date;
9 |
10 | @Data
11 | @Getter
12 | @Setter
13 | @Builder
14 | @AllArgsConstructor
15 | @NoArgsConstructor
16 | @ToString
17 | /**
18 | * @author hypery2k
19 | */
20 | public class EventDTO {
21 |
22 | @NotNull
23 | private String eventId;
24 |
25 | @NotNull
26 | @Size(min = 1, max = 32)
27 | private String eventDescription;
28 |
29 | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "CET")
30 | @NotNull
31 | private Date startDate;
32 |
33 | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "CET")
34 | private Date endDate;
35 |
36 | @JsonFormat(pattern = "yyyy-MM-dd", timezone = "CET")
37 | protected Date insertDate;
38 | }
39 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/dto/UserDTO.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import javax.validation.constraints.NotNull;
9 |
10 | @Data
11 | @AllArgsConstructor
12 | @NoArgsConstructor
13 | @Builder
14 | public class UserDTO {
15 | @NotNull
16 | private String username;
17 |
18 | @NotNull
19 | private boolean deleted;
20 | }
21 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/dto/UserProfileDTO.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import javax.validation.constraints.NotNull;
9 |
10 | @Data
11 | @AllArgsConstructor
12 | @NoArgsConstructor
13 | @Builder
14 | public class UserProfileDTO {
15 |
16 | private String userId;
17 |
18 | @NotNull
19 | private String username;
20 |
21 | @NotNull
22 | private String password;
23 |
24 | @NotNull
25 | private String passwordConfirmation;
26 | }
27 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/dto/UserRoleDTO.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import javax.validation.constraints.NotNull;
9 |
10 | @Data
11 | @AllArgsConstructor
12 | @NoArgsConstructor
13 | @Builder
14 | public class UserRoleDTO {
15 |
16 | @NotNull
17 | private String roleId;
18 |
19 | @NotNull
20 | private String roleName;
21 | }
22 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/entities/Event.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.entities;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import ngSpring.demo.domain.AbstractBaseEntity;
8 | import ngSpring.demo.validation.ValidateDateRange;
9 | import org.hibernate.annotations.GenericGenerator;
10 |
11 | import javax.persistence.Entity;
12 | import javax.persistence.GeneratedValue;
13 | import javax.persistence.Id;
14 | import javax.validation.constraints.NotNull;
15 | import javax.validation.constraints.Size;
16 | import java.util.Date;
17 |
18 | @Entity
19 | @Builder
20 | @Data
21 | @EqualsAndHashCode(callSuper = false)
22 | @AllArgsConstructor
23 | @ValidateDateRange(start = "startDate", end = "endDate", message = "{validation.date.range_error}", equal = true)
24 | public class Event extends AbstractBaseEntity {
25 |
26 | @GeneratedValue(generator = "uuid")
27 | @GenericGenerator(name = "uuid", strategy = "uuid.hex")
28 | @Id
29 | private String eventId;
30 |
31 | @NotNull
32 | @Size(min = 1, max = 50)
33 | private String eventDescription;
34 |
35 | @NotNull
36 | private Date startDate;
37 |
38 | private Date endDate;
39 |
40 | public Event() {
41 | super();
42 | }
43 |
44 | public Event(String eventDescription, Date startDate, Date endDate) {
45 | super();
46 | this.eventDescription = eventDescription;
47 | this.startDate = startDate;
48 | this.endDate = endDate;
49 | }
50 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/domain/entities/User.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain.entities;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.ToString;
6 | import ngSpring.demo.domain.AbstractBaseEntity;
7 | import org.hibernate.annotations.GenericGenerator;
8 | import org.springframework.security.core.GrantedAuthority;
9 | import org.springframework.security.core.userdetails.UserDetails;
10 |
11 | import javax.persistence.Column;
12 | import javax.persistence.Entity;
13 | import javax.persistence.GeneratedValue;
14 | import javax.persistence.Id;
15 | import javax.validation.constraints.NotNull;
16 | import java.util.Collection;
17 | import java.util.HashSet;
18 | import java.util.Set;
19 |
20 | @Entity
21 | @Builder
22 | @ToString
23 | @AllArgsConstructor
24 | @SuppressWarnings("serial")
25 | public class User extends AbstractBaseEntity implements UserDetails {
26 |
27 | @GeneratedValue(generator = "uuid")
28 | @GenericGenerator(name = "uuid", strategy = "uuid.hex")
29 | @Id
30 | private String userId;
31 |
32 | @Column(name = "user_name")
33 | @NotNull
34 | private String username;
35 |
36 | @NotNull
37 | private String password;
38 |
39 | private boolean enabled;
40 |
41 | public User() {
42 | super();
43 | }
44 |
45 | public User(String userName, String password) {
46 | super();
47 | this.username = userName;
48 | this.password = password;
49 | }
50 |
51 | public String getUserId() {
52 | return userId;
53 | }
54 |
55 | public void setUserId(String userId) {
56 | this.userId = userId;
57 | }
58 |
59 | @Override
60 | public String getUsername() {
61 | return username;
62 | }
63 |
64 | public void setUsername(String username) {
65 | this.username = username;
66 | }
67 |
68 | @Override
69 | public String getPassword() {
70 | return password;
71 | }
72 |
73 | public void setPassword(String password) {
74 | this.password = password;
75 | }
76 |
77 | public void setEnabled(boolean enabled) {
78 | this.enabled = enabled;
79 | }
80 |
81 | @Override
82 | public boolean isEnabled() {
83 | return enabled;
84 | }
85 |
86 | @Override
87 | public Collection getAuthorities() {
88 | Set authorities = new HashSet();
89 | return authorities;
90 | }
91 |
92 | @Override
93 | public boolean isAccountNonExpired() {
94 | return true;
95 | }
96 |
97 | @Override
98 | public boolean isAccountNonLocked() {
99 | return true;
100 | }
101 |
102 | @Override
103 | public boolean isCredentialsNonExpired() {
104 | return true;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/errorhandling/GlobalControllerExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.errorhandling;
2 |
3 | import ngSpring.demo.exceptions.EntityNotFoundException;
4 | import ngSpring.demo.exceptions.ValidationException;
5 | import ngSpring.demo.util.Message;
6 | import org.apache.log4j.Logger;
7 | import org.springframework.http.HttpStatus;
8 | import org.springframework.http.ResponseEntity;
9 | import org.springframework.security.access.AccessDeniedException;
10 | import org.springframework.validation.BindingResult;
11 | import org.springframework.validation.FieldError;
12 | import org.springframework.web.bind.MethodArgumentNotValidException;
13 | import org.springframework.web.bind.annotation.ControllerAdvice;
14 | import org.springframework.web.bind.annotation.ExceptionHandler;
15 | import org.springframework.web.bind.annotation.ResponseBody;
16 |
17 | import javax.persistence.RollbackException;
18 | import javax.validation.ConstraintViolation;
19 | import javax.validation.ConstraintViolationException;
20 | import javax.validation.Path;
21 | import java.util.ArrayList;
22 | import java.util.Iterator;
23 | import java.util.List;
24 |
25 | @ControllerAdvice
26 | public class GlobalControllerExceptionHandler {
27 |
28 | private static final Logger LOG = Logger
29 | .getLogger(GlobalControllerExceptionHandler.class);
30 |
31 | // SECURITY ACCESS HANDLING
32 |
33 | @ExceptionHandler(AccessDeniedException.class)
34 | @ResponseBody
35 | public ResponseEntity> handleSecurityErrors(AccessDeniedException ex) {
36 | LOG.debug("Got access error", ex);
37 | // fallback to server error
38 | return new ResponseEntity(new Message(ex.getMessage()), HttpStatus.FORBIDDEN);
39 | }
40 |
41 | // GENERAL ERROR HANDLING
42 |
43 | @ExceptionHandler(Exception.class)
44 | @ResponseBody
45 | public ResponseEntity> handleErrors(Exception ex) {
46 | if (ex.getCause() instanceof RollbackException
47 | && ex.getCause().getCause() instanceof ConstraintViolationException) {
48 | ConstraintViolationException constraintViolationException = (ConstraintViolationException) ex.getCause().getCause();
49 | return new ResponseEntity>(getValidationErrorResponse(constraintViolationException), HttpStatus.BAD_REQUEST);
50 | } else {
51 | LOG.error("Got unknown error", ex);
52 | // fallback to server error
53 | return new ResponseEntity(new Message(ex.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
54 | }
55 | }
56 | // VALIDATION ERROR HANDLING
57 |
58 | @ExceptionHandler(MethodArgumentNotValidException.class)
59 | @ResponseBody
60 | public ResponseEntity> handleValidationError(MethodArgumentNotValidException ex) {
61 | final List validationErrors = new ArrayList<>();
62 | BindingResult result = ex.getBindingResult();
63 | List fieldErrors = result.getFieldErrors();
64 | for (FieldError fieldError : fieldErrors) {
65 | validationErrors.add(ValidationMessage.builder()
66 | .entity(fieldError.getField())
67 | .messageTemplate(fieldError.getDefaultMessage())
68 | .build());
69 | }
70 | return new ResponseEntity>(validationErrors, HttpStatus.BAD_REQUEST);
71 | }
72 |
73 | @ExceptionHandler(ValidationException.class)
74 | @ResponseBody
75 | public ResponseEntity> handleBadRequestException(ValidationException ex) {
76 | LOG.error("Got validation errors", ex);
77 | if (ex.getValidationMessages() == null || ex.getValidationMessages().isEmpty()) {
78 | return new ResponseEntity(new Message(ex.getMessage()), HttpStatus.BAD_REQUEST);
79 | } else {
80 | return new ResponseEntity>(ex.getValidationMessages(), HttpStatus.BAD_REQUEST);
81 | }
82 | }
83 |
84 | @ExceptionHandler(EntityNotFoundException.class)
85 | @ResponseBody
86 | public ResponseEntity handleEntityNotFoundException(
87 | EntityNotFoundException ex) {
88 | LOG.error("Could not find entity with id " + ex.getId(), ex);
89 | return new ResponseEntity(new Message(ex.getMessage()), HttpStatus.NOT_FOUND);
90 | }
91 |
92 | private List getValidationErrorResponse(ConstraintViolationException constraintViolationException) {
93 | final List validationErrors = new ArrayList<>();
94 | LOG.error("Got validation errors", constraintViolationException);
95 | for (ConstraintViolation> violationSet : constraintViolationException.getConstraintViolations()) {
96 | List propertyList = new ArrayList<>();
97 | Iterator propertyIterator = violationSet
98 | .getPropertyPath().iterator();
99 | while (propertyIterator.hasNext()) {
100 | propertyList.add(propertyIterator.next().getName());
101 | }
102 | // add violations errors in response
103 | validationErrors.add(ValidationMessage.builder()
104 | .entity(violationSet.getRootBeanClass().getName())
105 | // remove { and }
106 | .messageTemplate(violationSet.getMessageTemplate().replaceAll("^[{]|[}]$", ""))
107 | .propertyList(propertyList).build());
108 | }
109 | return validationErrors;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/errorhandling/ValidationMessage.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.errorhandling;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.ToString;
7 |
8 | import java.io.Serializable;
9 | import java.util.List;
10 |
11 |
12 | @Builder
13 | @AllArgsConstructor
14 | @Getter
15 | @ToString
16 | @SuppressWarnings("serial")
17 | public class ValidationMessage implements Serializable {
18 |
19 | private String entity;
20 |
21 | private String messageTemplate;
22 |
23 | private List propertyList;
24 | }
25 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/exceptions/BusinessException.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.exceptions;
2 |
3 |
4 | /**
5 | * Common superclass for business exception in the application
6 | *
7 | * @author hypery2k
8 | */
9 | @SuppressWarnings("serial")
10 | public class BusinessException extends Exception {
11 |
12 | public BusinessException(String msg) {
13 | super(msg);
14 | }
15 |
16 | public BusinessException(Exception exception) {
17 | super(exception);
18 | }
19 |
20 | public BusinessException(String msg, Exception exception) {
21 | super(msg, exception);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/exceptions/EntityNotFoundException.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.exceptions;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 |
7 | // TODO add generic information
8 | @ResponseStatus(value = HttpStatus.NOT_FOUND)
9 | @SuppressWarnings("serial")
10 | public class EntityNotFoundException extends BusinessException {
11 |
12 | private String id;
13 |
14 | public EntityNotFoundException(String entityId) {
15 | super("could not find entity with id '" + entityId + "'.");
16 | this.id = entityId;
17 | }
18 |
19 | public EntityNotFoundException() {
20 | super("could not find entity");
21 | }
22 |
23 | public String getId() {
24 | return id;
25 | }
26 |
27 | public EntityNotFoundException setId(String id) {
28 | this.id = id;
29 | return this;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/exceptions/ValidationException.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.exceptions;
2 |
3 | import ngSpring.demo.errorhandling.ValidationMessage;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Indicate validation errors which are not handled via bean validation,
9 | * e.g. during file parsing
10 | *
11 | * @author hypery2k
12 | */
13 | @SuppressWarnings("serial")
14 | public class ValidationException extends BusinessException {
15 |
16 | private List validationMessages;
17 |
18 | public ValidationException(String message) {
19 | super(message);
20 | }
21 |
22 | public ValidationException(String message, List validationMessages) {
23 | super(message);
24 | this.validationMessages = validationMessages;
25 | }
26 |
27 | public List getValidationMessages() {
28 | return validationMessages;
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/mvc/MvcConfig.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.mvc;
2 |
3 |
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
7 |
8 |
9 | //tag::thymeleaf-config[]
10 | @Configuration
11 | public class MvcConfig extends WebMvcConfigurerAdapter {
12 |
13 | @Override
14 | public void addViewControllers(ViewControllerRegistry registry) {
15 | registry.addViewController("/login").setViewName("login");
16 | }
17 |
18 | }
19 | //end::thymeleaf-config[]
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/repositories/EventRepository.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.repositories;
2 |
3 | import ngSpring.demo.domain.entities.Event;
4 | import org.springframework.data.domain.Sort;
5 | import org.springframework.data.repository.CrudRepository;
6 |
7 | public interface EventRepository extends CrudRepository {
8 |
9 | Event findByEventIdAndDeleted(String eventId, boolean deleted, Sort sort);
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/repositories/UserRepository.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.repositories;
2 |
3 | import ngSpring.demo.domain.entities.User;
4 | import org.springframework.data.jpa.repository.Query;
5 | import org.springframework.data.repository.CrudRepository;
6 | import org.springframework.data.repository.query.Param;
7 |
8 | public interface UserRepository extends CrudRepository {
9 |
10 | @Query(nativeQuery = true, value = "select u.user_name from user u where u.customer_id = :customerId and exists (select * from user_roles where user_id = u.user_id and role_id = 2)")
11 | String findControllerUserNameByCustomerId(
12 | @Param("customerId") String customerId);
13 |
14 |
15 | @Query(nativeQuery = true, value = "select u.user_name from user u, user_branches ub where u.user_id = ub.user_id and ub.branch_id = :branchId")
16 | String findPlanerUserNameByBranchId(@Param("branchId") String branchId);
17 |
18 | User findByUsernameAndDeletedFalse(String username);
19 |
20 | User findByUserIdAndDeletedFalse(String userId);
21 | }
22 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/security/AngularSpringAuthenticationProvider.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.security;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
5 | import org.springframework.security.core.Authentication;
6 | import org.springframework.security.core.userdetails.UserDetailsService;
7 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
8 | import org.springframework.security.crypto.password.PasswordEncoder;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component("authenticationProvider")
12 | public class AngularSpringAuthenticationProvider extends DaoAuthenticationProvider {
13 |
14 | @Autowired
15 | public void setUserDetailsService(UserDetailsService userDetailsService) {
16 | super.setUserDetailsService(userDetailsService);
17 | super.setPasswordEncoder(passwordEncoder());
18 | }
19 |
20 | @Override
21 | public Authentication authenticate(Authentication authentication) {
22 | return super.authenticate(authentication);
23 | }
24 |
25 | public PasswordEncoder passwordEncoder() {
26 | return new BCryptPasswordEncoder();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/security/AppSecurityConfiguration.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.security;
2 |
3 | import org.springframework.boot.autoconfigure.security.SecurityProperties;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.core.annotation.Order;
6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
9 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
10 |
11 | /**
12 | * Enable security authentication for web app
13 | *
14 | * @author hypery2k
15 | */
16 | //tag::thymeleaf-config[]
17 | @Configuration
18 | @EnableWebMvcSecurity
19 | @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
20 | public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter {
21 | //end::thymeleaf-config[]
22 |
23 | // public ressources which are not secured
24 | private static final String[] UNSECURED_RESOURCE_LIST =
25 | new String[]{"/docs/*", "/styles/*", "/fonts/*", "/scripts/*", "/images/*", "/index.html", "/views/login.html"};
26 |
27 | @Override
28 | public void configure(WebSecurity web) throws Exception {
29 | web.ignoring().antMatchers(UNSECURED_RESOURCE_LIST);
30 | }
31 |
32 | //tag::thymeleaf-config[]
33 | @Override
34 | protected void configure(HttpSecurity http) throws Exception {
35 | http.authorizeRequests().antMatchers(UNSECURED_RESOURCE_LIST).authenticated();
36 | http.csrf().disable();
37 | // use form authentication for web app
38 | http.authorizeRequests().and().formLogin().loginPage("/login");
39 | // enable HTTP basic authentication for REST calls
40 | http.authorizeRequests().antMatchers("/api/**").authenticated().and().httpBasic();
41 | //end::thymeleaf-config[]
42 | }
43 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/security/AuthenticationSecurity.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.security;
2 |
3 |
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.annotation.Qualifier;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.core.Ordered;
8 | import org.springframework.core.annotation.Order;
9 | import org.springframework.security.authentication.AuthenticationProvider;
10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
11 | import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
12 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
13 | import org.springframework.security.core.userdetails.UserDetailsService;
14 |
15 | /**
16 | * Configures global authentication provider, e.g. for password encryption and user details service
17 | *
18 | * @author hypery2k
19 | */
20 | @Order(Ordered.HIGHEST_PRECEDENCE)
21 | @Configuration
22 | @EnableGlobalMethodSecurity(prePostEnabled = true)
23 | class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
24 |
25 | @Autowired
26 | @Qualifier("authenticationProvider")
27 | AuthenticationProvider authenticationProvider;
28 |
29 | @Autowired
30 | private UserDetailsService userDetailsService;
31 |
32 | @Override
33 | public void init(AuthenticationManagerBuilder auth) throws Exception {
34 | auth.userDetailsService(userDetailsService);
35 | auth.authenticationProvider(authenticationProvider);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/services/impl/UserDetailsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.services.impl;
2 |
3 | import ngSpring.demo.domain.entities.User;
4 | import ngSpring.demo.repositories.UserRepository;
5 | import org.apache.log4j.Logger;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.security.core.userdetails.UserDetails;
8 | import org.springframework.security.core.userdetails.UserDetailsService;
9 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service("userDetailsService")
13 | public class UserDetailsServiceImpl implements UserDetailsService {
14 |
15 | private static final Logger LOG = Logger
16 | .getLogger(UserDetailsServiceImpl.class);
17 |
18 | @Autowired
19 | UserRepository userRepository;
20 |
21 | @Override
22 | public UserDetails loadUserByUsername(String username)
23 | throws UsernameNotFoundException {
24 | User user = userRepository.findByUsernameAndDeletedFalse(username);
25 | if (user != null) {
26 | LOG.debug("Found user with name " + username);
27 | return user;
28 | } else {
29 | LOG.error("Cannot find user with name " + username + " in the database.");
30 | return new User(username, "");
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/transformer/GenericTransformer.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.transformer;
2 |
3 | import ngSpring.demo.exceptions.EntityNotFoundException;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * Commont DTO and Domain transformer methods used by any transformer
10 | *
11 | * @author hypery2k
12 | */
13 | public abstract class GenericTransformer implements Transformer {
14 |
15 | @Override
16 | public List transformToEntities(List dtoList) throws EntityNotFoundException {
17 | List entityList = new ArrayList();
18 | for (DTO dto : dtoList) {
19 | entityList.add(transformToEntity(dto));
20 | }
21 | return entityList;
22 | }
23 |
24 | @Override
25 | public List transformToDTOs(List entityList) {
26 | List dtoList = new ArrayList();
27 | for (Entity entity : entityList) {
28 | dtoList.add(transformToDTO(entity));
29 | }
30 | return dtoList;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/transformer/Transformer.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.transformer;
2 |
3 | import ngSpring.demo.exceptions.EntityNotFoundException;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Commont DTO and Domain transformer API
9 | *
10 | * @author hypery2k
11 | */
12 | public interface Transformer {
13 |
14 | Entity transformToEntity(DTO dto) throws EntityNotFoundException;
15 |
16 | DTO transformToDTO(Entity entity);
17 |
18 | List transformToEntities(List dtoList) throws EntityNotFoundException;
19 |
20 | List transformToDTOs(List entityList);
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/transformer/impl/EventTransformer.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.transformer.impl;
2 |
3 | import ngSpring.demo.domain.dto.EventDTO;
4 | import ngSpring.demo.domain.entities.Event;
5 | import ngSpring.demo.exceptions.EntityNotFoundException;
6 | import ngSpring.demo.transformer.GenericTransformer;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Component
10 | public class EventTransformer extends GenericTransformer {
11 |
12 | @Override
13 | public EventDTO transformToDTO(Event entity) {
14 | if (entity != null) {
15 | return EventDTO.builder()
16 | .eventId(entity.getEventId())
17 | .eventDescription(entity.getEventDescription())
18 | .startDate(entity.getStartDate())
19 | .endDate(entity.getEndDate())
20 | .insertDate(entity.getInsertDate())
21 | .build();
22 | }
23 | return null;
24 | }
25 |
26 | @Override
27 | public Event transformToEntity(EventDTO dto) throws EntityNotFoundException {
28 | if (dto != null) {
29 | Event event = Event.builder()
30 | .eventId(dto.getEventId())
31 | .eventDescription(dto.getEventDescription())
32 | .startDate(dto.getStartDate())
33 | .endDate(dto.getEndDate())
34 | .build();
35 | event.setInsertDate(dto.getInsertDate());
36 | return event;
37 | }
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/transformer/impl/UserProfileTransformer.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.transformer.impl;
2 |
3 |
4 | import ngSpring.demo.domain.dto.UserProfileDTO;
5 | import ngSpring.demo.domain.entities.User;
6 | import ngSpring.demo.repositories.UserRepository;
7 | import ngSpring.demo.transformer.GenericTransformer;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 | import org.springframework.stereotype.Component;
12 |
13 | @Component
14 | public class UserProfileTransformer extends GenericTransformer {
15 |
16 | @Autowired
17 | private UserRepository userRepository;
18 |
19 | @Override
20 | public User transformToEntity(UserProfileDTO dto) {
21 | PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
22 | return User.builder()
23 | .userId(dto.getUserId())
24 | .username(dto.getUsername())
25 | .password(dto.getPassword() != null ? passwordEncoder.encode(dto.getPassword()) : this.userRepository.findByUserIdAndDeletedFalse(dto.getUserId()).getPassword())
26 | .build();
27 | }
28 |
29 | @Override
30 | public UserProfileDTO transformToDTO(User user) {
31 | return UserProfileDTO.builder()
32 | .userId(user.getUserId())
33 | .username(user.getUsername())
34 | .build();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/transformer/impl/UserTransformer.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.transformer.impl;
2 |
3 |
4 | import ngSpring.demo.domain.dto.UserDTO;
5 | import ngSpring.demo.domain.entities.User;
6 | import ngSpring.demo.exceptions.EntityNotFoundException;
7 | import ngSpring.demo.repositories.UserRepository;
8 | import ngSpring.demo.transformer.GenericTransformer;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | @Component
16 | public class UserTransformer extends GenericTransformer {
17 |
18 | @Autowired
19 | private UserRepository userRepository;
20 |
21 | @Override
22 | public UserDTO transformToDTO(User entity) {
23 | if (entity != null) {
24 | List permissions = new ArrayList<>();
25 | return UserDTO.builder()
26 | .username(entity.getUsername())
27 | .deleted(entity.isDeleted())
28 | .build();
29 | }
30 | return null;
31 | }
32 |
33 | @Override
34 | public User transformToEntity(UserDTO dto) throws EntityNotFoundException {
35 | if (dto != null) {
36 | User user = userRepository.findByUsernameAndDeletedFalse(dto.getUsername());
37 | if (user == null) {
38 | throw new EntityNotFoundException(dto.getUsername());
39 | } else {
40 | return user;
41 | }
42 | }
43 | return null;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/util/Message.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.util;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.ToString;
7 |
8 | import java.io.Serializable;
9 |
10 | @Builder
11 | @AllArgsConstructor
12 | @Getter
13 | @ToString
14 | @SuppressWarnings("serial")
15 | public class Message implements Serializable {
16 |
17 | private String message;
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/validation/AbstractBeanValidator.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.validation;
2 |
3 |
4 | import org.springframework.util.StringUtils;
5 |
6 | import javax.validation.ConstraintValidator;
7 | import java.lang.annotation.Annotation;
8 |
9 | /**
10 | * Common superclass for bean validators to share some common functionality for reflection etc
11 | *
12 | * @author hypery2k
13 | */
14 | public abstract class AbstractBeanValidator implements ConstraintValidator {
15 |
16 | /**
17 | * @param pAttribute to get the method for
18 | * @return the getter method name for the given attribute
19 | */
20 | protected String getGetterDeclaration(final String pAttribute) {
21 | if (StringUtils.hasLength(pAttribute)) {
22 | final StringBuilder builder = new StringBuilder("get");
23 | builder.append(Character.toUpperCase(pAttribute.charAt(0)));
24 | builder.append(pAttribute.substring(1));
25 | return builder.toString();
26 | } else {
27 | return "";
28 | }
29 | }
30 |
31 | /**
32 | * @param pAttribute to get the method for
33 | * @return the is method name for the given boolean attribute
34 | */
35 | protected String getIsDeclaration(final String pAttribute) {
36 | if (StringUtils.hasLength(pAttribute)) {
37 | final StringBuilder builder = new StringBuilder("is");
38 | builder.append(Character.toUpperCase(pAttribute.charAt(0)));
39 | builder.append(pAttribute.substring(1));
40 | return builder.toString();
41 | } else {
42 | return "";
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/validation/DateRangeValidator.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.validation;
2 |
3 | import org.apache.log4j.Logger;
4 |
5 | import javax.validation.ConstraintValidatorContext;
6 | import java.lang.reflect.Method;
7 | import java.util.Date;
8 |
9 | /**
10 | * Validator for ensure that a start date is before a end date
11 | *
12 | * @author hypery2k
13 | */
14 | public class DateRangeValidator extends AbstractBeanValidator {
15 |
16 | /**
17 | * Write logging messages for this class.
18 | */
19 | private static final Logger LOG = Logger.getLogger(DateRangeValidator.class);
20 |
21 | private String start;
22 |
23 | private String end;
24 |
25 | private boolean equal;
26 |
27 | /**
28 | * @see javax.validation.ConstraintValidator#initialize(java.lang.annotation.Annotation)
29 | */
30 | @Override
31 | public void initialize(final ValidateDateRange constraintAnnotation) {
32 | this.start = constraintAnnotation.start();
33 | this.end = constraintAnnotation.end();
34 | this.equal = constraintAnnotation.equal();
35 | }
36 |
37 | /**
38 | * @see javax.validation.ConstraintValidator#isValid(java.lang.Object, javax.validation.ConstraintValidatorContext)
39 | */
40 | @SuppressWarnings({"rawtypes", "unchecked"})
41 | @Override
42 | public boolean isValid(final Object value, final ConstraintValidatorContext context) {
43 | boolean isValid = false;
44 | final Class clazz = value.getClass();
45 |
46 | try {
47 | Date startDate = null;
48 | final Method startMethod = clazz.getMethod(this.getGetterDeclaration(this.start), new Class[0]);
49 | if (startMethod != null) {
50 | startDate = (Date) startMethod.invoke(value, null);
51 | }
52 |
53 | Date endDate = null;
54 | final Method endMethod = clazz.getMethod(this.getGetterDeclaration(this.end), new Class[0]);
55 | if (startMethod != null) {
56 | endDate = (Date) endMethod.invoke(value, null);
57 | }
58 |
59 | if (endDate != null && startDate != null) {
60 | if (this.equal) {
61 | isValid = endDate.compareTo(startDate) >= 0;
62 | } else {
63 | isValid = endDate.after(startDate);
64 | }
65 | } else {
66 | isValid = true;
67 | }
68 | } catch (final Exception e) {
69 | LOG.error("Error occurred during validating date range.", e);
70 | }
71 | if (!isValid) {
72 | final String template = context.getDefaultConstraintMessageTemplate();
73 | context.disableDefaultConstraintViolation();
74 | context.buildConstraintViolationWithTemplate(template)
75 | .addPropertyNode(this.start)
76 | .addPropertyNode(this.end)
77 | .addBeanNode()
78 | .addConstraintViolation();
79 | }
80 | return isValid;
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/validation/TimeRangeValidator.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.validation;
2 |
3 | import org.apache.log4j.Logger;
4 |
5 | import javax.validation.ConstraintValidatorContext;
6 | import java.lang.reflect.Method;
7 | import java.text.SimpleDateFormat;
8 | import java.util.Date;
9 |
10 | /**
11 | * This bean validator checks the given morning and evening time stamps if they are valid (start
12 | * must before end for
13 | * each entry) and if both are set if the morning time is before evening time.
14 | *
15 | * Note that it's possible that two pairs ( morning) can be left empty or set to 00:00
16 | *
17 | * @author hypery2k
18 | */
19 | public class TimeRangeValidator extends AbstractBeanValidator {
20 |
21 | public static final String PLACEHOLDER_EMTPY_TIME = "00:00";
22 |
23 | private String start;
24 |
25 | private String end;
26 |
27 | /**
28 | * Write logging messages for this class.
29 | */
30 | private static final Logger LOG = Logger.getLogger(TimeRangeValidator.class);
31 |
32 | /**
33 | * @see javax.validation.ConstraintValidator#initialize(java.lang.annotation.Annotation)
34 | */
35 | @Override
36 | public void initialize(final ValidateTimeRange constraintAnnotation) {
37 | this.start = constraintAnnotation.start();
38 | this.end = constraintAnnotation.end();
39 | }
40 |
41 | /**
42 | * @see javax.validation.ConstraintValidator#isValid(java.lang.Object, javax.validation.ConstraintValidatorContext)
43 | */
44 | @SuppressWarnings({"rawtypes", "unchecked"})
45 | @Override
46 | public boolean isValid(final Object value, final ConstraintValidatorContext context) {
47 | boolean isValid = false;
48 | final Class clazz = value.getClass();
49 | try {
50 | final SimpleDateFormat format = new SimpleDateFormat("HH:mm");
51 | final Method start = clazz.getMethod(this.getGetterDeclaration(this.start), new Class[0]);
52 | if (start != null) {
53 | Date startDate = null;
54 | final String propertValue = (String) start.invoke(value, null);
55 | if (propertValue != null && !propertValue.equals("") && !propertValue.equals(PLACEHOLDER_EMTPY_TIME)) {
56 | startDate = format.parse(propertValue);
57 | }
58 | if (startDate == null) {
59 | isValid = true;
60 | } else {
61 | final Method end = clazz.getMethod(this.getGetterDeclaration(this.end), new Class[0]);
62 | if (end != null) {
63 | final String propertValueEnd = (String) end.invoke(value, null);
64 | if (propertValueEnd != null && !propertValueEnd.equals("") && !propertValueEnd.equals(PLACEHOLDER_EMTPY_TIME)) {
65 | Date endDate = format.parse(propertValueEnd);
66 | // both are not null and end is after start
67 | isValid = endDate.after(startDate);
68 | }
69 | }
70 | }
71 | }
72 | } catch (final Exception e) {
73 | LOG.error("Error occurred during validating date range.", e);
74 | }
75 | if (!isValid) {
76 | final String template = context.getDefaultConstraintMessageTemplate();
77 | context.disableDefaultConstraintViolation();
78 | context.buildConstraintViolationWithTemplate(template)
79 | .addPropertyNode(this.start)
80 | .addPropertyNode(this.end)
81 | .addBeanNode()
82 | .addConstraintViolation();
83 | }
84 | return isValid;
85 | }
86 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/validation/ValidateDateRange.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.validation;
2 |
3 |
4 | import javax.validation.Constraint;
5 | import javax.validation.Payload;
6 | import java.lang.annotation.*;
7 |
8 | /**
9 | * Simply checks if the given start date is before the end date
10 | *
11 | * @author hypery2k
12 | */
13 | @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Constraint(validatedBy = {DateRangeValidator.class})
16 | @Documented
17 | public @interface ValidateDateRange {
18 |
19 | String message() default "{validation.date.range_error}";
20 |
21 | /**
22 | * start date
23 | *
24 | * @return
25 | */
26 | String start();
27 |
28 | /**
29 | * end date
30 | *
31 | * @return
32 | */
33 | String end();
34 |
35 | /**
36 | * use this property to let the start and date be equal
37 | *
38 | * @return
39 | */
40 | boolean equal() default false;
41 |
42 | Class extends Payload>[] payload() default {};
43 |
44 | Class>[] groups() default {};
45 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/java/ngSpring/demo/validation/ValidateTimeRange.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.validation;
2 |
3 | import javax.validation.Constraint;
4 | import javax.validation.Payload;
5 | import java.lang.annotation.*;
6 |
7 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
8 |
9 | /**
10 | * Simply checks if the given start time is before the end time and evening time is later the
11 | * morning time
12 | *
13 | * @author hypery2k
14 | */
15 | @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
16 | @Retention(RetentionPolicy.RUNTIME)
17 | @Constraint(validatedBy = {TimeRangeValidator.class})
18 | @Documented
19 | public @interface ValidateTimeRange {
20 |
21 | String message() default "{validation.time.range_error}";
22 |
23 | String start();
24 |
25 | String end();
26 |
27 | Class extends Payload>[] payload() default {};
28 |
29 | Class>[] groups() default {};
30 |
31 | /**
32 | * Defines several {@code @ValidateTimeRange} annotations on the same element.
33 | */
34 | @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
35 | @Retention(RUNTIME)
36 | @Documented
37 | public @interface List {
38 | ValidateTimeRange[] value();
39 | }
40 | }
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/ValidationMessages_de.properties:
--------------------------------------------------------------------------------
1 |
2 | validation.date.range_error = Das Startdatum liegt nicht vor dem Enddatum.
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/application-heroku.properties:
--------------------------------------------------------------------------------
1 | # general
2 | spring.application.name=angular-spring-demo
3 | server.port=9080
4 |
5 | # http encoding
6 | spring.http.encoding.charset=UTF-8
7 | spring.http.encoding.enabled=true
8 | spring.http.encoding.force=true
9 |
10 | # database: mysql
11 | spring.datasource.driverClassName=com.mysql.jdbc.Driver
12 | spring.datasource.url=jdbc:mysql://localhost/NGSPRING
13 | spring.datasource.username=ngspring
14 | spring.datasource.password=password
15 | spring.jpa.hibernate.ddl-auto=update
16 | hibernate.dialect=mysql
17 |
18 | #flyway properties
19 | flyway.url=jdbc:mysql://localhost/NGSPRING
20 | flyway.user=ngspring
21 | flyway.password=password
22 | flyway.enabled=true
23 |
24 | # Show or not log for each sql query
25 | spring.jpa.show-sql = false
26 |
27 | org.springframework.security.level=DEBUG
28 |
29 | # monitoring
30 | management.context-path=/actuator
31 | endpoints.enabled=true
32 |
33 | # pretty-print output
34 | spring.jackson.serialization.INDENT_OUTPUT=true
35 | spring.jackson.serialization.write-dates-as-timestamps:false
36 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/application-test.properties:
--------------------------------------------------------------------------------
1 | # database for test: H2
2 | spring.datasource.driverClassName=org.h2.Driver
3 | spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL
4 | spring.datasource.username=sa
5 | spring.datasource.password=
6 |
7 | flyway.enabled=false
8 |
9 | spring.jpa.hibernate.ddl-auto=create-drop
10 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # general
2 | spring.application.name=angular-spring-demo
3 | server.port=9080
4 |
5 | # http encoding
6 | spring.http.encoding.charset=UTF-8
7 | spring.http.encoding.enabled=true
8 | spring.http.encoding.force=true
9 |
10 | # database: mysql
11 | spring.datasource.driverClassName=com.mysql.jdbc.Driver
12 | spring.datasource.url=jdbc:mysql://33.33.33.10:3306/NGSPRING?useUnicode=true&characterEncoding=utf8
13 | spring.datasource.username=ngspring
14 | spring.datasource.password=password
15 | spring.jpa.hibernate.ddl-auto=update
16 | hibernate.dialect=mysql
17 |
18 | #flyway properties
19 | flyway.url=jdbc:mysql://33.33.33.10:3306/NGSPRING
20 | flyway.user=ngspring
21 | flyway.password=password
22 | flyway.enabled=true
23 |
24 | # Show or not log for each sql query
25 | spring.jpa.show-sql = false
26 |
27 | org.springframework.security.level=DEBUG
28 |
29 | # monitoring
30 | management.context-path=/actuator
31 | endpoints.enabled=true
32 |
33 | # pretty-print output
34 | spring.jackson.serialization.INDENT_OUTPUT=true
35 | spring.jackson.serialization.write-dates-as-timestamps:false
36 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/db/migration/V1_0_01__Initial_db_version.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE event (
2 | event_id VARCHAR(50) NOT NULL,
3 | event_description VARCHAR(100),
4 | start_date DATE,
5 | end_date DATE,
6 | insert_date DATE,
7 | deleted BIT(1) DEFAULT 0,
8 | PRIMARY KEY(event_id)
9 | );
10 |
11 | CREATE TABLE user (
12 | user_id varchar(255) NOT NULL,
13 | enabled bit(1) NOT NULL,
14 | password varchar(255) NOT NULL,
15 | user_name varchar(255) NOT NULL,
16 | insert_date datetime DEFAULT NULL,
17 | deleted bit(1) NOT NULL,
18 | PRIMARY KEY (user_id)
19 | );
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | eventCMS - Login
16 |
17 |
20 |
21 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
eventCMS
85 |
86 |
95 |
96 |
97 | Error
98 | Invalid username and password.
99 |
100 |
101 |
102 | Success
103 | You have been logged out.
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "jasmine": true,
22 | "globals": {
23 | "angular": false,
24 | "browser": false,
25 | "inject": false
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/mocks/mock.app.js:
--------------------------------------------------------------------------------
1 | /*global mockApp: true*/
2 | var mockApp = angular.module('ngSpringBootAppMock', ['ngSpringBootApp']);
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/mocks/mock.srv.auth.js:
--------------------------------------------------------------------------------
1 | mockApp.factory('AuthServicePositiveMock', function () {
2 | 'use strict';
3 | return {
4 | login: function (credentials, callback, errorCallback) {
5 | callback(credentials);
6 | },
7 | logout: function (callback, errorCallback) {
8 | callback();
9 | }
10 | };
11 | }
12 | );
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/mocks/mock.srv.event.js:
--------------------------------------------------------------------------------
1 | mockApp.factory('EventServicePositiveMock', function () {
2 | 'use strict';
3 | return {
4 | listAllEvents: function (callback, errorCallback) {
5 | callback();
6 | },
7 | getEvent: function (eventId, callback, errorCallback) {
8 | callback({eventCategory: 'eventCategory'});
9 | },
10 | saveEvent: function (event, callback, errorCallback) {
11 | callback();
12 | },
13 | deleteEvent: function (event, callback, errorCallback) {
14 | callback();
15 | }
16 | };
17 | }
18 | );
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/mocks/mock.srv.redirect.js:
--------------------------------------------------------------------------------
1 | mockApp.factory('RedirectServicePositiveMock', function () {
2 | 'use strict';
3 | return {
4 | redirect: function (path) {
5 |
6 | }
7 | };
8 | }
9 | );
10 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/mocks/mock.srv.user.js:
--------------------------------------------------------------------------------
1 | mockApp.factory('UserServicePositiveMock', function (Domain) {
2 | 'use strict';
3 |
4 | return {
5 | saveUser: function (user, callback, errorCallback) {
6 | callback();
7 | },
8 | getControllerByCustomer: function (customerId, callback, errorCallback){
9 | callback();
10 | },
11 | getPlanerByBranch: function(branchId, callback, errorCallback){
12 | callback(Domain.UserProfile.build());
13 | },
14 | deleteUser: function(userId, callback, errorCallback){
15 | callback();
16 | }
17 | };
18 | }
19 | );
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/controllers/ctrl.eventSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: EventCtrl', function () {
4 | // load the controller's module
5 |
6 | beforeEach(function () {
7 | // load app module
8 | module('ngSpringBootApp');
9 | // load app mock module
10 | module('ngSpringBootAppMock');
11 | });
12 |
13 | var ctrl,
14 | scope,
15 | mockedFeedbackUIService,
16 | mockedEventService,
17 | mockedAuthService;
18 |
19 | // Initialize the controller and a mock scope
20 | beforeEach(inject(function ($controller, $rootScope, $translate, EventServicePositiveMock, AuthServicePositiveMock, feedbackUI) {
21 | scope = $rootScope.$new();
22 | mockedFeedbackUIService = feedbackUI;
23 | mockedEventService = EventServicePositiveMock;
24 | mockedAuthService = AuthServicePositiveMock;
25 | // init mocks
26 | ctrl = $controller('EventCtrl', {
27 | $scope: scope,
28 | $translate: $translate,
29 | feedbackUI: feedbackUI,
30 | // use mock module
31 | EventService: mockedEventService,
32 | AuthenticationService: mockedAuthService
33 | });
34 | }));
35 |
36 | it('should get event', function () {
37 | spyOn(mockedEventService, 'getEvent');
38 | scope.getEvent('1');
39 | scope.$apply();
40 | expect(mockedEventService.getEvent).toHaveBeenCalled();
41 | });
42 |
43 | it('should not allow transfer invalid values', function () {
44 | spyOn(mockedEventService, 'saveEvent');
45 | scope.saveEvent({$valid: false});
46 | scope.$apply();
47 | expect(mockedEventService.saveEvent).not.toHaveBeenCalled();
48 | });
49 |
50 | it('should not allow transfer valid values', function () {
51 | spyOn(mockedEventService, 'saveEvent');
52 | scope.saveEvent({$valid: true});
53 | scope.$apply();
54 | expect(mockedEventService.saveEvent).toHaveBeenCalled();
55 | });
56 |
57 | it('should delete event', function () {
58 | spyOn(mockedEventService, 'deleteEvent');
59 | spyOn(mockedEventService, 'getEvent').and.callThrough();
60 | scope.deleteEvent();
61 | scope.$apply();
62 | expect(mockedEventService.deleteEvent).toHaveBeenCalled();
63 | });
64 |
65 | it('should list all events for customer during init', function () {
66 | spyOn(mockedEventService, 'listAllEvents');
67 | scope.reset();
68 | expect(mockedEventService.listAllEvents).toHaveBeenCalled();
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/controllers/ctrl.mainSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: MainCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('ngSpringBootApp'));
7 |
8 | var MainCtrl,
9 | scope;
10 |
11 | // Initialize the controller and a mock scope
12 | beforeEach(inject(function ($controller, $rootScope) {
13 | scope = $rootScope.$new();
14 | MainCtrl = $controller('MainCtrl', {
15 | $scope: scope
16 | });
17 | }));
18 |
19 | it('should attach a list of awesomeThings to the scope', function () {
20 | expect(scope.awesomeThings.length).toBe(3);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/controllers/ctrl.navSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Controller: LoginCtrl', function () {
4 |
5 | beforeEach(function () {
6 | // load app module
7 | module('ngSpringBootApp');
8 | // load app mock module
9 | module('ngSpringBootAppMock');
10 | });
11 |
12 | var controller,
13 | mockedFeedbackUIService,
14 | mockedLoginService,
15 | rootScope,
16 | scope;
17 |
18 | // Initialize the controller and a mock scope
19 | beforeEach(inject(function ($controller, $rootScope, $translate, AuthServicePositiveMock, feedbackUI) {
20 | rootScope = $rootScope;
21 | scope = $rootScope.$new();
22 | mockedFeedbackUIService = feedbackUI;
23 | mockedLoginService = AuthServicePositiveMock;
24 | // init mocks
25 | controller = $controller('NavCtrl', {
26 | $scope: scope,
27 | $translate: $translate,
28 | feedbackUI: mockedFeedbackUIService,
29 | // use mock module
30 | AuthenticationService: mockedLoginService
31 | });
32 | spyOn(mockedFeedbackUIService, 'appendErrorMsg');
33 | spyOn(mockedLoginService, 'login').and.callThrough();
34 | spyOn(mockedLoginService, 'logout').and.callThrough();
35 | }));
36 |
37 | it('should logout successfully', function () {
38 | rootScope.user = {
39 | username: 'abc',
40 | password: 'pass'
41 | };
42 | scope.logout();
43 | scope.$apply();
44 | expect(mockedLoginService.logout).toHaveBeenCalled();
45 | expect(rootScope.user).not.toBeDefined();
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/services/srv.authSpec.js:
--------------------------------------------------------------------------------
1 | describe('Service: authenticationService', function () {
2 | 'use strict';
3 |
4 |
5 | // load the controller's module
6 | beforeEach(module('ngSpringBootAppMock'));
7 |
8 | var service,
9 | redirectService,
10 | rootScope,
11 | httpBackend;
12 |
13 | // Initialize the service
14 | beforeEach(inject(function (_$rootScope_,
15 | _$httpBackend_,
16 | RedirectService,
17 | AuthenticationService) {
18 | rootScope = _$rootScope_;
19 | redirectService = RedirectService;
20 | service = AuthenticationService;
21 | httpBackend = _$httpBackend_;
22 | spyOn(redirectService, 'redirect').and.callFake(function () {
23 | });
24 | }));
25 |
26 | describe('error handling', function () {
27 |
28 | it('should not login with spring errors', function (done) {
29 | httpBackend.expectPOST('./login').respond(400);
30 | service.login({username: 'abc', password: '123'}, function () {
31 | fail();
32 | }, function (user) {
33 | expect(user.isValid()).not.toBeTruthy();
34 | done();
35 | });
36 | httpBackend.flush();
37 | });
38 |
39 | it('should login with user errors', function (done) {
40 | httpBackend.expectPOST('./login').respond(200);
41 | httpBackend.expectGET('./api/login/user').respond(400, {
42 | username: 'abcUser',
43 | userRoles: ['role1', 'roles2']
44 | });
45 | service.login({username: 'abc', password: '123'}, function () {
46 | fail();
47 | }, function (user) {
48 | expect(user.isValid()).not.toBeTruthy();
49 | done();
50 | });
51 | httpBackend.flush();
52 | });
53 |
54 | it('should logout with errors', function (done) {
55 | httpBackend.expectPOST('./logout').respond(400);
56 | service.logout(function () {
57 | fail();
58 | }, function (user) {
59 | expect(user.isValid()).not.toBeTruthy();
60 | done();
61 | }
62 | );
63 | httpBackend.flush();
64 | });
65 | });
66 |
67 | describe('normal handling', function () {
68 |
69 | it('should login successfully', function (done) {
70 | httpBackend.expectPOST('./login').respond(200);
71 | httpBackend.expectGET('./api/login/user').respond(200, {
72 | username: 'abcUser',
73 | userRoles: ['role1', 'roles2']
74 | });
75 | service.login({username: 'abc', password: '123'}, function (user) {
76 | expect(user.isValid()).toBeTruthy();
77 | expect(user.username).toBe('abcUser');
78 | done();
79 | });
80 | httpBackend.flush();
81 | });
82 |
83 | it('should revalidate existing user session', function (done) {
84 | httpBackend.expectGET('./api/login/user').respond(200, {
85 | username: 'abcUser',
86 | userRoles: ['role1', 'roles2']
87 | });
88 | service.checkUser(function (user) {
89 | expect(user.isValid()).toBeTruthy();
90 | done();
91 | }, function () {
92 | fail();
93 | });
94 | httpBackend.flush();
95 | });
96 |
97 | it('should logout successfully', function (done) {
98 | httpBackend.expectPOST('./logout').respond(200);
99 | service.logout(function (user) {
100 | expect(user.isValid()).not.toBeTruthy();
101 | done();
102 | });
103 | httpBackend.flush();
104 | });
105 |
106 | it('should invalidate non existing user session', function (done) {
107 | httpBackend.expectGET('./api/login/user').respond(400);
108 | service.checkUser(function () {
109 | fail();
110 | }, function (user) {
111 | expect(user.isValid()).not.toBeTruthy();
112 | done();
113 | });
114 | httpBackend.flush();
115 | });
116 |
117 | it('should handle invalid user details', function (done) {
118 | httpBackend.expectGET('./api/login/user').respond(200, {
119 | user: 'abcUser'
120 | });
121 | service.checkUser(function (user) {
122 | expect(user.isValid()).not.toBeTruthy();
123 | done();
124 | }, function () {
125 | fail();
126 | });
127 | httpBackend.flush();
128 | });
129 | });
130 | });
131 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/services/srv.domainEventSpec.js:
--------------------------------------------------------------------------------
1 | describe('Service: Domain', function () {
2 | 'use strict';
3 |
4 | // load the controller's module
5 | beforeEach(module('ngSpringBootApp'));
6 |
7 | var service;
8 |
9 | // Initialize the service
10 | beforeEach(inject(function (Domain) {
11 | service = Domain;
12 | }));
13 |
14 | describe('Event', function () {
15 |
16 | it('should convert dates to strings to DTO', function () {
17 | var eventDTO = service.Event.build({
18 | 'eventDescription': 'ss',
19 | 'startDate': new Date(2015, 7, 13, 0, 0, 0, 0),
20 | 'endDate': new Date(2014, 1, 11, 0, 0, 0, 0)
21 | }).convertToDTO();
22 | expect(eventDTO.startDate.getTime()).toBe(new Date(2015, 7, 13, 12, 0, 0, 0).getTime());
23 | expect(eventDTO.endDate.getTime()).toBe(new Date(2014, 1, 11, 12, 0, 0, 0).getTime());
24 | });
25 |
26 | // TODO more tests
27 |
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/services/srv.domainValidationSpec.js:
--------------------------------------------------------------------------------
1 | describe('Service: Domain', function () {
2 | 'use strict';
3 |
4 | // load the controller's module
5 | beforeEach(module('ngSpringBootApp'));
6 |
7 | var service;
8 |
9 | // Initialize the service
10 | beforeEach(inject(function (Domain) {
11 | service = Domain;
12 | }));
13 |
14 | describe('user validation and security tests', function () {
15 |
16 | it('should validate user', function () {
17 | var validUser = service.User.build('user', '1', ['role1']);
18 | expect(validUser.isValid()).toBeTruthy();
19 | var invalidUser1 = service.User.build();
20 | expect(invalidUser1.isValid()).not.toBeTruthy();
21 | var invalidUser2 = service.User.build('anonymousUser');
22 | expect(invalidUser2.isValid()).not.toBeTruthy();
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/services/srv.errorHandlingSpec.js:
--------------------------------------------------------------------------------
1 | describe('Service: ErrorHandling', function () {
2 | 'use strict';
3 |
4 | // load the controller's module
5 | beforeEach(module('ngSpringBootApp'));
6 |
7 | var service, rootScope;
8 |
9 | // Initialize the service
10 | beforeEach(inject(function ($rootScope, ErrorHandlingService) {
11 | rootScope = $rootScope;
12 | service = ErrorHandlingService;
13 | }));
14 |
15 | it('should build validation messages for the http code 400', function (done) {
16 | service.resolve({
17 | error: {
18 | data: [{'messageTemplate': 'validation.date.range_error'}]
19 | },
20 | status: 500
21 | }, function (msg) {
22 | if (msg) {
23 | done();
24 | }
25 | });
26 | rootScope.$apply();
27 | });
28 |
29 | it('should build default error messages for the http code 403', function (done) {
30 | service.resolve({error: {}, status: 403}, function (msg) {
31 | if (msg) {
32 | done();
33 | }
34 | });
35 | rootScope.$apply();
36 | });
37 |
38 | it('should build default error messages for the http code 404', function (done) {
39 | service.resolve({error: {}, status: 404}, function (msg) {
40 | if (msg) {
41 | done();
42 | }
43 | });
44 | rootScope.$apply();
45 | });
46 |
47 | it('should build default error messages for the http code 405', function (done) {
48 | service.resolve({error: {}, status: 405}, function (msg) {
49 | if (msg) {
50 | done();
51 | }
52 | });
53 | rootScope.$apply();
54 | });
55 |
56 | it('should build default error messages for the http code 409', function (done) {
57 | service.resolve({error: {}, status: 409}, function (msg) {
58 | if (msg) {
59 | done();
60 | }
61 | });
62 | rootScope.$apply();
63 | });
64 |
65 | it('should build default error messages for the http code 500', function (done) {
66 | service.resolve({error: {}, status: 500}, function (msg) {
67 | if (msg) {
68 | done();
69 | }
70 | });
71 | rootScope.$apply();
72 | });
73 | });
74 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/frontend/spec/services/srv.eventSpec.js:
--------------------------------------------------------------------------------
1 | describe('Service: EventService', function () {
2 | 'use strict';
3 |
4 | // load the controller's module
5 | beforeEach(module('ngSpringBootApp'));
6 |
7 | var service,
8 | domain,
9 | scope,
10 | httpBackend;
11 |
12 | // Initialize the service
13 | beforeEach(inject(function (EventService, $rootScope, $httpBackend, Domain) {
14 | scope = $rootScope.$new();
15 | service = EventService;
16 | httpBackend = $httpBackend;
17 | domain = Domain;
18 | }));
19 |
20 | describe('error handling', function () {
21 | it('should not call normal handler', function (done) {
22 | httpBackend.expectGET('/api/events').respond(400);
23 | service.listAllEvents(function () {
24 | fail();
25 | }, function () {
26 | done();
27 | });
28 | httpBackend.flush();
29 | });
30 | });
31 |
32 | describe('normal handling', function () {
33 |
34 | describe('read', function () {
35 |
36 | it('should list events', function (done) {
37 | var events;
38 | httpBackend.expectGET('/api/events').respond(200, [{
39 | 'insertDate': '2015-07-07',
40 | 'deleted': false,
41 | 'eventId': '144',
42 | 'eventDescription': 'Beschreibung',
43 | 'startDate': '2015-07-17',
44 | 'endDate': '2015-07-17'
45 | }, {
46 | 'insertDate': '2015-07-07',
47 | 'deleted': false,
48 | 'eventId': '145',
49 | 'eventDescription': 'Beschreibung',
50 | 'startDate': '2015-07-28',
51 | 'endDate': '2015-07-30'
52 | }]);
53 | service.listAllEvents(function (response) {
54 | events = response;
55 | expect(events.length).toBe(2);
56 | expect(events[0].eventId).toBe('144');
57 | expect(events[1].eventId).toBe('145');
58 | done();
59 | });
60 | httpBackend.flush();
61 | });
62 |
63 | it('get event by eventId for customer', function (done) {
64 | var event;
65 | httpBackend.expectGET('/api/events/1').respond(200, {
66 | 'insertDate': '2015-07-07',
67 | 'deleted': false,
68 | 'eventId': '145',
69 | 'eventDescription': 'Beschreibung',
70 | 'startDate': '2015-07-28',
71 | 'endDate': '2015-07-30'
72 | });
73 | service.getEvent('1', function (response) {
74 | event = response;
75 | expect(event.eventId).toBe('145');
76 | done();
77 | });
78 | httpBackend.flush();
79 | });
80 | });
81 |
82 | describe('write', function () {
83 |
84 | it('should create event', function (done) {
85 | httpBackend.expectPOST('/api/events').respond(200);
86 | service.saveEvent(domain.Event.build({
87 | insertDate: new Date(),
88 | eventDescription: 'event',
89 | startDate: new Date(),
90 | endDate: new Date()
91 | }), function () {
92 | done();
93 | });
94 | httpBackend.flush();
95 | });
96 |
97 | it('should update event', function (done) {
98 | httpBackend.expectPUT('/api/events/1').respond(200);
99 | service.saveEvent(domain.Event.build({
100 | insertDate: new Date(),
101 | eventId: 1,
102 | eventDescription: 'event',
103 | startDate: new Date(),
104 | endDate: new Date()
105 | }), function () {
106 | done();
107 | });
108 | httpBackend.flush();
109 | });
110 |
111 | });
112 | });
113 | });
114 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/java/ngSpring/demo/AngularSpringApplicationTest.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.SpringApplicationConfiguration;
6 | import org.springframework.test.context.ActiveProfiles;
7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
8 | import org.springframework.test.context.web.WebAppConfiguration;
9 |
10 | @RunWith(SpringJUnit4ClassRunner.class)
11 | @ActiveProfiles("test")
12 | @SpringApplicationConfiguration(classes = AngularSpringApplication.class)
13 | @WebAppConfiguration
14 | public class AngularSpringApplicationTest {
15 |
16 | @Test
17 | public void contextLoads() {
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/angular-spring-boot-webapp/src/test/java/ngSpring/demo/domain/EventDomainTest.java:
--------------------------------------------------------------------------------
1 | package ngSpring.demo.domain;
2 |
3 | import ngSpring.demo.domain.entities.Event;
4 | import ngSpring.demo.domain.fixtures.EventFixture;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.junit.runners.Parameterized;
8 |
9 | import java.util.Arrays;
10 | import java.util.Collection;
11 |
12 | import static org.hamcrest.MatcherAssert.assertThat;
13 | import static org.hamcrest.Matchers.notNullValue;
14 |
15 |
16 | /**
17 | * @author hypery2k
18 | */
19 | @RunWith(Parameterized.class)
20 | public class EventDomainTest {
21 |
22 | private Event eventToTest;
23 |
24 | public EventDomainTest(Event event) {
25 | this.eventToTest = event;
26 | }
27 |
28 | @Parameterized.Parameters
29 | public static Collection