diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..516df2167 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,29 @@ +node { + // uncomment these 2 lines and edit the name 'node-4.4.7' according to what you choose in configuration + // def nodeHome = tool name: 'node-4.4.7', type: 'jenkins.plugins.nodejs.tools.NodeJSInstallation' + // env.PATH = "${nodeHome}/bin:${env.PATH}" + + stage 'check tools' + sh "node -v" + sh "npm -v" + sh "bower -v" + sh "gulp -v" + + stage 'checkout' + checkout scm + + stage 'npm install' + sh "npm install" + + stage 'clean' + sh "./mvnw clean" + + stage 'backend tests' + sh "./mvnw test" + + stage 'frontend tests' + sh "gulp test" + + stage 'packaging' + sh "./mvnw package -Pprod -DskipTests" +} diff --git a/README.md b/README.md new file mode 100644 index 000000000..b07ed9cfe --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# sprint + +This application was generated using JHipster, you can find documentation and help at [https://jhipster.github.io](https://jhipster.github.io). + +## Development + +Before you can build this project, you must install and configure the following dependencies on your machine: + +1. [Node.js][]: We use Node to run a development web server and build the project. + Depending on your system, you can install Node either from source or as a pre-packaged bundle. + +After installing Node, you should be able to run the following command to install development tools (like +[Bower][] and [BrowserSync][]). You will only need to run this command when dependencies change in package.json. + + npm install + +We use [Gulp][] as our build system. Install the Gulp command-line tool globally with: + + npm install -g gulp + +Run the following commands in two separate terminals to create a blissful development experience where your browser +auto-refreshes when files change on your hard drive. + + ./mvnw + gulp + +Bower is used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by +specifying a newer version in `bower.json`. You can also run `bower update` and `bower install` to manage dependencies. +Add the `-h` flag on any command to see how you can use it. For example, `bower update -h`. + + +## Building for production + +To optimize the sprint client for production, run: + + ./mvnw -Pprod clean package + +This will concatenate and minify CSS and JavaScript files. It will also modify `index.html` so it references +these new files. + +To ensure everything worked, run: + + java -jar target/*.war + +Then navigate to [http://localhost:8080](http://localhost:8080) in your browser. + +## Testing + +Unit tests are run by [Karma][] and written with [Jasmine][]. They're located in `src/test/javascript/` and can be run with: + + gulp test + + + +## Continuous Integration + +To setup this project in Jenkins, use the following configuration: + +* Project name: `sprint` +* Source Code Management + * Git Repository: `git@github.com:xxxx/sprint.git` + * Branches to build: `*/master` + * Additional Behaviours: `Wipe out repository & force clone` +* Build Triggers + * Poll SCM / Schedule: `H/5 * * * *` +* Build + * Invoke Maven / Tasks: `-Pprod clean package` +* Post-build Actions + * Publish JUnit test result report / Test Report XMLs: `build/test-results/*.xml` + +[JHipster]: https://jhipster.github.io/ +[Node.js]: https://nodejs.org/ +[Bower]: http://bower.io/ +[Gulp]: http://gulpjs.com/ +[BrowserSync]: http://www.browsersync.io/ +[Karma]: http://karma-runner.github.io/ +[Jasmine]: http://jasmine.github.io/2.0/introduction.html +[Protractor]: https://angular.github.io/protractor/ diff --git a/bower.json b/bower.json new file mode 100644 index 000000000..bb26918fc --- /dev/null +++ b/bower.json @@ -0,0 +1,64 @@ +{ + "version": "0.0.0", + "name": "sprint", + "appPath": "src/main/webapp/", + "testPath": "src/test/javascript/spec", + "dependencies": { + "angular": "1.5.8", + "angular-aria": "1.5.8", + "angular-bootstrap": "1.3.3", + "angular-cache-buster": "0.4.3", + "angular-cookies": "1.5.8", + "angular-dynamic-locale": "0.1.32", + "angular-i18n": "1.5.8", + "ngstorage": "0.3.10", + "angular-loading-bar": "0.9.0", + "angular-resource": "1.5.8", + "angular-sanitize": "1.5.8", + "angular-translate": "2.11.1", + "angular-translate-interpolation-messageformat": "2.11.1", + "angular-translate-loader-partial": "2.11.1", + "angular-translate-storage-cookie": "2.11.1", + "angular-ui-router": "0.3.1", + "bootstrap": "3.3.6", + "bootstrap-ui-datetime-picker": "2.4.3", + "jquery": "3.1.0", + "json3": "3.3.2", + "messageformat": "0.3.1", + "modernizr": "3.3.1", + "ng-file-upload": "12.0.4", + "ngInfiniteScroll": "1.3.0", + "swagger-ui": "2.1.5", + "angular-underscore-module": "^1.0.3" + }, + "devDependencies": { + "angular-mocks": "1.5.8" + }, + "overrides": { + "angular": { + "dependencies": { + "jquery": "3.1.0" + } + }, + "angular-cache-buster": { + "dependencies": { + "angular": "1.5.8" + } + }, + "angular-dynamic-locale": { + "dependencies": { + "angular": "1.5.8" + } + }, + "bootstrap": { + "main": [ + "dist/css/bootstrap.css" + ] + } + }, + "resolutions": { + "angular": "1.5.8", + "angular-bootstrap": "2.0.0", + "jquery": "3.1.0" + } +} diff --git a/databasechangelog.csv b/databasechangelog.csv new file mode 100644 index 000000000..c1c881853 --- /dev/null +++ b/databasechangelog.csv @@ -0,0 +1 @@ +"ID","AUTHOR","FILENAME","DATEEXECUTED","ORDEREXECUTED","EXECTYPE","MD5SUM","DESCRIPTION","COMMENTS","TAG","LIQUIBASE","CONTEXTS","LABELS" diff --git a/gulp/build.js b/gulp/build.js new file mode 100644 index 000000000..ecb5c362c --- /dev/null +++ b/gulp/build.js @@ -0,0 +1,51 @@ +'use strict'; + +var fs = require('fs'), + gulp = require('gulp'), + lazypipe = require('lazypipe'), + footer = require('gulp-footer'), + sourcemaps = require('gulp-sourcemaps'), + rev = require('gulp-rev'), + htmlmin = require('gulp-htmlmin'), + ngAnnotate = require('gulp-ng-annotate'), + prefix = require('gulp-autoprefixer'), + cssnano = require('gulp-cssnano'), + uglify = require('gulp-uglify'), + useref = require("gulp-useref"), + revReplace = require("gulp-rev-replace"), + plumber = require('gulp-plumber'), + gulpIf = require('gulp-if'), + handleErrors = require('./handle-errors'); + +var config = require('./config'); + +var initTask = lazypipe() + .pipe(sourcemaps.init); +var jsTask = lazypipe() + .pipe(ngAnnotate) + .pipe(uglify); +var cssTask = lazypipe() + .pipe(prefix) + .pipe(cssnano); + +module.exports = function() { + var templates = fs.readFileSync(config.tmp + '/templates.js'); + var manifest = gulp.src(config.revManifest); + + return gulp.src([config.app + '**/*.html', + '!' + config.app + 'app/**/*.html', + '!' + config.app + 'swagger-ui/**/*', + '!' + config.bower + '**/*.html']) + .pipe(plumber({errorHandler: handleErrors})) + //init sourcemaps and prepend semicolon + .pipe(useref({}, initTask)) + //append html templates + .pipe(gulpIf('**/app.js', footer(templates))) + .pipe(gulpIf('*.js', jsTask())) + .pipe(gulpIf('*.css', cssTask())) + .pipe(gulpIf('*.html', htmlmin({collapseWhitespace: true}))) + .pipe(gulpIf('**/*.!(html)', rev())) + .pipe(revReplace({manifest: manifest})) + .pipe(sourcemaps.write('.')) + .pipe(gulp.dest(config.dist)); +}; diff --git a/gulp/config.js b/gulp/config.js new file mode 100644 index 000000000..49df6e6dd --- /dev/null +++ b/gulp/config.js @@ -0,0 +1,23 @@ +'use strict'; + +module.exports = { + app: 'src/main/webapp/', + dist: 'target/www/', + swaggerDist: 'target/www/swagger-ui/', + test: 'src/test/javascript/', + bower: 'src/main/webapp/bower_components/', + tmp: 'target/tmp', + revManifest: 'target/tmp/rev-manifest.json', + port: 9000, + apiPort: 8080, + liveReloadPort: 35729, + uri: 'http://localhost:', + constantTemplate: + '(function () {\n' + + ' \'use strict\';\n' + + ' // DO NOT EDIT THIS FILE, EDIT THE GULP TASK NGCONSTANT SETTINGS INSTEAD WHICH GENERATES THIS FILE\n' + + ' angular\n' + + ' .module(\'<%- moduleName %>\')\n' + + '<% constants.forEach(function(constant) { %> .constant(\'<%- constant.name %>\', <%= constant.value %>)\n<% }) %>;\n' + + '})();\n' +}; diff --git a/gulp/copy.js b/gulp/copy.js new file mode 100644 index 000000000..5f202198d --- /dev/null +++ b/gulp/copy.js @@ -0,0 +1,102 @@ +'use strict'; + +var gulp = require('gulp'), + rev = require('gulp-rev'), + plumber = require('gulp-plumber'), + es = require('event-stream'), + flatten = require('gulp-flatten'), + replace = require('gulp-replace'), + bowerFiles = require('main-bower-files'), + changed = require('gulp-changed'); + +var handleErrors = require('./handle-errors'); +var config = require('./config'); + +module.exports = { + i18n: i18n, + languages: languages, + fonts: fonts, + common: common, + swagger: swagger, + images: images +} + +var yorc = require('../.yo-rc.json')['generator-jhipster']; + +function i18n() { + return gulp.src(config.app + 'i18n/**') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist + 'i18n/')) + .pipe(gulp.dest(config.dist + 'i18n/')); +} + +function languages() { + var locales = yorc.languages.map(function (locale) { + return config.bower + 'angular-i18n/angular-locale_' + locale + '.js'; + }); + return gulp.src(locales) + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.app + 'i18n/')) + .pipe(gulp.dest(config.app + 'i18n/')); +} + +function fonts() { + return es.merge(gulp.src(config.bower + 'bootstrap/fonts/*.*') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist + 'content/fonts/')) + .pipe(rev()) + .pipe(gulp.dest(config.dist + 'content/fonts/')) + .pipe(rev.manifest(config.revManifest, { + base: config.dist, + merge: true + })) + .pipe(gulp.dest(config.dist)), + gulp.src(config.app + 'content/**/*.{woff,woff2,svg,ttf,eot,otf}') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist + 'content/fonts/')) + .pipe(flatten()) + .pipe(rev()) + .pipe(gulp.dest(config.dist + 'content/fonts/')) + .pipe(rev.manifest(config.revManifest, { + base: config.dist, + merge: true + })) + .pipe(gulp.dest(config.dist)) + ); +} + +function common() { + return gulp.src([config.app + 'robots.txt', config.app + 'favicon.ico', config.app + '.htaccess'], { dot: true }) + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist)) + .pipe(gulp.dest(config.dist)); +} + +function swagger() { + return es.merge( + gulp.src([config.bower + 'swagger-ui/dist/**', + '!' + config.bower + 'swagger-ui/dist/index.html', + '!' + config.bower + 'swagger-ui/dist/swagger-ui.min.js', + '!' + config.bower + 'swagger-ui/dist/swagger-ui.js']) + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.swaggerDist)) + .pipe(gulp.dest(config.swaggerDist)), + gulp.src(config.app + 'swagger-ui/index.html') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.swaggerDist)) + .pipe(replace('../bower_components/swagger-ui/dist/', '')) + .pipe(replace('swagger-ui.js', 'lib/swagger-ui.min.js')) + .pipe(gulp.dest(config.swaggerDist)), + gulp.src(config.bower + 'swagger-ui/dist/swagger-ui.min.js') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.swaggerDist + 'lib/')) + .pipe(gulp.dest(config.swaggerDist + 'lib/')) + ); +} + +function images() { + return gulp.src(bowerFiles({filter: ['**/*.{gif,jpg,png}']}), { base: config.bower }) + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist + 'bower_components')) + .pipe(gulp.dest(config.dist + 'bower_components')); +} diff --git a/gulp/handle-errors.js b/gulp/handle-errors.js new file mode 100644 index 000000000..98c4d4a64 --- /dev/null +++ b/gulp/handle-errors.js @@ -0,0 +1,22 @@ +'use strict'; + +var notify = require("gulp-notify"); +var argv = require('yargs').argv; + +module.exports = function() { + + var args = Array.prototype.slice.call(arguments); + var notification = argv.notification === undefined ? true : argv.notification; + // Send error to notification center with gulp-notify + if(notification) { + notify.onError({ + title: "JHipster Gulp Build", + subtitle: "Failure!", + message: "Error: <%= error.message %>", + sound: "Beep" + }).apply(this, args); + } + // Keep gulp from hanging on this task + this.emit('end'); + +}; diff --git a/gulp/inject.js b/gulp/inject.js new file mode 100644 index 000000000..30c575b08 --- /dev/null +++ b/gulp/inject.js @@ -0,0 +1,68 @@ +'use strict'; + +var gulp = require('gulp'), + plumber = require('gulp-plumber'), + inject = require('gulp-inject'), + es = require('event-stream'), + naturalSort = require('gulp-natural-sort'), + angularFilesort = require('gulp-angular-filesort'), + bowerFiles = require('main-bower-files'); + +var handleErrors = require('./handle-errors'); + +var config = require('./config'); + +module.exports = { + app: app, + vendor: vendor, + test: test, + troubleshoot: troubleshoot +} + +function app() { + return gulp.src(config.app + 'index.html') + .pipe(inject(gulp.src(config.app + 'app/**/*.js') + .pipe(naturalSort()) + .pipe(angularFilesort()), {relative: true})) + .pipe(gulp.dest(config.app)); +} + +function vendor() { + var stream = gulp.src(config.app + 'index.html') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(inject(gulp.src(bowerFiles(), {read: false}), { + name: 'bower', + relative: true + })) + .pipe(gulp.dest(config.app)); + + return stream; +} + +function test() { + return gulp.src(config.test + 'karma.conf.js') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(inject(gulp.src(bowerFiles({includeDev: true, filter: ['**/*.js']}), {read: false}), { + starttag: '// bower:js', + endtag: '// endbower', + transform: function (filepath) { + return '\'' + filepath.substring(1, filepath.length) + '\','; + } + })) + .pipe(gulp.dest(config.test)); +} + +function troubleshoot() { + /* this task removes the troubleshooting content from index.html*/ + return gulp.src(config.app + 'index.html') + .pipe(plumber({errorHandler: handleErrors})) + /* having empty src as we dont have to read any files*/ + .pipe(inject(gulp.src('', {read: false}), { + starttag: '', + removeTags: true, + transform: function () { + return ''; + } + })) + .pipe(gulp.dest(config.app)); +} diff --git a/gulp/serve.js b/gulp/serve.js new file mode 100644 index 000000000..243a01784 --- /dev/null +++ b/gulp/serve.js @@ -0,0 +1,62 @@ +'use strict'; + +var gulp = require('gulp'), + util = require('./utils'), + url = require('url'), + browserSync = require('browser-sync'), + proxy = require('proxy-middleware'); + +var config = require('./config'); + +module.exports = function () { + var baseUri = config.uri + config.apiPort; + // Routes to proxy to the backend. Routes ending with a / will setup + // a redirect so that if accessed without a trailing slash, will + // redirect. This is required for some endpoints for proxy-middleware + // to correctly handle them. + var proxyRoutes = [ + '/' + ]; + + var requireTrailingSlash = proxyRoutes.filter(function (r) { + return util.endsWith(r, '/'); + }).map(function (r) { + // Strip trailing slash so we can use the route to match requests + // with non trailing slash + return r.substr(0, r.length - 1); + }); + + var proxies = [ + // Ensure trailing slash in routes that require it + function (req, res, next) { + requireTrailingSlash.forEach(function (route){ + if (url.parse(req.url).path === route) { + res.statusCode = 301; + res.setHeader('Location', route + '/'); + res.end(); + } + }); + + next(); + } + ] + .concat( + // Build a list of proxies for routes: [route1_proxy, route2_proxy, ...] + proxyRoutes.map(function (r) { + var options = url.parse(baseUri + r); + options.route = r; + options.preserveHost = true; + return proxy(options); + })); + + browserSync({ + open: true, + port: config.port, + server: { + baseDir: config.app, + middleware: proxies + } + }); + + gulp.start('watch'); +}; diff --git a/gulp/utils.js b/gulp/utils.js new file mode 100644 index 000000000..abb80d3e3 --- /dev/null +++ b/gulp/utils.js @@ -0,0 +1,36 @@ +'use strict'; + +var fs = require('fs'); + +module.exports = { + endsWith : endsWith, + parseVersion : parseVersion, + isLintFixed : isLintFixed +}; + +function endsWith(str, suffix) { + return str.indexOf('/', str.length - suffix.length) !== -1; +} + +var parseString = require('xml2js').parseString; +// return the version number from `pom.xml` file +function parseVersion() { + var version = null; + var pomXml = fs.readFileSync('pom.xml', 'utf8'); + parseString(pomXml, function (err, result) { + if (result.project.version && result.project.version[0]) { + version = result.project.version[0]; + } else if (result.project.parent && result.project.parent[0] && result.project.parent[0].version && result.project.parent[0].version[0]) { + version = result.project.parent[0].version[0]; + } + }); + if (version === null) { + throw new Error('pom.xml is malformed. No version is defined'); + } + return version; +} + +function isLintFixed(file) { + // Has ESLint fixed the file contents? + return file.eslint !== null && file.eslint.fixed; +} diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 000000000..e24c855da --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,170 @@ +// Generated on 2016-09-07 using generator-jhipster 3.6.1 +'use strict'; + +var gulp = require('gulp'), + rev = require('gulp-rev'), + templateCache = require('gulp-angular-templatecache'), + htmlmin = require('gulp-htmlmin'), + imagemin = require('gulp-imagemin'), + ngConstant = require('gulp-ng-constant'), + rename = require('gulp-rename'), + eslint = require('gulp-eslint'), + del = require('del'), + runSequence = require('run-sequence'), + browserSync = require('browser-sync'), + KarmaServer = require('karma').Server, + plumber = require('gulp-plumber'), + changed = require('gulp-changed'), + gulpIf = require('gulp-if'); + +var handleErrors = require('./gulp/handle-errors'), + serve = require('./gulp/serve'), + util = require('./gulp/utils'), + copy = require('./gulp/copy'), + inject = require('./gulp/inject'), + build = require('./gulp/build'); + +var config = require('./gulp/config'); + +gulp.task('clean', function () { + return del([config.dist], { dot: true }); +}); + +gulp.task('copy', ['copy:i18n', 'copy:fonts', 'copy:common']); + +gulp.task('copy:i18n', copy.i18n); + +gulp.task('copy:languages', copy.languages); + +gulp.task('copy:fonts', copy.fonts); + +gulp.task('copy:common', copy.common); + +gulp.task('copy:swagger', copy.swagger); + +gulp.task('copy:images', copy.images); + +gulp.task('images', function () { + return gulp.src(config.app + 'content/images/**') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(changed(config.dist + 'content/images')) + .pipe(imagemin({optimizationLevel: 5, progressive: true, interlaced: true})) + .pipe(rev()) + .pipe(gulp.dest(config.dist + 'content/images')) + .pipe(rev.manifest(config.revManifest, { + base: config.dist, + merge: true + })) + .pipe(gulp.dest(config.dist)) + .pipe(browserSync.reload({stream: true})); +}); + + +gulp.task('styles', [], function () { + return gulp.src(config.app + 'content/css') + .pipe(browserSync.reload({stream: true})); +}); + +gulp.task('inject', function() { + runSequence('inject:dep', 'inject:app'); +}); + +gulp.task('inject:dep', ['inject:test', 'inject:vendor']); + +gulp.task('inject:app', inject.app); + +gulp.task('inject:vendor', inject.vendor); + +gulp.task('inject:test', inject.test); + +gulp.task('inject:troubleshoot', inject.troubleshoot); + +gulp.task('assets:prod', ['images', 'styles', 'html', 'copy:swagger', 'copy:images'], build); + +gulp.task('html', function () { + return gulp.src(config.app + 'app/**/*.html') + .pipe(htmlmin({collapseWhitespace: true})) + .pipe(templateCache({ + module: 'sprintApp', + root: 'app/', + moduleSystem: 'IIFE' + })) + .pipe(gulp.dest(config.tmp)); +}); + +gulp.task('ngconstant:dev', function () { + return ngConstant({ + name: 'sprintApp', + constants: { + VERSION: util.parseVersion(), + DEBUG_INFO_ENABLED: true + }, + template: config.constantTemplate, + stream: true + }) + .pipe(rename('app.constants.js')) + .pipe(gulp.dest(config.app + 'app/')); +}); + +gulp.task('ngconstant:prod', function () { + return ngConstant({ + name: 'sprintApp', + constants: { + VERSION: util.parseVersion(), + DEBUG_INFO_ENABLED: false + }, + template: config.constantTemplate, + stream: true + }) + .pipe(rename('app.constants.js')) + .pipe(gulp.dest(config.app + 'app/')); +}); + +// check app for eslint errors +gulp.task('eslint', function () { + return gulp.src(['gulpfile.js', config.app + 'app/**/*.js']) + .pipe(plumber({errorHandler: handleErrors})) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failOnError()); +}); + +// check app for eslint errors anf fix some of them +gulp.task('eslint:fix', function () { + return gulp.src(config.app + 'app/**/*.js') + .pipe(plumber({errorHandler: handleErrors})) + .pipe(eslint({ + fix: true + })) + .pipe(eslint.format()) + .pipe(gulpIf(util.isLintFixed, gulp.dest(config.app + 'app'))); +}); + +gulp.task('test', ['inject:test', 'ngconstant:dev'], function (done) { + new KarmaServer({ + configFile: __dirname + '/' + config.test + 'karma.conf.js', + singleRun: true + }, done).start(); +}); + + +gulp.task('watch', function () { + gulp.watch('bower.json', ['install']); + gulp.watch(['gulpfile.js', 'pom.xml'], ['ngconstant:dev']); + gulp.watch(config.app + 'content/css/**/*.css', ['styles']); + gulp.watch(config.app + 'content/images/**', ['images']); + gulp.watch(config.app + 'app/**/*.js', ['inject:app']); + gulp.watch([config.app + '*.html', config.app + 'app/**', config.app + 'i18n/**']).on('change', browserSync.reload); +}); + +gulp.task('install', function () { + runSequence(['inject:dep', 'ngconstant:dev'], 'copy:languages', 'inject:app', 'inject:troubleshoot'); +}); + +gulp.task('serve', ['install'], serve); + +gulp.task('build', ['clean'], function (cb) { + runSequence(['copy', 'inject:vendor', 'ngconstant:prod', 'copy:languages'], 'inject:app', 'inject:troubleshoot', 'assets:prod', cb); +}); + +gulp.task('default', ['serve']); diff --git a/mvnw b/mvnw new file mode 100755 index 000000000..a1ba1bf55 --- /dev/null +++ b/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 000000000..2b934e89d --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 000000000..5ca3f257d --- /dev/null +++ b/package.json @@ -0,0 +1,67 @@ +{ + "name": "sprint", + "version": "0.0.0", + "description": "Description for sprint", + "private": true, + "cacheDirectories": [ + "node_modules", + "src/main/webapp/bower_components" + ], + "devDependencies": { + "bower": "1.7.9", + "browser-sync": "2.13.0", + "del": "2.2.1", + "eslint-config-angular": "0.5.0", + "eslint-plugin-angular": "1.3.1", + "event-stream": "3.3.4", + "generator-jhipster": "3.6.1", + "gulp": "3.9.1", + "gulp-angular-filesort": "1.1.1", + "gulp-angular-templatecache": "2.0.0", + "gulp-autoprefixer": "3.1.0", + "gulp-changed": "1.3.1", + "gulp-cssnano": "2.1.2", + "gulp-eslint": "3.0.1", + "gulp-flatten": "0.3.0", + "gulp-footer": "1.0.5", + "gulp-htmlmin": "2.0.0", + "gulp-if": "2.0.1", + "gulp-imagemin": "3.0.2", + "gulp-inject": "4.1.0", + "gulp-natural-sort": "0.1.1", + "gulp-ng-annotate": "2.0.0", + "gulp-ng-constant": "1.1.0", + "gulp-notify": "2.2.0", + "gulp-plumber": "1.1.0", + "gulp-rename": "1.2.2", + "gulp-replace": "0.5.4", + "gulp-rev": "7.1.0", + "gulp-rev-replace": "0.4.3", + "gulp-sourcemaps": "1.6.0", + "gulp-uglify": "1.5.4", + "gulp-useref": "3.1.0", + "jasmine-core": "2.4.1", + "karma": "1.1.2", + "karma-chrome-launcher": "1.0.1", + "karma-coverage": "1.1.1", + "karma-jasmine": "1.0.2", + "karma-junit-reporter": "1.1.0", + "karma-phantomjs-launcher": "1.0.1", + "karma-script-launcher": "1.0.0", + "lazypipe": "1.0.1", + "lodash": "4.14.0", + "main-bower-files": "2.13.1", + "map-stream": "0.0.6", + "phantomjs-prebuilt": "2.1.8", + "proxy-middleware": "0.15.0", + "run-sequence": "1.2.2", + "xml2js": "0.4.16", + "yargs": "4.8.1" + }, + "engines": { + "node": "^4.3" + }, + "scripts": { + "test": "gulp test" + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..4d788b183 --- /dev/null +++ b/pom.xml @@ -0,0 +1,670 @@ + + + 4.0.0 + + + archetype + it.cnr.si + 1.0.3 + + + it.cnr.si.sprint + sprint-ace + 0.2.0-SNAPSHOT + war + + sprint-ace + + + 3.0.0 + + + + scm:git:ssh://git@git.si.cnr.it/dev/sprint-ace.git + scm:git:ssh://git@git.si.cnr.it/dev/sprint-ace.git + HEAD + + + + 3.5.2 + 2.1.7 + 0.7.7.201606060606 + 2.2.0 + 3.5 + 3.4.2 + 1.0.0.Final + 1.4.1 + 3.0.1 + + yyyyMMddHHmmss + 3.0.2 + 2.5.0 + 1.4.0.RELEASE + 2.0.1 + it.cnr.si.SprintApp + + + + + + + it.cnr.si.sprint + sprint-ldap + ${sprint.version} + + + it.cnr.si.sprint + sprint-core + ${sprint.version} + + + + + + org.activiti + activiti-spring + 5.21.0 + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + + + + + + + org.activiti + activiti-rest + 5.21.0 + + + + + + + + + + + + + + + org.slf4j + slf4j-log4j12 + + + + + + + + + + + spring-boot:run + + + com.github.ekryd.sortpom + sortpom-maven-plugin + ${sortpom-maven-plugin.version} + + + verify + + sort + + + + + true + 4 + groupId,artifactId + groupId,artifactId + true + false + + + + io.gatling + gatling-maven-plugin + ${gatling-maven-plugin.version} + + src/test/gatling/conf + src/test/gatling/data + target/gatling/results + src/test/gatling/bodies + src/test/gatling/simulations + + * + + + + org.apache.maven.plugins + maven-eclipse-plugin + + true + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-versions + + enforce + + + + + + + You are running an older version of Maven. + JHipster requires at least Maven 3.0 + [3.0.0,) + + + You are running an older version of Java. + JHipster requires at least JDK ${java.version} + [${java.version}.0,) + + + + + + org.apache.maven.plugins + maven-resources-plugin + ${maven-resources-plugin.version} + + + default-resources + validate + + copy-resources + + + target/classes + false + + # + + + + src/main/resources/ + true + + **/*.xml + **/*.yml + + + + src/main/resources/ + false + + **/*.xml + **/*.yml + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -Djava.security.egd=file:/dev/./urandom -Xmx256m + ${surefireArgLine} + + alphabetical + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + pre-unit-tests + + prepare-agent + + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + + surefireArgLine + + + + + post-unit-test + test + + report + + + ${project.testresult.directory}/coverage/jacoco/jacoco.exec + ${project.testresult.directory}/coverage/jacoco + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar-maven-plugin.version} + + + org.bsc.maven + maven-processor-plugin + 2.2.4 + + + ${project.build.directory}/generated-sources + + + org.mapstruct.ap.MappingProcessor + + + true + spring + + + + + process + generate-sources + + process + + + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + org.liquibase + liquibase-maven-plugin + ${liquibase.version} + + src/main/resources/config/liquibase/master.xml + src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml + + + + sprint + + hibernate:spring:it.cnr.si.domain?dialect=&hibernate.ejb.naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy + true + debug + oauth_access_token, oauth_approvals, + oauth_client_details, oauth_client_token, oauth_code, + oauth_refresh_token + + + + org.javassist + javassist + 3.18.2-GA + + + org.liquibase.ext + liquibase-hibernate4 + ${liquibase-hibernate4.version} + + + org.springframework.boot + spring-boot-starter-data-jpa + ${project.parent.version} + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + com.spotify + docker-maven-plugin + 0.4.10 + + sprint + src/main/docker + + + / + ${project.build.directory} + ${project.build.finalName}.war + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + ${start-class} + + + + + ${start-class} + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + + jacoco-maven-plugin + + + ${jacoco-maven-plugin.version} + + + prepare-agent + + + + + + + + + com.github.eirslett + + frontend-maven-plugin + + + ${frontend-maven-plugin.version} + + + install-node-and-npm + npm + bower + gulp + + + + + + + + + + + + + + + + + no-liquibase + + ,no-liquibase + + + + swagger + + ,swagger + + + + dev + + true + + + + org.springframework.boot + spring-boot-starter-tomcat + ${spring-boot.version} + + + org.springframework.boot + spring-boot-devtools + ${spring-boot.version} + true + + + + + + org.apache.maven.plugins + maven-war-plugin + + src/main/webapp/ + WEB-INF/lib/tomcat-*.jar + + + + + + + DEBUG + + dev,cnr${profile.no-liquibase} + + + + prod + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + com.github.eirslett + frontend-maven-plugin + 1.0 + + + install node and npm + + install-node-and-npm + + + v4.4.7 + 3.10.5 + + + + npm install + + npm + + + install + + + + bower install + + bower + + + install --no-color + + + + gulp build + + gulp + + + build --no-notification + + + + gulp test + + gulp + + test + + test --no-notification + + + + + + maven-clean-plugin + 2.5 + + + + target/www/ + + + + + + org.apache.maven.plugins + maven-war-plugin + + target/www/ + WEB-INF/lib/tomcat-*.jar + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + + INFO + + prod${profile.swagger}${profile.no-liquibase} + + + + + + + + org.springframework + spring-core + 4.3.2.RELEASE + + + org.springframework + spring-context + 4.3.2.RELEASE + + + org.springframework + spring-tx + 4.3.2.RELEASE + + + org.springframework + spring-web + 4.3.2.RELEASE + + + org.springframework + spring-webmvc + 4.3.2.RELEASE + + + org.slf4j + slf4j-api + 1.7.21 + + + org.springframework.security + spring-security-ldap + 4.1.1.RELEASE + + + org.springframework.security + spring-security-core + 4.1.1.RELEASE + + + org.springframework.security + spring-security-web + 4.1.1.RELEASE + + + org.springframework.security + spring-security-data + 4.1.1.RELEASE + + + org.springframework.security + spring-security-config + 4.1.1.RELEASE + + + + + + + + + + + + + + diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile new file mode 100644 index 000000000..01354228d --- /dev/null +++ b/src/main/docker/Dockerfile @@ -0,0 +1,13 @@ +FROM java:openjdk-8-jre-alpine + +ENV JHIPSTER_SLEEP 0 + +# add directly the war +ADD *.war /app.war + +RUN sh -c 'touch /app.war' +VOLUME /tmp +EXPOSE 8080 5701/udp +CMD echo "The application will start in ${JHIPSTER_SLEEP}s..." && \ + sleep ${JHIPSTER_SLEEP} && \ + java -Djava.security.egd=file:/dev/./urandom -jar /app.war diff --git a/src/main/docker/app.yml b/src/main/docker/app.yml new file mode 100644 index 000000000..f3f3790e9 --- /dev/null +++ b/src/main/docker/app.yml @@ -0,0 +1,16 @@ +version: '2' +services: + sprint-app: + image: sprint + external_links: + - sprint-postgresql:postgresql + environment: + - SPRING_PROFILES_ACTIVE=prod,swagger + - SPRING_DATASOURCE_URL=jdbc:postgresql://postgresql:5432/sprint + - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application + ports: + - 8080:8080 + sprint-postgresql: + extends: + file: postgresql.yml + service: sprint-postgresql diff --git a/src/main/docker/postgresql.yml b/src/main/docker/postgresql.yml new file mode 100644 index 000000000..697170263 --- /dev/null +++ b/src/main/docker/postgresql.yml @@ -0,0 +1,12 @@ +version: '2' +services: + sprint-postgresql: + container_name: sprint-postgresql + image: postgres:9.5.3 + # volumes: + # - ~/volumes/jhipster/sprint/postgresql/:/var/lib/postgresql/ + environment: + - POSTGRES_USER=sprint + - POSTGRES_PASSWORD= + ports: + - 5432:5432 diff --git a/src/main/docker/sonar.yml b/src/main/docker/sonar.yml new file mode 100644 index 000000000..026933f9a --- /dev/null +++ b/src/main/docker/sonar.yml @@ -0,0 +1,8 @@ +version: '2' +services: + sprint-sonar: + container_name: sprint-sonar + image: sonarqube:5.6-alpine + ports: + - 9000:9000 + - 9092:9092 diff --git a/src/main/java/it/cnr/si/flows/ng/config/ActivitiBeanNameGenerator.java b/src/main/java/it/cnr/si/flows/ng/config/ActivitiBeanNameGenerator.java new file mode 100644 index 000000000..48c999451 --- /dev/null +++ b/src/main/java/it/cnr/si/flows/ng/config/ActivitiBeanNameGenerator.java @@ -0,0 +1,17 @@ +package it.cnr.si.flows.ng.config; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotationBeanNameGenerator; + +public class ActivitiBeanNameGenerator extends AnnotationBeanNameGenerator { + + public ActivitiBeanNameGenerator() { + super(); + } + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return "activiti"+super.generateBeanName(definition, registry); + } +} diff --git a/src/main/java/it/cnr/si/flows/ng/config/FlowsConfigurations.java b/src/main/java/it/cnr/si/flows/ng/config/FlowsConfigurations.java new file mode 100644 index 000000000..0f9bc4ea5 --- /dev/null +++ b/src/main/java/it/cnr/si/flows/ng/config/FlowsConfigurations.java @@ -0,0 +1,111 @@ +package it.cnr.si.flows.ng.config; + +import javax.annotation.PostConstruct; + +import org.activiti.engine.FormService; +import org.activiti.engine.HistoryService; +import org.activiti.engine.IdentityService; +import org.activiti.engine.ManagementService; +import org.activiti.engine.ProcessEngine; +import org.activiti.engine.ProcessEngineConfiguration; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.TaskService; +import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.activiti.engine.impl.history.HistoryLevel; +import org.activiti.engine.repository.DeploymentBuilder; +import org.activiti.rest.common.application.ContentTypeResolver; +import org.activiti.rest.service.api.RestResponseFactory; +import org.activiti.spring.ProcessEngineFactoryBean; +import org.activiti.spring.SpringProcessEngineConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.transaction.PlatformTransactionManager; + +import com.zaxxer.hikari.HikariDataSource; + + +@Configuration +@ComponentScan(basePackages = {"org.activiti.rest",}, +// excludeFilters = {@ComponentScan.Filter( +// type = FilterType.ASSIGNABLE_TYPE, +// value = {UserResource.class} +// )} +// , + includeFilters = {@ComponentScan.Filter( + type = FilterType.ASSIGNABLE_TYPE, + value = {RestResponseFactory.class, ContentTypeResolver.class} + ) + }, + nameGenerator = ActivitiBeanNameGenerator.class) +public class FlowsConfigurations { + + + @Autowired + private PlatformTransactionManager transactionManager; + + @Autowired + private HikariDataSource dataSource; + + @Bean + public ProcessEngineConfigurationImpl getProcessEngineConfiguration() { + SpringProcessEngineConfiguration conf = new SpringProcessEngineConfiguration(); + conf.setDataSource(dataSource); + conf.setTransactionManager(transactionManager); + conf.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); + + conf.setHistoryLevel(HistoryLevel.FULL); + + return conf; + } + + @Bean(name= {"processEngine", "engine"}) + public ProcessEngine getProcessEngine() throws Exception { + ProcessEngineFactoryBean bean = new ProcessEngineFactoryBean(); + bean.setProcessEngineConfiguration(getProcessEngineConfiguration()); + return bean.getObject(); + } + + @Bean + public RepositoryService getRepositoryService() throws Exception { + return getProcessEngine().getRepositoryService(); + + } + + + @Bean + public RuntimeService getRuntimeService() throws Exception { + return getProcessEngine().getRuntimeService(); + } + + @Bean FormService getFormService() throws Exception { + return getProcessEngine().getFormService(); + } + + @Bean HistoryService getHistoryService() throws Exception { + return getProcessEngine().getHistoryService(); + } + + @Bean TaskService getTaskService() throws Exception { + return getProcessEngine().getTaskService(); + } + + @Bean IdentityService getIdentityService() throws Exception { + return getProcessEngine().getIdentityService(); + } + + @Bean ManagementService getManagementService() throws Exception { + return getProcessEngine().getManagementService(); + } + + @PostConstruct + public void createDeployments() throws Exception { + DeploymentBuilder builder = getRepositoryService().createDeployment(); + builder.addClasspathResource("processes/PermessiFerieProcess.bpmn20.xml"); + builder.deploy(); + } + +} diff --git a/src/main/java/it/cnr/si/flows/ng/resource/DiagramResource.java b/src/main/java/it/cnr/si/flows/ng/resource/DiagramResource.java new file mode 100644 index 000000000..73624c08d --- /dev/null +++ b/src/main/java/it/cnr/si/flows/ng/resource/DiagramResource.java @@ -0,0 +1,124 @@ +package it.cnr.si.flows.ng.resource; + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.activiti.bpmn.model.BpmnModel; +import org.activiti.engine.ActivitiIllegalArgumentException; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.image.ProcessDiagramGenerator; +import org.activiti.rest.service.api.runtime.task.TaskResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.codahale.metrics.annotation.Timed; + + +@Controller +@RequestMapping("rest") +public class DiagramResource { + + @Autowired + private RepositoryService repositoryService; + @Autowired + private RuntimeService runtimeService; +// @Autowired + private ProcessDiagramGenerator pdg; + + @RequestMapping(value = "/diagram/{id}", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE) + @ResponseBody + @Timed + public void getDiagramForProcess( + @PathVariable String id, + HttpServletRequest request, + HttpServletResponse response + ) throws IOException { + + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionId(id) + .singleResult(); + + String diagramResourceName = processDefinition.getDiagramResourceName(); + InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName()); + + + response.setContentType(MediaType.IMAGE_PNG_VALUE); + org.apache.commons.io.IOUtils.copy(resourceAsStream, response.getOutputStream()); + + } + + @RequestMapping(value = "/diagram", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE) + @ResponseBody + @Timed + public void getDiagram( + HttpServletRequest request, + HttpServletResponse response + ) throws IOException { + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() + .processDefinitionKey("permessiFerieProcess") + .latestVersion() + .singleResult(); + + String diagramResourceName = processDefinition.getDiagramResourceName(); + InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName()); + + + response.setContentType(MediaType.IMAGE_PNG_VALUE); + org.apache.commons.io.IOUtils.copy(resourceAsStream, response.getOutputStream()); + + } + + @RequestMapping(value = "/diagram2", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE) + @ResponseBody + @Timed + public void getDiagram2( + HttpServletRequest request, + HttpServletResponse response + ) throws IOException { +// ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() +// .processDefinitionKey("permessiFerieProcess") +// .latestVersion() +// .singleResult(); +// +// String diagramResourceName = processDefinition.getDiagramResourceName(); +// InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName()); +// +// +// response.setContentType(MediaType.IMAGE_PNG_VALUE); +// org.apache.commons.io.IOUtils.copy(resourceAsStream, response.getOutputStream()); + + TaskResponse tr; + + ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery() + .processDefinitionKey("permessiFerieProcess") + .latestVersion() + .singleResult(); + + + ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId()); + + + if (processDefinition != null && processDefinition.isGraphicalNotationDefined()) { + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + InputStream resource = pdg.generateDiagram(bpmnModel, "png", runtimeService.getActiveActivityIds(processInstance.getId())); + + response.setContentType(MediaType.IMAGE_PNG_VALUE); + org.apache.commons.io.IOUtils.copy(resource, response.getOutputStream()); + + } else { + throw new ActivitiIllegalArgumentException("Process instance with id '" + processInstance.getId() + "' has no graphical notation defined."); + } + } +} diff --git a/src/main/java/it/cnr/si/flows/ng/resource/FlowsTaskResource.java b/src/main/java/it/cnr/si/flows/ng/resource/FlowsTaskResource.java new file mode 100644 index 000000000..ea58866ed --- /dev/null +++ b/src/main/java/it/cnr/si/flows/ng/resource/FlowsTaskResource.java @@ -0,0 +1,353 @@ +package it.cnr.si.flows.ng.resource; + +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.TaskService; +import org.activiti.engine.task.Task; +import org.activiti.rest.common.api.DataResponse; +import org.activiti.rest.service.api.RestResponseFactory; +import org.activiti.rest.service.api.runtime.task.TaskCollectionResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.codahale.metrics.annotation.Timed; + +import it.cnr.si.repository.UserRepository; +import it.cnr.si.security.AuthoritiesConstants; +import it.cnr.si.security.SecurityUtils; +import it.cnr.si.service.UserService; + + +/** + * @author mtrycz + * + */ +@RestController +@RequestMapping("rest/tasks") +public class FlowsTaskResource { + + @Deprecated + private static final String ERRORE_PERMESSI_TASK = "ERRORE PERMESSI TASK"; + + private static final Logger LOGGER = LoggerFactory.getLogger(FlowsTaskResource.class); + + @Inject + private UserRepository userRepository; + @Inject + private UserService userService; + + @Autowired + protected RestResponseFactory restResponseFactory; + + @Autowired + private RepositoryService repositoryService; + @Autowired + private RuntimeService runtimeService; + + @Autowired + private TaskCollectionResource activitiTaskResource; + + @Autowired + private TaskService taskService; + + @RequestMapping(value = "/mytasks", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured(AuthoritiesConstants.USER) + @Timed + public ResponseEntity getMyTasks(Principal user, + @RequestParam Map params) { + + String username = SecurityUtils.getCurrentUserLogin(); + + List list = taskService.createTaskQuery() + .taskAssignee(username).list(); + + DataResponse response = new DataResponse(); + response.setStart(0); + response.setSize(list.size()); + response.setTotal(list.size()); + response.setData(list); + + return ResponseEntity.ok(response); + } + + @RequestMapping(value = "/mytasksavailable", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured(AuthoritiesConstants.USER) + @Timed + public ResponseEntity getMyTasksAvailable( + @RequestParam Map params) { + + String username = SecurityUtils.getCurrentUserLogin(); + + List list = taskService.createTaskQuery() + .taskCandidateUser(username).list(); + + DataResponse response = new DataResponse(); + response.setStart(0); + response.setSize(list.size()); + response.setTotal(list.size()); + response.setData(list); + + return ResponseEntity.ok(response); + } + + @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> getTaskInstance( + HttpServletRequest req, + @PathVariable("id") String id, + @RequestParam Map params) { + + return null; +// long taskId = extractId(id); +// +// Task task = taskService.createTaskQuery().taskId(""+taskId).singleResult(); +// List tasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); +// ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); +// +// List> tasksMaps = tasks.stream().map(t -> mappaTaskInMap(t)).collect(Collectors.toList()); +// +// Map result = new HashMap<>(); +// Map definition = new HashMap<>(); +// definition.put("id", "cnrdsftm:validaTask"); +// +// Map mappaTaskInMap = mappaTaskInMap(task); +// ((Map) mappaTaskInMap.get("entry")).put("tasks", tasksMaps); +// ((Map) mappaTaskInMap.get("entry")).put("workflowInstance", mappaProcessInstanceInMap(pi)); +// ((Map) mappaTaskInMap.get("entry")).put("definition", definition); +// +// +// result.put("data", mappaTaskInMap.get("entry")); +// +// +// return new ResponseEntity>(result, HttpStatus.OK); + +// // TODO verificare se ci possono essere parametri aggiuntivi utili// boolean detailed = Boolean.parseBoolean(params.get("detailed")); +// long taskId = Utils.extractId(id); +// CMISUser user = cmisService.getCMISUserFromSession(req); +// BindingSession session = cmisService.getCurrentBindingSession(req); +// +// try { +// Map taskInstance = flowsTaskService.getTask(user, session, taskId, detailed); +// return new ResponseEntity>(taskInstance, HttpStatus.OK); +// } catch (PermissionException e) { +// LOGGER.error(e.getMessage(), e); +// return new ResponseEntity>(HttpStatus.FORBIDDEN); +// } catch (IOException e) { +// Map response = new HashMap<>(); +// response.put("error", e.getMessage()); +// return new ResponseEntity>(response, HttpStatus.INTERNAL_SERVER_ERROR); +// } + } + + /** + * Questo metodo serve per assegnare un taskInstance a un'utente o rilasciare il task al pool + * + * TODO Considerare la possibilità di modificare nome e signature Map-data in String-username + * + * @param req + * @param id + * @param params + * @return + */ + // TODO rifattorizzare, il parametro data è confusionario + @RequestMapping(value = "/claim/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> claimTask( + HttpServletRequest req, + @PathVariable("id") String id) { + + return null; +// CMISUser user = cmisService.getCMISUserFromSession(req); +// BindingSession session = cmisService.getCurrentBindingSession(req); +// String cm_owner = user.getUserName(); +// long taskId = Utils.extractId(id); +// +// LOGGER.info("Setting owner of task "+ id +" to "+ cm_owner); +// +// try { +// Map taskInstance = flowsTaskService.claimTask(user, session, taskId); +// +// return new ResponseEntity>(taskInstance, HttpStatus.OK); +// } catch (IOException e) { +// Map response = new HashMap<>(); +// response.put("error", e.getMessage()); +// return new ResponseEntity>(response, HttpStatus.INTERNAL_SERVER_ERROR); +// } + } + + @RequestMapping(value = "/unclaim/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> unclaimTask( + HttpServletRequest req, + @PathVariable("id") String id) { + + return null; +// CMISUser user = cmisService.getCMISUserFromSession(req); +// BindingSession session = cmisService.getCurrentBindingSession(req); +// long taskId = Utils.extractId(id); +// +// LOGGER.info("Unsetting owner of task "+ id); +// +// try { +// Map task = flowsTaskService.getTask(user, session, taskId, true); +// Map data = (Map) task.get("data"); +// Map owner = (Map) data.get("owner"); +// String ownerName = (String) owner.get("userName"); +// +// if( !user.getUserName().equals(ownerName) ) { +// throw new PermissionException("L'utente può solo rinunciare a un task di cui è owner. Utente che ha fatto la richiesta: "+ user.getUserName() +", owner: "+ ownerName); +// } +// +// Map taskInstance = flowsTaskService.unclaimTask(user, session, taskId); +// +// return new ResponseEntity>(taskInstance, HttpStatus.OK); +// +// } catch (PermissionException e) { +// LOGGER.error(e.getMessage(), e); +// return new ResponseEntity>(HttpStatus.FORBIDDEN); +// } catch (IOException e) { +// Map response = new HashMap<>(); +// response.put("error", e.getMessage()); +// return new ResponseEntity>(response, HttpStatus.INTERNAL_SERVER_ERROR); +// } + } + + @RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> assignTask( + HttpServletRequest req, + @PathVariable("id") String id, + @RequestBody Map data) { + + return null; +// CMISUser user = cmisService.getCMISUserFromSession(req); +// BindingSession session = cmisService.getCurrentBindingSession(req); +// String cm_owner = (String) data.get("cm_owner"); +// long taskId = Utils.extractId(id); +// +// LOGGER.info("Setting owner of task "+ id +" to "+ cm_owner); +// +// try { +// Map taskInstance = flowsTaskService.setTaskOwner(user, session, taskId, data); +// +// return new ResponseEntity>(taskInstance, HttpStatus.OK); +// } catch (PermissionException e) { +// LOGGER.error(e.getMessage(), e); +// return new ResponseEntity>(HttpStatus.FORBIDDEN); +// } catch (IOException e) { +// Map response = new HashMap<>(); +// response.put("error", e.getMessage()); +// return new ResponseEntity>(response, HttpStatus.INTERNAL_SERVER_ERROR); +// } + } + + // TODO returns ResponseEntity> + @RequestMapping(value = "variables/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> getTaskVariables( + HttpServletRequest req, + HttpServletResponse resp, + @PathVariable("id") String id) + throws IOException { + + Map result = new HashMap<>(); + Map list = new HashMap<>(); + List> entries = new ArrayList<>(); + + result.put("list", list); + list.put("entries", entries); + +// taskService.getVariables(id); + + return new ResponseEntity>(result, HttpStatus.OK); + +// CMISUser user = cmisService.getCMISUserFromSession(req); +// LOGGER.debug("getTaskVariables user: "+ user +", id: "+id); +// +// try { +// Map workflowVariables = workflowService.getTaskVariables(user, id); +// JSONObject res = new JSONObject(workflowVariables); +// PrintWriter writer = resp.getWriter(); +// writer.write(res.toString()); +// writer.flush(); +// // return new ResponseEntity>(workflowVariables, HttpStatus.OK); +// } catch (IllegalAccessException e) { +// LOGGER.info(ERRORE_PERMESSI_TASK); +// LOGGER.info("L'utente ha richiesto variabili per un flusso che non deve poter vedere", e); +// getVariablesOldMethod(req, resp, id); +// // return new ResponseEntity>(HttpStatus.FORBIDDEN);// ;resp.sendError(HttpServletResponse.SC_FORBIDDEN); +// } catch (WorkflowException e) { +// LOGGER.info("Errore durante il recupero di un flusso", e); +// resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); +// // return new ResponseEntity>(HttpStatus.INTERNAL_SERVER_ERROR);//resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); +// } + } + + @RequestMapping(value = "complete/{id}", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @Timed + public ResponseEntity> completeTask( + HttpServletRequest req, + @PathVariable("id") String id, + @RequestBody Map data) { + + taskService.complete(id); + + return new ResponseEntity>(HttpStatus.OK); + +// CMISUser user = cmisService.getCMISUserFromSession(req); +// BindingSession session = cmisService.getCurrentBindingSession(req); +// boolean userHasWriteAccessToTask = true; // TODO +// +// if (userHasWriteAccessToTask) { +// try { +// workflowService.completeTask(user, id, data, session); +// } catch (AlfrescoResponseException e) { +// LOGGER.error(e.getMessage() + " " + e.getResponse(), e); +// return new ResponseEntity>(e.getResponse(), HttpStatus.INTERNAL_SERVER_ERROR); +// } catch (PermissionException e) { +// LOGGER.error(e.getMessage(), e); +// return new ResponseEntity>(HttpStatus.FORBIDDEN); +// } catch (IOException e) { +// LOGGER.error(e.getMessage(), e); +// Map response = new HashMap<>(); +// response.put("error", e.getMessage()); +// return new ResponseEntity>(response, HttpStatus.INTERNAL_SERVER_ERROR); +// } +// } +// +// return null; + } + + public static long extractId(String id) throws IllegalArgumentException { + try { + if (id.contains("$")) + id = id.split("\\$")[1]; + return Long.parseLong(id); + + } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + throw new IllegalArgumentException("L'id dato non è valido", e); + } + } +} diff --git a/src/main/java/it/cnr/si/flows/ng/resource/ProcessDefinitionResource.java b/src/main/java/it/cnr/si/flows/ng/resource/ProcessDefinitionResource.java new file mode 100644 index 000000000..eb3035f5b --- /dev/null +++ b/src/main/java/it/cnr/si/flows/ng/resource/ProcessDefinitionResource.java @@ -0,0 +1,72 @@ +package it.cnr.si.flows.ng.resource; + +import java.util.List; + +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.rest.common.api.DataResponse; +import org.activiti.rest.service.api.RestResponseFactory; +import org.activiti.rest.service.api.repository.ProcessDefinitionResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.codahale.metrics.annotation.Timed; + +import it.cnr.si.security.AuthoritiesConstants; + +@RestController +@RequestMapping("rest/processdefinitions") +public class ProcessDefinitionResource { + + @Autowired + private RuntimeService runtimeService; + + @Autowired + private RepositoryService repositoryService; + + @Autowired + protected RestResponseFactory restResponseFactory; + + @RequestMapping(value = "/all", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured(AuthoritiesConstants.USER) + @Timed + public Object getAllProcessDefinitions() { + + List listraw = repositoryService.createProcessDefinitionQuery().latestVersion().list(); + + List list = restResponseFactory.createProcessDefinitionResponseList(listraw); + + // Get result and set pagination parameters + DataResponse response = new DataResponse(); + response.setStart(0); + response.setSize(list.size()); + response.setTotal(list.size()); + response.setData(list); + return response; + + + } + + @RequestMapping(value = "/{key}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured(AuthoritiesConstants.USER) + @Timed + public ResponseEntity getProcessDefinitionById(@PathVariable String key) { + + ProcessDefinition definitionraw = repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).latestVersion().singleResult(); + + if (definitionraw != null) { + ProcessDefinitionResponse definition = restResponseFactory.createProcessDefinitionResponse(definitionraw); + return ResponseEntity.ok(definition); + } else { + return ResponseEntity.notFound().build(); + } + } + +} diff --git a/src/main/resources/.h2.server.properties b/src/main/resources/.h2.server.properties new file mode 100644 index 000000000..02906e9dd --- /dev/null +++ b/src/main/resources/.h2.server.properties @@ -0,0 +1,5 @@ +#H2 Server Properties +0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:sprint|sprint +webAllowOthers=true +webPort=8082 +webSSL=false diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 000000000..1e0423130 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,9 @@ + + ${AnsiColor.GREEN} ██ ${AnsiColor.RED} ██ ██ ████████ ███████ ██████ ████████ ████████ ███████ + ${AnsiColor.GREEN} ██ ${AnsiColor.RED} ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ${AnsiColor.GREEN} ██ ${AnsiColor.RED} ████████ ██ ███████ █████ ██ ██████ ███████ + ${AnsiColor.GREEN}██ ██ ${AnsiColor.RED} ██ ██ ██ ██ ██ ██ ██ ██ ██ + ${AnsiColor.GREEN} ██████ ${AnsiColor.RED} ██ ██ ████████ ██ ██████ ██ ████████ ██ ██ + +${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} :: +:: http://jhipster.github.io ::${AnsiColor.DEFAULT} diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties new file mode 100644 index 000000000..e3b893486 --- /dev/null +++ b/src/main/resources/i18n/messages.properties @@ -0,0 +1,22 @@ +# Error page +error.title=Your request cannot be processed +error.subtitle=Sorry, an error has occurred. +error.status=Status: +error.message=Message: + +# Activation e-mail +email.activation.title=sprint account activation +email.activation.greeting=Dear {0} +email.activation.text1=Your sprint account has been created, please click on the URL below to activate it: +email.activation.text2=Regards, +email.signature=sprint Team. + +# Creation email +email.creation.text1=Your sprint account has been created, please click on the URL below to access it: + +# Reset e-mail +email.reset.title=sprint password reset +email.reset.greeting=Dear {0} +email.reset.text1=For your sprint account a password reset was requested, please click on the URL below to reset it: +email.reset.text2=Regards, + diff --git a/src/main/resources/i18n/messages_it.properties b/src/main/resources/i18n/messages_it.properties new file mode 100644 index 000000000..ca0c2bd27 --- /dev/null +++ b/src/main/resources/i18n/messages_it.properties @@ -0,0 +1,22 @@ +# Error page +error.title=La tua richiesta non può essere processata +error.subtitle= E' stato riscontrato un errore. +error.status=Stato: +error.message=Messaggio: + +# Activation e-mail +email.activation.title=sprint attivazione +email.activation.greeting=Caro {0} +email.activation.text1=Il tuo account sprint è stato creato, clicca sul link qui sotto per attivare: +email.activation.text2=Saluti, +email.signature=sprint. + +# Creation email +email.creation.text1=L'account sprint è stato attivato, clicca sul link qui sotto per accedere: + +# Reset e-mail +email.reset.title=sprint reimpostazione della password +email.reset.greeting=Caro {0} +email.reset.text1=E' stata richiesta una reimpostazione della password per il tuo account sprint, clicca sul seguente URL per ripristinarlo: +email.reset.text2=Saluti, + diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..3d3661faf --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + diff --git a/src/main/resources/processes/PermessiFerieProcess.bpmn20.xml b/src/main/resources/processes/PermessiFerieProcess.bpmn20.xml new file mode 100644 index 000000000..66a4ded17 --- /dev/null +++ b/src/main/resources/processes/PermessiFerieProcess.bpmn20.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/processes/hire.bpmn20.xml b/src/main/resources/processes/hire.bpmn20.xml new file mode 100644 index 000000000..b34d6ad70 --- /dev/null +++ b/src/main/resources/processes/hire.bpmn20.xml @@ -0,0 +1,229 @@ + + + + + + Conduct a telephone interview with ${applicantName}. Phone number = ${phoneNumber} + + + + + + + + + ${email} + + + test@activiti.org + + + + + + Dear ${applicantName}, + +We're sorry to inform you that your recent application has been rejected. We have stored your information in our data systems and will contact you if in the future a potential matching application is posted on our website. + +Regards, +My Corp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${email} + + + test@activiti.org + + + + + + Dear ${applicantName}, + +We're happy to inform you that your recent application has been accepted. We will contact you soon for more information. + +Regards, +My Corp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/.gitignore b/src/main/webapp/.gitignore new file mode 100644 index 000000000..fbe05fc93 --- /dev/null +++ b/src/main/webapp/.gitignore @@ -0,0 +1 @@ +bower_components/ diff --git a/src/main/webapp/404.html b/src/main/webapp/404.html new file mode 100644 index 000000000..0a55b15b6 --- /dev/null +++ b/src/main/webapp/404.html @@ -0,0 +1,60 @@ + + + + + Page Not Found + + + + + Page Not Found + Sorry, but the page you were trying to view does not exist. + + + diff --git a/src/main/webapp/app/account/account.state.js b/src/main/webapp/app/account/account.state.js new file mode 100644 index 000000000..bb08a7a11 --- /dev/null +++ b/src/main/webapp/app/account/account.state.js @@ -0,0 +1,16 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('account', { + abstract: true, + parent: 'app' + }); + } +})(); diff --git a/src/main/webapp/app/account/activate/activate.controller.js b/src/main/webapp/app/account/activate/activate.controller.js new file mode 100644 index 000000000..84a893ab1 --- /dev/null +++ b/src/main/webapp/app/account/activate/activate.controller.js @@ -0,0 +1,23 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('ActivationController', ActivationController); + + ActivationController.$inject = ['$stateParams', 'Auth', 'LoginService']; + + function ActivationController ($stateParams, Auth, LoginService) { + var vm = this; + + Auth.activateAccount({key: $stateParams.key}).then(function () { + vm.error = null; + vm.success = 'OK'; + }).catch(function () { + vm.success = null; + vm.error = 'ERROR'; + }); + + vm.login = LoginService.open; + } +})(); diff --git a/src/main/webapp/app/account/activate/activate.html b/src/main/webapp/app/account/activate/activate.html new file mode 100644 index 000000000..dd5779d3e --- /dev/null +++ b/src/main/webapp/app/account/activate/activate.html @@ -0,0 +1,16 @@ + + + + Activation + + + Your user has been activated. Please sign in. + + + + Your user could not be activated. Please use the registration form to sign up. + + + + + diff --git a/src/main/webapp/app/account/activate/activate.state.js b/src/main/webapp/app/account/activate/activate.state.js new file mode 100644 index 000000000..90cfa8135 --- /dev/null +++ b/src/main/webapp/app/account/activate/activate.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('activate', { + parent: 'account', + url: '/activate?key', + data: { + authorities: [], + pageTitle: 'activate.title' + }, + views: { + 'content@': { + templateUrl: 'app/account/activate/activate.html', + controller: 'ActivationController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('activate'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/account/password/password-strength-bar.directive.js b/src/main/webapp/app/account/password/password-strength-bar.directive.js new file mode 100644 index 000000000..f9f7f5b78 --- /dev/null +++ b/src/main/webapp/app/account/password/password-strength-bar.directive.js @@ -0,0 +1,95 @@ +/* globals $ */ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('passwordStrengthBar', passwordStrengthBar); + + function passwordStrengthBar () { + var directive = { + replace: true, + restrict: 'E', + template: '' + + 'Password strength:' + + '' + + '' + + '' + + '', + scope: { + passwordToCheck: '=' + }, + link: linkFunc + }; + + return directive; + + /* private helper methods*/ + + function linkFunc(scope, iElement) { + var strength = { + colors: ['#F00', '#F90', '#FF0', '#9F0', '#0F0'], + mesureStrength: function (p) { + + var _force = 0; + var _regex = /[$-/:-?{-~!"^_`\[\]]/g; // " + + var _lowerLetters = /[a-z]+/.test(p); + var _upperLetters = /[A-Z]+/.test(p); + var _numbers = /[0-9]+/.test(p); + var _symbols = _regex.test(p); + + var _flags = [_lowerLetters, _upperLetters, _numbers, _symbols]; + var _passedMatches = $.grep(_flags, function (el) { + return el === true; + }).length; + + _force += 2 * p.length + ((p.length >= 10) ? 1 : 0); + _force += _passedMatches * 10; + + // penality (short password) + _force = (p.length <= 6) ? Math.min(_force, 10) : _force; + + // penality (poor variety of characters) + _force = (_passedMatches === 1) ? Math.min(_force, 10) : _force; + _force = (_passedMatches === 2) ? Math.min(_force, 20) : _force; + _force = (_passedMatches === 3) ? Math.min(_force, 40) : _force; + + return _force; + + }, + getColor: function (s) { + + var idx = 0; + if (s <= 10) { + idx = 0; + } + else if (s <= 20) { + idx = 1; + } + else if (s <= 30) { + idx = 2; + } + else if (s <= 40) { + idx = 3; + } + else { + idx = 4; + } + + return { idx: idx + 1, col: this.colors[idx] }; + } + }; + scope.$watch('passwordToCheck', function (password) { + if (password) { + var c = strength.getColor(strength.mesureStrength(password)); + iElement.removeClass('ng-hide'); + iElement.find('ul').children('li') + .css({ 'background-color': '#DDD' }) + .slice(0, c.idx) + .css({ 'background-color': c.col }); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/account/password/password.controller.js b/src/main/webapp/app/account/password/password.controller.js new file mode 100644 index 000000000..f29bb338e --- /dev/null +++ b/src/main/webapp/app/account/password/password.controller.js @@ -0,0 +1,39 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('PasswordController', PasswordController); + + PasswordController.$inject = ['Auth', 'Principal']; + + function PasswordController (Auth, Principal) { + var vm = this; + + vm.changePassword = changePassword; + vm.doNotMatch = null; + vm.error = null; + vm.success = null; + + Principal.identity().then(function(account) { + vm.account = account; + }); + + function changePassword () { + if (vm.password !== vm.confirmPassword) { + vm.error = null; + vm.success = null; + vm.doNotMatch = 'ERROR'; + } else { + vm.doNotMatch = null; + Auth.changePassword(vm.password).then(function () { + vm.error = null; + vm.success = 'OK'; + }).catch(function () { + vm.success = null; + vm.error = 'ERROR'; + }); + } + } + } +})(); diff --git a/src/main/webapp/app/account/password/password.html b/src/main/webapp/app/account/password/password.html new file mode 100644 index 000000000..da400acb5 --- /dev/null +++ b/src/main/webapp/app/account/password/password.html @@ -0,0 +1,63 @@ + + + + Password for [{{vm.account.login}}] + + + Password changed! + + + An error has occurred! The password could not be changed. + + + + The password and its confirmation do not match! + + + + + + New password + + + + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + + + + + + New password confirmation + + + + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + + + + + Save + + + + diff --git a/src/main/webapp/app/account/password/password.state.js b/src/main/webapp/app/account/password/password.state.js new file mode 100644 index 000000000..d5d92450c --- /dev/null +++ b/src/main/webapp/app/account/password/password.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('password', { + parent: 'account', + url: '/password', + data: { + authorities: ['ROLE_USER'], + pageTitle: 'global.menu.account.password' + }, + views: { + 'content@': { + templateUrl: 'app/account/password/password.html', + controller: 'PasswordController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('password'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/account/register/register.controller.js b/src/main/webapp/app/account/register/register.controller.js new file mode 100644 index 000000000..dd2445ddc --- /dev/null +++ b/src/main/webapp/app/account/register/register.controller.js @@ -0,0 +1,49 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('RegisterController', RegisterController); + + + RegisterController.$inject = ['$translate', '$timeout', 'Auth', 'LoginService']; + + function RegisterController ($translate, $timeout, Auth, LoginService) { + var vm = this; + + vm.doNotMatch = null; + vm.error = null; + vm.errorUserExists = null; + vm.login = LoginService.open; + vm.register = register; + vm.registerAccount = {}; + vm.success = null; + + $timeout(function (){angular.element('#login').focus();}); + + function register () { + if (vm.registerAccount.password !== vm.confirmPassword) { + vm.doNotMatch = 'ERROR'; + } else { + vm.registerAccount.langKey = $translate.use(); + vm.doNotMatch = null; + vm.error = null; + vm.errorUserExists = null; + vm.errorEmailExists = null; + + Auth.createAccount(vm.registerAccount).then(function () { + vm.success = 'OK'; + }).catch(function (response) { + vm.success = null; + if (response.status === 400 && response.data === 'login already in use') { + vm.errorUserExists = 'ERROR'; + } else if (response.status === 400 && response.data === 'e-mail address already in use') { + vm.errorEmailExists = 'ERROR'; + } else { + vm.error = 'ERROR'; + } + }); + } + } + } +})(); diff --git a/src/main/webapp/app/account/register/register.html b/src/main/webapp/app/account/register/register.html new file mode 100644 index 000000000..b98190603 --- /dev/null +++ b/src/main/webapp/app/account/register/register.html @@ -0,0 +1,123 @@ + + + + Registration + + + Registration saved! Please check your email for confirmation. + + + + Registration failed! Please try again later. + + + + Login name already registered! Please choose another one. + + + + E-mail is already in use! Please choose another one. + + + + The password and its confirmation do not match! + + + + + + + Username + + + + Your username is required. + + + Your username is required to be at least 1 character. + + + Your username cannot be longer than 50 characters. + + + Your username can only contain lower-case letters and digits. + + + + + E-mail + + + + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + + + + + New password + + + + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + + + + + + New password confirmation + + + + Your confirmation password is required. + + + Your confirmation password is required to be at least 4 characters. + + + Your confirmation password cannot be longer than 50 characters. + + + + + Register + + + + If you want to sign in, you can try the default accounts:- Administrator (login="admin" and password="admin") - User (login="user" and password="user"). + + + + diff --git a/src/main/webapp/app/account/register/register.state.js b/src/main/webapp/app/account/register/register.state.js new file mode 100644 index 000000000..c5b916595 --- /dev/null +++ b/src/main/webapp/app/account/register/register.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('register', { + parent: 'account', + url: '/register', + data: { + authorities: [], + pageTitle: 'register.title' + }, + views: { + 'content@': { + templateUrl: 'app/account/register/register.html', + controller: 'RegisterController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('register'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/account/reset/finish/reset.finish.controller.js b/src/main/webapp/app/account/reset/finish/reset.finish.controller.js new file mode 100644 index 000000000..2395a63dc --- /dev/null +++ b/src/main/webapp/app/account/reset/finish/reset.finish.controller.js @@ -0,0 +1,39 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('ResetFinishController', ResetFinishController); + + ResetFinishController.$inject = ['$stateParams', '$timeout', 'Auth', 'LoginService']; + + function ResetFinishController ($stateParams, $timeout, Auth, LoginService) { + var vm = this; + + vm.keyMissing = angular.isUndefined($stateParams.key); + vm.confirmPassword = null; + vm.doNotMatch = null; + vm.error = null; + vm.finishReset = finishReset; + vm.login = LoginService.open; + vm.resetAccount = {}; + vm.success = null; + + $timeout(function (){angular.element('#password').focus();}); + + function finishReset() { + vm.doNotMatch = null; + vm.error = null; + if (vm.resetAccount.password !== vm.confirmPassword) { + vm.doNotMatch = 'ERROR'; + } else { + Auth.resetPasswordFinish({key: $stateParams.key, newPassword: vm.resetAccount.password}).then(function () { + vm.success = 'OK'; + }).catch(function () { + vm.success = null; + vm.error = 'ERROR'; + }); + } + } + } +})(); diff --git a/src/main/webapp/app/account/reset/finish/reset.finish.html b/src/main/webapp/app/account/reset/finish/reset.finish.html new file mode 100644 index 000000000..2c45df7d6 --- /dev/null +++ b/src/main/webapp/app/account/reset/finish/reset.finish.html @@ -0,0 +1,74 @@ + + + + Reset password + + + The password reset key is missing. + + + + Choose a new password + + + + Your password couldn't be reset. Remember a password request is only valid for 24 hours. + + + + Your password has been reset. Please sign in. + + + + The password and its confirmation do not match! + + + + + + New password + + + + Your password is required. + + + Your password is required to be at least 4 characters. + + + Your password cannot be longer than 50 characters. + + + + + + + New password confirmation + + + + Your password confirmation is required. + + + Your password confirmation is required to be at least 4 characters. + + + Your password confirmation cannot be longer than 50 characters. + + + + Reset Password + + + + + + diff --git a/src/main/webapp/app/account/reset/finish/reset.finish.state.js b/src/main/webapp/app/account/reset/finish/reset.finish.state.js new file mode 100644 index 000000000..84303432f --- /dev/null +++ b/src/main/webapp/app/account/reset/finish/reset.finish.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('finishReset', { + parent: 'account', + url: '/reset/finish?key', + data: { + authorities: [] + }, + views: { + 'content@': { + templateUrl: 'app/account/reset/finish/reset.finish.html', + controller: 'ResetFinishController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('reset'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/account/reset/request/reset.request.controller.js b/src/main/webapp/app/account/reset/request/reset.request.controller.js new file mode 100644 index 000000000..e29abda5f --- /dev/null +++ b/src/main/webapp/app/account/reset/request/reset.request.controller.js @@ -0,0 +1,38 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('RequestResetController', RequestResetController); + + RequestResetController.$inject = ['$timeout', 'Auth']; + + function RequestResetController ($timeout, Auth) { + var vm = this; + + vm.error = null; + vm.errorEmailNotExists = null; + vm.requestReset = requestReset; + vm.resetAccount = {}; + vm.success = null; + + $timeout(function (){angular.element('#email').focus();}); + + function requestReset () { + + vm.error = null; + vm.errorEmailNotExists = null; + + Auth.resetPasswordInit(vm.resetAccount.email).then(function () { + vm.success = 'OK'; + }).catch(function (response) { + vm.success = null; + if (response.status === 400 && response.data === 'e-mail address not registered') { + vm.errorEmailNotExists = 'ERROR'; + } else { + vm.error = 'ERROR'; + } + }); + } + } +})(); diff --git a/src/main/webapp/app/account/reset/request/reset.request.html b/src/main/webapp/app/account/reset/request/reset.request.html new file mode 100644 index 000000000..95a5c6258 --- /dev/null +++ b/src/main/webapp/app/account/reset/request/reset.request.html @@ -0,0 +1,47 @@ + + + + Reset your password + + + E-Mail address isn't registered! Please check and try again. + + + + Enter the e-mail address you used to register. + + + + Check your e-mails for details on how to reset your password. + + + + + E-mail + + + + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + + + + Reset + + + + + diff --git a/src/main/webapp/app/account/reset/request/reset.request.state.js b/src/main/webapp/app/account/reset/request/reset.request.state.js new file mode 100644 index 000000000..1d587a9aa --- /dev/null +++ b/src/main/webapp/app/account/reset/request/reset.request.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('requestReset', { + parent: 'account', + url: '/reset/request', + data: { + authorities: [] + }, + views: { + 'content@': { + templateUrl: 'app/account/reset/request/reset.request.html', + controller: 'RequestResetController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('reset'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/account/settings/settings.controller.js b/src/main/webapp/app/account/settings/settings.controller.js new file mode 100644 index 000000000..64f0c80fe --- /dev/null +++ b/src/main/webapp/app/account/settings/settings.controller.js @@ -0,0 +1,54 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('SettingsController', SettingsController); + + SettingsController.$inject = ['Principal', 'Auth', 'JhiLanguageService', '$translate']; + + function SettingsController (Principal, Auth, JhiLanguageService, $translate) { + var vm = this; + + vm.error = null; + vm.save = save; + vm.settingsAccount = null; + vm.success = null; + + /** + * Store the "settings account" in a separate variable, and not in the shared "account" variable. + */ + var copyAccount = function (account) { + return { + activated: account.activated, + email: account.email, + firstName: account.firstName, + langKey: account.langKey, + lastName: account.lastName, + login: account.login + }; + }; + + Principal.identity().then(function(account) { + vm.settingsAccount = copyAccount(account); + }); + + function save () { + Auth.updateAccount(vm.settingsAccount).then(function() { + vm.error = null; + vm.success = 'OK'; + Principal.identity(true).then(function(account) { + vm.settingsAccount = copyAccount(account); + }); + JhiLanguageService.getCurrent().then(function(current) { + if (vm.settingsAccount.langKey !== current) { + $translate.use(vm.settingsAccount.langKey); + } + }); + }).catch(function() { + vm.success = null; + vm.error = 'ERROR'; + }); + } + } +})(); diff --git a/src/main/webapp/app/account/settings/settings.html b/src/main/webapp/app/account/settings/settings.html new file mode 100644 index 000000000..1e9c5daf0 --- /dev/null +++ b/src/main/webapp/app/account/settings/settings.html @@ -0,0 +1,85 @@ + + + + User settings for [{{vm.settingsAccount.login}}] + + + Settings saved! + + + + + + + + First Name + + + + Your first name is required. + + + Your first name is required to be at least 1 character. + + + Your first name cannot be longer than 50 characters. + + + + + Last Name + + + + Your last name is required. + + + Your last name is required to be at least 1 character. + + + Your last name cannot be longer than 50 characters. + + + + + E-mail + + + + Your e-mail is required. + + + Your e-mail is invalid. + + + Your e-mail is required to be at least 5 characters. + + + Your e-mail cannot be longer than 100 characters. + + + + + Language + + + + Save + + + + + diff --git a/src/main/webapp/app/account/settings/settings.state.js b/src/main/webapp/app/account/settings/settings.state.js new file mode 100644 index 000000000..388b29451 --- /dev/null +++ b/src/main/webapp/app/account/settings/settings.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('settings', { + parent: 'account', + url: '/settings', + data: { + authorities: ['ROLE_USER'], + pageTitle: 'global.menu.account.settings' + }, + views: { + 'content@': { + templateUrl: 'app/account/settings/settings.html', + controller: 'SettingsController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('settings'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/admin.state.js b/src/main/webapp/app/admin/admin.state.js new file mode 100644 index 000000000..5d413ff85 --- /dev/null +++ b/src/main/webapp/app/admin/admin.state.js @@ -0,0 +1,16 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig ($stateProvider) { + $stateProvider.state('admin', { + abstract: true, + parent: 'app' + }); + } +})(); diff --git a/src/main/webapp/app/admin/audits/audits.controller.js b/src/main/webapp/app/admin/audits/audits.controller.js new file mode 100644 index 000000000..8fd80e499 --- /dev/null +++ b/src/main/webapp/app/admin/audits/audits.controller.js @@ -0,0 +1,63 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('AuditsController', AuditsController); + + AuditsController.$inject = ['$filter', 'AuditsService', 'ParseLinks']; + + function AuditsController ($filter, AuditsService, ParseLinks) { + var vm = this; + + vm.audits = null; + vm.fromDate = null; + vm.links = null; + vm.loadPage = loadPage; + vm.onChangeDate = onChangeDate; + vm.page = 1; + vm.previousMonth = previousMonth; + vm.toDate = null; + vm.today = today; + vm.totalItems = null; + + vm.today(); + vm.previousMonth(); + vm.onChangeDate(); + + function onChangeDate () { + var dateFormat = 'yyyy-MM-dd'; + var fromDate = $filter('date')(vm.fromDate, dateFormat); + var toDate = $filter('date')(vm.toDate, dateFormat); + + AuditsService.query({page: vm.page -1, size: 20, fromDate: fromDate, toDate: toDate}, function(result, headers){ + vm.audits = result; + vm.links = ParseLinks.parse(headers('link')); + vm.totalItems = headers('X-Total-Count'); + }); + } + + // Date picker configuration + function today () { + // Today + 1 day - needed if the current day must be included + var today = new Date(); + vm.toDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1); + } + + function previousMonth () { + var fromDate = new Date(); + if (fromDate.getMonth() === 0) { + fromDate = new Date(fromDate.getFullYear() - 1, 11, fromDate.getDate()); + } else { + fromDate = new Date(fromDate.getFullYear(), fromDate.getMonth() - 1, fromDate.getDate()); + } + + vm.fromDate = fromDate; + } + + function loadPage (page) { + vm.page = page; + vm.onChangeDate(); + } + } +})(); diff --git a/src/main/webapp/app/admin/audits/audits.html b/src/main/webapp/app/admin/audits/audits.html new file mode 100644 index 000000000..7aa778bb7 --- /dev/null +++ b/src/main/webapp/app/admin/audits/audits.html @@ -0,0 +1,41 @@ + + Audits + + + + Filter by date + + from + + to + + + + + + + + + + Date + User + State + Extra data + + + + + {{audit.timestamp| date:'medium'}} + {{audit.principal}} + {{audit.type}} + + {{audit.data.message}} + Remote Address {{audit.data.remoteAddress}} + + + + + + + + diff --git a/src/main/webapp/app/admin/audits/audits.service.js b/src/main/webapp/app/admin/audits/audits.service.js new file mode 100644 index 000000000..96b46d1ad --- /dev/null +++ b/src/main/webapp/app/admin/audits/audits.service.js @@ -0,0 +1,25 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('AuditsService', AuditsService); + + AuditsService.$inject = ['$resource']; + + function AuditsService ($resource) { + var service = $resource('management/jhipster/audits/:id', {}, { + 'get': { + method: 'GET', + isArray: true + }, + 'query': { + method: 'GET', + isArray: true, + params: {fromDate: null, toDate: null} + } + }); + + return service; + } +})(); diff --git a/src/main/webapp/app/admin/audits/audits.state.js b/src/main/webapp/app/admin/audits/audits.state.js new file mode 100644 index 000000000..4dbbdfdf7 --- /dev/null +++ b/src/main/webapp/app/admin/audits/audits.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('audits', { + parent: 'admin', + url: '/audits', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'audits.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/audits/audits.html', + controller: 'AuditsController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('audits'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/configuration/configuration.controller.js b/src/main/webapp/app/admin/configuration/configuration.controller.js new file mode 100644 index 000000000..1e4d7d928 --- /dev/null +++ b/src/main/webapp/app/admin/configuration/configuration.controller.js @@ -0,0 +1,23 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('JhiConfigurationController', JhiConfigurationController); + + JhiConfigurationController.$inject = ['$filter','JhiConfigurationService']; + + function JhiConfigurationController (filter,JhiConfigurationService) { + var vm = this; + + vm.allConfiguration = null; + vm.configuration = null; + + JhiConfigurationService.get().then(function(configuration) { + vm.configuration = configuration; + }); + JhiConfigurationService.getEnv().then(function (configuration) { + vm.allConfiguration = configuration; + }); + } +})(); diff --git a/src/main/webapp/app/admin/configuration/configuration.html b/src/main/webapp/app/admin/configuration/configuration.html new file mode 100644 index 000000000..705263049 --- /dev/null +++ b/src/main/webapp/app/admin/configuration/configuration.html @@ -0,0 +1,47 @@ + + Configuration + + Filter (by prefix) + Spring configuration + + + + Prefix + Properties + + + + + {{entry.prefix}} + + + {{key}} + + {{value}} + + + + + + + {{key}} + + + + Property + Value + + + + + {{item.key}} + + {{item.val}} + + + + + + diff --git a/src/main/webapp/app/admin/configuration/configuration.service.js b/src/main/webapp/app/admin/configuration/configuration.service.js new file mode 100644 index 000000000..2d1991501 --- /dev/null +++ b/src/main/webapp/app/admin/configuration/configuration.service.js @@ -0,0 +1,47 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('JhiConfigurationService', JhiConfigurationService); + + JhiConfigurationService.$inject = ['$filter', '$http']; + + function JhiConfigurationService ($filter, $http) { + var service = { + get: get, + getEnv: getEnv + }; + + return service; + + function get () { + return $http.get('management/configprops').then(getConfigPropsComplete); + + function getConfigPropsComplete (response) { + var properties = []; + angular.forEach(response.data, function (data) { + properties.push(data); + }); + var orderBy = $filter('orderBy'); + return orderBy(properties, 'prefix'); + } + } + + function getEnv () { + return $http.get('management/env').then(getEnvComplete); + + function getEnvComplete (response) { + var properties = {}; + angular.forEach(response.data, function (val,key) { + var vals = []; + angular.forEach(val, function (v,k) { + vals.push({ key:k, val:v }); + }); + properties[key] = vals; + }); + return properties; + } + } + } +})(); diff --git a/src/main/webapp/app/admin/configuration/configuration.state.js b/src/main/webapp/app/admin/configuration/configuration.state.js new file mode 100644 index 000000000..7c63b7a6e --- /dev/null +++ b/src/main/webapp/app/admin/configuration/configuration.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('jhi-configuration', { + parent: 'admin', + url: '/configuration', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'configuration.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/configuration/configuration.html', + controller: 'JhiConfigurationController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('configuration'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/docs/docs.html b/src/main/webapp/app/admin/docs/docs.html new file mode 100644 index 000000000..24ab028f4 --- /dev/null +++ b/src/main/webapp/app/admin/docs/docs.html @@ -0,0 +1,2 @@ + diff --git a/src/main/webapp/app/admin/docs/docs.state.js b/src/main/webapp/app/admin/docs/docs.state.js new file mode 100644 index 000000000..6fcec93a9 --- /dev/null +++ b/src/main/webapp/app/admin/docs/docs.state.js @@ -0,0 +1,30 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig ($stateProvider) { + $stateProvider.state('docs', { + parent: 'admin', + url: '/docs', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'global.menu.admin.apidocs' + }, + views: { + 'content@': { + templateUrl: 'app/admin/docs/docs.html' + } + }, + resolve: { + translatePartialLoader: ['$translate', function ($translate) { + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/health/health.controller.js b/src/main/webapp/app/admin/health/health.controller.js new file mode 100644 index 000000000..304abe204 --- /dev/null +++ b/src/main/webapp/app/admin/health/health.controller.js @@ -0,0 +1,63 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('JhiHealthCheckController', JhiHealthCheckController); + + JhiHealthCheckController.$inject = ['JhiHealthService', '$uibModal']; + + function JhiHealthCheckController (JhiHealthService, $uibModal) { + var vm = this; + + vm.updatingHealth = true; + vm.getLabelClass = getLabelClass; + vm.refresh = refresh; + vm.showHealth = showHealth; + vm.baseName = JhiHealthService.getBaseName; + vm.subSystemName = JhiHealthService.getSubSystemName; + + vm.refresh(); + + function getLabelClass (statusState) { + if (statusState === 'UP') { + return 'label-success'; + } else { + return 'label-danger'; + } + } + + function refresh () { + vm.updatingHealth = true; + JhiHealthService.checkHealth().then(function (response) { + vm.healthData = JhiHealthService.transformHealthData(response); + vm.updatingHealth = false; + }, function (response) { + vm.healthData = JhiHealthService.transformHealthData(response.data); + vm.updatingHealth = false; + }); + } + + function showHealth (health) { + $uibModal.open({ + templateUrl: 'app/admin/health/health.modal.html', + controller: 'HealthModalController', + controllerAs: 'vm', + size: 'lg', + resolve: { + currentHealth: function() { + return health; + }, + baseName: function() { + return vm.baseName; + }, + subSystemName: function() { + return vm.subSystemName; + } + + } + }); + } + + } +})(); diff --git a/src/main/webapp/app/admin/health/health.html b/src/main/webapp/app/admin/health/health.html new file mode 100644 index 000000000..9040d9ef2 --- /dev/null +++ b/src/main/webapp/app/admin/health/health.html @@ -0,0 +1,34 @@ + + Health Checks + + + Refresh + + + + + + + Service Name + Status + Details + + + + + + {{'health.indicator.' + vm.baseName(health.name) | translate}} {{vm.subSystemName(health.name)}} + + + {{'health.status.' + health.status | translate}} + + + + + + + + + + + diff --git a/src/main/webapp/app/admin/health/health.modal.controller.js b/src/main/webapp/app/admin/health/health.modal.controller.js new file mode 100644 index 000000000..2ab2a2412 --- /dev/null +++ b/src/main/webapp/app/admin/health/health.modal.controller.js @@ -0,0 +1,21 @@ +(function() { + 'use strict'; + + angular.module('sprintApp') + .controller('HealthModalController', HealthModalController); + + HealthModalController.$inject = ['$uibModalInstance', 'currentHealth', 'baseName', 'subSystemName']; + + function HealthModalController ($uibModalInstance, currentHealth, baseName, subSystemName) { + var vm = this; + + vm.cancel = cancel; + vm.currentHealth = currentHealth; + vm.baseName = baseName; + vm.subSystemName = subSystemName; + + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } +})(); diff --git a/src/main/webapp/app/admin/health/health.modal.html b/src/main/webapp/app/admin/health/health.modal.html new file mode 100644 index 000000000..1b329c2a8 --- /dev/null +++ b/src/main/webapp/app/admin/health/health.modal.html @@ -0,0 +1,34 @@ + + × + + + {{'health.indicator.' + vm.baseName(vm.currentHealth.name) | translate}} + {{vm.subSystemName(vm.currentHealth.name)}} + + + + + Properties + + + + Name + Value + + + + + {{k}} + {{v}} + + + + + + Error + {{vm.currentHealth.error}} + + + diff --git a/src/main/webapp/app/admin/health/health.service.js b/src/main/webapp/app/admin/health/health.service.js new file mode 100644 index 000000000..06fa6a3ea --- /dev/null +++ b/src/main/webapp/app/admin/health/health.service.js @@ -0,0 +1,130 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('JhiHealthService', JhiHealthService); + + JhiHealthService.$inject = ['$rootScope', '$http']; + + function JhiHealthService ($rootScope, $http) { + var separator = '.'; + var service = { + checkHealth: checkHealth, + transformHealthData: transformHealthData, + getBaseName: getBaseName, + getSubSystemName: getSubSystemName + }; + + return service; + + function checkHealth () { + return $http.get('management/health').then(function (response) { + return response.data; + }); + } + + function transformHealthData (data) { + var response = []; + flattenHealthData(response, null, data); + return response; + } + + function getBaseName (name) { + if (name) { + var split = name.split('.'); + return split[0]; + } + } + + function getSubSystemName (name) { + if (name) { + var split = name.split('.'); + split.splice(0, 1); + var remainder = split.join('.'); + return remainder ? ' - ' + remainder : ''; + } + } + + /* private methods */ + function flattenHealthData (result, path, data) { + angular.forEach(data, function (value, key) { + if (isHealthObject(value)) { + if (hasSubSystem(value)) { + addHealthObject(result, false, value, getModuleName(path, key)); + flattenHealthData(result, getModuleName(path, key), value); + } else { + addHealthObject(result, true, value, getModuleName(path, key)); + } + } + }); + return result; + } + + function addHealthObject (result, isLeaf, healthObject, name) { + + var healthData = { + 'name': name + }; + var details = {}; + var hasDetails = false; + + angular.forEach(healthObject, function (value, key) { + if (key === 'status' || key === 'error') { + healthData[key] = value; + } else { + if (!isHealthObject(value)) { + details[key] = value; + hasDetails = true; + } + } + }); + + // Add the of the details + if (hasDetails) { + angular.extend(healthData, { 'details': details}); + } + + // Only add nodes if they provide additional information + if (isLeaf || hasDetails || healthData.error) { + result.push(healthData); + } + return healthData; + } + + function getModuleName (path, name) { + var result; + if (path && name) { + result = path + separator + name; + } else if (path) { + result = path; + } else if (name) { + result = name; + } else { + result = ''; + } + return result; + } + + function hasSubSystem (healthObject) { + var result = false; + angular.forEach(healthObject, function (value) { + if (value && value.status) { + result = true; + } + }); + return result; + } + + function isHealthObject (healthObject) { + var result = false; + angular.forEach(healthObject, function (value, key) { + if (key === 'status') { + result = true; + } + }); + return result; + } + + } +})(); diff --git a/src/main/webapp/app/admin/health/health.state.js b/src/main/webapp/app/admin/health/health.state.js new file mode 100644 index 000000000..bedfea4fa --- /dev/null +++ b/src/main/webapp/app/admin/health/health.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('jhi-health', { + parent: 'admin', + url: '/health', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'health.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/health/health.html', + controller: 'JhiHealthCheckController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('health'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/logs/logs.controller.js b/src/main/webapp/app/admin/logs/logs.controller.js new file mode 100644 index 000000000..b95f2f98f --- /dev/null +++ b/src/main/webapp/app/admin/logs/logs.controller.js @@ -0,0 +1,22 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('LogsController', LogsController); + + LogsController.$inject = ['LogsService']; + + function LogsController (LogsService) { + var vm = this; + + vm.changeLevel = changeLevel; + vm.loggers = LogsService.findAll(); + + function changeLevel (name, level) { + LogsService.changeLevel({name: name, level: level}, function () { + vm.loggers = LogsService.findAll(); + }); + } + } +})(); diff --git a/src/main/webapp/app/admin/logs/logs.html b/src/main/webapp/app/admin/logs/logs.html new file mode 100644 index 000000000..e35147b8f --- /dev/null +++ b/src/main/webapp/app/admin/logs/logs.html @@ -0,0 +1,27 @@ + + Logs + + There are {{ vm.loggers.length }} loggers. + + Filter + + + + + Name + Level + + + + + {{logger.name | characters:140}} + + TRACE + DEBUG + INFO + WARN + ERROR + + + + diff --git a/src/main/webapp/app/admin/logs/logs.service.js b/src/main/webapp/app/admin/logs/logs.service.js new file mode 100644 index 000000000..037e3dd01 --- /dev/null +++ b/src/main/webapp/app/admin/logs/logs.service.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('LogsService', LogsService); + + LogsService.$inject = ['$resource']; + + function LogsService ($resource) { + var service = $resource('management/jhipster/logs', {}, { + 'findAll': { method: 'GET', isArray: true}, + 'changeLevel': { method: 'PUT'} + }); + + return service; + } +})(); diff --git a/src/main/webapp/app/admin/logs/logs.state.js b/src/main/webapp/app/admin/logs/logs.state.js new file mode 100644 index 000000000..c1511d417 --- /dev/null +++ b/src/main/webapp/app/admin/logs/logs.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('logs', { + parent: 'admin', + url: '/logs', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'logs.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/logs/logs.html', + controller: 'LogsController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('logs'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/metrics/metrics.controller.js b/src/main/webapp/app/admin/metrics/metrics.controller.js new file mode 100644 index 000000000..0b433f5d3 --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.controller.js @@ -0,0 +1,76 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('JhiMetricsMonitoringController', JhiMetricsMonitoringController); + + JhiMetricsMonitoringController.$inject = ['$scope','JhiMetricsService', '$uibModal']; + + function JhiMetricsMonitoringController ($scope, JhiMetricsService, $uibModal) { + var vm = this; + + vm.cachesStats = {}; + vm.metrics = {}; + vm.refresh = refresh; + vm.refreshThreadDumpData = refreshThreadDumpData; + vm.servicesStats = {}; + vm.updatingMetrics = true; + vm.refresh(); + + JhiMetricsService.getBeans().then(function (promise) { + vm.beans = promise; + }); + $scope.$watch('vm.metrics', function (newValue) { + vm.servicesStats = {}; + vm.cachesStats = {}; + angular.forEach(newValue.timers, function (value, key) { + if (key.indexOf('web.rest') !== -1 || key.indexOf('service') !== -1) { + vm.servicesStats[key] = value; + } + if (key.indexOf('net.sf.ehcache.Cache') !== -1) { + // remove gets or puts + var index = key.lastIndexOf('.'); + var newKey = key.substr(0, index); + + // Keep the name of the domain + index = newKey.lastIndexOf('.'); + vm.cachesStats[newKey] = { + 'name': newKey.substr(index + 1), + 'value': value + }; + } + }); + }); + + function refresh () { + vm.updatingMetrics = true; + JhiMetricsService.getMetrics().then(function (promise) { + vm.metrics = promise; + vm.updatingMetrics = false; + }, function (promise) { + vm.metrics = promise.data; + vm.updatingMetrics = false; + }); + } + + function refreshThreadDumpData () { + JhiMetricsService.threadDump().then(function(data) { + $uibModal.open({ + templateUrl: 'app/admin/metrics/metrics.modal.html', + controller: 'JhiMetricsMonitoringModalController', + controllerAs: 'vm', + size: 'lg', + resolve: { + threadDump: function() { + return data; + } + + } + }); + }); + } + + + } +})(); diff --git a/src/main/webapp/app/admin/metrics/metrics.html b/src/main/webapp/app/admin/metrics/metrics.html new file mode 100644 index 000000000..88902a29f --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.html @@ -0,0 +1,213 @@ + + Application Metrics + + Refresh + + + JVM Metrics + + + Memory + Total Memory ({{vm.metrics.gauges['jvm.memory.total.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.total.max'].value / 1000000 | number:0}}M) + + {{vm.metrics.gauges['jvm.memory.total.used'].value * 100 / vm.metrics.gauges['jvm.memory.total.max'].value | number:0}}% + + Heap Memory ({{vm.metrics.gauges['jvm.memory.heap.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.heap.max'].value / 1000000 | number:0}}M) + + {{vm.metrics.gauges['jvm.memory.heap.used'].value * 100 / vm.metrics.gauges['jvm.memory.heap.max'].value | number:0}}% + + Non-Heap Memory ({{vm.metrics.gauges['jvm.memory.non-heap.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.non-heap.committed'].value / 1000000 | number:0}}M) + + {{vm.metrics.gauges['jvm.memory.non-heap.used'].value * 100 / vm.metrics.gauges['jvm.memory.non-heap.committed'].value | number:0}}% + + + + Threads (Total: {{vm.metrics.gauges['jvm.threads.count'].value}}) + Runnable {{vm.metrics.gauges['jvm.threads.runnable.count'].value}} + + {{vm.metrics.gauges['jvm.threads.runnable.count'].value * 100 / vm.metrics.gauges['jvm.threads.count'].value | number:0}}% + + Timed Waiting ({{vm.metrics.gauges['jvm.threads.timed_waiting.count'].value}}) + + {{vm.metrics.gauges['jvm.threads.timed_waiting.count'].value * 100 / vm.metrics.gauges['jvm.threads.count'].value | number:0}}% + + Waiting ({{vm.metrics.gauges['jvm.threads.waiting.count'].value}}) + + {{vm.metrics.gauges['jvm.threads.waiting.count'].value * 100 / vm.metrics.gauges['jvm.threads.count'].value | number:0}}% + + Blocked ({{vm.metrics.gauges['jvm.threads.blocked.count'].value}}) + + {{vm.metrics.gauges['jvm.threads.blocked.count'].value * 100 / vm.metrics.gauges['jvm.threads.count'].value | number:0}}% + + + + Garbage collections + + Mark Sweep count + {{vm.metrics.gauges['jvm.garbage.PS-MarkSweep.count'].value}} + + + Mark Sweep time + {{vm.metrics.gauges['jvm.garbage.PS-MarkSweep.time'].value}}ms + + + Scavenge count + {{vm.metrics.gauges['jvm.garbage.PS-Scavenge.count'].value}} + + + Scavenge time + {{vm.metrics.gauges['jvm.garbage.PS-Scavenge.time'].value}}ms + + + + Updating... + + HTTP requests (events per second) + Active requests {{vm.metrics.counters['com.codahale.metrics.servlet.InstrumentedFilter.activeRequests'].count | number:0}} - Total requests {{vm.metrics.timers['com.codahale.metrics.servlet.InstrumentedFilter.requests'].count | number:0}} + + + + + Code + Count + Mean + Average (1 min) + Average (5 min) + Average (15 min) + + + + + OK + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].count}} + + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].mean_rate | number:2}} + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m1_rate | number:2}} + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m5_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.ok'].m15_rate | number:2}} + + + + Not Found + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].count}} + + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].mean_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m1_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m5_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.notFound'].m15_rate | number:2}} + + + + Server error + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].count}} + + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].mean_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m1_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m5_rate | number:2}} + + + {{vm.metrics.meters['com.codahale.metrics.servlet.InstrumentedFilter.responseCodes.serverError'].m15_rate | number:2}} + + + + + + + Services statistics (time in millisecond) + + + + + Service name + Count + Mean + Min + p50 + p75 + p95 + p99 + Max + + + + + {{k}} + {{v.count}} + {{v.mean * 1000 | number:0}} + {{v.min * 1000 | number:0}} + {{v.p50 * 1000 | number:0}} + {{v.p75 * 1000 | number:0}} + {{v.p95 * 1000 | number:0}} + {{v.p99 * 1000 | number:0}} + {{v.max * 1000 | number:0}} + + + + + + DataSource statistics (time in millisecond) + + + + + Usage ({{vm.metrics.gauges['HikariPool-1.pool.ActiveConnections'].value}} / {{vm.metrics.gauges['HikariPool-1.pool.TotalConnections'].value}}) + Count + Mean + Min + p50 + p75 + p95 + p99 + Max + + + + + + + + {{vm.metrics.gauges['HikariPool-1.pool.ActiveConnections'].value * 100 / vm.metrics.gauges['HikariPool-1.pool.TotalConnections'].value | number:0}}% + + + + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].count}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].mean | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].min | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].p50 | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].p75 | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].p95 | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].p99 | number:2}} + {{vm.metrics.histograms['HikariPool-1.pool.Usage'].max | number:2}} + + + + {{vm.beans | json}} + + + diff --git a/src/main/webapp/app/admin/metrics/metrics.modal.controller.js b/src/main/webapp/app/admin/metrics/metrics.modal.controller.js new file mode 100644 index 000000000..1cc8e9096 --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.modal.controller.js @@ -0,0 +1,53 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('JhiMetricsMonitoringModalController', JhiMetricsMonitoringModalController); + + JhiMetricsMonitoringModalController.$inject = ['$uibModalInstance', 'threadDump']; + + function JhiMetricsMonitoringModalController ($uibModalInstance, threadDump) { + var vm = this; + + vm.cancel = cancel; + vm.getLabelClass = getLabelClass; + vm.threadDump = threadDump; + vm.threadDumpAll = 0; + vm.threadDumpBlocked = 0; + vm.threadDumpRunnable = 0; + vm.threadDumpTimedWaiting = 0; + vm.threadDumpWaiting = 0; + + angular.forEach(threadDump, function(value) { + if (value.threadState === 'RUNNABLE') { + vm.threadDumpRunnable += 1; + } else if (value.threadState === 'WAITING') { + vm.threadDumpWaiting += 1; + } else if (value.threadState === 'TIMED_WAITING') { + vm.threadDumpTimedWaiting += 1; + } else if (value.threadState === 'BLOCKED') { + vm.threadDumpBlocked += 1; + } + }); + + vm.threadDumpAll = vm.threadDumpRunnable + vm.threadDumpWaiting + + vm.threadDumpTimedWaiting + vm.threadDumpBlocked; + + function cancel () { + $uibModalInstance.dismiss('cancel'); + } + + function getLabelClass (threadState) { + if (threadState === 'RUNNABLE') { + return 'label-success'; + } else if (threadState === 'WAITING') { + return 'label-info'; + } else if (threadState === 'TIMED_WAITING') { + return 'label-warning'; + } else if (threadState === 'BLOCKED') { + return 'label-danger'; + } + } + } +})(); diff --git a/src/main/webapp/app/admin/metrics/metrics.modal.html b/src/main/webapp/app/admin/metrics/metrics.modal.html new file mode 100644 index 000000000..7d07d6aa1 --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.modal.html @@ -0,0 +1,53 @@ + + + × + Threads dump + + + All {{vm.threadDumpAll}} + Runnable {{vm.threadDumpRunnable}} + Waiting {{vm.threadDumpWaiting}} + Timed Waiting {{vm.threadDumpTimedWaiting}} + Blocked {{vm.threadDumpBlocked}} + + Filter + + + {{v.threadState}} {{v.threadName}} (ID {{v.threadId}}) + + Show StackTrace + Hide StackTrace + + + + + {{stV.className}}.{{stV.methodName}}({{stV.fileName}}:{{stV.lineNumber}}) + + + + + + + Blocked Time + Blocked Count + Waited Time + Waited Count + Lock Name + + + + + {{v.blockedTime}} + {{v.blockedCount}} + {{v.waitedTime}} + {{v.waitedCount}} + {{v.lockName}} + + + + + + + diff --git a/src/main/webapp/app/admin/metrics/metrics.service.js b/src/main/webapp/app/admin/metrics/metrics.service.js new file mode 100644 index 000000000..34bd09abd --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.service.js @@ -0,0 +1,37 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('JhiMetricsService', JhiMetricsService); + + JhiMetricsService.$inject = ['$rootScope', '$http']; + + function JhiMetricsService ($rootScope, $http) { + var service = { + getMetrics: getMetrics, + threadDump: threadDump, + getBeans: getBeans + }; + + return service; + + function getMetrics () { + return $http.get('management/jhipster/metrics').then(function (response) { + return response.data; + }); + } + + function threadDump () { + return $http.get('management/dump').then(function (response) { + return response.data; + }); + } + + function getBeans () { + return $http.get('management/beans').then(function (response) { + return response.data; + }); + } + } +})(); diff --git a/src/main/webapp/app/admin/metrics/metrics.state.js b/src/main/webapp/app/admin/metrics/metrics.state.js new file mode 100644 index 000000000..52a76c87e --- /dev/null +++ b/src/main/webapp/app/admin/metrics/metrics.state.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('jhi-metrics', { + parent: 'admin', + url: '/metrics', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'metrics.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/metrics/metrics.html', + controller: 'JhiMetricsMonitoringController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('metrics'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/admin/user-management/user-management-delete-dialog.controller.js b/src/main/webapp/app/admin/user-management/user-management-delete-dialog.controller.js new file mode 100644 index 000000000..1c0eb4504 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-delete-dialog.controller.js @@ -0,0 +1,28 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('UserManagementDeleteController', UserManagementDeleteController); + + UserManagementDeleteController.$inject = ['$uibModalInstance', 'entity', 'User']; + + function UserManagementDeleteController ($uibModalInstance, entity, User) { + var vm = this; + + vm.user = entity; + vm.clear = clear; + vm.confirmDelete = confirmDelete; + + function clear () { + $uibModalInstance.dismiss('cancel'); + } + + function confirmDelete (login) { + User.delete({login: login}, + function () { + $uibModalInstance.close(true); + }); + } + } +})(); diff --git a/src/main/webapp/app/admin/user-management/user-management-delete-dialog.html b/src/main/webapp/app/admin/user-management/user-management-delete-dialog.html new file mode 100644 index 000000000..25c6c1a85 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-delete-dialog.html @@ -0,0 +1,19 @@ + + + × + Confirm delete operation + + + + Are you sure you want to delete this User? + + + diff --git a/src/main/webapp/app/admin/user-management/user-management-detail.controller.js b/src/main/webapp/app/admin/user-management/user-management-detail.controller.js new file mode 100644 index 000000000..00e37ab83 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-detail.controller.js @@ -0,0 +1,24 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('UserManagementDetailController', UserManagementDetailController); + + UserManagementDetailController.$inject = ['$stateParams', 'User']; + + function UserManagementDetailController ($stateParams, User) { + var vm = this; + + vm.load = load; + vm.user = {}; + + vm.load($stateParams.login); + + function load (login) { + User.get({login: login}, function(result) { + vm.user = result; + }); + } + } +})(); diff --git a/src/main/webapp/app/admin/user-management/user-management-detail.html b/src/main/webapp/app/admin/user-management/user-management-detail.html new file mode 100644 index 000000000..28d02e7b3 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-detail.html @@ -0,0 +1,36 @@ + + User "{{vm.user.login}}" + + Login + {{vm.user.login}} + First Name + {{vm.user.firstName}} + Last Name + {{vm.user.lastName}} + Email + {{vm.user.email}} + Activated + {{vm.user.activated}} + Lang Key + {{vm.user.langKey}} + Created By + {{vm.user.createdBy}} + Created Date + {{vm.user.createdDate | date:'dd/MM/yy HH:mm' }} + Last Modified By + {{vm.user.lastModifiedBy}} + Last Modified Date + {{vm.user.lastModifiedDate | date:'dd/MM/yy HH:mm'}} + Profiles + + + {{authority}} + + + + + Back + + diff --git a/src/main/webapp/app/admin/user-management/user-management-dialog.controller.js b/src/main/webapp/app/admin/user-management/user-management-dialog.controller.js new file mode 100644 index 000000000..4d58aa87e --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-dialog.controller.js @@ -0,0 +1,46 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('UserManagementDialogController',UserManagementDialogController); + + UserManagementDialogController.$inject = ['$stateParams', '$uibModalInstance', 'entity', 'User', 'JhiLanguageService']; + + function UserManagementDialogController ($stateParams, $uibModalInstance, entity, User, JhiLanguageService) { + var vm = this; + + vm.authorities = ['ROLE_USER', 'ROLE_ADMIN']; + vm.clear = clear; + vm.languages = null; + vm.save = save; + vm.user = entity; + + + JhiLanguageService.getAll().then(function (languages) { + vm.languages = languages; + }); + + function clear () { + $uibModalInstance.dismiss('cancel'); + } + + function onSaveSuccess (result) { + vm.isSaving = false; + $uibModalInstance.close(result); + } + + function onSaveError () { + vm.isSaving = false; + } + + function save () { + vm.isSaving = true; + if (vm.user.id !== null) { + User.update(vm.user, onSaveSuccess, onSaveError); + } else { + User.save(vm.user, onSaveSuccess, onSaveError); + } + } + } +})(); diff --git a/src/main/webapp/app/admin/user-management/user-management-dialog.html b/src/main/webapp/app/admin/user-management/user-management-dialog.html new file mode 100644 index 000000000..6a194d64f --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management-dialog.html @@ -0,0 +1,113 @@ + + + + × + + Create or edit a User + + + + + ID + + + + + Login + + + + + This field is required. + + + + This field cannot be longer than 50 characters. + + + + + First Name + + + + + This field cannot be longer than 50 characters. + + + + + Last Name + + + + + This field cannot be longer than 50 characters. + + + + + Email + + + + + This field is required. + + + + This field cannot be longer than 100 characters. + + + Your e-mail is invalid. + + + + + + + Activated + + + + + Lang Key + + + + + + Profiles + + + + + + diff --git a/src/main/webapp/app/admin/user-management/user-management.controller.js b/src/main/webapp/app/admin/user-management/user-management.controller.js new file mode 100644 index 000000000..159b52399 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management.controller.js @@ -0,0 +1,102 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('UserManagementController', UserManagementController); + + UserManagementController.$inject = ['Principal', 'User', 'ParseLinks', 'AlertService', '$state', 'pagingParams', 'paginationConstants', 'JhiLanguageService']; + + function UserManagementController(Principal, User, ParseLinks, AlertService, $state, pagingParams, paginationConstants, JhiLanguageService) { + var vm = this; + + vm.authorities = ['ROLE_USER', 'ROLE_ADMIN']; + vm.currentAccount = null; + vm.languages = null; + vm.loadAll = loadAll; + vm.setActive = setActive; + vm.users = []; + vm.page = 1; + vm.totalItems = null; + vm.clear = clear; + vm.links = null; + vm.loadPage = loadPage; + vm.predicate = pagingParams.predicate; + vm.reverse = pagingParams.ascending; + vm.itemsPerPage = paginationConstants.itemsPerPage; + vm.transition = transition; + + vm.loadAll(); + + JhiLanguageService.getAll().then(function (languages) { + vm.languages = languages; + }); + Principal.identity().then(function(account) { + vm.currentAccount = account; + }); + + function setActive (user, isActivated) { + user.activated = isActivated; + User.update(user, function () { + vm.loadAll(); + vm.clear(); + }); + } + + function loadAll () { + User.query({ + page: pagingParams.page - 1, + size: vm.itemsPerPage, + sort: sort() + }, onSuccess, onError); + } + + function onSuccess(data, headers) { + //hide anonymous user from user management: it's a required user for Spring Security + for (var i in data) { + if (data[i]['login'] === 'anonymoususer') { + data.splice(i, 1); + } + } + vm.links = ParseLinks.parse(headers('link')); + vm.totalItems = headers('X-Total-Count'); + vm.queryCount = vm.totalItems; + vm.page = pagingParams.page; + vm.users = data; + } + + function onError(error) { + AlertService.error(error.data.message); + } + + function clear () { + vm.user = { + id: null, login: null, firstName: null, lastName: null, email: null, + activated: null, langKey: null, createdBy: null, createdDate: null, + lastModifiedBy: null, lastModifiedDate: null, resetDate: null, + resetKey: null, authorities: null + }; + } + + function sort () { + var result = [vm.predicate + ',' + (vm.reverse ? 'asc' : 'desc')]; + if (vm.predicate !== 'id') { + result.push('id'); + } + return result; + } + + function loadPage (page) { + vm.page = page; + vm.transition(); + } + + function transition () { + $state.transitionTo($state.$current, { + page: vm.page, + sort: vm.predicate + ',' + (vm.reverse ? 'asc' : 'desc'), + search: vm.currentSearch + }); + } + } +})(); diff --git a/src/main/webapp/app/admin/user-management/user-management.html b/src/main/webapp/app/admin/user-management/user-management.html new file mode 100644 index 000000000..c24432834 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management.html @@ -0,0 +1,75 @@ + + Users + + + + + Create a new User + + + + + + + + ID + Login + Email + + Lang Key Profiles Created Date + Last Modified By + Last Modified Date + + + + + + {{user.id}} + {{user.login}} + {{user.email}} + + Deactivated + Activated + + {{user.langKey}} + + + {{ authority }} + + + {{user.createdDate | date:'dd/MM/yy HH:mm'}} + {{user.lastModifiedBy}} + {{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}} + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/app/admin/user-management/user-management.state.js b/src/main/webapp/app/admin/user-management/user-management.state.js new file mode 100644 index 000000000..df3b1e807 --- /dev/null +++ b/src/main/webapp/app/admin/user-management/user-management.state.js @@ -0,0 +1,151 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider + .state('user-management', { + parent: 'admin', + url: '/user-management?page&sort', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'userManagement.home.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/user-management/user-management.html', + controller: 'UserManagementController', + controllerAs: 'vm' + } + }, params: { + page: { + value: '1', + squash: true + }, + sort: { + value: 'id,asc', + squash: true + } + }, + resolve: { + pagingParams: ['$stateParams', 'PaginationUtil', function ($stateParams, PaginationUtil) { + return { + page: PaginationUtil.parsePage($stateParams.page), + sort: $stateParams.sort, + predicate: PaginationUtil.parsePredicate($stateParams.sort), + ascending: PaginationUtil.parseAscending($stateParams.sort) + }; + }], + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('user-management'); + return $translate.refresh(); + }] + + } }) + .state('user-management-detail', { + parent: 'admin', + url: '/user/:login', + data: { + authorities: ['ROLE_ADMIN'], + pageTitle: 'user-management.detail.title' + }, + views: { + 'content@': { + templateUrl: 'app/admin/user-management/user-management-detail.html', + controller: 'UserManagementDetailController', + controllerAs: 'vm' + } + }, + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('user-management'); + return $translate.refresh(); + }] + } + }) + .state('user-management.new', { + parent: 'user-management', + url: '/new', + data: { + authorities: ['ROLE_ADMIN'] + }, + onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) { + $uibModal.open({ + templateUrl: 'app/admin/user-management/user-management-dialog.html', + controller: 'UserManagementDialogController', + controllerAs: 'vm', + backdrop: 'static', + size: 'lg', + resolve: { + entity: function () { + return { + id: null, login: null, firstName: null, lastName: null, email: null, + activated: true, langKey: null, createdBy: null, createdDate: null, + lastModifiedBy: null, lastModifiedDate: null, resetDate: null, + resetKey: null, authorities: null + }; + } + } + }).result.then(function() { + $state.go('user-management', null, { reload: true }); + }, function() { + $state.go('user-management'); + }); + }] + }) + .state('user-management.edit', { + parent: 'user-management', + url: '/{login}/edit', + data: { + authorities: ['ROLE_ADMIN'] + }, + onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) { + $uibModal.open({ + templateUrl: 'app/admin/user-management/user-management-dialog.html', + controller: 'UserManagementDialogController', + controllerAs: 'vm', + backdrop: 'static', + size: 'lg', + resolve: { + entity: ['User', function(User) { + return User.get({login : $stateParams.login}); + }] + } + }).result.then(function() { + $state.go('user-management', null, { reload: true }); + }, function() { + $state.go('^'); + }); + }] + }) + .state('user-management.delete', { + parent: 'user-management', + url: '/{login}/delete', + data: { + authorities: ['ROLE_ADMIN'] + }, + onEnter: ['$stateParams', '$state', '$uibModal', function($stateParams, $state, $uibModal) { + $uibModal.open({ + templateUrl: 'app/admin/user-management/user-management-delete-dialog.html', + controller: 'UserManagementDeleteController', + controllerAs: 'vm', + size: 'md', + resolve: { + entity: ['User', function(User) { + return User.get({login : $stateParams.login}); + }] + } + }).result.then(function() { + $state.go('user-management', null, { reload: true }); + }, function() { + $state.go('^'); + }); + }] + }); + } +})(); diff --git a/src/main/webapp/app/app.constants.js b/src/main/webapp/app/app.constants.js new file mode 100644 index 000000000..0f117e66a --- /dev/null +++ b/src/main/webapp/app/app.constants.js @@ -0,0 +1,9 @@ +(function () { + 'use strict'; + // DO NOT EDIT THIS FILE, EDIT THE GULP TASK NGCONSTANT SETTINGS INSTEAD WHICH GENERATES THIS FILE + angular + .module('sprintApp') + .constant('VERSION', "0.2.0-SNAPSHOT") + .constant('DEBUG_INFO_ENABLED', true) +; +})(); diff --git a/src/main/webapp/app/app.module.js b/src/main/webapp/app/app.module.js new file mode 100644 index 000000000..66213dacd --- /dev/null +++ b/src/main/webapp/app/app.module.js @@ -0,0 +1,29 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp', [ + 'ngStorage', + 'tmh.dynamicLocale', + 'pascalprecht.translate', + 'ngResource', + 'ngCookies', + 'ngAria', + 'ngCacheBuster', + 'ngFileUpload', + 'ui.bootstrap', + 'ui.bootstrap.datetimepicker', + 'ui.router', + 'infinite-scroll', + // jhipster-needle-angularjs-add-module JHipster will add new module here + 'angular-loading-bar' + ]) + .run(run); + + run.$inject = ['stateHandler', 'translationHandler']; + + function run(stateHandler, translationHandler) { + stateHandler.initialize(); + translationHandler.initialize(); + } +})(); diff --git a/src/main/webapp/app/app.state.js b/src/main/webapp/app/app.state.js new file mode 100644 index 000000000..109e17f4f --- /dev/null +++ b/src/main/webapp/app/app.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('app', { + abstract: true, + views: { + 'navbar@': { + templateUrl: 'app/layouts/navbar/navbar.html', + controller: 'NavbarController', + controllerAs: 'vm' + } + }, + resolve: { + authorize: ['Auth', + function (Auth) { + return Auth.authorize(); + } + ], + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('global'); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/blocks/config/alert.config.js b/src/main/webapp/app/blocks/config/alert.config.js new file mode 100644 index 000000000..71821bbb4 --- /dev/null +++ b/src/main/webapp/app/blocks/config/alert.config.js @@ -0,0 +1,14 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(alertServiceConfig); + + alertServiceConfig.$inject = ['AlertServiceProvider']; + + function alertServiceConfig(AlertServiceProvider) { + // set below to true to make alerts look like toast + AlertServiceProvider.showAsToast(false); + } +})(); diff --git a/src/main/webapp/app/blocks/config/compile.config.js b/src/main/webapp/app/blocks/config/compile.config.js new file mode 100644 index 000000000..8c0aa3f45 --- /dev/null +++ b/src/main/webapp/app/blocks/config/compile.config.js @@ -0,0 +1,22 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(compileServiceConfig); + + compileServiceConfig.$inject = ['$compileProvider','DEBUG_INFO_ENABLED']; + + function compileServiceConfig($compileProvider,DEBUG_INFO_ENABLED) { + // disable debug data on prod profile to improve performance + $compileProvider.debugInfoEnabled(DEBUG_INFO_ENABLED); + + /* + If you wish to debug an application with this information + then you should open up a debug console in the browser + then call this method directly in this console: + + angular.reloadWithDebugInfo(); + */ + } +})(); diff --git a/src/main/webapp/app/blocks/config/http.config.js b/src/main/webapp/app/blocks/config/http.config.js new file mode 100644 index 000000000..9ab905a7a --- /dev/null +++ b/src/main/webapp/app/blocks/config/http.config.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(httpConfig); + + httpConfig.$inject = ['$urlRouterProvider', '$httpProvider', 'httpRequestInterceptorCacheBusterProvider', '$urlMatcherFactoryProvider']; + + function httpConfig($urlRouterProvider, $httpProvider, httpRequestInterceptorCacheBusterProvider, $urlMatcherFactoryProvider) { + + //Cache everything except rest api requests + httpRequestInterceptorCacheBusterProvider.setMatchlist([/.*api.*/, /.*protected.*/], true); + + $urlRouterProvider.otherwise('/'); + + $httpProvider.interceptors.push('errorHandlerInterceptor'); + $httpProvider.interceptors.push('authExpiredInterceptor'); + $httpProvider.interceptors.push('authInterceptor'); + $httpProvider.interceptors.push('notificationInterceptor'); + // jhipster-needle-angularjs-add-interceptor JHipster will add new application http interceptor here + + $urlMatcherFactoryProvider.type('boolean', { + name : 'boolean', + decode: function(val) { return val === true || val === 'true'; }, + encode: function(val) { return val ? 1 : 0; }, + equals: function(a, b) { return this.is(a) && a === b; }, + is: function(val) { return [true,false,0,1].indexOf(val) >= 0; }, + pattern: /bool|true|0|1/ + }); + } +})(); diff --git a/src/main/webapp/app/blocks/config/localstorage.config.js b/src/main/webapp/app/blocks/config/localstorage.config.js new file mode 100644 index 000000000..599bc20fc --- /dev/null +++ b/src/main/webapp/app/blocks/config/localstorage.config.js @@ -0,0 +1,14 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(localStorageConfig); + + localStorageConfig.$inject = ['$localStorageProvider', '$sessionStorageProvider']; + + function localStorageConfig($localStorageProvider, $sessionStorageProvider) { + $localStorageProvider.setKeyPrefix('jhi-'); + $sessionStorageProvider.setKeyPrefix('jhi-'); + } +})(); diff --git a/src/main/webapp/app/blocks/config/translation-storage.provider.js b/src/main/webapp/app/blocks/config/translation-storage.provider.js new file mode 100644 index 000000000..0f4d0bbb2 --- /dev/null +++ b/src/main/webapp/app/blocks/config/translation-storage.provider.js @@ -0,0 +1,28 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('translationStorageProvider', translationStorageProvider); + + translationStorageProvider.$inject = ['$cookies', '$log', 'LANGUAGES']; + + function translationStorageProvider($cookies, $log, LANGUAGES) { + return { + get: get, + put: put + }; + + function get(name) { + if (LANGUAGES.indexOf($cookies.getObject(name)) === -1) { + $log.info('Resetting invalid cookie language "' + $cookies.getObject(name) + '" to prefered language "it"'); + $cookies.putObject(name, 'it'); + } + return $cookies.getObject(name); + } + + function put(name, value) { + $cookies.putObject(name, value); + } + } +})(); diff --git a/src/main/webapp/app/blocks/config/translation.config.js b/src/main/webapp/app/blocks/config/translation.config.js new file mode 100644 index 000000000..63fea09ef --- /dev/null +++ b/src/main/webapp/app/blocks/config/translation.config.js @@ -0,0 +1,25 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(translationConfig); + + translationConfig.$inject = ['$translateProvider', 'tmhDynamicLocaleProvider']; + + function translationConfig($translateProvider, tmhDynamicLocaleProvider) { + // Initialize angular-translate + $translateProvider.useLoader('$translatePartialLoader', { + urlTemplate: 'i18n/{lang}/{part}.json' + }); + + $translateProvider.preferredLanguage('it'); + $translateProvider.useStorage('translationStorageProvider'); + $translateProvider.useSanitizeValueStrategy('escaped'); + $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); + + tmhDynamicLocaleProvider.localeLocationPattern('i18n/angular-locale_{{locale}}.js'); + tmhDynamicLocaleProvider.useCookieStorage(); + tmhDynamicLocaleProvider.storageKey('NG_TRANSLATE_LANG_KEY'); + } +})(); diff --git a/src/main/webapp/app/blocks/config/uib-pager.config.js b/src/main/webapp/app/blocks/config/uib-pager.config.js new file mode 100644 index 000000000..b04bc12a9 --- /dev/null +++ b/src/main/webapp/app/blocks/config/uib-pager.config.js @@ -0,0 +1,15 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + .config(pagerConfig); + + pagerConfig.$inject = ['uibPagerConfig', 'paginationConstants']; + + function pagerConfig(uibPagerConfig, paginationConstants) { + uibPagerConfig.itemsPerPage = paginationConstants.itemsPerPage; + uibPagerConfig.previousText = '«'; + uibPagerConfig.nextText = '»'; + } +})(); diff --git a/src/main/webapp/app/blocks/config/uib-pagination.config.js b/src/main/webapp/app/blocks/config/uib-pagination.config.js new file mode 100644 index 000000000..1443b867c --- /dev/null +++ b/src/main/webapp/app/blocks/config/uib-pagination.config.js @@ -0,0 +1,19 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(paginationConfig); + + paginationConfig.$inject = ['uibPaginationConfig', 'paginationConstants']; + + function paginationConfig(uibPaginationConfig, paginationConstants) { + uibPaginationConfig.itemsPerPage = paginationConstants.itemsPerPage; + uibPaginationConfig.maxSize = 5; + uibPaginationConfig.boundaryLinks = true; + uibPaginationConfig.firstText = '«'; + uibPaginationConfig.previousText = '‹'; + uibPaginationConfig.nextText = '›'; + uibPaginationConfig.lastText = '»'; + } +})(); diff --git a/src/main/webapp/app/blocks/handlers/state.handler.js b/src/main/webapp/app/blocks/handlers/state.handler.js new file mode 100644 index 000000000..6748e0ea4 --- /dev/null +++ b/src/main/webapp/app/blocks/handlers/state.handler.js @@ -0,0 +1,63 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('stateHandler', stateHandler); + + stateHandler.$inject = ['$rootScope', '$state', '$sessionStorage', '$translate', 'JhiLanguageService', 'translationHandler', '$window', + 'Auth', 'Principal', 'VERSION']; + + function stateHandler($rootScope, $state, $sessionStorage, $translate, JhiLanguageService, translationHandler, $window, + Auth, Principal, VERSION) { + return { + initialize: initialize + }; + + function initialize() { + $rootScope.VERSION = VERSION; + + var stateChangeStart = $rootScope.$on('$stateChangeStart', function (event, toState, toStateParams, fromState) { + $rootScope.toState = toState; + $rootScope.toStateParams = toStateParams; + $rootScope.fromState = fromState; + + // Redirect to a state with an external URL (http://stackoverflow.com/a/30221248/1098564) + if (toState.external) { + event.preventDefault(); + $window.open(toState.url, '_self'); + } + + if (Principal.isIdentityResolved()) { + Auth.authorize(); + } + + + // Update the language + JhiLanguageService.getCurrent().then(function (language) { + $translate.use(language); + }); + + }); + + var stateChangeSuccess = $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) { + var titleKey = 'global.title' ; + + // Set the page title key to the one configured in state or use default one + if (toState.data.pageTitle) { + titleKey = toState.data.pageTitle; + } + translationHandler.updateTitle(titleKey); + }); + + $rootScope.$on('$destroy', function () { + if(angular.isDefined(stateChangeStart) && stateChangeStart !== null){ + stateChangeStart(); + } + if(angular.isDefined(stateChangeSuccess) && stateChangeSuccess !== null){ + stateChangeSuccess(); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/blocks/handlers/translation.handler.js b/src/main/webapp/app/blocks/handlers/translation.handler.js new file mode 100644 index 000000000..77d4c8694 --- /dev/null +++ b/src/main/webapp/app/blocks/handlers/translation.handler.js @@ -0,0 +1,43 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('translationHandler', translationHandler); + + translationHandler.$inject = ['$rootScope', '$window', '$state', '$translate']; + + function translationHandler($rootScope, $window, $state, $translate) { + return { + initialize: initialize, + updateTitle: updateTitle + }; + + function initialize() { + // if the current translation changes, update the window title + var translateChangeSuccess = $rootScope.$on('$translateChangeSuccess', function() { + updateTitle(); + }); + + $rootScope.$on('$destroy', function () { + if(angular.isDefined(translateChangeSuccess) && translateChangeSuccess !== null){ + translateChangeSuccess(); + } + }); + } + + // update the window title using params in the following + // precendence + // 1. titleKey parameter + // 2. $state.$current.data.pageTitle (current state page title) + // 3. 'global.title' + function updateTitle(titleKey) { + if (!titleKey && $state.$current.data && $state.$current.data.pageTitle) { + titleKey = $state.$current.data.pageTitle; + } + $translate(titleKey || 'global.title').then(function (title) { + $window.document.title = title; + }); + } + } +})(); diff --git a/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js b/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js new file mode 100644 index 000000000..d3dafe8e9 --- /dev/null +++ b/src/main/webapp/app/blocks/interceptor/auth-expired.interceptor.js @@ -0,0 +1,31 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('authExpiredInterceptor', authExpiredInterceptor); + + + authExpiredInterceptor.$inject = ['$rootScope', '$q', '$injector', '$localStorage', '$sessionStorage']; + + function authExpiredInterceptor($rootScope, $q, $injector, $localStorage, $sessionStorage) { + var service = { + responseError: responseError + }; + + return service; + + function responseError(response) { + if (response.status === 401) { + delete $localStorage.authenticationToken; + delete $sessionStorage.authenticationToken; + var Principal = $injector.get('Principal'); + if (Principal.isAuthenticated()) { + var Auth = $injector.get('Auth'); + Auth.authorize(true); + } + } + return $q.reject(response); + } + } +})(); diff --git a/src/main/webapp/app/blocks/interceptor/auth.interceptor.js b/src/main/webapp/app/blocks/interceptor/auth.interceptor.js new file mode 100644 index 000000000..f658c16df --- /dev/null +++ b/src/main/webapp/app/blocks/interceptor/auth.interceptor.js @@ -0,0 +1,29 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('authInterceptor', authInterceptor); + + authInterceptor.$inject = ['$rootScope', '$q', '$location', '$localStorage', '$sessionStorage']; + + function authInterceptor ($rootScope, $q, $location, $localStorage, $sessionStorage) { + var service = { + request: request + }; + + return service; + + function request (config) { + /*jshint camelcase: false */ + config.headers = config.headers || {}; + var token = $localStorage.authenticationToken || $sessionStorage.authenticationToken; + + if (token && token.expires_at && token.expires_at > new Date().getTime()) { + config.headers.Authorization = 'Bearer ' + token.access_token; + } + + return config; + } + } +})(); diff --git a/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.js b/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.js new file mode 100644 index 000000000..60622bcfd --- /dev/null +++ b/src/main/webapp/app/blocks/interceptor/errorhandler.interceptor.js @@ -0,0 +1,24 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('errorHandlerInterceptor', errorHandlerInterceptor); + + errorHandlerInterceptor.$inject = ['$q', '$rootScope']; + + function errorHandlerInterceptor ($q, $rootScope) { + var service = { + responseError: responseError + }; + + return service; + + function responseError (response) { + if (!(response.status === 401 && (response.data === '' || (response.data.path && response.data.path.indexOf('/api/account') === 0 )))) { + $rootScope.$emit('sprintApp.httpError', response); + } + return $q.reject(response); + } + } +})(); diff --git a/src/main/webapp/app/blocks/interceptor/notification.interceptor.js b/src/main/webapp/app/blocks/interceptor/notification.interceptor.js new file mode 100644 index 000000000..3c96c06c8 --- /dev/null +++ b/src/main/webapp/app/blocks/interceptor/notification.interceptor.js @@ -0,0 +1,25 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('notificationInterceptor', notificationInterceptor); + + notificationInterceptor.$inject = ['$q', 'AlertService']; + + function notificationInterceptor ($q, AlertService) { + var service = { + response: response + }; + + return service; + + function response (response) { + var alertKey = response.headers('X-sprintApp-alert'); + if (angular.isString(alertKey)) { + AlertService.success(alertKey, { param : response.headers('X-sprintApp-params')}); + } + return response; + } + } +})(); diff --git a/src/main/webapp/app/components/alert/alert-error.directive.js b/src/main/webapp/app/components/alert/alert-error.directive.js new file mode 100644 index 000000000..5ea0d23c4 --- /dev/null +++ b/src/main/webapp/app/components/alert/alert-error.directive.js @@ -0,0 +1,91 @@ +(function() { + 'use strict'; + + var jhiAlertError = { + template: '' + + '' + + '{{ alert.msg }}' + + '' + + '', + controller: jhiAlertErrorController + }; + + angular + .module('sprintApp') + .component('jhiAlertError', jhiAlertError); + + jhiAlertErrorController.$inject = ['$scope', 'AlertService', '$rootScope', '$translate']; + + function jhiAlertErrorController ($scope, AlertService, $rootScope, $translate) { + var vm = this; + + vm.alerts = []; + + function addErrorAlert (message, key, data) { + key = key && key !== null ? key : message; + vm.alerts.push( + AlertService.add( + { + type: 'danger', + msg: key, + params: data, + timeout: 5000, + toast: AlertService.isToast(), + scoped: true + }, + vm.alerts + ) + ); + } + + var cleanHttpErrorListener = $rootScope.$on('sprintApp.httpError', function (event, httpResponse) { + var i; + event.stopPropagation(); + switch (httpResponse.status) { + // connection refused, server not reachable + case 0: + addErrorAlert('Server not reachable','error.server.not.reachable'); + break; + + case 400: + var errorHeader = httpResponse.headers('X-sprintApp-error'); + var entityKey = httpResponse.headers('X-sprintApp-params'); + if (errorHeader) { + var entityName = $translate.instant('global.menu.entities.' + entityKey); + addErrorAlert(errorHeader, errorHeader, {entityName: entityName}); + } else if (httpResponse.data && httpResponse.data.fieldErrors) { + for (i = 0; i < httpResponse.data.fieldErrors.length; i++) { + var fieldError = httpResponse.data.fieldErrors[i]; + // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it + var convertedField = fieldError.field.replace(/\[\d*\]/g, '[]'); + var fieldName = $translate.instant('sprintApp.' + fieldError.objectName + '.' + convertedField); + addErrorAlert('Field ' + fieldName + ' cannot be empty', 'error.' + fieldError.message, {fieldName: fieldName}); + } + } else if (httpResponse.data && httpResponse.data.message) { + addErrorAlert(httpResponse.data.message, httpResponse.data.message, httpResponse.data); + } else { + addErrorAlert(httpResponse.data); + } + break; + + case 404: + addErrorAlert('Not found','error.url.not.found'); + break; + + default: + if (httpResponse.data && httpResponse.data.message) { + addErrorAlert(httpResponse.data.message); + } else { + addErrorAlert(angular.toJson(httpResponse)); + } + } + }); + + $scope.$on('$destroy', function () { + if(angular.isDefined(cleanHttpErrorListener) && cleanHttpErrorListener !== null){ + cleanHttpErrorListener(); + vm.alerts = []; + } + }); + } +})(); diff --git a/src/main/webapp/app/components/alert/alert.directive.js b/src/main/webapp/app/components/alert/alert.directive.js new file mode 100644 index 000000000..950a8a951 --- /dev/null +++ b/src/main/webapp/app/components/alert/alert.directive.js @@ -0,0 +1,27 @@ +(function() { + 'use strict'; + + var jhiAlert = { + template: '' + + '' + + '' + + '' + + '', + controller: jhiAlertController + }; + + angular + .module('sprintApp') + .component('jhiAlert', jhiAlert); + + jhiAlertController.$inject = ['$scope', 'AlertService']; + + function jhiAlertController($scope, AlertService) { + var vm = this; + + vm.alerts = AlertService.get(); + $scope.$on('$destroy', function () { + vm.alerts = []; + }); + } +})(); diff --git a/src/main/webapp/app/components/alert/alert.service.js b/src/main/webapp/app/components/alert/alert.service.js new file mode 100644 index 000000000..ab5df7699 --- /dev/null +++ b/src/main/webapp/app/components/alert/alert.service.js @@ -0,0 +1,137 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .provider('AlertService', AlertService); + + function AlertService () { + this.toast = false; + /*jshint validthis: true */ + this.$get = getService; + + this.showAsToast = function(isToast) { + this.toast = isToast; + }; + + getService.$inject = ['$timeout', '$sce', '$translate']; + + function getService ($timeout, $sce,$translate) { + var toast = this.toast, + alertId = 0, // unique id for each alert. Starts from 0. + alerts = [], + timeout = 5000; // default timeout + + return { + factory: factory, + isToast: isToast, + add: addAlert, + closeAlert: closeAlert, + closeAlertByIndex: closeAlertByIndex, + clear: clear, + get: get, + success: success, + error: error, + info: info, + warning : warning + }; + + function isToast() { + return toast; + } + + function clear() { + alerts = []; + } + + function get() { + return alerts; + } + + function success(msg, params, position) { + return this.add({ + type: 'success', + msg: msg, + params: params, + timeout: timeout, + toast: toast, + position: position + }); + } + + function error(msg, params, position) { + return this.add({ + type: 'danger', + msg: msg, + params: params, + timeout: timeout, + toast: toast, + position: position + }); + } + + function warning(msg, params, position) { + return this.add({ + type: 'warning', + msg: msg, + params: params, + timeout: timeout, + toast: toast, + position: position + }); + } + + function info(msg, params, position) { + return this.add({ + type: 'info', + msg: msg, + params: params, + timeout: timeout, + toast: toast, + position: position + }); + } + + function factory(alertOptions) { + var alert = { + type: alertOptions.type, + msg: $sce.trustAsHtml(alertOptions.msg), + id: alertOptions.alertId, + timeout: alertOptions.timeout, + toast: alertOptions.toast, + position: alertOptions.position ? alertOptions.position : 'top right', + scoped: alertOptions.scoped, + close: function (alerts) { + return closeAlert(this.id, alerts); + } + }; + if(!alert.scoped) { + alerts.push(alert); + } + return alert; + } + + function addAlert(alertOptions, extAlerts) { + alertOptions.alertId = alertId++; + alertOptions.msg = $translate.instant(alertOptions.msg, alertOptions.params); + var that = this; + var alert = this.factory(alertOptions); + if (alertOptions.timeout && alertOptions.timeout > 0) { + $timeout(function () { + that.closeAlert(alertOptions.alertId, extAlerts); + }, alertOptions.timeout); + } + return alert; + } + + function closeAlert(id, extAlerts) { + var thisAlerts = extAlerts ? extAlerts : alerts; + return closeAlertByIndex(thisAlerts.map(function(e) { return e.id; }).indexOf(id), thisAlerts); + } + + function closeAlertByIndex(index, thisAlerts) { + return thisAlerts.splice(index, 1); + } + } + } +})(); diff --git a/src/main/webapp/app/components/form/maxbytes.directive.js b/src/main/webapp/app/components/form/maxbytes.directive.js new file mode 100644 index 000000000..2cbfa8fe2 --- /dev/null +++ b/src/main/webapp/app/components/form/maxbytes.directive.js @@ -0,0 +1,46 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('maxbytes', maxbytes); + + function maxbytes () { + var directive = { + restrict: 'A', + require: '?ngModel', + link: linkFunc + }; + + return directive; + + function linkFunc (scope, element, attrs, ngModel) { + if (!ngModel) { + return; + } + + ngModel.$validators.maxbytes = function (modelValue) { + return ngModel.$isEmpty(modelValue) || numberOfBytes(modelValue) <= attrs.maxbytes; + }; + } + + function endsWith(suffix, str) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function paddingSize(base64String) { + if (endsWith('==', base64String)) { + return 2; + } + if (endsWith('=', base64String)) { + return 1; + } + return 0; + } + + function numberOfBytes(base64String) { + return base64String.length / 4 * 3 - paddingSize(base64String); + } + } + +})(); diff --git a/src/main/webapp/app/components/form/minbytes.directive.js b/src/main/webapp/app/components/form/minbytes.directive.js new file mode 100644 index 000000000..07009d4e8 --- /dev/null +++ b/src/main/webapp/app/components/form/minbytes.directive.js @@ -0,0 +1,45 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('minbytes', minbytes); + + function minbytes () { + var directive = { + restrict: 'A', + require: '?ngModel', + link: linkFunc + }; + + return directive; + + function linkFunc (scope, element, attrs, ngModel) { + if (!ngModel) { + return; + } + + ngModel.$validators.minbytes = function (modelValue) { + return ngModel.$isEmpty(modelValue) || numberOfBytes(modelValue) >= attrs.minbytes; + }; + } + + function endsWith(suffix, str) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function paddingSize(base64String) { + if (endsWith('==', base64String)) { + return 2; + } + if (endsWith('=', base64String)) { + return 1; + } + return 0; + } + + function numberOfBytes(base64String) { + return base64String.length / 4 * 3 - paddingSize(base64String); + } + } +})(); diff --git a/src/main/webapp/app/components/form/pagination.constants.js b/src/main/webapp/app/components/form/pagination.constants.js new file mode 100644 index 000000000..dac1b4c29 --- /dev/null +++ b/src/main/webapp/app/components/form/pagination.constants.js @@ -0,0 +1,9 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .constant('paginationConstants', { + 'itemsPerPage': 20 + }); +})(); diff --git a/src/main/webapp/app/components/form/show-validation.directive.js b/src/main/webapp/app/components/form/show-validation.directive.js new file mode 100644 index 000000000..8eb6ad62a --- /dev/null +++ b/src/main/webapp/app/components/form/show-validation.directive.js @@ -0,0 +1,36 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('showValidation', showValidation); + + function showValidation () { + var directive = { + restrict: 'A', + require: 'form', + link: linkFunc + }; + + return directive; + + function linkFunc (scope, element, attrs, formCtrl) { + element.find('.form-group').each(function() { + var $formGroup = angular.element(this); + var $inputs = $formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]'); + + if ($inputs.length > 0) { + $inputs.each(function() { + var $input = angular.element(this); + var inputName = $input.attr('name'); + scope.$watch(function() { + return formCtrl[inputName].$invalid && formCtrl[inputName].$dirty; + }, function(isInvalid) { + $formGroup.toggleClass('has-error', isInvalid); + }); + }); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/components/language/language.constants.js b/src/main/webapp/app/components/language/language.constants.js new file mode 100644 index 000000000..4ab96cfd4 --- /dev/null +++ b/src/main/webapp/app/components/language/language.constants.js @@ -0,0 +1,17 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + + /* + Languages codes are ISO_639-1 codes, see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + They are written in English to avoid character encoding issues (not a perfect solution) + */ + .constant('LANGUAGES', [ + 'it', + 'en' + // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array + ] + ); +})(); diff --git a/src/main/webapp/app/components/language/language.controller.js b/src/main/webapp/app/components/language/language.controller.js new file mode 100644 index 000000000..0c16a0e6d --- /dev/null +++ b/src/main/webapp/app/components/language/language.controller.js @@ -0,0 +1,25 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('JhiLanguageController', JhiLanguageController); + + JhiLanguageController.$inject = ['$translate', 'JhiLanguageService', 'tmhDynamicLocale']; + + function JhiLanguageController ($translate, JhiLanguageService, tmhDynamicLocale) { + var vm = this; + + vm.changeLanguage = changeLanguage; + vm.languages = null; + + JhiLanguageService.getAll().then(function (languages) { + vm.languages = languages; + }); + + function changeLanguage (languageKey) { + $translate.use(languageKey); + tmhDynamicLocale.set(languageKey); + } + } +})(); diff --git a/src/main/webapp/app/components/language/language.filter.js b/src/main/webapp/app/components/language/language.filter.js new file mode 100644 index 000000000..38ce49208 --- /dev/null +++ b/src/main/webapp/app/components/language/language.filter.js @@ -0,0 +1,43 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .filter('findLanguageFromKey', findLanguageFromKey); + + function findLanguageFromKey() { + return findLanguageFromKeyFilter; + + function findLanguageFromKeyFilter(lang) { + return { + 'ca': 'Català', + 'cs': 'Český', + 'da': 'Dansk', + 'de': 'Deutsch', + 'el': 'Ελληνικά', + 'en': 'English', + 'es': 'Español', + 'fr': 'Français', + 'gl': 'Galego', + 'hu': 'Magyar', + 'hi': 'हिंदी', + 'it': 'Italiano', + 'ja': '日本語', + 'ko': '한국어', + 'mr': 'मराठी', + 'nl': 'Nederlands', + 'pl': 'Polski', + 'pt-br': 'Português (Brasil)', + 'pt-pt': 'Português', + 'ro': 'Română', + 'ru': 'Русский', + 'sk': 'Slovenský', + 'sv': 'Svenska', + 'ta': 'தமிழ்', + 'tr': 'Türkçe', + 'zh-cn': '中文(简体)', + 'zh-tw': '繁體中文' + }[lang]; + } + } +})(); diff --git a/src/main/webapp/app/components/language/language.service.js b/src/main/webapp/app/components/language/language.service.js new file mode 100644 index 000000000..0f17c32c2 --- /dev/null +++ b/src/main/webapp/app/components/language/language.service.js @@ -0,0 +1,33 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + .factory('JhiLanguageService', JhiLanguageService); + + JhiLanguageService.$inject = ['$q', '$http', '$translate', 'LANGUAGES']; + + function JhiLanguageService ($q, $http, $translate, LANGUAGES) { + var service = { + getAll: getAll, + getCurrent: getCurrent + }; + + return service; + + function getAll () { + var deferred = $q.defer(); + deferred.resolve(LANGUAGES); + return deferred.promise; + } + + function getCurrent () { + var deferred = $q.defer(); + var language = $translate.storage().get('NG_TRANSLATE_LANG_KEY'); + + deferred.resolve(language); + + return deferred.promise; + } + } +})(); diff --git a/src/main/webapp/app/components/login/login.controller.js b/src/main/webapp/app/components/login/login.controller.js new file mode 100644 index 000000000..c5af4408c --- /dev/null +++ b/src/main/webapp/app/components/login/login.controller.js @@ -0,0 +1,73 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('LoginController', LoginController); + + LoginController.$inject = ['$rootScope', '$state', '$timeout', 'Auth', '$uibModalInstance']; + + function LoginController ($rootScope, $state, $timeout, Auth, $uibModalInstance) { + var vm = this; + + vm.authenticationError = false; + vm.cancel = cancel; + vm.credentials = {}; + vm.login = login; + vm.password = null; + vm.register = register; + vm.rememberMe = true; + vm.requestResetPassword = requestResetPassword; + vm.username = null; + + $timeout(function (){angular.element('#username').focus();}); + + function cancel () { + vm.credentials = { + username: null, + password: null, + rememberMe: true + }; + vm.authenticationError = false; + $uibModalInstance.dismiss('cancel'); + } + + function login (event) { + event.preventDefault(); + Auth.login({ + username: vm.username, + password: vm.password, + rememberMe: vm.rememberMe + }).then(function () { + vm.authenticationError = false; + $uibModalInstance.close(); + if ($state.current.name === 'register' || $state.current.name === 'activate' || + $state.current.name === 'finishReset' || $state.current.name === 'requestReset') { + $state.go('home'); + } + + $rootScope.$broadcast('authenticationSuccess'); + + // previousState was set in the authExpiredInterceptor before being redirected to login modal. + // since login is succesful, go to stored previousState and clear previousState + if (Auth.getPreviousState()) { + var previousState = Auth.getPreviousState(); + Auth.resetPreviousState(); + $state.go(previousState.name, previousState.params); + } + }).catch(function () { + vm.authenticationError = true; + }); + } + + function register () { + $uibModalInstance.dismiss('cancel'); + $state.go('register'); + } + + function requestResetPassword () { + $uibModalInstance.dismiss('cancel'); + $state.go('requestReset'); + } + } +})(); diff --git a/src/main/webapp/app/components/login/login.html b/src/main/webapp/app/components/login/login.html new file mode 100644 index 000000000..6ee0e9d79 --- /dev/null +++ b/src/main/webapp/app/components/login/login.html @@ -0,0 +1,38 @@ + + × + Sign in + + + + + Sign in + + + + Failed to sign in! Please check your credentials and try again. + + + + + + Login + + + + Password + + + Sign in + + + + Did you forget your password? + + + You don't have an account yet? Register a new account + + + + diff --git a/src/main/webapp/app/components/login/login.service.js b/src/main/webapp/app/components/login/login.service.js new file mode 100644 index 000000000..f3bdc61c9 --- /dev/null +++ b/src/main/webapp/app/components/login/login.service.js @@ -0,0 +1,42 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('LoginService', LoginService); + + LoginService.$inject = ['$uibModal']; + + function LoginService ($uibModal) { + var service = { + open: open + }; + + var modalInstance = null; + var resetModal = function () { + modalInstance = null; + }; + + return service; + + function open () { + if (modalInstance !== null) return; + modalInstance = $uibModal.open({ + animation: true, + templateUrl: 'app/components/login/login.html', + controller: 'LoginController', + controllerAs: 'vm', + resolve: { + translatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate, $translatePartialLoader) { + $translatePartialLoader.addPart('login'); + return $translate.refresh(); + }] + } + }); + modalInstance.result.then( + resetModal, + resetModal + ); + } + } +})(); diff --git a/src/main/webapp/app/components/util/base64.service.js b/src/main/webapp/app/components/util/base64.service.js new file mode 100644 index 000000000..cb1acc40d --- /dev/null +++ b/src/main/webapp/app/components/util/base64.service.js @@ -0,0 +1,92 @@ +(function() { + /*jshint bitwise: false*/ + 'use strict'; + + angular + .module('sprintApp') + .factory('Base64', Base64); + + function Base64 () { + var keyStr = 'ABCDEFGHIJKLMNOP' + + 'QRSTUVWXYZabcdef' + + 'ghijklmnopqrstuv' + + 'wxyz0123456789+/' + + '='; + + var service = { + decode : decode, + encode : encode + }; + + return service; + + function encode (input) { + var output = '', + chr1, chr2, chr3 = '', + enc1, enc2, enc3, enc4 = '', + i = 0; + + while (i < input.length) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + + keyStr.charAt(enc1) + + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + + keyStr.charAt(enc4); + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + } + + return output; + } + + function decode (input) { + var output = '', + chr1, chr2, chr3 = '', + enc1, enc2, enc3, enc4 = '', + i = 0; + + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + while (i < input.length) { + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 !== 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 !== 64) { + output = output + String.fromCharCode(chr3); + } + + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + } + + return output; + } + } +})(); diff --git a/src/main/webapp/app/components/util/capitalize.filter.js b/src/main/webapp/app/components/util/capitalize.filter.js new file mode 100644 index 000000000..e5cbb2860 --- /dev/null +++ b/src/main/webapp/app/components/util/capitalize.filter.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .filter('capitalize', capitalize); + + function capitalize() { + return capitalizeFilter; + + function capitalizeFilter (input) { + if (input !== null) { + input = input.toLowerCase(); + } + return input.substring(0, 1).toUpperCase() + input.substring(1); + } + } +})(); diff --git a/src/main/webapp/app/components/util/data-util.service.js b/src/main/webapp/app/components/util/data-util.service.js new file mode 100644 index 000000000..166e369e1 --- /dev/null +++ b/src/main/webapp/app/components/util/data-util.service.js @@ -0,0 +1,74 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('DataUtils', DataUtils); + + DataUtils.$inject = ['$window']; + + function DataUtils ($window) { + + var service = { + abbreviate: abbreviate, + byteSize: byteSize, + openFile: openFile, + toBase64: toBase64 + }; + + return service; + + function abbreviate (text) { + if (!angular.isString(text)) { + return ''; + } + if (text.length < 30) { + return text; + } + return text ? (text.substring(0, 15) + '...' + text.slice(-10)) : ''; + } + + function byteSize (base64String) { + if (!angular.isString(base64String)) { + return ''; + } + + function endsWith(suffix, str) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function paddingSize(base64String) { + if (endsWith('==', base64String)) { + return 2; + } + if (endsWith('=', base64String)) { + return 1; + } + return 0; + } + + function size(base64String) { + return base64String.length / 4 * 3 - paddingSize(base64String); + } + + function formatAsBytes(size) { + return size.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ') + ' bytes'; + } + + return formatAsBytes(size(base64String)); + } + + function openFile (type, data) { + $window.open('data:' + type + ';base64,' + data, '_blank', 'height=300,width=400'); + } + + function toBase64 (file, cb) { + var fileReader = new FileReader(); + fileReader.readAsDataURL(file); + fileReader.onload = function (e) { + var base64Data = e.target.result.substr(e.target.result.indexOf('base64,') + 'base64,'.length); + cb(base64Data); + }; + } + } +})(); diff --git a/src/main/webapp/app/components/util/date-util.service.js b/src/main/webapp/app/components/util/date-util.service.js new file mode 100644 index 000000000..983e6f2b3 --- /dev/null +++ b/src/main/webapp/app/components/util/date-util.service.js @@ -0,0 +1,50 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('DateUtils', DateUtils); + + DateUtils.$inject = ['$filter']; + + function DateUtils ($filter) { + + var service = { + convertDateTimeFromServer : convertDateTimeFromServer, + convertLocalDateFromServer : convertLocalDateFromServer, + convertLocalDateToServer : convertLocalDateToServer, + dateformat : dateformat + }; + + return service; + + function convertDateTimeFromServer (date) { + if (date) { + return new Date(date); + } else { + return null; + } + } + + function convertLocalDateFromServer (date) { + if (date) { + var dateString = date.split('-'); + return new Date(dateString[0], dateString[1] - 1, dateString[2]); + } + return null; + } + + function convertLocalDateToServer (date) { + if (date) { + return $filter('date')(date, 'yyyy-MM-dd'); + } else { + return null; + } + } + + function dateformat () { + return 'yyyy-MM-dd'; + } + } + +})(); diff --git a/src/main/webapp/app/components/util/jhi-item-count.directive.js b/src/main/webapp/app/components/util/jhi-item-count.directive.js new file mode 100644 index 000000000..d54169cf3 --- /dev/null +++ b/src/main/webapp/app/components/util/jhi-item-count.directive.js @@ -0,0 +1,20 @@ +(function() { + 'use strict'; + + var jhiItemCount = { + template: '' + + 'Showing {{(($ctrl.page - 1) * $ctrl.itemsPerPage) == 0 ? 1 : (($ctrl.page - 1) * $ctrl.itemsPerPage + 1)}} - ' + + '{{($ctrl.page * $ctrl.itemsPerPage) < $ctrl.queryCount ? ($ctrl.page * $ctrl.itemsPerPage) : $ctrl.queryCount}} ' + + 'of {{$ctrl.queryCount}} items.' + + '', + bindings: { + page: '<', + queryCount: ' 1){ + return sort.split(',').slice(-1)[0] === 'asc'; + } else { + // default to true if no sort defined + return true; + } + } + + // query params are strings, and need to be parsed + function parsePage (page) { + return parseInt(page); + } + + // sort can be in the format `id,asc` or `id` + function parsePredicate (sort) { + var sortArray = sort.split(','); + if (sortArray.length > 1){ + sortArray.pop(); + } + return sortArray.join(','); + } + } +})(); diff --git a/src/main/webapp/app/components/util/parse-links.service.js b/src/main/webapp/app/components/util/parse-links.service.js new file mode 100644 index 000000000..63463d623 --- /dev/null +++ b/src/main/webapp/app/components/util/parse-links.service.js @@ -0,0 +1,46 @@ +(function(){ + 'use strict'; + + angular + .module('sprintApp') + .factory('ParseLinks', ParseLinks); + + function ParseLinks () { + + var service = { + parse : parse + }; + + return service; + + function parse(header) { + if (header.length === 0) { + throw new Error('input must not be of zero length'); + } + + // Split parts by comma + var parts = header.split(','); + var links = {}; + // Parse each part into a named link + angular.forEach(parts, function(p) { + var section = p.split(';'); + if (section.length !== 2) { + throw new Error('section could not be split on ";"'); + } + var url = section[0].replace(/<(.*)>/, '$1').trim(); + var queryString = {}; + url.replace( + new RegExp('([^?=&]+)(=([^&]*))?', 'g'), + function($0, $1, $2, $3) { queryString[$1] = $3; } + ); + var page = queryString.page; + if (angular.isString(page)) { + page = parseInt(page); + } + var name = section[1].replace(/rel="(.*)"/, '$1').trim(); + links[name] = page; + }); + return links; + } + } +})(); diff --git a/src/main/webapp/app/components/util/sort-by.directive.js b/src/main/webapp/app/components/util/sort-by.directive.js new file mode 100644 index 000000000..1e80fe02d --- /dev/null +++ b/src/main/webapp/app/components/util/sort-by.directive.js @@ -0,0 +1,24 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('jhSortBy', jhSortBy); + + function jhSortBy() { + var directive = { + restrict: 'A', + scope: false, + require: '^jhSort', + link: linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs, parentCtrl) { + element.bind('click', function () { + parentCtrl.sort(attrs.jhSortBy); + }); + } + } +})(); diff --git a/src/main/webapp/app/components/util/sort.directive.js b/src/main/webapp/app/components/util/sort.directive.js new file mode 100644 index 000000000..7f47996ab --- /dev/null +++ b/src/main/webapp/app/components/util/sort.directive.js @@ -0,0 +1,80 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('jhSort', jhSort); + + function jhSort () { + var directive = { + restrict: 'A', + scope: { + predicate: '=jhSort', + ascending: '=', + callback: '&' + }, + controller: SortController, + controllerAs: 'vm', + bindToController: true + }; + + return directive; + } + + SortController.$inject = ['$scope', '$element']; + + function SortController ($scope, $element) { + var vm = this; + + vm.applyClass = applyClass; + vm.resetClasses = resetClasses; + vm.sort = sort; + vm.triggerApply = triggerApply; + + $scope.$watchGroup(['vm.predicate', 'vm.ascending'], vm.triggerApply); + vm.triggerApply(); + + function applyClass (element) { + var thisIcon = element.find('span.glyphicon'), + sortIcon = 'glyphicon-sort', + sortAsc = 'glyphicon-sort-by-attributes', + sortDesc = 'glyphicon-sort-by-attributes-alt', + remove = sortIcon + ' ' + sortDesc, + add = sortAsc; + if (!vm.ascending) { + remove = sortIcon + ' ' + sortAsc; + add = sortDesc; + } + vm.resetClasses(); + thisIcon.removeClass(remove); + thisIcon.addClass(add); + } + + function resetClasses () { + var allThIcons = $element.find('span.glyphicon'), + sortIcon = 'glyphicon-sort', + sortAsc = 'glyphicon-sort-by-attributes', + sortDesc = 'glyphicon-sort-by-attributes-alt'; + allThIcons.removeClass(sortAsc + ' ' + sortDesc); + allThIcons.addClass(sortIcon); + } + + function sort (field) { + if (field !== vm.predicate) { + vm.ascending = true; + } else { + vm.ascending = !vm.ascending; + } + vm.predicate = field; + $scope.$apply(); + vm.callback(); + } + + function triggerApply (values) { + vm.resetClasses(); + if (values && values[0] !== '_score') { + vm.applyClass($element.find('th[jh-sort-by=\'' + values[0] + '\']')); + } + } + } +})(); diff --git a/src/main/webapp/app/components/util/truncate-characters.filter.js b/src/main/webapp/app/components/util/truncate-characters.filter.js new file mode 100644 index 000000000..c41573ca7 --- /dev/null +++ b/src/main/webapp/app/components/util/truncate-characters.filter.js @@ -0,0 +1,37 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .filter('characters', characters); + + function characters () { + return charactersFilter; + + function charactersFilter(input, chars, breakOnWord) { + if (isNaN(chars)) { + return input; + } + if (chars <= 0) { + return ''; + } + if (input && input.length > chars) { + input = input.substring(0, chars); + + if (!breakOnWord) { + var lastspace = input.lastIndexOf(' '); + // Get last space + if (lastspace !== -1) { + input = input.substr(0, lastspace); + } + } else { + while (input.charAt(input.length-1) === ' ') { + input = input.substr(0, input.length - 1); + } + } + return input + '...'; + } + return input; + } + } +})(); diff --git a/src/main/webapp/app/components/util/truncate-words.filter.js b/src/main/webapp/app/components/util/truncate-words.filter.js new file mode 100644 index 000000000..b6c708227 --- /dev/null +++ b/src/main/webapp/app/components/util/truncate-words.filter.js @@ -0,0 +1,28 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .filter('words', words); + + function words() { + return wordsFilter; + + function wordsFilter(input, words) { + if (isNaN(words)) { + return input; + } + if (words <= 0) { + return ''; + } + if (input) { + var inputWords = input.split(/\s+/); + if (inputWords.length > words) { + input = inputWords.slice(0, words).join(' ') + '...'; + } + } + + return input; + } + } +})(); diff --git a/src/main/webapp/app/entities/entity.state.js b/src/main/webapp/app/entities/entity.state.js new file mode 100644 index 000000000..d441fc51b --- /dev/null +++ b/src/main/webapp/app/entities/entity.state.js @@ -0,0 +1,16 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('entity', { + abstract: true, + parent: 'app' + }); + } +})(); diff --git a/src/main/webapp/app/forms/permessiFerieProcess/start.html b/src/main/webapp/app/forms/permessiFerieProcess/start.html new file mode 100644 index 000000000..8e95c69aa --- /dev/null +++ b/src/main/webapp/app/forms/permessiFerieProcess/start.html @@ -0,0 +1,41 @@ + + + Documenti Principali + + + + + Documenti Allegati + + + + + Titolo + + + + + Commento + + + + + + Data Da + + + + Data A + + + + + + Numero Giorni + + + + + One Time Password + + diff --git a/src/main/webapp/app/home/home.controller.js b/src/main/webapp/app/home/home.controller.js new file mode 100644 index 000000000..e79e6cc79 --- /dev/null +++ b/src/main/webapp/app/home/home.controller.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('HomeController', HomeController); + + HomeController.$inject = ['$scope', 'Principal', 'LoginService', '$state']; + + function HomeController ($scope, Principal, LoginService, $state) { + var vm = this; + + vm.account = null; + vm.isAuthenticated = null; + vm.login = LoginService.open; + vm.register = register; + $scope.$on('authenticationSuccess', function() { + getAccount(); + }); + + getAccount(); + + function getAccount() { + Principal.identity().then(function(account) { + vm.account = account; + vm.isAuthenticated = Principal.isAuthenticated; + }); + } + function register () { + $state.go('register'); + } + } +})(); diff --git a/src/main/webapp/app/home/home.html b/src/main/webapp/app/home/home.html new file mode 100644 index 000000000..94cce698b --- /dev/null +++ b/src/main/webapp/app/home/home.html @@ -0,0 +1,41 @@ + + + + + + + Welcome, Java Hipster! + This is your homepage + + + + You are logged in as user "{{vm.account.login}}". + + + + If you want to sign in, you can try the default accounts:- Administrator (login="admin" and password="admin") - User (login="user" and password="user"). + + + + You don't have an account yet? Register a new account + + + + + If you have any question on JHipster: + + + + JHipster homepage + JHipster on Stack Overflow + JHipster bug tracker + JHipster public chat room + follow @java_hipster on Twitter + + + + If you like JHipster, don't forget to give us a star on Github! + + + + diff --git a/src/main/webapp/app/home/home.state.js b/src/main/webapp/app/home/home.state.js new file mode 100644 index 000000000..72ca0b05c --- /dev/null +++ b/src/main/webapp/app/home/home.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('home', { + parent: 'app', + url: '/', + data: { + authorities: [] + }, + views: { + 'content@': { + templateUrl: 'app/home/home.html', + controller: 'HomeController', + controllerAs: 'vm' + } + }, + resolve: { + mainTranslatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate,$translatePartialLoader) { + $translatePartialLoader.addPart('home'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/layouts/error/accessdenied.html b/src/main/webapp/app/layouts/error/accessdenied.html new file mode 100644 index 000000000..5a4ad126e --- /dev/null +++ b/src/main/webapp/app/layouts/error/accessdenied.html @@ -0,0 +1,13 @@ + + + + + + + Error Page! + + You are not authorized to access the page. + + + + diff --git a/src/main/webapp/app/layouts/error/error.html b/src/main/webapp/app/layouts/error/error.html new file mode 100644 index 000000000..65ad8a407 --- /dev/null +++ b/src/main/webapp/app/layouts/error/error.html @@ -0,0 +1,15 @@ + + + + + + + Error Page! + + + {{errorMessage}} + + + + + diff --git a/src/main/webapp/app/layouts/error/error.state.js b/src/main/webapp/app/layouts/error/error.state.js new file mode 100644 index 000000000..0bf65800f --- /dev/null +++ b/src/main/webapp/app/layouts/error/error.state.js @@ -0,0 +1,50 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider + .state('error', { + parent: 'app', + url: '/error', + data: { + authorities: [], + pageTitle: 'error.title' + }, + views: { + 'content@': { + templateUrl: 'app/layouts/error/error.html' + } + }, + resolve: { + mainTranslatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate,$translatePartialLoader) { + $translatePartialLoader.addPart('error'); + return $translate.refresh(); + }] + } + }) + .state('accessdenied', { + parent: 'app', + url: '/accessdenied', + data: { + authorities: [] + }, + views: { + 'content@': { + templateUrl: 'app/layouts/error/accessdenied.html' + } + }, + resolve: { + mainTranslatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate,$translatePartialLoader) { + $translatePartialLoader.addPart('error'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/layouts/navbar/active-link.directive.js b/src/main/webapp/app/layouts/navbar/active-link.directive.js new file mode 100644 index 000000000..2bbbf2201 --- /dev/null +++ b/src/main/webapp/app/layouts/navbar/active-link.directive.js @@ -0,0 +1,30 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('activeLink', activeLink); + + function activeLink() { + var directive = { + restrict: 'A', + link: linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs) { + var clazz = attrs.activeLink; + var path = attrs.href; + path = path.substring(1); //hack because path does bot return including hashbang + scope.location = location; + scope.$watch('location.path()', function(newPath) { + if (path === newPath) { + element.addClass(clazz); + } else { + element.removeClass(clazz); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/layouts/navbar/active-menu.directive.js b/src/main/webapp/app/layouts/navbar/active-menu.directive.js new file mode 100644 index 000000000..5ef748d98 --- /dev/null +++ b/src/main/webapp/app/layouts/navbar/active-menu.directive.js @@ -0,0 +1,33 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('activeMenu', activeMenu); + + activeMenu.$inject = ['$translate', '$locale', 'tmhDynamicLocale']; + + function activeMenu($translate, $locale, tmhDynamicLocale) { + var directive = { + restrict: 'A', + link: linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs) { + var language = attrs.activeMenu; + + scope.$watch(function() { + return $translate.use(); + }, function(selectedLanguage) { + if (language === selectedLanguage) { + tmhDynamicLocale.set(language); + element.addClass('active'); + } else { + element.removeClass('active'); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/layouts/navbar/navbar.controller.js b/src/main/webapp/app/layouts/navbar/navbar.controller.js new file mode 100644 index 000000000..328f1b2f0 --- /dev/null +++ b/src/main/webapp/app/layouts/navbar/navbar.controller.js @@ -0,0 +1,54 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('NavbarController', NavbarController); + + NavbarController.$inject = ['$state', 'Auth', 'Principal', 'ProfileService', 'LoginService', 'dataService', '$log']; + + function NavbarController ($state, Auth, Principal, ProfileService, LoginService, dataService, $log) { + var vm = this; + + vm.isNavbarCollapsed = true; + vm.isAuthenticated = Principal.isAuthenticated; + + ProfileService.getProfileInfo().then(function(response) { + vm.inProduction = response.inProduction; + vm.swaggerEnabled = response.swaggerEnabled; + }); + + vm.login = login; + vm.logout = logout; + vm.toggleNavbar = toggleNavbar; + vm.collapseNavbar = collapseNavbar; + vm.$state = $state; + + function login() { + collapseNavbar(); + LoginService.open(); + } + + function logout() { + collapseNavbar(); + Auth.logout(); + $state.go('home'); + } + + function toggleNavbar() { + vm.isNavbarCollapsed = !vm.isNavbarCollapsed; + } + + function collapseNavbar() { + vm.isNavbarCollapsed = true; + } + + dataService.definitions.all().then( + function(response) { + vm.wfDefs = response.data.data; + }, function (response) { + $log.error(response); + } + ); + } +})(); diff --git a/src/main/webapp/app/layouts/navbar/navbar.html b/src/main/webapp/app/layouts/navbar/navbar.html new file mode 100644 index 000000000..c934c619f --- /dev/null +++ b/src/main/webapp/app/layouts/navbar/navbar.html @@ -0,0 +1,182 @@ + + + + + Toggle navigation + + + + + + + Sprint v{{VERSION}} + + + + + + + + Home + + + + + + I miei compiti + + + + + + + + Avvia Flusso + + + + + + + + {{wfDef.name}} + + + + + + + + + + + Entities + + + + + + + + + + + + + + Account + + + + + + + + + Settings + + + + + + Password + + + + + + Sign out + + + + + + Sign in + + + + + + Register + + + + + + + + + Administration + + + + + + + + User management + + + + + + Metrics + + + + + + Health + + + + + + Configuration + + + + + + Audits + + + + + + Logs + + + + + + API + + + + + + + Database + + + + + + + + + Language + + + + + + {{language | findLanguageFromKey}} + + + + + + + diff --git a/src/main/webapp/app/pages/main/main.controller.js b/src/main/webapp/app/pages/main/main.controller.js new file mode 100644 index 000000000..b3e19eaa7 --- /dev/null +++ b/src/main/webapp/app/pages/main/main.controller.js @@ -0,0 +1,50 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('MainController', HomeController); + + HomeController.$inject = ['$scope', 'Principal', 'LoginService', '$state', 'dataService', '$log']; + + function HomeController ($scope, Principal, LoginService, $state, dataService, $log) { + var vm = this; + + vm.account = null; + vm.isAuthenticated = null; + vm.login = LoginService.open; + vm.register = register; + $scope.$on('authenticationSuccess', function() { + getAccount(); + }); + + getAccount(); + + function getAccount() { + Principal.identity().then(function(account) { + vm.account = account; + vm.isAuthenticated = Principal.isAuthenticated; + }); + } + function register () { + $state.go('register'); + } + + dataService.tasks.myTasksAvailable() + .then(function (response) { + vm.pooledTask = response.data.total; + }, function (response) { + $log.error(response); + }); + + dataService.tasks.myTasks() + .then(function (response) { + vm.summary = { + 'total' : response.data.total + }; + }, function (response) { + $log.error(response); + }); + + } +})(); diff --git a/src/main/webapp/app/pages/main/main.html b/src/main/webapp/app/pages/main/main.html new file mode 100644 index 000000000..fdf17eaa5 --- /dev/null +++ b/src/main/webapp/app/pages/main/main.html @@ -0,0 +1,45 @@ + + + + + compiti assegnati a me: {{vm.summary.total}}seleziona per avere la lista completa dei compiti assegnati a me + + + compiti di gruppo da prendere in carico: {{vm.pooledTask}}seleziona per avere la lista dei compiti di gruppo da prendere in carico + + + + + + + + + + + + + + + + + + modalità {{advanced ? 'semplice' : 'avanzata'}} + + + Tipologie + + + + + {{assegnatiAMe ? 'Lista dei compiti assegnati a me' : 'Lista dei compiti di gruppo da prendere in carico'}} + + + + {{tasks | json}} + + {{vm | json}} + + diff --git a/src/main/webapp/app/pages/main/main.state.js b/src/main/webapp/app/pages/main/main.state.js new file mode 100644 index 000000000..5ab573b2c --- /dev/null +++ b/src/main/webapp/app/pages/main/main.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('main', { + parent: 'app', + url: '/main', + data: { + authorities: ['ROLE_USER'] + }, + views: { + 'content@': { + templateUrl: 'app/pages/main/main.html', + controller: 'MainController', + controllerAs: 'vm' + } + }, + resolve: { + mainTranslatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate,$translatePartialLoader) { + $translatePartialLoader.addPart('main'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/pages/task/task.controller.js b/src/main/webapp/app/pages/task/task.controller.js new file mode 100644 index 000000000..ce0ad278d --- /dev/null +++ b/src/main/webapp/app/pages/task/task.controller.js @@ -0,0 +1,30 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .controller('TaskController', HomeController); + + HomeController.$inject = ['$scope', 'Principal', 'LoginService', '$state', 'dataService', '$log']; + + function HomeController ($scope, Principal, LoginService, $state, dataService, $log) { + var vm = this; + vm.data = {}; + vm.formUrl = 'app/forms/'+ $state.params.processDefinition +'/'+ $state.params.taskName +'.html'; + $scope.data = {}; + + dataService.definitions.get($state.params.processDefinition) + .then( + function(response) { + vm.definition = response.data; + }, + function(response) { + $log.error(response); + } + ); + + $scope.submitTask = function() { + $log.info(vm.data); + } + } +})(); diff --git a/src/main/webapp/app/pages/task/task.html b/src/main/webapp/app/pages/task/task.html new file mode 100644 index 000000000..6b4356827 --- /dev/null +++ b/src/main/webapp/app/pages/task/task.html @@ -0,0 +1,30 @@ + + + + + {{vm.definition.name}} + {{vm.definition.description}} + + + + + + + + + + + + + Reimposta + + + Avvia Flusso + + + + + + {{scope | json}} + {{vm | json}} + diff --git a/src/main/webapp/app/pages/task/task.state.js b/src/main/webapp/app/pages/task/task.state.js new file mode 100644 index 000000000..ee769d54b --- /dev/null +++ b/src/main/webapp/app/pages/task/task.state.js @@ -0,0 +1,32 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .config(stateConfig); + + stateConfig.$inject = ['$stateProvider']; + + function stateConfig($stateProvider) { + $stateProvider.state('task', { + parent: 'app', + url: '/task?processDefinition&taskName', + data: { + authorities: ['ROLE_USER'] + }, + views: { + 'content@': { + templateUrl: 'app/pages/task/task.html', + controller: 'TaskController', + controllerAs: 'vm' + } + }, + resolve: { + mainTranslatePartialLoader: ['$translate', '$translatePartialLoader', function ($translate,$translatePartialLoader) { + $translatePartialLoader.addPart('task'); + return $translate.refresh(); + }] + } + }); + } +})(); diff --git a/src/main/webapp/app/services/auth/account.service.js b/src/main/webapp/app/services/auth/account.service.js new file mode 100644 index 000000000..a1f355f77 --- /dev/null +++ b/src/main/webapp/app/services/auth/account.service.js @@ -0,0 +1,25 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('Account', Account); + + Account.$inject = ['$resource']; + + function Account ($resource) { + var service = $resource('api/ldap-account', {}, { + 'get': { method: 'GET', params: {}, isArray: false, + interceptor: { + response: function(response) { + // expose response + response.data.langKey = 'it'; + return response; + } + } + } + }); + + return service; + } +})(); diff --git a/src/main/webapp/app/services/auth/activate.service.js b/src/main/webapp/app/services/auth/activate.service.js new file mode 100644 index 000000000..db0aec09e --- /dev/null +++ b/src/main/webapp/app/services/auth/activate.service.js @@ -0,0 +1,17 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('Activate', Activate); + + Activate.$inject = ['$resource']; + + function Activate ($resource) { + var service = $resource('api/activate', {}, { + 'get': { method: 'GET', params: {}, isArray: false} + }); + + return service; + } +})(); diff --git a/src/main/webapp/app/services/auth/auth.oauth2.service.js b/src/main/webapp/app/services/auth/auth.oauth2.service.js new file mode 100644 index 000000000..7c8eef853 --- /dev/null +++ b/src/main/webapp/app/services/auth/auth.oauth2.service.js @@ -0,0 +1,52 @@ +(function() { + /*jshint camelcase: false */ + 'use strict'; + + angular + .module('sprintApp') + .factory('AuthServerProvider', AuthServerProvider); + + AuthServerProvider.$inject = ['$http', '$localStorage', 'Base64']; + + function AuthServerProvider ($http, $localStorage, Base64) { + var service = { + getToken: getToken, + login: login, + logout: logout + }; + + return service; + + function getToken () { + return $localStorage.authenticationToken; + } + + function login (credentials) { + var data = 'username=' + encodeURIComponent(credentials.username) + '&password=' + + encodeURIComponent(credentials.password) + '&grant_type=password&scope=read%20write&' + + 'client_secret=my-secret-token-to-change-in-production&client_id=sprintapp'; + + return $http.post('oauth/token', data, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + 'Authorization': 'Basic ' + Base64.encode('sprintapp' + ':' + 'my-secret-token-to-change-in-production') + } + }).success(authSucess); + + function authSucess (response) { + var expiredAt = new Date(); + expiredAt.setSeconds(expiredAt.getSeconds() + response.expires_in); + response.expires_at = expiredAt.getTime(); + $localStorage.authenticationToken = response; + return response; + } + } + + function logout () { + $http.post('api/logout').then(function() { + delete $localStorage.authenticationToken; + }); + } + } +})(); diff --git a/src/main/webapp/app/services/auth/auth.service.js b/src/main/webapp/app/services/auth/auth.service.js new file mode 100644 index 000000000..eec22911e --- /dev/null +++ b/src/main/webapp/app/services/auth/auth.service.js @@ -0,0 +1,183 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('Auth', Auth); + + Auth.$inject = ['$rootScope', '$state', '$sessionStorage', '$q', '$translate', 'Principal', 'AuthServerProvider', 'Account', 'LoginService', 'Register', 'Activate', 'Password', 'PasswordResetInit', 'PasswordResetFinish']; + + function Auth ($rootScope, $state, $sessionStorage, $q, $translate, Principal, AuthServerProvider, Account, LoginService, Register, Activate, Password, PasswordResetInit, PasswordResetFinish) { + var service = { + activateAccount: activateAccount, + authorize: authorize, + changePassword: changePassword, + createAccount: createAccount, + getPreviousState: getPreviousState, + login: login, + logout: logout, + resetPasswordFinish: resetPasswordFinish, + resetPasswordInit: resetPasswordInit, + resetPreviousState: resetPreviousState, + storePreviousState: storePreviousState, + updateAccount: updateAccount + }; + + return service; + + function activateAccount (key, callback) { + var cb = callback || angular.noop; + + return Activate.get(key, + function (response) { + return cb(response); + }, + function (err) { + return cb(err); + }.bind(this)).$promise; + } + + function authorize (force) { + var authReturn = Principal.identity(force).then(authThen); + + return authReturn; + + function authThen () { + var isAuthenticated = Principal.isAuthenticated(); + + // an authenticated user can't access to login and register pages + if (isAuthenticated && $rootScope.toState.parent === 'account' && ($rootScope.toState.name === 'login' || $rootScope.toState.name === 'register')) { + $state.go('home'); + } + + // recover and clear previousState after external login redirect (e.g. oauth2) + if (isAuthenticated && !$rootScope.fromState.name && getPreviousState()) { + var previousState = getPreviousState(); + resetPreviousState(); + $state.go(previousState.name, previousState.params); + } + + if ($rootScope.toState.data.authorities && $rootScope.toState.data.authorities.length > 0 && !Principal.hasAnyAuthority($rootScope.toState.data.authorities)) { + if (isAuthenticated) { + // user is signed in but not authorized for desired state + $state.go('accessdenied'); + } + else { + // user is not authenticated. stow the state they wanted before you + // send them to the login service, so you can return them when you're done + storePreviousState($rootScope.toState.name, $rootScope.toStateParams); + + // now, send them to the signin state so they can log in + $state.go('accessdenied').then(function() { + LoginService.open(); + }); + } + } + } + } + + function changePassword (newPassword, callback) { + var cb = callback || angular.noop; + + return Password.save(newPassword, function () { + return cb(); + }, function (err) { + return cb(err); + }).$promise; + } + + function createAccount (account, callback) { + var cb = callback || angular.noop; + + return Register.save(account, + function () { + return cb(account); + }, + function (err) { + this.logout(); + return cb(err); + }.bind(this)).$promise; + } + + function login (credentials, callback) { + var cb = callback || angular.noop; + var deferred = $q.defer(); + + AuthServerProvider.login(credentials) + .then(loginThen) + .catch(function (err) { + this.logout(); + deferred.reject(err); + return cb(err); + }.bind(this)); + + function loginThen (data) { + Principal.identity(true).then(function(account) { + // After the login the language will be changed to + // the language selected by the user during his registration + if (account!== null) { + $translate.use(account.langKey).then(function () { + $translate.refresh(); + }); + } + deferred.resolve(data); + }); + return cb(); + } + + return deferred.promise; + } + + + function logout () { + AuthServerProvider.logout(); + Principal.authenticate(null); + } + + function resetPasswordFinish (keyAndPassword, callback) { + var cb = callback || angular.noop; + + return PasswordResetFinish.save(keyAndPassword, function () { + return cb(); + }, function (err) { + return cb(err); + }).$promise; + } + + function resetPasswordInit (mail, callback) { + var cb = callback || angular.noop; + + return PasswordResetInit.save(mail, function() { + return cb(); + }, function (err) { + return cb(err); + }).$promise; + } + + function updateAccount (account, callback) { + var cb = callback || angular.noop; + + return Account.save(account, + function () { + return cb(account); + }, + function (err) { + return cb(err); + }.bind(this)).$promise; + } + + function getPreviousState() { + var previousState = $sessionStorage.previousState; + return previousState; + } + + function resetPreviousState() { + delete $sessionStorage.previousState; + } + + function storePreviousState(previousStateName, previousStateParams) { + var previousState = { "name": previousStateName, "params": previousStateParams }; + $sessionStorage.previousState = previousState; + } + } +})(); diff --git a/src/main/webapp/app/services/auth/has-any-authority.directive.js b/src/main/webapp/app/services/auth/has-any-authority.directive.js new file mode 100644 index 000000000..deed9eb46 --- /dev/null +++ b/src/main/webapp/app/services/auth/has-any-authority.directive.js @@ -0,0 +1,52 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('hasAnyAuthority', hasAnyAuthority); + + hasAnyAuthority.$inject = ['Principal']; + + function hasAnyAuthority(Principal) { + var directive = { + restrict: 'A', + link: linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs) { + var authorities = attrs.hasAnyAuthority.replace(/\s+/g, '').split(','); + + var setVisible = function () { + element.removeClass('hidden'); + }, + setHidden = function () { + element.addClass('hidden'); + }, + defineVisibility = function (reset) { + var result; + if (reset) { + setVisible(); + } + + result = Principal.hasAnyAuthority(authorities); + if (result) { + setVisible(); + } else { + setHidden(); + } + }; + + if (authorities.length > 0) { + defineVisibility(true); + + scope.$watch(function() { + return Principal.isAuthenticated(); + }, function() { + defineVisibility(true); + }); + } + } + } +})(); diff --git a/src/main/webapp/app/services/auth/has-authority.directive.js b/src/main/webapp/app/services/auth/has-authority.directive.js new file mode 100644 index 000000000..6fc28348d --- /dev/null +++ b/src/main/webapp/app/services/auth/has-authority.directive.js @@ -0,0 +1,54 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('hasAuthority', hasAuthority); + + hasAuthority.$inject = ['Principal']; + + function hasAuthority(Principal) { + var directive = { + restrict: 'A', + link: linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs) { + var authority = attrs.hasAuthority.replace(/\s+/g, ''); + + var setVisible = function () { + element.removeClass('hidden'); + }, + setHidden = function () { + element.addClass('hidden'); + }, + defineVisibility = function (reset) { + + if (reset) { + setVisible(); + } + + Principal.hasAuthority(authority) + .then(function (result) { + if (result) { + setVisible(); + } else { + setHidden(); + } + }); + }; + + if (authority.length > 0) { + defineVisibility(true); + + scope.$watch(function() { + return Principal.isAuthenticated(); + }, function() { + defineVisibility(true); + }); + } + } + } +})(); diff --git a/src/main/webapp/app/services/auth/password-reset-finish.service.js b/src/main/webapp/app/services/auth/password-reset-finish.service.js new file mode 100644 index 000000000..19af0c741 --- /dev/null +++ b/src/main/webapp/app/services/auth/password-reset-finish.service.js @@ -0,0 +1,15 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('PasswordResetFinish', PasswordResetFinish); + + PasswordResetFinish.$inject = ['$resource']; + + function PasswordResetFinish($resource) { + var service = $resource('api/account/reset_password/finish', {}, {}); + + return service; + } +})(); diff --git a/src/main/webapp/app/services/auth/password-reset-init.service.js b/src/main/webapp/app/services/auth/password-reset-init.service.js new file mode 100644 index 000000000..cefcb2a66 --- /dev/null +++ b/src/main/webapp/app/services/auth/password-reset-init.service.js @@ -0,0 +1,15 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('PasswordResetInit', PasswordResetInit); + + PasswordResetInit.$inject = ['$resource']; + + function PasswordResetInit($resource) { + var service = $resource('api/account/reset_password/init', {}, {}); + + return service; + } +})(); diff --git a/src/main/webapp/app/services/auth/password.service.js b/src/main/webapp/app/services/auth/password.service.js new file mode 100644 index 000000000..666b6476b --- /dev/null +++ b/src/main/webapp/app/services/auth/password.service.js @@ -0,0 +1,15 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('Password', Password); + + Password.$inject = ['$resource']; + + function Password($resource) { + var service = $resource('api/account/change_password', {}, {}); + + return service; + } +})(); diff --git a/src/main/webapp/app/services/auth/principal.service.js b/src/main/webapp/app/services/auth/principal.service.js new file mode 100644 index 000000000..24663e9c0 --- /dev/null +++ b/src/main/webapp/app/services/auth/principal.service.js @@ -0,0 +1,99 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('Principal', Principal); + + Principal.$inject = ['$q', 'Account']; + + function Principal ($q, Account) { + var _identity, + _authenticated = false; + + var service = { + authenticate: authenticate, + hasAnyAuthority: hasAnyAuthority, + hasAuthority: hasAuthority, + identity: identity, + isAuthenticated: isAuthenticated, + isIdentityResolved: isIdentityResolved + }; + + return service; + + function authenticate (identity) { + _identity = identity; + _authenticated = identity !== null; + } + + function hasAnyAuthority (authorities) { + if (!_authenticated || !_identity || !_identity.authorities) { + return false; + } + + for (var i = 0; i < authorities.length; i++) { + if (_identity.authorities.indexOf(authorities[i]) !== -1) { + return true; + } + } + + return false; + } + + function hasAuthority (authority) { + if (!_authenticated) { + return $q.when(false); + } + + return this.identity().then(function(_id) { + return _id.authorities && _id.authorities.indexOf(authority) !== -1; + }, function(){ + return false; + }); + } + + function identity (force) { + var deferred = $q.defer(); + + if (force === true) { + _identity = undefined; + } + + // check and see if we have retrieved the identity data from the server. + // if we have, reuse it by immediately resolving + if (angular.isDefined(_identity)) { + deferred.resolve(_identity); + + return deferred.promise; + } + + // retrieve the identity data from the server, update the identity object, and then resolve. + Account.get().$promise + .then(getAccountThen) + .catch(getAccountCatch); + + return deferred.promise; + + function getAccountThen (account) { + _identity = account.data; + _authenticated = true; + deferred.resolve(_identity); + } + + function getAccountCatch () { + _identity = null; + _authenticated = false; + deferred.resolve(_identity); + } + } + + function isAuthenticated () { + return _authenticated; + } + + function isIdentityResolved () { + return angular.isDefined(_identity); + } + } +})(); diff --git a/src/main/webapp/app/services/auth/register.service.js b/src/main/webapp/app/services/auth/register.service.js new file mode 100644 index 000000000..38ebcf4c8 --- /dev/null +++ b/src/main/webapp/app/services/auth/register.service.js @@ -0,0 +1,13 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + .factory('Register', Register); + + Register.$inject = ['$resource']; + + function Register ($resource) { + return $resource('api/register', {}, {}); + } +})(); diff --git a/src/main/webapp/app/services/cnr/data.js b/src/main/webapp/app/services/cnr/data.js new file mode 100644 index 000000000..7b44d4d59 --- /dev/null +++ b/src/main/webapp/app/services/cnr/data.js @@ -0,0 +1,38 @@ +(function() { + 'use strict'; + + angular.module('sprintApp') + .factory('dataService', Data); + + + Data.$inject = ['$http', '$location', '$rootScope', '$log', '$sessionStorage']; + + function Data ($http, $location, $rootScope, $log, $sessionStorage) { + + var development = $location.$$port === 9000; //GRUNT PORT; + var proxy = 'proxy'; + var base = 'rest/'; + + $rootScope.development = development; + + + return { + tasks: { + myTasks : function() { + return $http.get('rest/tasks/mytasks'); + }, + myTasksAvailable : function() { + return $http.get('rest/tasks/mytasksavailable'); + } + }, + definitions : { + all : function() { + return $http.get('rest/processdefinitions/all'); + }, + get: function(id) { + return $http.get('rest/processdefinitions/'+ id); + } + } + }; + } +})(); \ No newline at end of file diff --git a/src/main/webapp/app/services/cnr/data_old.js b/src/main/webapp/app/services/cnr/data_old.js new file mode 100644 index 000000000..e1bb53730 --- /dev/null +++ b/src/main/webapp/app/services/cnr/data_old.js @@ -0,0 +1,277 @@ +(function() { + 'use strict'; + + angular.module('sprintApp') + .factory('dataServiceDeprecated', Data); + + + Data.$inject = ['$http', '$location', '$rootScope', '$log', '$sessionStorage']; + + function Data ($http, $location, $rootScope, $log, $sessionStorage) { + + var development = $location.$$port === 9000; //GRUNT PORT; + var proxy = 'proxy'; + var base = 'rest/'; + + $rootScope.development = development; + + function ajax (url, settings) { + var defaults = { + method: 'GET', + headers: { + 'X-CNR-Client': 'flowsApp', + 'X-alfresco-ticket': $sessionStorage.ticket + } + }; + + var conf = _.extend({ + url: base + url + }, defaults, settings); + + $log.debug(conf); + + return $http(conf); + } + + return { + urls: { + drop: base + 'drop', + dropupdate: base + 'drop-update', + proxy: base + proxy + '/', + content: base + proxy + '/service/api/node/content/workspace/SpacesStore', + person: base + proxy + '/service/cnr/person/autocomplete-person', + instances: base + 'instances', + bulkinfotest: base + 'bulkinfotest', + metadata: base + 'metadata' + }, + descendants: function (id) { + return ajax('descendants', { + params: { + id: id + } + }); + }, + groupMembers: function (id, format) { + return ajax('authority/members?id='+ id +'&format='+format); + }, + search: function (params) { + + var defaultParams = { + maxItems: 10, + skipCount: 0, + fetchCmisObject: false, + calculateTotalNumItems: false + }; + + return ajax('search', { + params: _.extend({}, defaultParams, params) + }); + }, + security: { + login: function (username, password) { + return ajax('security/login', { + method: 'POST', + data: { + username: username, + password: password + } + }); + }, + logout: function () { + return ajax('security/logout', { + method: 'DELETE' + }); + } + }, + common: function () { + return ajax('common'); + }, + i18n: function () { + return ajax('i18n'); + }, + bulkInfo: function (key, name, type) { + return ajax('bulkInfo/view/' + key + '/' + (type || 'form') + '/' + (name || 'default')); + }, + bulkInfoTest: function (xml) { + return ajax('bulkInfoTest', {method: 'POST', headers: { "Content-Type": 'application/xml' }, data: xml}); + }, + processinstances: { + myinstances: function (params) { + return ajax('processinstances/myinstances', { + params: params || {} + }); + }, + startProcessInstance: function (processName, data) { + return ajax('processinstances/start/'+ processName, { + method: 'GET', + data: data + }); + }, + completeTask: function (taskId, data) { + return ajax('taskinstances/complete/'+ taskId, { + method: 'POST', + data: data + }); + }, + getTaskInstance: function (params, id) { + return ajax('taskinstances/'+ id, { + params: params + }); + }, + assignTask: function (id, data) { + return ajax('taskinstances/'+ id, { + method: 'PUT', + data: data + }); + }, + claimTask: function (id) { + return ajax('taskinstances/claim/'+ id, { + method: 'PUT' + }); + }, + unclaimTask: function (id) { + return ajax('taskinstances/unclaim/'+ id, { + method: 'PUT' + }); + }, + processes: function (params) { + return ajax('processinstances/processes', { + params: params || {} + }); + }, + workflowDefinitions: function (definitionId) { + return ajax('workflowResource/workflowDefinitions', { + params: { + definitionId: definitionId + } + }); + }, + workflowInstancesById: function (id) { + return ajax('processinstances/' + id, { + params: { + includeTasks: true + } + }); + }, + workflowVariableById: function (id) { + return ajax('processinstances/variables/' + id.substring(id.indexOf('$') + 1)) + }, + taskVariableById: function (id) { + return ajax('taskinstances/variables/' + id.substring(id.indexOf('$') + 1)); + }, + myTasks: function (params) { + return ajax('taskinstances/mytasks', { + params: params || {} + }); + }, + myTasksAvailable: function (params) { + return ajax('taskinstances/mytasksavailable', { + params: params || {} + }); + }, + processDefinitions: function (where) { + return ajax('workflowResource/processDefinitions', { + params: { + where: where + } + }); + }, + deleteWorkflow: function (id) { + return ajax('processinstances/deleteWorkflow', { + method: 'DELETE', + params: { + workflowId: id.split('$')[1] + } + }); + } + // missioni: { + // bulkInfo: function () { + // return ajax(proxy + '_nodes', { + // params: { + // backend: 'missioni', + // } + // }); + // } + // } + }, + metadata: { + byNodeRef: function (params) { + return ajax('metadata', { + params: params + }); + }, + byId: function (qname, id) { + return ajax('metadataById', { + params: { + properties: qname, + assignedByMeWorkflowIds: id + } + }); + } + }, + authority: { + groups: { +// todo: da testare la chiamata dall'applicazione + myGroupsDescendant: function (userId) { + return ajax('authority/myGroupsDescendant', { + params: { + userId: userId + } + }); + } + }, + person: { +// todo: da testare la chiamata dall'applicazione + whoami: function () { + return ajax('authority/whoami'); + } + }, + incarichi: function() { + return ajax('authority/incarichi'); + }, + incarica: function(groupName, userName) { + return ajax('authority/incarica', { + method: 'PUT', + data: { + groupName: groupName, + userName: userName + } + }); + }, + rimuoviIncarico: function(groupName, userName) { + return ajax('authority/incarica?groupName='+groupName+'&userName='+userName, { + method: 'DELETE' + }); + } + }, + + // TODO deprecated + proxySupervisor: { + api: { + workflowInstances: function (definitionName, params) { + return ajax('processinstances/workflowInstances/' + definitionName, { + params: { + skipCount: params["skipCount"], + maxItems: params["maxItems"], + where: params["where"] + } + }); + }, + workflowInstanceById: function (id, workflowInstanceById) { + return ajax('processinstances/workflowInstancesById/' + workflowInstanceById + '/' + id); + }, +// workflowVariableById: function (id, workflowInstanceById) { +// return ajax(supervisorProxy + '/workflow-variable/' + workflowInstanceById + '/' + id.substring(id.indexOf('$') + 1)); +// nuovo da testare + workflowVariableById: function (id) { + return ajax('processinstances/variables/' + id); + } + } + }, + + user: function() { + return ajax('user'); + } + }; + } +})(); \ No newline at end of file diff --git a/src/main/webapp/app/services/profiles/page-ribbon.directive.js b/src/main/webapp/app/services/profiles/page-ribbon.directive.js new file mode 100644 index 000000000..e162c64f0 --- /dev/null +++ b/src/main/webapp/app/services/profiles/page-ribbon.directive.js @@ -0,0 +1,30 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .directive('pageRibbon', pageRibbon); + + pageRibbon.$inject = ['ProfileService', '$rootScope', '$translate']; + + function pageRibbon(ProfileService, $rootScope, $translate) { + var directive = { + replace : true, + restrict : 'AE', + template : '{{ribbonEnv}}', + link : linkFunc + }; + + return directive; + + function linkFunc(scope, element, attrs) { + ProfileService.getProfileInfo().then(function(response) { + if (response.ribbonEnv) { + scope.ribbonEnv = response.ribbonEnv; + element.addClass(response.ribbonEnv); + element.removeClass('hidden'); + } + }); + } + } +})(); diff --git a/src/main/webapp/app/services/profiles/profile.service.js b/src/main/webapp/app/services/profiles/profile.service.js new file mode 100644 index 000000000..cf74b92ba --- /dev/null +++ b/src/main/webapp/app/services/profiles/profile.service.js @@ -0,0 +1,36 @@ +(function() { + 'use strict'; + + angular + .module('sprintApp') + .factory('ProfileService', ProfileService); + + ProfileService.$inject = ['$q', '$http']; + + function ProfileService($q, $http) { + + var dataPromise; + + var service = { + getProfileInfo : getProfileInfo + }; + + return service; + + function getProfileInfo() { + if (angular.isUndefined(dataPromise)) { + dataPromise = $http.get('api/profile-info').then(function(result) { + if (result.data.activeProfiles) { + var response = {}; + response.activeProfiles = result.data.activeProfiles; + response.ribbonEnv = result.data.ribbonEnv; + response.inProduction = result.data.activeProfiles.indexOf("prod") !== -1; + response.swaggerEnabled = result.data.activeProfiles.indexOf("swagger") !== -1; + return response; + } + }); + } + return dataPromise; + } + } +})(); diff --git a/src/main/webapp/app/services/user/user.service.js b/src/main/webapp/app/services/user/user.service.js new file mode 100644 index 000000000..a060920ab --- /dev/null +++ b/src/main/webapp/app/services/user/user.service.js @@ -0,0 +1,27 @@ +(function () { + 'use strict'; + + angular + .module('sprintApp') + .factory('User', User); + + User.$inject = ['$resource']; + + function User ($resource) { + var service = $resource('api/users/:login', {}, { + 'query': {method: 'GET', isArray: true}, + 'get': { + method: 'GET', + transformResponse: function (data) { + data = angular.fromJson(data); + return data; + } + }, + 'save': { method:'POST' }, + 'update': { method:'PUT' }, + 'delete':{ method:'DELETE'} + }); + + return service; + } +})(); diff --git a/src/main/webapp/content/css/documentation.css b/src/main/webapp/content/css/documentation.css new file mode 100644 index 000000000..ba600a3f9 --- /dev/null +++ b/src/main/webapp/content/css/documentation.css @@ -0,0 +1,3 @@ +/*! + * Your CSS files will be generated in this directory by "gulp sass" + */ diff --git a/src/main/webapp/content/css/main.css b/src/main/webapp/content/css/main.css new file mode 100644 index 000000000..44e9fc772 --- /dev/null +++ b/src/main/webapp/content/css/main.css @@ -0,0 +1,342 @@ +body { + background: #fafafa; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #333; +} + +/* ========================================================================== +Hide ng-cloak on page load, https://docs.angularjs.org/api/ng/directive/ngCloak +========================================================================== */ +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +/* ========================================================================== +Developement Ribbon +========================================================================== */ +.ribbon { + background-color: #a00; + box-shadow: 0 0 10px #888; + left: -3.5em; + moz-box-shadow: 0 0 10px #888; + moz-transform: rotate(-45deg); + ms-transform: rotate(-45deg); + o-transform: rotate(-45deg); + overflow: hidden; + position: absolute; + top: 40px; + transform: rotate(-45deg); + webkit-box-shadow: 0 0 10px #888; + webkit-transform: rotate(-45deg); + white-space: nowrap; + width: 15em; + z-index: 9999; + pointer-events: none; +} + +.ribbon a { + border: 1px solid #faa; + color: #fff; + display: block; + font: bold 81.25% 'Helvetica Neue', Helvetica, Arial, sans-serif; + margin: 1px 0; + padding: 10px 50px; + text-align: center; + text-decoration: none; + text-shadow: 0 0 5px #444; + pointer-events: none; +} + +/* ========================================================================== +Version number in navbar +========================================================================== */ +.navbar-version { + font-size: 10px; + color: #ccc +} + +/* ========================================================================== +Browser Upgrade Prompt +========================================================================== */ +.browserupgrade { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +/* ========================================================================== +Logo styles +========================================================================== */ +.navbar-brand.logo { + padding: 5px 15px; +} + +.logo .logo-img { + height: 45px; + display: inline-block; +} + +/* ========================================================================== +Main page styles +========================================================================== */ +.hero-unit { + margin: 50px auto 0 auto; + width: 300px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + background-color: #eee; + border-radius: 6px; + padding: 60px; +} + +.hero-unit h1 { + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} + +.hipster { + display: inline-block; + width: 347px; + height: 497px; + background: url("../images/hipster.png") no-repeat center top; + background-size: contain; +} + +/* wait autoprefixer update to allow simple generation of high pixel density media query */ +@media +only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and ( min--moz-device-pixel-ratio: 2), +only screen and ( -o-min-device-pixel-ratio: 2/1), +only screen and ( min-device-pixel-ratio: 2), +only screen and ( min-resolution: 192dpi), +only screen and ( min-resolution: 2dppx) { + .hipster { + background: url("../images/hipster2x.png") no-repeat center top; + background-size: contain; + } +} + +/* ========================================================================== +Generic styles +========================================================================== */ +.error { + color: white; + background-color: red; +} + +.pad { + padding: 10px; +} + +.break { + white-space: normal; + word-break:break-all; +} + +.voffset { margin-top: 2px; } +.voffset1 { margin-top: 5px; } +.voffset2 { margin-top: 10px; } +.voffset3 { margin-top: 15px; } +.voffset4 { margin-top: 30px; } +.voffset5 { margin-top: 40px; } +.voffset6 { margin-top: 60px; } +.voffset7 { margin-top: 80px; } +.voffset8 { margin-top: 100px; } +.voffset9 { margin-top: 150px; } + +.readonly { + background-color: #eee; + opacity: 1; +} + +/* ========================================================================== +make sure browsers use the pointer cursor for anchors, even with no href +========================================================================== */ +a:hover { + cursor: pointer; +} + +.hand { + cursor: pointer; +} + +/* ========================================================================== +Metrics and Health styles +========================================================================== */ +#threadDump .popover, #healthCheck .popover { + top: inherit; + display: block; + font-size: 10px; + max-width: 1024px; +} + +#healthCheck .popover { + margin-left: -50px; +} + +.health-details { + min-width: 400px; +} + +/* ========================================================================== +start Password strength bar style +========================================================================== */ +ul#strengthBar { + display:inline; + list-style:none; + margin:0; + margin-left:15px; + padding:0; + vertical-align:2px; +} + +.point:last { + margin:0 !important; +} +.point { + background:#DDD; + border-radius:2px; + display:inline-block; + height:5px; + margin-right:1px; + width:20px; +} + +/* ========================================================================== +Custom alerts for notification +========================================================================== */ +.alerts .alert{ + text-overflow: ellipsis; +} +.alert pre{ + background: none; + border: none; + font: inherit; + color: inherit; + padding: 0; + margin: 0; +} + +.alert .popover pre { + font-size: 10px; +} + +.alerts .toast { + position: fixed; + width: 100%; +} + +.alerts .toast.left { + left: 5px; +} + +.alerts .toast.right { + right: 5px; +} + +.alerts .toast.top { + top: 55px; +} + +.alerts .toast.bottom { + bottom: 55px; +} + +@media screen and (min-width: 480px) { + .alerts .toast { + width: 50%; + } +} + +/* ========================================================================== +entity tables helpers +========================================================================== */ +/* Remove Bootstrap padding from the element + http://stackoverflow.com/questions/19562903/remove-padding-from-columns-in-bootstrap-3 */ +.no-padding-left { padding-left: 0 !important; } +.no-padding-right { padding-right: 0 !important; } +.no-padding-top { padding-top: 0 !important; } +.no-padding-bottom { padding-bottom: 0 !important; } +.no-padding { padding: 0 !important; } + +/* bootstrap 3 input-group 100% width + http://stackoverflow.com/questions/23436430/bootstrap-3-input-group-100-width */ +.width-min { width: 1% !important; } + +/* Makes toolbar not wrap on smaller screens + http://www.sketchingwithcss.com/samplechapter/cheatsheet.html#right */ +.flex-btn-group-container { + display: -webkit-flex; + display: flex; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-justify-content: flex-end; + justify-content: flex-end; +} + +.jh-table > tbody > tr > td { + /* Align text in td verifically (top aligned by Bootstrap) */ + vertical-align: middle; +} + +.jh-table > thead > tr > th > .glyphicon-sort, .jh-table > thead > tr > th > .glyphicon-sort-by-attributes, .jh-table > thead > tr > th > .glyphicon-sort-by-attributes-alt { + /* less visible sorting icons */ + opacity: 0.5; +} + +.jh-table > thead > tr > th > .glyphicon-sort:hover, .jh-table > thead > tr > th > .glyphicon-sort-by-attributes:hover, .jh-table > thead > tr > th > .glyphicon-sort-by-attributes-alt:hover { + /* full visible sorting icons and pointer when mouse is over them */ + opacity: 1; + cursor: pointer; +} + +/* ========================================================================== +entity detail page css +========================================================================== */ +.dl-horizontal.jh-entity-details > dd { + margin-bottom: 15px; +} + +@media screen and (min-width: 768px) { + .dl-horizontal.jh-entity-details > dt { + margin-bottom: 15px; + } + + .dl-horizontal.jh-entity-details > dd { + border-bottom: 1px solid #eee; + padding-left: 180px; + margin-left: 0; + } +} + +/* ========================================================================== +ui bootstrap tweaks +========================================================================== */ +.nav, .pagination, .carousel, .panel-title a { + cursor: pointer; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table .btn-default, +.uib-datepicker-popup > li > div.uib-datepicker > table .btn-default { + border: 0; +} + +.datetime-picker-dropdown > li.date-picker-menu div > table:focus, +.uib-datepicker-popup > li > div.uib-datepicker > table:focus { + outline: none; +} + + + +/* jhipster-needle-css-add-main JHipster will add new css style */ + +.img-bordered { + box-shadow: 4px 4px 13px 2px rgba(0, 0, 0, 0.5) +} + +input.ng-dirty.ng-invalid { + border: solid 1px red; +} \ No newline at end of file diff --git a/src/main/webapp/content/images/hipster.png b/src/main/webapp/content/images/hipster.png new file mode 100644 index 000000000..141778d48 Binary files /dev/null and b/src/main/webapp/content/images/hipster.png differ diff --git a/src/main/webapp/content/images/hipster2x.png b/src/main/webapp/content/images/hipster2x.png new file mode 100644 index 000000000..4751c9168 Binary files /dev/null and b/src/main/webapp/content/images/hipster2x.png differ diff --git a/src/main/webapp/content/images/logo-jhipster.png b/src/main/webapp/content/images/logo-jhipster.png new file mode 100644 index 000000000..d8eb48da0 Binary files /dev/null and b/src/main/webapp/content/images/logo-jhipster.png differ diff --git a/src/main/webapp/favicon.ico b/src/main/webapp/favicon.ico new file mode 100644 index 000000000..44c7595f5 Binary files /dev/null and b/src/main/webapp/favicon.ico differ diff --git a/src/main/webapp/i18n/angular-locale_en.js b/src/main/webapp/i18n/angular-locale_en.js new file mode 100644 index 000000000..f794bab8b --- /dev/null +++ b/src/main/webapp/i18n/angular-locale_en.js @@ -0,0 +1,143 @@ +'use strict'; +angular.module("ngLocale", [], ["$provide", function($provide) { +var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"}; +function getDecimals(n) { + n = n + ''; + var i = n.indexOf('.'); + return (i == -1) ? 0 : n.length - i - 1; +} + +function getVF(n, opt_precision) { + var v = opt_precision; + + if (undefined === v) { + v = Math.min(getDecimals(n), 3); + } + + var base = Math.pow(10, v); + var f = ((n * base) | 0) % base; + return {v: v, f: f}; +} + +$provide.value("$locale", { + "DATETIME_FORMATS": { + "AMPMS": [ + "AM", + "PM" + ], + "DAY": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "ERANAMES": [ + "Before Christ", + "Anno Domini" + ], + "ERAS": [ + "BC", + "AD" + ], + "FIRSTDAYOFWEEK": 6, + "MONTH": [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + ], + "SHORTDAY": [ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + ], + "SHORTMONTH": [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ], + "STANDALONEMONTH": [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + ], + "WEEKENDRANGE": [ + 5, + 6 + ], + "fullDate": "EEEE, MMMM d, y", + "longDate": "MMMM d, y", + "medium": "MMM d, y h:mm:ss a", + "mediumDate": "MMM d, y", + "mediumTime": "h:mm:ss a", + "short": "M/d/yy h:mm a", + "shortDate": "M/d/yy", + "shortTime": "h:mm a" + }, + "NUMBER_FORMATS": { + "CURRENCY_SYM": "$", + "DECIMAL_SEP": ".", + "GROUP_SEP": ",", + "PATTERNS": [ + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 3, + "minFrac": 0, + "minInt": 1, + "negPre": "-", + "negSuf": "", + "posPre": "", + "posSuf": "" + }, + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 2, + "minFrac": 2, + "minInt": 1, + "negPre": "-\u00a4", + "negSuf": "", + "posPre": "\u00a4", + "posSuf": "" + } + ] + }, + "id": "en", + "localeID": "en", + "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;} +}); +}]); diff --git a/src/main/webapp/i18n/angular-locale_it.js b/src/main/webapp/i18n/angular-locale_it.js new file mode 100644 index 000000000..9b6a662ff --- /dev/null +++ b/src/main/webapp/i18n/angular-locale_it.js @@ -0,0 +1,143 @@ +'use strict'; +angular.module("ngLocale", [], ["$provide", function($provide) { +var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"}; +function getDecimals(n) { + n = n + ''; + var i = n.indexOf('.'); + return (i == -1) ? 0 : n.length - i - 1; +} + +function getVF(n, opt_precision) { + var v = opt_precision; + + if (undefined === v) { + v = Math.min(getDecimals(n), 3); + } + + var base = Math.pow(10, v); + var f = ((n * base) | 0) % base; + return {v: v, f: f}; +} + +$provide.value("$locale", { + "DATETIME_FORMATS": { + "AMPMS": [ + "AM", + "PM" + ], + "DAY": [ + "domenica", + "luned\u00ec", + "marted\u00ec", + "mercoled\u00ec", + "gioved\u00ec", + "venerd\u00ec", + "sabato" + ], + "ERANAMES": [ + "a.C.", + "d.C." + ], + "ERAS": [ + "aC", + "dC" + ], + "FIRSTDAYOFWEEK": 0, + "MONTH": [ + "gennaio", + "febbraio", + "marzo", + "aprile", + "maggio", + "giugno", + "luglio", + "agosto", + "settembre", + "ottobre", + "novembre", + "dicembre" + ], + "SHORTDAY": [ + "dom", + "lun", + "mar", + "mer", + "gio", + "ven", + "sab" + ], + "SHORTMONTH": [ + "gen", + "feb", + "mar", + "apr", + "mag", + "giu", + "lug", + "ago", + "set", + "ott", + "nov", + "dic" + ], + "STANDALONEMONTH": [ + "Gennaio", + "Febbraio", + "Marzo", + "Aprile", + "Maggio", + "Giugno", + "Luglio", + "Agosto", + "Settembre", + "Ottobre", + "Novembre", + "Dicembre" + ], + "WEEKENDRANGE": [ + 5, + 6 + ], + "fullDate": "EEEE d MMMM y", + "longDate": "d MMMM y", + "medium": "dd MMM y HH:mm:ss", + "mediumDate": "dd MMM y", + "mediumTime": "HH:mm:ss", + "short": "dd/MM/yy HH:mm", + "shortDate": "dd/MM/yy", + "shortTime": "HH:mm" + }, + "NUMBER_FORMATS": { + "CURRENCY_SYM": "\u20ac", + "DECIMAL_SEP": ",", + "GROUP_SEP": ".", + "PATTERNS": [ + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 3, + "minFrac": 0, + "minInt": 1, + "negPre": "-", + "negSuf": "", + "posPre": "", + "posSuf": "" + }, + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 2, + "minFrac": 2, + "minInt": 1, + "negPre": "-", + "negSuf": "\u00a0\u00a4", + "posPre": "", + "posSuf": "\u00a0\u00a4" + } + ] + }, + "id": "it", + "localeID": "it", + "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;} +}); +}]); diff --git a/src/main/webapp/i18n/en/activate.json b/src/main/webapp/i18n/en/activate.json new file mode 100644 index 000000000..7c9e31cdc --- /dev/null +++ b/src/main/webapp/i18n/en/activate.json @@ -0,0 +1,9 @@ +{ + "activate": { + "title": "Activation", + "messages": { + "success": "Your user has been activated. Please sign in.", + "error": "Your user could not be activated. Please use the registration form to sign up." + } + } +} diff --git a/src/main/webapp/i18n/en/audits.json b/src/main/webapp/i18n/en/audits.json new file mode 100644 index 000000000..ed5e16d4c --- /dev/null +++ b/src/main/webapp/i18n/en/audits.json @@ -0,0 +1,27 @@ +{ + "audits": { + "title": "Audits", + "filter": { + "title": "Filter per date", + "from": "from", + "to": "to", + "button": { + "weeks": "Weeks", + "today": "today", + "clear": "clear", + "close": "close" + } + }, + "table": { + "header": { + "principal": "User", + "date": "Date", + "status": "State", + "data": "Extra data" + }, + "data": { + "remoteAddress": "Remote Address:" + } + } + } +} diff --git a/src/main/webapp/i18n/en/configuration.json b/src/main/webapp/i18n/en/configuration.json new file mode 100644 index 000000000..81e208de5 --- /dev/null +++ b/src/main/webapp/i18n/en/configuration.json @@ -0,0 +1,10 @@ +{ + "configuration": { + "title": "Configuration", + "filter": "Filter (by prefix)", + "table": { + "prefix": "Prefix", + "properties": "Properties" + } + } +} diff --git a/src/main/webapp/i18n/en/error.json b/src/main/webapp/i18n/en/error.json new file mode 100644 index 000000000..65246c3b0 --- /dev/null +++ b/src/main/webapp/i18n/en/error.json @@ -0,0 +1,6 @@ +{ + "error": { + "title": "Error page!", + "403": "You are not authorized to access the page." + } +} diff --git a/src/main/webapp/i18n/en/gateway.json b/src/main/webapp/i18n/en/gateway.json new file mode 100644 index 000000000..8c8bbd7e9 --- /dev/null +++ b/src/main/webapp/i18n/en/gateway.json @@ -0,0 +1,15 @@ +{ + "gateway": { + "title": "Gateway", + "routes": { + "title": "Current routes", + "url": "URL", + "service": "service", + "servers": "Available servers", + "error": "Warning: no server available!" + }, + "refresh": { + "button": "Refresh" + } + } +} diff --git a/src/main/webapp/i18n/en/global.json b/src/main/webapp/i18n/en/global.json new file mode 100644 index 000000000..ac1186657 --- /dev/null +++ b/src/main/webapp/i18n/en/global.json @@ -0,0 +1,123 @@ +{ + "global": { + "title": "Sprint", + "browsehappy": "You are using an outdated browser. Please upgrade your browser to improve your experience.", + "menu": { + "home": "Home", + "jhipster-needle-menu-add-element": "JHipster will add additional menu entries here (do not translate!)", + "entities": { + "main": "Entities", + "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" + }, + "account": { + "main": "Account", + "settings": "Settings", + "password": "Password", + "sessions": "Sessions", + "login": "Sign in", + "logout": "Sign out", + "register": "Register" + }, + "admin": { + "main": "Administration", + "userManagement": "User management", + "tracker": "User tracker", + "metrics": "Metrics", + "health": "Health", + "configuration": "Configuration", + "logs": "Logs", + "audits": "Audits", + "apidocs": "API", + "database": "Database", + "jhipster-needle-menu-add-admin-element": "JHipster will add additional menu entries here (do not translate!)" + }, + "language": "Language" + }, + "form": { + "username": "Username", + "username.placeholder": "Your username", + "newpassword": "New password", + "newpassword.placeholder": "New password", + "confirmpassword": "New password confirmation", + "confirmpassword.placeholder": "Confirm the new password", + "email": "E-mail", + "email.placeholder": "Your e-mail" + }, + "messages": { + "info": { + "authenticated": "If you want to sign in, you can try the default accounts:- Administrator (login=\"admin\" and password=\"admin\") - User (login=\"user\" and password=\"user\").", + "register": "You don't have an account yet? Register a new account" + }, + "error": { + "dontmatch": "The password and its confirmation do not match!" + }, + "validate": { + "newpassword": { + "required": "Your password is required.", + "minlength": "Your password is required to be at least 4 characters.", + "maxlength": "Your password cannot be longer than 50 characters.", + "strength": "Password strength:" + }, + "confirmpassword": { + "required": "Your confirmation password is required.", + "minlength": "Your confirmation password is required to be at least 4 characters.", + "maxlength": "Your confirmation password cannot be longer than 50 characters." + }, + "email": { + "required": "Your e-mail is required.", + "invalid": "Your e-mail is invalid.", + "minlength": "Your e-mail is required to be at least 5 characters.", + "maxlength": "Your e-mail cannot be longer than 50 characters." + } + } + }, + "field": { + "id": "ID" + }, + "ribbon": { + "dev":"Development" + } + }, + "entity": { + "action": { + "addblob": "Add blob", + "addimage": "Add image", + "back": "Back", + "cancel": "Cancel", + "delete": "Delete", + "edit": "Edit", + "open": "Open", + "save": "Save", + "view": "View" + }, + "detail": { + "field": "Field", + "value": "Value" + }, + "delete": { + "title": "Confirm delete operation" + }, + "validation": { + "required": "This field is required.", + "minlength": "This field is required to be at least {{ min }} characters.", + "maxlength": "This field cannot be longer than {{ max }} characters.", + "min": "This field should be more than {{ min }}.", + "max": "This field cannot be more than {{ max }}.", + "minbytes": "This field should be more than {{ min }} bytes.", + "maxbytes": "This field cannot be more than {{ max }} bytes.", + "pattern": "This field should follow pattern {{ pattern }}.", + "number": "This field should be a number.", + "datetimelocal": "This field should be a date and time." + } + }, + "error": { + "server.not.reachable": "Server not reachable", + "url.not.found": "Not found", + "NotNull": "Field {{ fieldName }} cannot be empty!", + "Size": "Field {{ fieldName }} does not meet min/max size requirements!", + "userexists": "Login name already used!", + "emailexists": "E-mail is already in use!", + "idexists": "A new {{ entityName }} cannot already have an ID" + }, + "footer": "This is your footer" +} diff --git a/src/main/webapp/i18n/en/health.json b/src/main/webapp/i18n/en/health.json new file mode 100644 index 000000000..868ea3fda --- /dev/null +++ b/src/main/webapp/i18n/en/health.json @@ -0,0 +1,27 @@ +{ + "health": { + "title": "Health Checks", + "refresh.button": "Refresh", + "stacktrace": "Stacktrace", + "details": { + "details": "Details", + "properties": "Properties", + "name": "Name", + "value": "Value", + "error": "Error" + }, + "indicator": { + "diskSpace": "Disk space", + "mail": "Email", + "db": "Database" + }, + "table": { + "service": "Service name", + "status": "Status" + }, + "status": { + "UP": "UP", + "DOWN": "DOWN" + } + } +} diff --git a/src/main/webapp/i18n/en/home.json b/src/main/webapp/i18n/en/home.json new file mode 100644 index 000000000..402f18700 --- /dev/null +++ b/src/main/webapp/i18n/en/home.json @@ -0,0 +1,19 @@ +{ + "home": { + "title": "Welcome, Java Hipster!", + "subtitle": "This is your homepage", + "logged": { + "message": "You are logged in as user \"{{username}}\"." + }, + "question": "If you have any question on JHipster:", + "link": { + "homepage": "JHipster homepage", + "stackoverflow": "JHipster on Stack Overflow", + "bugtracker": "JHipster bug tracker", + "chat": "JHipster public chat room", + "follow": "follow @java_hipster on Twitter" + }, + "like": "If you like JHipster, don't forget to give us a star on", + "github": "GitHub" + } +} diff --git a/src/main/webapp/i18n/en/login.json b/src/main/webapp/i18n/en/login.json new file mode 100644 index 000000000..3a000852e --- /dev/null +++ b/src/main/webapp/i18n/en/login.json @@ -0,0 +1,19 @@ +{ + "login": { + "title": "Sign in", + "form": { + "password": "Password", + "password.placeholder": "Your password", + "rememberme": "Remember me", + "button": "Sign in" + }, + "messages": { + "error": { + "authentication": "Failed to sign in! Please check your credentials and try again." + } + }, + "password" : { + "forgot": "Did you forget your password?" + } + } +} diff --git a/src/main/webapp/i18n/en/logs.json b/src/main/webapp/i18n/en/logs.json new file mode 100644 index 000000000..a614b128d --- /dev/null +++ b/src/main/webapp/i18n/en/logs.json @@ -0,0 +1,11 @@ +{ + "logs": { + "title": "Logs", + "nbloggers": "There are {{ total }} loggers.", + "filter": "Filter", + "table": { + "name": "Name", + "level": "Level" + } + } +} diff --git a/src/main/webapp/i18n/en/main.json b/src/main/webapp/i18n/en/main.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/webapp/i18n/en/metrics.json b/src/main/webapp/i18n/en/metrics.json new file mode 100644 index 000000000..da155d1b3 --- /dev/null +++ b/src/main/webapp/i18n/en/metrics.json @@ -0,0 +1,95 @@ +{ + "metrics": { + "title": "Application Metrics", + "refresh.button": "Refresh", + "updating": "Updating...", + "jvm": { + "title": "JVM Metrics", + "memory": { + "title": "Memory", + "total": "Total Memory", + "heap": "Heap Memory", + "nonheap": "Non-Heap Memory" + }, + "threads": { + "title": "Threads", + "all": "All", + "runnable": "Runnable", + "timedwaiting": "Timed waiting", + "waiting": "Waiting", + "blocked": "Blocked", + "dump": { + "title": "Threads dump", + "id": "Id: ", + "blockedtime": "Blocked Time", + "blockedcount": "Blocked Count", + "waitedtime": "Waited Time", + "waitedcount": "Waited Count", + "lockname": "Lock name", + "stacktrace": "Stacktrace", + "show": "Show Stacktrace", + "hide": "Hide Stacktrace" + } + }, + "gc": { + "title": "Garbage collections", + "marksweepcount": "Mark Sweep count", + "marksweeptime": "Mark Sweep time", + "scavengecount": "Scavenge count", + "scavengetime": "Scavenge time" + }, + "http": { + "title": "HTTP requests (events per second)", + "active": "Active requests:", + "total": "Total requests:", + "table": { + "code": "Code", + "count": "Count", + "mean": "Mean", + "average": "Average" + }, + "code": { + "ok": "Ok", + "notfound": "Not found", + "servererror": "Server Error" + } + } + }, + "servicesstats": { + "title": "Services statistics (time in millisecond)", + "table": { + "name": "Service name", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + }, + "ehcache": { + "title": "Ehcache statistics", + "cachename": "Cache name", + "objects": "Objects", + "hits": "Hits", + "misses": "Misses", + "evictioncount": "Eviction count", + "mean": "Mean get time (ms)" + }, + "datasource": { + "usage": "Usage", + "title": "DataSource statistics (time in millisecond)", + "name": "Pool usage", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + } +} diff --git a/src/main/webapp/i18n/en/password.json b/src/main/webapp/i18n/en/password.json new file mode 100644 index 000000000..46227a770 --- /dev/null +++ b/src/main/webapp/i18n/en/password.json @@ -0,0 +1,12 @@ +{ + "password": { + "title": "Password for [{{username}}]", + "form": { + "button": "Save" + }, + "messages": { + "error": "An error has occurred! The password could not be changed.", + "success": "Password changed!" + } + } +} diff --git a/src/main/webapp/i18n/en/register.json b/src/main/webapp/i18n/en/register.json new file mode 100644 index 000000000..df8f6e31b --- /dev/null +++ b/src/main/webapp/i18n/en/register.json @@ -0,0 +1,24 @@ +{ + "register": { + "title": "Registration", + "form": { + "button": "Register" + }, + "messages": { + "validate": { + "login": { + "required": "Your username is required.", + "minlength": "Your username is required to be at least 1 character.", + "maxlength": "Your username cannot be longer than 50 characters.", + "pattern": "Your username can only contain lower-case letters and digits." + } + }, + "success": "Registration saved! Please check your email for confirmation.", + "error": { + "fail": "Registration failed! Please try again later.", + "userexists": "Login name already registered! Please choose another one.", + "emailexists": "E-mail is already in use! Please choose another one." + } + } + } +} diff --git a/src/main/webapp/i18n/en/reset.json b/src/main/webapp/i18n/en/reset.json new file mode 100644 index 000000000..d790e6753 --- /dev/null +++ b/src/main/webapp/i18n/en/reset.json @@ -0,0 +1,30 @@ +{ + "reset": { + "request": { + "title": "Reset your password", + "form": { + "button": "Reset password" + }, + "messages": { + "info": "Enter the e-mail address you used to register", + "success": "Check your e-mails for details on how to reset your password.", + "notfound": "E-Mail address isn't registered! Please check and try again" + + } + + }, + "finish" : { + "title": "Reset password", + "form": { + "button": "Validate new password" + }, + "messages": { + "info": "Choose a new password", + "success": "Your password has been reset. Please sign in.", + "keymissing": "The reset key is missing.", + "error": "Your password couldn't be reset. Remember a password request is only valid for 24 hours." + } + } + } + +} diff --git a/src/main/webapp/i18n/en/sessions.json b/src/main/webapp/i18n/en/sessions.json new file mode 100644 index 000000000..d410035ee --- /dev/null +++ b/src/main/webapp/i18n/en/sessions.json @@ -0,0 +1,15 @@ +{ + "sessions": { + "title": "Active sessions for [{{username}}]", + "table": { + "ipaddress": "IP address", + "useragent": "User Agent", + "date": "Date", + "button": "Invalidate" + }, + "messages": { + "success": "Session invalidated!", + "error": "An error has occurred! The session could not be invalidated." + } + } +} diff --git a/src/main/webapp/i18n/en/settings.json b/src/main/webapp/i18n/en/settings.json new file mode 100644 index 000000000..919ab51cc --- /dev/null +++ b/src/main/webapp/i18n/en/settings.json @@ -0,0 +1,32 @@ +{ + "settings": { + "title": "User settings for [{{username}}]", + "form": { + "firstname": "First Name", + "firstname.placeholder": "Your first name", + "lastname": "Last Name", + "lastname.placeholder": "Your last name", + "language": "Language", + "button": "Save" + }, + "messages": { + "error": { + "fail": "An error has occurred! Settings could not be saved.", + "emailexists": "E-mail is already in use! Please choose another one." + }, + "success": "Settings saved!", + "validate": { + "firstname": { + "required": "Your first name is required.", + "minlength": "Your first name is required to be at least 1 character", + "maxlength": "Your first name cannot be longer than 50 characters" + }, + "lastname": { + "required": "Your last name is required.", + "minlength": "Your last name is required to be at least 1 character", + "maxlength": "Your last name cannot be longer than 50 characters" + } + } + } + } +} diff --git a/src/main/webapp/i18n/en/task.json b/src/main/webapp/i18n/en/task.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/webapp/i18n/en/user-management.json b/src/main/webapp/i18n/en/user-management.json new file mode 100644 index 000000000..30c125b6d --- /dev/null +++ b/src/main/webapp/i18n/en/user-management.json @@ -0,0 +1,30 @@ +{ + "userManagement": { + "home": { + "title": "Users", + "createLabel": "Create a new user", + "createOrEditLabel": "Create or edit a user" + }, + "created": "A new user is created with identifier {{ param }}", + "updated": "An user is updated with identifier {{ param }}", + "deleted": "An user is deleted with identifier {{ param }}", + "delete": { + "question": "Are you sure you want to delete user {{ login }}?" + }, + "detail": { + "title": "User" + }, + "login": "Login", + "firstName": "First name", + "lastName": "Last name", + "email": "Email", + "activated": "Activated", + "deactivated": "Deactivated", + "profiles": "Profiles", + "langKey": "Language", + "createdBy": "Created by", + "createdDate": "Created date", + "lastModifiedBy": "Modified by", + "lastModifiedDate": "Modified date" + } +} diff --git a/src/main/webapp/i18n/it/activate.json b/src/main/webapp/i18n/it/activate.json new file mode 100644 index 000000000..6730b76ff --- /dev/null +++ b/src/main/webapp/i18n/it/activate.json @@ -0,0 +1,9 @@ +{ + "activate": { + "title": "Attivazione", + "messages": { + "success": "Il tuo account è stato attivato. Si prega di accedere.", + "error": "Il tuo account non può essere verificato. Si prega di compilare il modulo, per registrarsi." + } + } +} diff --git a/src/main/webapp/i18n/it/audits.json b/src/main/webapp/i18n/it/audits.json new file mode 100644 index 000000000..10c0abeb8 --- /dev/null +++ b/src/main/webapp/i18n/it/audits.json @@ -0,0 +1,27 @@ +{ + "audits": { + "title": "Cambiamenti", + "filter": { + "title": "Filtra per data", + "from": "da", + "to": "a", + "button": { + "weeks": "Settimane", + "today": "oggi", + "clear": "cancella", + "close": "chiudi" + } + }, + "table": { + "header": { + "principal": "Utente", + "date": "Data", + "status": "Stato", + "data": "Altre informazioni" + }, + "data": { + "remoteAddress": "Indirizzo remoto:" + } + } + } +} diff --git a/src/main/webapp/i18n/it/configuration.json b/src/main/webapp/i18n/it/configuration.json new file mode 100644 index 000000000..180a205b6 --- /dev/null +++ b/src/main/webapp/i18n/it/configuration.json @@ -0,0 +1,10 @@ +{ + "configuration": { + "title": "Configurazione", + "filter": "Filtro (per prefisso)", + "table": { + "prefix": "Prefisso", + "properties": "Proprietà" + } + } +} diff --git a/src/main/webapp/i18n/it/error.json b/src/main/webapp/i18n/it/error.json new file mode 100644 index 000000000..b43174f7c --- /dev/null +++ b/src/main/webapp/i18n/it/error.json @@ -0,0 +1,6 @@ +{ + "error": { + "title": "Pagina di errore!", + "403": "Non si dispongono i privilegi sufficienti per accedere a qusta pagina." + } +} diff --git a/src/main/webapp/i18n/it/gateway.json b/src/main/webapp/i18n/it/gateway.json new file mode 100644 index 000000000..51f36bee2 --- /dev/null +++ b/src/main/webapp/i18n/it/gateway.json @@ -0,0 +1,15 @@ +{ + "gateway": { + "title": "Gateway", + "routes": { + "title": "Itinerari attuali", + "url": "URL", + "service": "servizio", + "servers": "Server disponibili", + "error": "Attenzione: non ci sono server disponibili!" + }, + "refresh": { + "button": "Aggiorna" + } + } +} diff --git a/src/main/webapp/i18n/it/global.json b/src/main/webapp/i18n/it/global.json new file mode 100644 index 000000000..89db7111b --- /dev/null +++ b/src/main/webapp/i18n/it/global.json @@ -0,0 +1,123 @@ +{ + "global": { + "title": "Sprint", + "browsehappy": "Stai utilizzando un browser non aggiornato strong> Aggiorna il tuo browser per migliorare la tua esperienza.", + "menu": { + "home": "Home", + "jhipster-needle-menu-add-element": "JHipster will add additional menu entries here (do not translate!)", + "entities": { + "main": "Entità", + "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" + }, + "account": { + "main": "Utente", + "settings": "Impostazioni", + "password": "Password", + "sessions": "Sessione", + "login": "Accesso", + "logout": "Esci", + "register": "Registrazione" + }, + "admin": { + "main": "Amministratore", + "userManagement": "Gestione utenti", + "tracker": "Tracciamento utente", + "metrics": "Metriche", + "health": "Integrità", + "configuration": "Configurazione", + "logs": "Log", + "audits": "Cambiamenti", + "apidocs": "API", + "database": "Database", + "jhipster-needle-menu-add-admin-element": "JHipster will add additional menu entries here (do not translate!)" + }, + "language": "Lingua" + }, + "form": { + "username": "Utente", + "username.placeholder": "Il tuo nome utente", + "newpassword": "Nuova password", + "newpassword.placeholder": "Nuova password", + "confirmpassword": "Conferma nuova password", + "confirmpassword.placeholder": "Conferma nuova password", + "email": "Email", + "email.placeholder": "Il tuo indirizzo email" + }, + "messages": { + "info": { + "authenticated": "Se vuoi avviare una sessione, puoi provare ad utilizzare gli account di default: - Amministratore (user = \"admin\" e la password = \"admin\") - utente (user = \"user\" e la password = \"user\")", + "register": "Non hai ancora un account? Crea un account" + }, + "error": { + "dontmatch" : "La password e la conferma non corrispondono!" + }, + "validate": { + "newpassword": { + "required": "È necessario immettere una password.", + "minlength": "La tua password deve essere di almeno 4 caratteri", + "maxlength": "La tua password non può essere più di 50 caratteri", + "strength": "Robustezza della password:" + }, + "confirmpassword": { + "required": "È necessario la password di conferma.", + "minlength": "La tua password deve essere di almeno 4 caratteri", + "maxlength": "La tua password non può essere più di 50 caratteri" + }, + "email": { + "required": "È necessario un indirizzo e-mail.", + "invalid": "Il tuo indirizzo email non è valido.", + "minlength": "È necessario che la tua email sia di almeno 4 caratteri", + "maxlength": "Il tuo indirizzo email non può essere più di 50 caratteri" + } + } + }, + "field": { + "id" : "ID" + }, + "ribbon": { + "dev":"Development" + } + }, + "entity": { + "action": { + "addblob": "Aggiungi blob", + "addimage": "Aggiungi immagine", + "back": "Indietro", + "cancel": "Annulla", + "delete": "Elimina", + "edit": "Modifica", + "open": "Open", + "save": "Salva", + "view": "Visualizza" + }, + "detail": { + "field": "Campo", + "value": "Valore" + }, + "delete": { + "title": "Conferma operazione di cancellazione" + }, + "validation": { + "required": "Questo campo è obbligatorio.", + "minlength": "Questo campo deve essere di almeno {{ min }} caratteri.", + "maxlength": "Questo campo non può essere più di {{ max }} caratteri.", + "min": "Questo campo dovrebbe essere più di {{ min }}.", + "max": "Questo campo non può essere superiore a {{ max }}.", + "minbytes": "Questo campo dovrebbe essere più di {{ min }} byte.", + "maxbytes": "Questo campo non può essere superiore a {{ max }} byte.", + "pattern": "Questo campo dovrebbe corrispondere al modello {{ pattern }}.", + "number": "Questo campo deve essere un numero.", + "datetimelocal": "Questo campo dovrebbe essere data e ora." + } + }, + "error": { + "server.not.reachable": "Server non raggiungibile", + "url.not.found": "Non trovato", + "NotNull": "Il campo {{ fieldName }} non può essere vuoto!", + "Size": "Il campo {{ fieldName }} non è conforme ai requisiti di lunghezza min/max!", + "userexists": "Il nome utente è già in uso!", + "emailexists": "L' email è già in uso!", + "idexists": "Un(a) nuovo/a {{entityName}} non può già avere un ID" + }, + "footer": "pié di pagina" +} diff --git a/src/main/webapp/i18n/it/health.json b/src/main/webapp/i18n/it/health.json new file mode 100644 index 000000000..e436ecab3 --- /dev/null +++ b/src/main/webapp/i18n/it/health.json @@ -0,0 +1,27 @@ +{ + "health": { + "title": "Verifiche", + "refresh.button": "Aggiorna", + "stacktrace": "Stacktrace", + "details": { + "details": "Dettagli", + "properties": "Proprietà", + "name": "Nome", + "value": "Valore", + "error": "Errore" + }, + "indicator": { + "diskSpace": "Spazio su disco", + "mail": "Email", + "db": "Database" + }, + "table": { + "service": "Nome del servizio", + "status": "Stato" + }, + "status": { + "UP": "DISPONIBILE", + "DOWN": "NON DISPONIBILE" + } + } +} diff --git a/src/main/webapp/i18n/it/home.json b/src/main/webapp/i18n/it/home.json new file mode 100644 index 000000000..8fcd93d08 --- /dev/null +++ b/src/main/webapp/i18n/it/home.json @@ -0,0 +1,19 @@ +{ + "home": { + "title": "Benvenuto, Java Hipster!", + "subtitle": "Questa è la tua home page", + "logged": { + "message": "Autenticato come \"{{username}}\"." + }, + "question": "In caso di domande su JHipster:", + "link": { + "homepage": "Homepage JHipster", + "stackoverflow": "JHipster su Stack Overflow", + "bugtracker": "JHipster tracciamento errori", + "chat": "Chat room pubblica di JHipster", + "follow": "segui @java_hipster su Twitter" + }, + "like": "Se ti piace JHipster, non dimenticarti di assegnarci una stella", + "github": "GitHub" + } +} diff --git a/src/main/webapp/i18n/it/login.json b/src/main/webapp/i18n/it/login.json new file mode 100644 index 000000000..a59027575 --- /dev/null +++ b/src/main/webapp/i18n/it/login.json @@ -0,0 +1,19 @@ +{ + "login": { + "title": "Accedi", + "form": { + "password": "Password", + "password.placeholder": "la password", + "rememberme": "Login automatico", + "button": "Login" + }, + "messages": { + "error": { + "authentication": "Accesso non riuscito! Si prega di controllare le credenziali e riprovare." + } + }, + "password" : { + "forgot": "Password dimenticata?" + } + } +} diff --git a/src/main/webapp/i18n/it/logs.json b/src/main/webapp/i18n/it/logs.json new file mode 100644 index 000000000..e07851309 --- /dev/null +++ b/src/main/webapp/i18n/it/logs.json @@ -0,0 +1,11 @@ +{ + "logs": { + "title": "Log", + "nbloggers": "Hai {{ total }} logger.", + "filter": "Filtro", + "table": { + "name": "Nome", + "level": "Livello" + } + } +} diff --git a/src/main/webapp/i18n/it/main.json b/src/main/webapp/i18n/it/main.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/webapp/i18n/it/metrics.json b/src/main/webapp/i18n/it/metrics.json new file mode 100644 index 000000000..bf3ad2804 --- /dev/null +++ b/src/main/webapp/i18n/it/metrics.json @@ -0,0 +1,95 @@ +{ + "metrics": { + "title": "Metriche dell'applicazione", + "refresh.button": "Aggiorna", + "updating": "Aggiornamento...", + "jvm": { + "title": "Metriche di JVM", + "memory": { + "title": "Memoria", + "total": "Memoria Totale", + "heap": "Memoria Heap", + "nonheap": "Memoria Non-Heap" + }, + "threads": { + "title": "Threads", + "all": "Tutti", + "runnable": "Runnable", + "timedwaiting": "Timed waiting", + "waiting": "Waiting", + "blocked": "Blocked", + "dump": { + "title": "Threads dump", + "id": "Id: ", + "blockedtime": "Blocked Time", + "blockedcount": "Blocked Count", + "waitedtime": "Waited Time", + "waitedcount": "Waited Count", + "lockname": "Lock name", + "stacktrace": "Stacktrace", + "show": "Show", + "hide": "Hide" + } + }, + "gc": { + "title": "Garbage collections", + "marksweepcount": "Mark Sweep count", + "marksweeptime": "Mark Sweep time", + "scavengecount": "Scavenge count", + "scavengetime": "Scavenge time" + }, + "http": { + "title": "Richieste HTTP (eventi al secondo)", + "active": "Richieste attive:", + "total": "Richieste totali:", + "table": { + "code": "Codice", + "count": "Numero", + "mean": "Mediana", + "average": "Media" + }, + "code": { + "ok": "Ok", + "notfound": "Non trovato/i", + "servererror": "Errore Server" + } + } + }, + "servicesstats": { + "title": "Statistiche Servizi (in millisecondi), + "table": { + "name": "Nome servizio", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + }, + "ehcache": { + "title": "Statistiche Ehcache", + "cachename": "Nome Cache", + "objects": "Oggetti", + "hits": "Hits", + "misses": "Misses", + "evictioncount": "Eviction count", + "mean": "Mean get time (ms)" + }, + "datasource": { + "usage": "Utilizzo", + "title": "Statistiche DataSource (in millisecondi)", + "name": "Pool usage", + "count": "Count", + "mean": "Mean", + "min": "Min", + "max": "Max", + "p50": "p50", + "p75": "p75", + "p95": "p95", + "p99": "p99" + } + } +} diff --git a/src/main/webapp/i18n/it/password.json b/src/main/webapp/i18n/it/password.json new file mode 100644 index 000000000..e92a9b290 --- /dev/null +++ b/src/main/webapp/i18n/it/password.json @@ -0,0 +1,12 @@ +{ + "password": { + "title": "Password per [{{username}}]", + "form": { + "button": "Salva" + }, + "messages": { + "error": "C'è stato un errore! Impossibile cambiare password.", + "success": "Password modificata correttamente!" + } + } +} diff --git a/src/main/webapp/i18n/it/register.json b/src/main/webapp/i18n/it/register.json new file mode 100644 index 000000000..8ea03e908 --- /dev/null +++ b/src/main/webapp/i18n/it/register.json @@ -0,0 +1,24 @@ +{ + "register": { + "title": "Registrazione", + "form": { + "button": "Crea Account" + }, + "messages": { + "validate": { + "login": { + "required": "È necessario per autenticarsi.", + "minlength": "È necessario che l'utente abbia almeno 1 carattere", + "maxlength": "L'utente non può avere più di 50 caratteri", + "pattern": "Il nome utente può contenere solo lettere e cifre." + } + }, + "success": "La registrazione account è stata salvata! Controlla la tua email per confermare.", + "error": { + "fail": "La registrazione dell'account è fallita! Riprova più tardi.", + "userexists": "Il nome utente scelto è già registrato! Si prega di scegliere un altro nome utente.", + "emailexists": "L'indirizzo email è già in uso Si prega di scegliere un altro." + } + } + } +} diff --git a/src/main/webapp/i18n/it/reset.json b/src/main/webapp/i18n/it/reset.json new file mode 100644 index 000000000..53f5b005c --- /dev/null +++ b/src/main/webapp/i18n/it/reset.json @@ -0,0 +1,30 @@ +{ + "reset": { + "request": { + "title": "Cambia la password", + "form": { + "button": "Reimposta Password" + }, + "messages": { + "info": "Inserire l'indirizzo e-mail utilizzato per la registrazione", + "success": "Controlla la tua e-mail per i dettagli su come reimpostare la password.", + "notfound": "E-Mail non registrata! Si prega di verificarla e riprovare!" + + } + + }, + "finish" : { + "title": "Reimposta Password", + "form": { + "button": "Convalida la nuova password" + }, + "messages": { + "info": "Scegliere una nuova password", + "success": "La tua password è stata reimpostata . Per favore autenticati.", + "keymissing": "La chiave di reimpostazione non è presente.", + "error": "La tua password potrebbe non essere ripristinata. Ricorda che la richiesta della password è valida solo per 24 ore." + } + } + } + +} diff --git a/src/main/webapp/i18n/it/sessions.json b/src/main/webapp/i18n/it/sessions.json new file mode 100644 index 000000000..f117bff51 --- /dev/null +++ b/src/main/webapp/i18n/it/sessions.json @@ -0,0 +1,15 @@ +{ + "sessions": { + "title": "Sessioni attive per [{{username}}]", + "table": { + "ipaddress": "Indirizzo IP", + "useragent": "User Agent", + "date": "Data", + "button": "Invalida" + }, + "messages": { + "success": "Sessione invalidata!", + "error": "Si è verificato un errore! Impossibile invalidare la sessione." + } + } +} diff --git a/src/main/webapp/i18n/it/settings.json b/src/main/webapp/i18n/it/settings.json new file mode 100644 index 000000000..2563f46fa --- /dev/null +++ b/src/main/webapp/i18n/it/settings.json @@ -0,0 +1,33 @@ +{ + "settings": { + "title": "Impostazioni per l'utente [{{username}}]", + "form": { + "firstname": "Nome", + "firstname.placeholder": "Tuo nome", + "lastname": "Cognome", + "lastname.placeholder": "Tuo cognome", + "button": "Salva", + "language": "Lingua" + + }, + "messages": { + "error": { + "fail": "Si è verificato un errore! Impossibile salvare le impostazioni.", + "emailexists": "L'indirizzo email è già in uso! Sceglierne un altro per favore." + }, + "success": "Impostazioni salvate!", + "validate": { + "firstname": { + "required": "È richiesto l'inserimento di un nome.", + "minlength": "Il nome deve contenere almeno un carattere", + "maxlength": "Il nome può avere una lunghezza massima di 50 caratteri" + }, + "lastname": { + "required": "È richiesto l'inserimento di un cognome.", + "minlength": "Il cognome deve contenere almeno un carattere", + "maxlength": "Il cognome può avere una lunghezza massima di 50 caratteri" + } + } + } + } +} diff --git a/src/main/webapp/i18n/it/task.json b/src/main/webapp/i18n/it/task.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/webapp/i18n/it/user-management.json b/src/main/webapp/i18n/it/user-management.json new file mode 100644 index 000000000..b97c51aa4 --- /dev/null +++ b/src/main/webapp/i18n/it/user-management.json @@ -0,0 +1,30 @@ +{ + "userManagement": { + "home": { + "title": "Utenti", + "createLabel": "Crea un nuovo utente", + "createOrEditLabel": "Crea o modifica un utente" + }, + "created": "È stato creato un nuovo utente con identificativo {{ param }}", + "updated": "Sono stato aggiornati i dati dell'utente identificato da {{ param }}", + "deleted": "È stato eliminato l'utente identificato da {{ param }}", + "delete": { + "question": "Si è sicuri di volere eliminare l'utente {{ login }}?" + }, + "detail": { + "title": "Utente" + }, + "login": "Login", + "firstName": "Nome", + "lastName": "Cognome", + "email": "Email", + "activated": "Attivato", + "deactivated": "Disattivato", + "profiles": "Profili", + "langKey": "Lingua", + "createdBy": "Creato da", + "createdDate": "Creato il", + "lastModifiedBy": "Modificato da", + "lastModifiedDate": "Modificato il" + } +} diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 000000000..af9eacb75 --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,187 @@ + + + + + + sprint + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/webapp/robots.txt b/src/main/webapp/robots.txt new file mode 100644 index 000000000..7de2585cf --- /dev/null +++ b/src/main/webapp/robots.txt @@ -0,0 +1,11 @@ +# robotstxt.org/ + +User-agent: * +Disallow: /api/account +Disallow: /api/account/change_password +Disallow: /api/account/sessions +Disallow: /api/audits/ +Disallow: /api/logs/ +Disallow: /api/users/ +Disallow: /management/ +Disallow: /v2/api-docs/ diff --git a/src/main/webapp/swagger-ui/images/throbber.gif b/src/main/webapp/swagger-ui/images/throbber.gif new file mode 100644 index 000000000..063938892 Binary files /dev/null and b/src/main/webapp/swagger-ui/images/throbber.gif differ diff --git a/src/main/webapp/swagger-ui/index.html b/src/main/webapp/swagger-ui/index.html new file mode 100644 index 000000000..b47960940 --- /dev/null +++ b/src/main/webapp/swagger-ui/index.html @@ -0,0 +1,183 @@ + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + swagger + + + + + + + + + + + + + + + diff --git a/src/test/gatling/conf/gatling.conf b/src/test/gatling/conf/gatling.conf new file mode 100644 index 000000000..3f74e080c --- /dev/null +++ b/src/test/gatling/conf/gatling.conf @@ -0,0 +1,153 @@ +######################### +# Gatling Configuration # +######################### + +# This file contains all the settings configurable for Gatling with their default values + +gatling { + core { + #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp) + #runDescription = "" # The description for this simulation run, displayed in each report + #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation + #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated) + #disableCompiler = false # When set to true, skip compiling and load an already compiled simulation (used in conjunction with simulationClass) + #mute = false # When set to true, don't ask for simulation name nor run description (currently only used by Gatling SBT plugin) + + extract { + regex { + #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching + } + xpath { + #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching + } + jsonPath { + #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching + #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations + jackson { + #allowComments = false # Allow comments in JSON files + #allowUnquotedFieldNames = false # Allow unquoted JSON fields names + #allowSingleQuotes = false # Allow single quoted JSON field names + } + + } + css { + #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching + } + } + + timeOut { + #simulation = 8640000 # Absolute timeout, in seconds, of a simulation + } + directory { + #data = user-files/data # Folder where user's data (e.g. files used by Feeders) is located + #requestBodies = user-files/request-bodies # Folder where request bodies are located + #simulations = user-files/simulations # Folder where the bundle's simulations are located + #reportsOnly = "" # If set, name of report folder to look for in order to generate its report + #binaries = "" # If set, name of the folder where compiles classes are located + #results = results # Name of the folder where all reports folder are located + } + zinc { + #jvmArgs = "-Xss10M" # JVM args passed to Zinc (in charge of compiling Gatling Simulations) + } + } + charting { + #noReports = false # When set to true, don't generate HTML reports + #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports + #accuracy = 10 # Accuracy, in milliseconds, of the report's stats + indicators { + #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary + #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary + #percentile1 = 95 # Value for the first percentile to track in the reports, the console summary and GraphiteDataWriter + #percentile2 = 99 # Value for the second percentile to track in the reports, the console summary and GraphiteDataWriter + } + } + http { + #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable + #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable + #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable + #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable + #redirectPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent redirects, set to 0 to disable + #expirePerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Expire' headers, set to 0 to disable + #lastModifiedPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent 'Last-Modified' headers, set to 0 to disable + #etagPerUserCacheMaxCapacity = 200 # Per virtual user cache size for permanent ETag headers, set to 0 to disable + #warmUpUrl = "http://goo.gl/pq1Xwu" # The URL to use to warm-up the HTTP stack (blank means disabled) + ssl { + trustStore { + #type = "" # Type of SSLContext's TrustManagers store + #file = "" # Location of SSLContext's TrustManagers store + #password = "" # Password for SSLContext's TrustManagers store + #algorithm = "" # Algorithm used by SSLContext's TrustManagers store + } + keyStore { + #type = "" # Type of SSLContext's KeyManagers store + #file = "" # Location of SSLContext's KeyManagers store + #password = "" # Password for SSLContext's KeyManagers store + #algorithm = "" # Algorithm used SSLContext's KeyManagers store + } + } + ahc { + #allowPoolingConnections = true # Allow pooling HTTP connections (keep-alive header automatically added) + #allowPoolingSslConnections = true # Allow pooling HTTPS connections (keep-alive header automatically added) + #compressionEnforced = false # Enforce gzip/deflate when Accept-Encoding header is not defined + #connectTimeout = 60000 # Timeout when establishing a connection + #pooledConnectionIdleTimeout = 60000 # Timeout when a connection stays unused in the pool + #readTimeout = 60000 # Timeout when a used connection stays idle + #connectionTTL = -1 # Max duration a connection can stay open (-1 means no limit) + #ioThreadMultiplier = 2 # Number of Netty worker threads per core + #maxConnectionsPerHost = -1 # Max number of connections per host (-1 means no limit) + #maxConnections = -1 # Max number of connections (-1 means no limit) + #maxRetry = 0 # Number of times that a request should be tried again + #requestTimeout = 60000 # Timeout of the requests + #useProxyProperties = false # When set to true, supports standard Proxy System properties + #webSocketTimeout = 60000 # Timeout when a used websocket connection stays idle + #useRelativeURIsWithConnectProxies = true # When set to true, use relative URIs when talking with an SSL proxy or a WebSocket proxy + #acceptAnyCertificate = true # When set to true, doesn't validate SSL certificates + #httpClientCodecMaxInitialLineLength = 4096 # Maximum length of the initial line of the response (e.g. "HTTP/1.0 200 OK") + #httpClientCodecMaxHeaderSize = 8192 # Maximum size, in bytes, of each request's headers + #httpClientCodecMaxChunkSize = 8192 # Maximum length of the content or each chunk + #keepEncodingHeader = true # Don't drop Encoding response header after decoding + #webSocketMaxFrameSize = 10240 # Maximum frame payload size + } + } + data { + #writers = "console, file" # The lists of DataWriters to which Gatling write simulation data (currently supported : "console", "file", "graphite", "jdbc") + #reader = file # The DataReader used by the charting engine for reading simulation results + console { + #light = false # When set to true, displays a light version without detailed request stats + } + file { + #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes + } + leak { + #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening + } + jdbc { + db { + #url = "jdbc:mysql://localhost:3306/temp" # The JDBC URL used by the JDBC DataWriter + #username = "root" # The database user used by the JDBC DataWriter + #password = "123123q" # The password for the specified user + } + #bufferSize = 20 # The size for each batch of SQL inserts to send to the database + create { + #createRunRecordTable = "CREATE TABLE IF NOT EXISTS `RunRecords` ( `id` INT NOT NULL AUTO_INCREMENT , `runDate` DATETIME NULL , `simulationId` VARCHAR(45) NULL , `runDescription` VARCHAR(45) NULL , PRIMARY KEY (`id`) )" + #createRequestRecordTable = "CREATE TABLE IF NOT EXISTS `RequestRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenario` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `name` varchar(50) DEFAULT NULL, `requestStartDate` bigint DEFAULT NULL, `requestEndDate` bigint DEFAULT NULL, `responseStartDate` bigint DEFAULT NULL, `responseEndDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, `message` varchar(4500) DEFAULT NULL, `responseTime` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" + #createScenarioRecordTable = "CREATE TABLE IF NOT EXISTS `ScenarioRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `event` varchar(50) DEFAULT NULL, `startDate` bigint DEFAULT NULL, `endDate` bigint DEFAULT NULL, PRIMARY KEY (`id`) )" + #createGroupRecordTable = "CREATE TABLE IF NOT EXISTS `GroupRecords` (`id` int(11) NOT NULL AUTO_INCREMENT, `runId` int DEFAULT NULL, `scenarioName` varchar(45) DEFAULT NULL, `userId` VARCHAR(20) NULL, `entryDate` bigint DEFAULT NULL, `exitDate` bigint DEFAULT NULL, `status` varchar(2) DEFAULT NULL, PRIMARY KEY (`id`) )" + } + insert { + #insertRunRecord = "INSERT INTO RunRecords (runDate, simulationId, runDescription) VALUES (?,?,?)" + #insertRequestRecord = "INSERT INTO RequestRecords (runId, scenario, userId, name, requestStartDate, requestEndDate, responseStartDate, responseEndDate, status, message, responseTime) VALUES (?,?,?,?,?,?,?,?,?,?,?)" + #insertScenarioRecord = "INSERT INTO ScenarioRecords (runId, scenarioName, userId, event, startDate, endDate) VALUES (?,?,?,?,?,?)" + #insertGroupRecord = "INSERT INTO GroupRecords (runId, scenarioName, userId, entryDate, exitDate, status) VALUES (?,?,?,?,?,?)" + } + } + graphite { + #light = false # only send the all* stats + #host = "localhost" # The host where the Carbon server is located + #port = 2003 # The port to which the Carbon server listens to + #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp") + #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite + #bufferSize = 8192 # GraphiteDataWriter's internal data buffer size, in bytes + } + } +} diff --git a/src/test/resources/config/application.yml b/src/test/resources/config/application.yml new file mode 100644 index 000000000..1cbacfd3c --- /dev/null +++ b/src/test/resources/config/application.yml @@ -0,0 +1,84 @@ +# =================================================================== +# Spring Boot configuration. +# +# This configuration is used for unit/integration tests. +# =================================================================== + +# =================================================================== +# Standard Spring Boot properties. +# Full reference is available at: +# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html +# =================================================================== + +spring: + application: + name: sprint + jackson: + serialization.write_dates_as_timestamps: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:h2:mem:sprint;DB_CLOSE_DELAY=-1 + name: + username: + password: + jpa: + database-platform: it.cnr.si.domain.util.FixedH2Dialect + database: H2 + open-in-view: false + show-sql: true + hibernate: + ddl-auto: none + naming: + strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy + properties: + hibernate.cache.use_second_level_cache: false + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: true + hibernate.hbm2ddl.auto: validate + mail: + host: localhost + mvc: + favicon: + enabled: false + thymeleaf: + mode: XHTML + +liquibase: + contexts: test + +security: + basic: + enabled: false + +server: + port: 10344 + address: localhost + +# =================================================================== +# JHipster specific properties +# =================================================================== + +jhipster: + async: + corePoolSize: 2 + maxPoolSize: 50 + queueCapacity: 10000 + security: + authentication: + oauth: + clientid: sprintapp + secret: my-secret-token-to-change-in-production + # Token is valid 30 minutes + tokenValidityInSeconds: 1800 + metrics: # DropWizard Metrics configuration, used by MetricsConfiguration + jmx.enabled: true + swagger: + title: sprint API + description: sprint API documentation + version: 0.0.1 + termsOfServiceUrl: + contactName: + contactUrl: + contactEmail: + license: + licenseUrl: diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 000000000..9d8086003 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +
Sorry, but the page you were trying to view does not exist.
+ Your password is required. +
+ Your password is required to be at least 4 characters. +
+ Your password cannot be longer than 50 characters. +
+ Your confirmation password is required. +
+ Your confirmation password is required to be at least 4 characters. +
+ Your confirmation password cannot be longer than 50 characters. +
+ Your username is required. +
+ Your username is required to be at least 1 character. +
+ Your username cannot be longer than 50 characters. +
+ Your username can only contain lower-case letters and digits. +
+ Your e-mail is required. +
+ Your e-mail is invalid. +
+ Your e-mail is required to be at least 5 characters. +
+ Your e-mail cannot be longer than 100 characters. +
Choose a new password
Your password couldn't be reset. Remember a password request is only valid for 24 hours.
Your password has been reset. Please sign in.
+ Your password confirmation is required. +
+ Your password confirmation is required to be at least 4 characters. +
+ Your password confirmation cannot be longer than 50 characters. +
Enter the e-mail address you used to register.
Check your e-mails for details on how to reset your password.
+ Your first name is required. +
+ Your first name is required to be at least 1 character. +
+ Your first name cannot be longer than 50 characters. +
+ Your last name is required. +
+ Your last name is required to be at least 1 character. +
+ Your last name cannot be longer than 50 characters. +
+ from + + to + +
+ Refresh + +
{{vm.currentHealth.error}}
There are {{ vm.loggers.length }} loggers.
+ Refresh +
Total Memory ({{vm.metrics.gauges['jvm.memory.total.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.total.max'].value / 1000000 | number:0}}M)
Heap Memory ({{vm.metrics.gauges['jvm.memory.heap.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.heap.max'].value / 1000000 | number:0}}M)
Non-Heap Memory ({{vm.metrics.gauges['jvm.memory.non-heap.used'].value / 1000000 | number:0}}M / {{vm.metrics.gauges['jvm.memory.non-heap.committed'].value / 1000000 | number:0}}M)
Runnable {{vm.metrics.gauges['jvm.threads.runnable.count'].value}}
Timed Waiting ({{vm.metrics.gauges['jvm.threads.timed_waiting.count'].value}})
Waiting ({{vm.metrics.gauges['jvm.threads.waiting.count'].value}})
Blocked ({{vm.metrics.gauges['jvm.threads.blocked.count'].value}})
Active requests {{vm.metrics.counters['com.codahale.metrics.servlet.InstrumentedFilter.activeRequests'].count | number:0}} - Total requests {{vm.metrics.timers['com.codahale.metrics.servlet.InstrumentedFilter.requests'].count | number:0}}
{{vm.beans | json}}
Are you sure you want to delete this User?
+ This field is required. +
+ This field cannot be longer than 50 characters. +
+ This field cannot be longer than 100 characters. +
{{ alert.msg }}
This is your homepage
+ If you have any question on JHipster: +
+ If you like JHipster, don't forget to give us a star on Github! +
+ {{tasks | json}} +
{{vm | json}}
{{vm.definition.description}}
{{scope | json}}