1
0

Initial application generated by JHipster-5.8.2

This commit is contained in:
Michael Hoennig
2019-04-01 13:14:56 +02:00
commit e0b3d2a36d
404 changed files with 49698 additions and 0 deletions

61
src/main/webapp/404.html Normal file
View File

@ -0,0 +1,61 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Page Not Found</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="favicon.ico" />
<style>
* {
line-height: 1.2;
margin: 0;
}
html {
color: #888;
display: table;
font-family: sans-serif;
height: 100%;
text-align: center;
width: 100%;
}
body {
display: table-cell;
vertical-align: middle;
margin: 2em auto;
}
h1 {
color: #555;
font-size: 2em;
font-weight: 400;
}
p {
margin: 0 auto;
width: 280px;
}
@media only screen and (max-width: 280px) {
body, p {
width: 95%;
}
h1 {
font-size: 1.5em;
margin: 0 0 0.3em;
}
}
</style>
</head>
<body>
<h1>Page Not Found</h1>
<p>Sorry, but the page you were trying to view does not exist.</p>
</body>
</html>
<!-- IE needs 512+ bytes: http://blogs.msdn.com/b/ieinternals/archive/2010/08/19/http-error-pages-in-internet-explorer.aspx -->

View File

@ -0,0 +1,30 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HsadminNgSharedModule } from 'app/shared';
import {
PasswordStrengthBarComponent,
RegisterComponent,
ActivateComponent,
PasswordComponent,
PasswordResetInitComponent,
PasswordResetFinishComponent,
SettingsComponent,
accountState
} from './';
@NgModule({
imports: [HsadminNgSharedModule, RouterModule.forChild(accountState)],
declarations: [
ActivateComponent,
RegisterComponent,
PasswordComponent,
PasswordStrengthBarComponent,
PasswordResetInitComponent,
PasswordResetFinishComponent,
SettingsComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class HsadminNgAccountModule {}

View File

@ -0,0 +1,12 @@
import { Routes } from '@angular/router';
import { activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute } from './';
const ACCOUNT_ROUTES = [activateRoute, passwordRoute, passwordResetFinishRoute, passwordResetInitRoute, registerRoute, settingsRoute];
export const accountState: Routes = [
{
path: '',
children: ACCOUNT_ROUTES
}
];

View File

@ -0,0 +1,17 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h1 jhiTranslate="activate.title">Activation</h1>
<div class="alert alert-success" *ngIf="success">
<span jhiTranslate="activate.messages.success"><strong>Your user account has been activated.</strong> Please </span>
<a class="alert-link" (click)="login()" jhiTranslate="global.messages.info.authenticated.link">sign in</a>.
</div>
<div class="alert alert-danger" *ngIf="error" jhiTranslate="activate.messages.error">
<strong>Your user could not be activated.</strong> Please use the registration form to sign up.
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,37 @@
import { Component, OnInit } from '@angular/core';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ActivatedRoute } from '@angular/router';
import { LoginModalService } from 'app/core';
import { ActivateService } from './activate.service';
@Component({
selector: 'jhi-activate',
templateUrl: './activate.component.html'
})
export class ActivateComponent implements OnInit {
error: string;
success: string;
modalRef: NgbModalRef;
constructor(private activateService: ActivateService, private loginModalService: LoginModalService, private route: ActivatedRoute) {}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.activateService.get(params['key']).subscribe(
() => {
this.error = null;
this.success = 'OK';
},
() => {
this.success = null;
this.error = 'ERROR';
}
);
});
}
login() {
this.modalRef = this.loginModalService.open();
}
}

View File

@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { ActivateComponent } from './activate.component';
export const activateRoute: Route = {
path: 'activate',
component: ActivateComponent,
data: {
authorities: [],
pageTitle: 'activate.title'
}
};

View File

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class ActivateService {
constructor(private http: HttpClient) {}
get(key: string): Observable<any> {
return this.http.get(SERVER_API_URL + 'api/activate', {
params: new HttpParams().set('key', key)
});
}
}

View File

@ -0,0 +1,19 @@
export * from './activate/activate.component';
export * from './activate/activate.service';
export * from './activate/activate.route';
export * from './password/password.component';
export * from './password/password-strength-bar.component';
export * from './password/password.service';
export * from './password/password.route';
export * from './password-reset/finish/password-reset-finish.component';
export * from './password-reset/finish/password-reset-finish.service';
export * from './password-reset/finish/password-reset-finish.route';
export * from './password-reset/init/password-reset-init.component';
export * from './password-reset/init/password-reset-init.service';
export * from './password-reset/init/password-reset-init.route';
export * from './register/register.component';
export * from './register/register.service';
export * from './register/register.route';
export * from './settings/settings.component';
export * from './settings/settings.route';
export * from './account.route';

View File

@ -0,0 +1,77 @@
<div>
<div class="row justify-content-center">
<div class="col-md-4">
<h1 jhiTranslate="reset.finish.title">Reset password</h1>
<div class="alert alert-danger" jhiTranslate="reset.finish.messages.keymissing" *ngIf="keyMissing">
<strong>The password reset key is missing.</strong>
</div>
<div class="alert alert-warning" *ngIf="!success && !keyMissing">
<p jhiTranslate="reset.finish.messages.info">Choose a new password</p>
</div>
<div class="alert alert-danger" *ngIf="error">
<p jhiTranslate="reset.finish.messages.error">Your password couldn't be reset. Remember a password request is only valid for 24 hours.</p>
</div>
<p class="alert alert-success" *ngIf="success">
<span jhiTranslate="reset.finish.messages.success"><strong>Your password has been reset.</strong> Please </span>
<a class="alert-link" (click)="login()" jhiTranslate="global.messages.info.authenticated.link">sign in</a>.
</p>
<div class="alert alert-danger" *ngIf="doNotMatch" jhiTranslate="global.messages.error.dontmatch">
The password and its confirmation do not match!
</div>
<div *ngIf="!keyMissing">
<form *ngIf="!success" name="form" role="form" (ngSubmit)="finishReset()" #passwordForm="ngForm">
<div class="form-group">
<label class="form-control-label" for="password" jhiTranslate="global.form.newpassword">New password</label>
<input type="password" class="form-control" id="password" name="password" #passwordInput="ngModel"
placeholder="{{'global.form.newpassword.placeholder' | translate}}"
[(ngModel)]="resetAccount.password" minlength=4 maxlength=50 required>
<div *ngIf="passwordInput.dirty && passwordInput.invalid">
<small class="form-text text-danger"
*ngIf="passwordInput.errors.required" jhiTranslate="global.messages.validate.newpassword.required">
Your password is required.
</small>
<small class="form-text text-danger"
*ngIf="passwordInput.errors.minlength" jhiTranslate="global.messages.validate.newpassword.minlength">
Your password is required to be at least 4 characters.
</small>
<small class="form-text text-danger"
*ngIf="passwordInput.errors.maxlength" jhiTranslate="global.messages.validate.newpassword.maxlength">
Your password cannot be longer than 50 characters.
</small>
</div>
<jhi-password-strength-bar [passwordToCheck]="resetAccount.password"></jhi-password-strength-bar>
</div>
<div class="form-group">
<label class="form-control-label" for="confirmPassword" jhiTranslate="global.form.confirmpassword">New password confirmation</label>
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" #confirmPasswordInput="ngModel"
placeholder="{{'global.form.confirmpassword.placeholder' | translate}}"
[(ngModel)]="confirmPassword" minlength=4 maxlength=50 required>
<div *ngIf="confirmPasswordInput.dirty && confirmPasswordInput.invalid">
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.required" jhiTranslate="global.messages.validate.confirmpassword.required">
Your password confirmation is required.
</small>
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.minlength" jhiTranslate="global.messages.validate.confirmpassword.minlength">
Your password confirmation is required to be at least 4 characters.
</small>
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.maxlength" jhiTranslate="global.messages.validate.confirmpassword.maxlength">
Your password confirmation cannot be longer than 50 characters.
</small>
</div>
</div>
<button type="submit" [disabled]="passwordForm.form.invalid" class="btn btn-primary" jhiTranslate="reset.finish.form.button">Reset Password</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,65 @@
import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ActivatedRoute } from '@angular/router';
import { LoginModalService } from 'app/core';
import { PasswordResetFinishService } from './password-reset-finish.service';
@Component({
selector: 'jhi-password-reset-finish',
templateUrl: './password-reset-finish.component.html'
})
export class PasswordResetFinishComponent implements OnInit, AfterViewInit {
confirmPassword: string;
doNotMatch: string;
error: string;
keyMissing: boolean;
resetAccount: any;
success: string;
modalRef: NgbModalRef;
key: string;
constructor(
private passwordResetFinishService: PasswordResetFinishService,
private loginModalService: LoginModalService,
private route: ActivatedRoute,
private elementRef: ElementRef,
private renderer: Renderer
) {}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.key = params['key'];
});
this.resetAccount = {};
this.keyMissing = !this.key;
}
ngAfterViewInit() {
if (this.elementRef.nativeElement.querySelector('#password') != null) {
this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#password'), 'focus', []);
}
}
finishReset() {
this.doNotMatch = null;
this.error = null;
if (this.resetAccount.password !== this.confirmPassword) {
this.doNotMatch = 'ERROR';
} else {
this.passwordResetFinishService.save({ key: this.key, newPassword: this.resetAccount.password }).subscribe(
() => {
this.success = 'OK';
},
() => {
this.success = null;
this.error = 'ERROR';
}
);
}
}
login() {
this.modalRef = this.loginModalService.open();
}
}

View File

@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { PasswordResetFinishComponent } from './password-reset-finish.component';
export const passwordResetFinishRoute: Route = {
path: 'reset/finish',
component: PasswordResetFinishComponent,
data: {
authorities: [],
pageTitle: 'global.menu.account.password'
}
};

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class PasswordResetFinishService {
constructor(private http: HttpClient) {}
save(keyAndPassword: any): Observable<any> {
return this.http.post(SERVER_API_URL + 'api/account/reset-password/finish', keyAndPassword);
}
}

View File

@ -0,0 +1,46 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h1 jhiTranslate="reset.request.title">Reset your password</h1>
<div class="alert alert-danger" jhiTranslate="reset.request.messages.notfound" *ngIf="errorEmailNotExists">
<strong>Email address isn't registered!</strong> Please check and try again.
</div>
<div class="alert alert-warning" *ngIf="!success">
<p jhiTranslate="reset.request.messages.info">Enter the email address you used to register.</p>
</div>
<div class="alert alert-success" *ngIf="success === 'OK'">
<p jhiTranslate="reset.request.messages.success">Check your emails for details on how to reset your password.</p>
</div>
<form *ngIf="!success" name="form" role="form" (ngSubmit)="requestReset()" #resetRequestForm="ngForm">
<div class="form-group">
<label class="form-control-label" for="email" jhiTranslate="global.form.email">Email</label>
<input type="email" class="form-control" id="email" name="email" placeholder="{{'global.form.email.placeholder' | translate}}"
[(ngModel)]="resetAccount.email" minlength=5 maxlength=254 #emailInput="ngModel" email required>
<div *ngIf="emailInput.dirty && emailInput.invalid">
<small class="form-text text-danger"
*ngIf="emailInput.errors.required" jhiTranslate="global.messages.validate.email.required">
Your email is required.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.email" jhiTranslate="global.messages.validate.email.invalid">
Your email is invalid.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.minlength" jhiTranslate="global.messages.validate.email.minlength">
Your email is required to be at least 5 characters.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.maxlength" jhiTranslate="global.messages.validate.email.maxlength">
Your email cannot be longer than 100 characters.
</small>
</div>
</div>
<button type="submit" [disabled]="resetRequestForm.form.invalid" class="btn btn-primary" jhiTranslate="reset.request.form.button">Reset</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,43 @@
import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core';
import { EMAIL_NOT_FOUND_TYPE } from 'app/shared';
import { PasswordResetInitService } from './password-reset-init.service';
@Component({
selector: 'jhi-password-reset-init',
templateUrl: './password-reset-init.component.html'
})
export class PasswordResetInitComponent implements OnInit, AfterViewInit {
error: string;
errorEmailNotExists: string;
resetAccount: any;
success: string;
constructor(private passwordResetInitService: PasswordResetInitService, private elementRef: ElementRef, private renderer: Renderer) {}
ngOnInit() {
this.resetAccount = {};
}
ngAfterViewInit() {
this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#email'), 'focus', []);
}
requestReset() {
this.error = null;
this.errorEmailNotExists = null;
this.passwordResetInitService.save(this.resetAccount.email).subscribe(
() => {
this.success = 'OK';
},
response => {
this.success = null;
if (response.status === 400 && response.error.type === EMAIL_NOT_FOUND_TYPE) {
this.errorEmailNotExists = 'ERROR';
} else {
this.error = 'ERROR';
}
}
);
}
}

View File

@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { PasswordResetInitComponent } from './password-reset-init.component';
export const passwordResetInitRoute: Route = {
path: 'reset/request',
component: PasswordResetInitComponent,
data: {
authorities: [],
pageTitle: 'global.menu.account.password'
}
};

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class PasswordResetInitService {
constructor(private http: HttpClient) {}
save(mail: string): Observable<any> {
return this.http.post(SERVER_API_URL + 'api/account/reset-password/init', mail);
}
}

View File

@ -0,0 +1,85 @@
import { Component, ElementRef, Input, Renderer } from '@angular/core';
@Component({
selector: 'jhi-password-strength-bar',
template: `
<div id="strength">
<small jhiTranslate="global.messages.validate.newpassword.strength">Password strength:</small>
<ul id="strengthBar">
<li class="point"></li>
<li class="point"></li>
<li class="point"></li>
<li class="point"></li>
<li class="point"></li>
</ul>
</div>
`,
styleUrls: ['password-strength-bar.css']
})
export class PasswordStrengthBarComponent {
colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
constructor(private renderer: Renderer, private elementRef: ElementRef) {}
measureStrength(p: string): number {
let force = 0;
const regex = /[$-/:-?{-~!"^_`\[\]]/g; // "
const lowerLetters = /[a-z]+/.test(p);
const upperLetters = /[A-Z]+/.test(p);
const numbers = /[0-9]+/.test(p);
const symbols = regex.test(p);
const flags = [lowerLetters, upperLetters, numbers, symbols];
const passedMatches = flags.filter((isMatchedFlag: boolean) => {
return isMatchedFlag === true;
}).length;
force += 2 * p.length + (p.length >= 10 ? 1 : 0);
force += passedMatches * 10;
// penalty (short password)
force = p.length <= 6 ? Math.min(force, 10) : force;
// penalty (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(s: number): any {
let 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] };
}
@Input()
set passwordToCheck(password: string) {
if (password) {
const c = this.getColor(this.measureStrength(password));
const element = this.elementRef.nativeElement;
if (element.className) {
this.renderer.setElementClass(element, element.className, false);
}
const lis = element.getElementsByTagName('li');
for (let i = 0; i < lis.length; i++) {
if (i < c.idx) {
this.renderer.setElementStyle(lis[i], 'backgroundColor', c.col);
} else {
this.renderer.setElementStyle(lis[i], 'backgroundColor', '#DDD');
}
}
}
}
}

View File

@ -0,0 +1,24 @@
/* ==========================================================================
start Password strength bar style
========================================================================== */
ul#strengthBar {
display: inline;
list-style: none;
margin: 0;
margin-left: 15px;
padding: 0;
vertical-align: 2px;
}
.point {
background: #ddd;
border-radius: 2px;
display: inline-block;
height: 5px;
margin-right: 1px;
width: 20px;
}
.point:last-child {
margin: 0 !important;
}

View File

@ -0,0 +1,77 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h2 jhiTranslate="password.title" [translateValues]="{username: account.login}" *ngIf="account">Password for [<b>{{account.login}}</b>]</h2>
<div class="alert alert-success" *ngIf="success" jhiTranslate="password.messages.success">
<strong>Password changed!</strong>
</div>
<div class="alert alert-danger" *ngIf="error" jhiTranslate="password.messages.error">
<strong>An error has occurred!</strong> The password could not be changed.
</div>
<div class="alert alert-danger" *ngIf="doNotMatch" jhiTranslate="global.messages.error.dontmatch">
The password and its confirmation do not match!
</div>
<form name="form" role="form" (ngSubmit)="changePassword()" #passwordForm="ngForm">
<div class="form-group">
<label class="form-control-label" for="currentPassword" jhiTranslate="global.form.currentpassword">Current password</label>
<input type="password" class="form-control" id="currentPassword" name="currentPassword" #currentPasswordInput="ngModel"
placeholder="{{'global.form.currentpassword.placeholder' | translate}}"
[(ngModel)]="currentPassword" required>
<div *ngIf="currentPasswordInput.dirty && currentPasswordInput.invalid">
<small class="form-text text-danger"
*ngIf="currentPasswordInput.errors.required" jhiTranslate="global.messages.validate.newpassword.required">
Your password is required.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="newPassword" jhiTranslate="global.form.newpassword">New password</label>
<input type="password" class="form-control" id="newPassword" name="newPassword" #newPasswordInput="ngModel"
placeholder="{{'global.form.newpassword.placeholder' | translate}}"
[(ngModel)]="newPassword" minlength=4 maxlength=50 required>
<div *ngIf="newPasswordInput.dirty && newPasswordInput.invalid">
<small class="form-text text-danger"
*ngIf="newPasswordInput.errors.required" jhiTranslate="global.messages.validate.newpassword.required">
Your password is required.
</small>
<small class="form-text text-danger"
*ngIf="newPasswordInput.errors.minlength" jhiTranslate="global.messages.validate.newpassword.minlength">
Your password is required to be at least 4 characters.
</small>
<small class="form-text text-danger"
*ngIf="newPasswordInput.errors.maxlength" jhiTranslate="global.messages.validate.newpassword.maxlength">
Your password cannot be longer than 50 characters.
</small>
</div>
<jhi-password-strength-bar [passwordToCheck]="newPassword"></jhi-password-strength-bar>
</div>
<div class="form-group">
<label class="form-control-label" for="confirmPassword" jhiTranslate="global.form.confirmpassword">New password confirmation</label>
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" #confirmPasswordInput="ngModel"
placeholder="{{'global.form.confirmpassword.placeholder' | translate}}"
[(ngModel)]="confirmPassword" minlength=4 maxlength=50 required>
<div *ngIf="confirmPasswordInput.dirty && confirmPasswordInput.invalid">
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.required" jhiTranslate="global.messages.validate.confirmpassword.required">
Your confirmation password is required.
</small>
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.minlength" jhiTranslate="global.messages.validate.confirmpassword.minlength">
Your confirmation password is required to be at least 4 characters.
</small>
<small class="form-text text-danger"
*ngIf="confirmPasswordInput.errors.maxlength" jhiTranslate="global.messages.validate.confirmpassword.maxlength">
Your confirmation password cannot be longer than 50 characters.
</small>
</div>
</div>
<button type="submit" [disabled]="passwordForm.form.invalid" class="btn btn-primary" jhiTranslate="password.form.button">Save</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import { AccountService } from 'app/core';
import { PasswordService } from './password.service';
@Component({
selector: 'jhi-password',
templateUrl: './password.component.html'
})
export class PasswordComponent implements OnInit {
doNotMatch: string;
error: string;
success: string;
account: any;
currentPassword: string;
newPassword: string;
confirmPassword: string;
constructor(private passwordService: PasswordService, private accountService: AccountService) {}
ngOnInit() {
this.accountService.identity().then(account => {
this.account = account;
});
}
changePassword() {
if (this.newPassword !== this.confirmPassword) {
this.error = null;
this.success = null;
this.doNotMatch = 'ERROR';
} else {
this.doNotMatch = null;
this.passwordService.save(this.newPassword, this.currentPassword).subscribe(
() => {
this.error = null;
this.success = 'OK';
},
() => {
this.success = null;
this.error = 'ERROR';
}
);
}
}
}

View File

@ -0,0 +1,14 @@
import { Route } from '@angular/router';
import { UserRouteAccessService } from 'app/core';
import { PasswordComponent } from './password.component';
export const passwordRoute: Route = {
path: 'password',
component: PasswordComponent,
data: {
authorities: ['ROLE_USER'],
pageTitle: 'global.menu.account.password'
},
canActivate: [UserRouteAccessService]
};

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class PasswordService {
constructor(private http: HttpClient) {}
save(newPassword: string, currentPassword: string): Observable<any> {
return this.http.post(SERVER_API_URL + 'api/account/change-password', { currentPassword, newPassword });
}
}

View File

@ -0,0 +1,124 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h1 jhiTranslate="register.title">Registration</h1>
<div class="alert alert-success" *ngIf="success" jhiTranslate="register.messages.success">
<strong>Registration saved!</strong> Please check your email for confirmation.
</div>
<div class="alert alert-danger" *ngIf="error" jhiTranslate="register.messages.error.fail">
<strong>Registration failed!</strong> Please try again later.
</div>
<div class="alert alert-danger" *ngIf="errorUserExists" jhiTranslate="register.messages.error.userexists">
<strong>Login name already registered!</strong> Please choose another one.
</div>
<div class="alert alert-danger" *ngIf="errorEmailExists" jhiTranslate="register.messages.error.emailexists">
<strong>Email is already in use!</strong> Please choose another one.
</div>
<div class="alert alert-danger" *ngIf="doNotMatch" jhiTranslate="global.messages.error.dontmatch">
The password and its confirmation do not match!
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-8">
<form name="form" role="form" (ngSubmit)="register()" #registerForm="ngForm" *ngIf="!success">
<div class="form-group">
<label class="form-control-label" for="login" jhiTranslate="global.form.username">Username</label>
<input type="text" class="form-control" [(ngModel)]="registerAccount.login" id="login" name="login" #login="ngModel" placeholder="{{'global.form.username.placeholder' | translate}}"
required minlength="1" maxlength="50" pattern="^[_.@A-Za-z0-9-]*$">
<div *ngIf="login.dirty && login.invalid">
<small class="form-text text-danger" *ngIf="login.errors.required" jhiTranslate="register.messages.validate.login.required">
Your username is required.
</small>
<small class="form-text text-danger" *ngIf="login.errors.minlength"
jhiTranslate="register.messages.validate.login.minlength">
Your username is required to be at least 1 character.
</small>
<small class="form-text text-danger" *ngIf="login.errors.maxlength"
jhiTranslate="register.messages.validate.login.maxlength">
Your username cannot be longer than 50 characters.
</small>
<small class="form-text text-danger" *ngIf="login.errors.pattern"
jhiTranslate="register.messages.validate.login.pattern">
Your username can only contain letters and digits.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="email" jhiTranslate="global.form.email">Email</label>
<input type="email" class="form-control" id="email" name="email" #email="ngModel" placeholder="{{'global.form.email.placeholder' | translate}}"
[(ngModel)]="registerAccount.email" minlength=5 maxlength=254 email required>
<div *ngIf="email.dirty && email.invalid">
<small class="form-text text-danger" *ngIf="email.errors.required"
jhiTranslate="global.messages.validate.email.required">
Your email is required.
</small>
<small class="form-text text-danger" *ngIf="email.errors.invalid"
jhiTranslate="global.messages.validate.email.invalid">
Your email is invalid.
</small>
<small class="form-text text-danger" *ngIf="email.errors.minlength"
jhiTranslate="global.messages.validate.email.minlength">
Your email is required to be at least 5 characters.
</small>
<small class="form-text text-danger" *ngIf="email.errors.maxlength"
jhiTranslate="global.messages.validate.email.maxlength">
Your email cannot be longer than 100 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="password" jhiTranslate="global.form.newpassword">New password</label>
<input type="password" class="form-control" id="password" name="password" #password="ngModel" placeholder="{{'global.form.newpassword.placeholder' | translate}}"
[(ngModel)]="registerAccount.password" minlength=4 maxlength=50 required>
<div *ngIf="password.dirty && password.invalid">
<small class="form-text text-danger" *ngIf="password.errors.required"
jhiTranslate="global.messages.validate.newpassword.required">
Your password is required.
</small>
<small class="form-text text-danger" *ngIf="password.errors.minlength"
jhiTranslate="global.messages.validate.newpassword.minlength">
Your password is required to be at least 4 characters.
</small>
<small class="form-text text-danger" *ngIf="password.errors.maxlength"
jhiTranslate="global.messages.validate.newpassword.maxlength">
Your password cannot be longer than 50 characters.
</small>
</div>
<jhi-password-strength-bar [passwordToCheck]="registerAccount.password"></jhi-password-strength-bar>
</div>
<div class="form-group">
<label class="form-control-label" for="confirmPassword" jhiTranslate="global.form.confirmpassword">New password confirmation</label>
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword" #confirmPasswordInput="ngModel" placeholder="{{'global.form.confirmpassword.placeholder' | translate}}"
[(ngModel)]="confirmPassword" minlength=4 maxlength=50 required>
<div *ngIf="confirmPasswordInput.dirty && confirmPasswordInput.invalid">
<small class="form-text text-danger" *ngIf="confirmPasswordInput.errors.required"
jhiTranslate="global.messages.validate.confirmpassword.required">
Your confirmation password is required.
</small>
<small class="form-text text-danger" *ngIf="confirmPasswordInput.errors.minlength"
jhiTranslate="global.messages.validate.confirmpassword.minlength">
Your confirmation password is required to be at least 4 characters.
</small>
<small class="form-text text-danger" *ngIf="confirmPasswordInput.errors.maxlength"
jhiTranslate="global.messages.validate.confirmpassword.maxlength">
Your confirmation password cannot be longer than 50 characters.
</small>
</div>
</div>
<button type="submit" [disabled]="registerForm.form.invalid" class="btn btn-primary" jhiTranslate="register.form.button">Register</button>
</form>
<p></p>
<div class="alert alert-warning">
<span jhiTranslate="global.messages.info.authenticated.prefix">If you want to </span>
<a class="alert-link" (click)="openLogin()" jhiTranslate="global.messages.info.authenticated.link">sign in</a><span jhiTranslate="global.messages.info.authenticated.suffix">, you can try the default accounts:<br/>- Administrator (login="admin" and password="admin") <br/>- User (login="user" and password="user").</span>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,75 @@
import { Component, OnInit, AfterViewInit, Renderer, ElementRef } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { JhiLanguageService } from 'ng-jhipster';
import { EMAIL_ALREADY_USED_TYPE, LOGIN_ALREADY_USED_TYPE } from 'app/shared';
import { LoginModalService } from 'app/core';
import { Register } from './register.service';
@Component({
selector: 'jhi-register',
templateUrl: './register.component.html'
})
export class RegisterComponent implements OnInit, AfterViewInit {
confirmPassword: string;
doNotMatch: string;
error: string;
errorEmailExists: string;
errorUserExists: string;
registerAccount: any;
success: boolean;
modalRef: NgbModalRef;
constructor(
private languageService: JhiLanguageService,
private loginModalService: LoginModalService,
private registerService: Register,
private elementRef: ElementRef,
private renderer: Renderer
) {}
ngOnInit() {
this.success = false;
this.registerAccount = {};
}
ngAfterViewInit() {
this.renderer.invokeElementMethod(this.elementRef.nativeElement.querySelector('#login'), 'focus', []);
}
register() {
if (this.registerAccount.password !== this.confirmPassword) {
this.doNotMatch = 'ERROR';
} else {
this.doNotMatch = null;
this.error = null;
this.errorUserExists = null;
this.errorEmailExists = null;
this.languageService.getCurrent().then(key => {
this.registerAccount.langKey = key;
this.registerService.save(this.registerAccount).subscribe(
() => {
this.success = true;
},
response => this.processError(response)
);
});
}
}
openLogin() {
this.modalRef = this.loginModalService.open();
}
private processError(response: HttpErrorResponse) {
this.success = null;
if (response.status === 400 && response.error.type === LOGIN_ALREADY_USED_TYPE) {
this.errorUserExists = 'ERROR';
} else if (response.status === 400 && response.error.type === EMAIL_ALREADY_USED_TYPE) {
this.errorEmailExists = 'ERROR';
} else {
this.error = 'ERROR';
}
}
}

View File

@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { RegisterComponent } from './register.component';
export const registerRoute: Route = {
path: 'register',
component: RegisterComponent,
data: {
authorities: [],
pageTitle: 'register.title'
}
};

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class Register {
constructor(private http: HttpClient) {}
save(account: any): Observable<any> {
return this.http.post(SERVER_API_URL + 'api/register', account);
}
}

View File

@ -0,0 +1,86 @@
<div>
<div class="row justify-content-center">
<div class="col-md-8">
<h2 jhiTranslate="settings.title" [translateValues]="{username: settingsAccount.login}" *ngIf="settingsAccount">User settings for [<b>{{settingsAccount.login}}</b>]</h2>
<div class="alert alert-success" *ngIf="success" jhiTranslate="settings.messages.success">
<strong>Settings saved!</strong>
</div>
<jhi-alert-error></jhi-alert-error>
<form name="form" role="form" (ngSubmit)="save()" #settingsForm="ngForm" *ngIf="settingsAccount" novalidate>
<div class="form-group">
<label class="form-control-label" for="firstName" jhiTranslate="settings.form.firstname">First Name</label>
<input type="text" class="form-control" id="firstName" name="firstName" placeholder="{{'settings.form.firstname.placeholder' | translate}}"
[(ngModel)]="settingsAccount.firstName" minlength=1 maxlength=50 #firstNameInput="ngModel" required>
<div *ngIf="firstNameInput.dirty && firstNameInput.invalid">
<small class="form-text text-danger"
*ngIf="firstNameInput.errors.required" jhiTranslate="settings.messages.validate.firstname.required">
Your first name is required.
</small>
<small class="form-text text-danger"
*ngIf="firstNameInput.errors.minlength" jhiTranslate="settings.messages.validate.firstname.minlength">
Your first name is required to be at least 1 character.
</small>
<small class="form-text text-danger"
*ngIf="firstNameInput.errors.maxlength" jhiTranslate="settings.messages.validate.firstname.maxlength">
Your first name cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="lastName" jhiTranslate="settings.form.lastname">Last Name</label>
<input type="text" class="form-control" id="lastName" name="lastName" placeholder="{{'settings.form.lastname.placeholder' | translate}}"
[(ngModel)]="settingsAccount.lastName" minlength=1 maxlength=50 #lastNameInput="ngModel" required>
<div *ngIf="lastNameInput.dirty && lastNameInput.invalid">
<small class="form-text text-danger"
*ngIf="lastNameInput.errors.required" jhiTranslate="settings.messages.validate.lastname.required">
Your last name is required.
</small>
<small class="form-text text-danger"
*ngIf="lastNameInput.errors.minlength" jhiTranslate="settings.messages.validate.lastname.minlength">
Your last name is required to be at least 1 character.
</small>
<small class="form-text text-danger"
*ngIf="lastNameInput.errors.maxlength" jhiTranslate="settings.messages.validate.lastname.maxlength">
Your last name cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="email" jhiTranslate="global.form.email">Email</label>
<input type="email" class="form-control" id="email" name="email" placeholder="{{'global.form.email.placeholder' | translate}}"
[(ngModel)]="settingsAccount.email" minlength="5" maxlength="254" #emailInput="ngModel" email required>
<div *ngIf="emailInput.dirty && emailInput.invalid">
<small class="form-text text-danger"
*ngIf="emailInput.errors.required" jhiTranslate="global.messages.validate.email.required">
Your email is required.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.email" jhiTranslate="global.messages.validate.email.invalid">
Your email is invalid.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.minlength" jhiTranslate="global.messages.validate.email.minlength">
Your email is required to be at least 5 characters.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.maxlength" jhiTranslate="global.messages.validate.email.maxlength">
Your email cannot be longer than 100 characters.
</small>
</div>
</div>
<div class="form-group" *ngIf="languages && languages.length > 0">
<label for="langKey" jhiTranslate="settings.form.language">Language</label>
<select class="form-control" id="langKey" name="langKey" [(ngModel)]="settingsAccount.langKey">
<option *ngFor="let language of languages" [value]="language">{{language | findLanguageFromKey}}</option>
</select>
</div>
<button type="submit" [disabled]="settingsForm.form.invalid" class="btn btn-primary" jhiTranslate="settings.form.button">Save</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,63 @@
import { Component, OnInit } from '@angular/core';
import { JhiLanguageService } from 'ng-jhipster';
import { AccountService, JhiLanguageHelper } from 'app/core';
@Component({
selector: 'jhi-settings',
templateUrl: './settings.component.html'
})
export class SettingsComponent implements OnInit {
error: string;
success: string;
settingsAccount: any;
languages: any[];
constructor(
private accountService: AccountService,
private languageService: JhiLanguageService,
private languageHelper: JhiLanguageHelper
) {}
ngOnInit() {
this.accountService.identity().then(account => {
this.settingsAccount = this.copyAccount(account);
});
this.languageHelper.getAll().then(languages => {
this.languages = languages;
});
}
save() {
this.accountService.save(this.settingsAccount).subscribe(
() => {
this.error = null;
this.success = 'OK';
this.accountService.identity(true).then(account => {
this.settingsAccount = this.copyAccount(account);
});
this.languageService.getCurrent().then(current => {
if (this.settingsAccount.langKey !== current) {
this.languageService.changeLanguage(this.settingsAccount.langKey);
}
});
},
() => {
this.success = null;
this.error = 'ERROR';
}
);
}
copyAccount(account) {
return {
activated: account.activated,
email: account.email,
firstName: account.firstName,
langKey: account.langKey,
lastName: account.lastName,
login: account.login,
imageUrl: account.imageUrl
};
}
}

View File

@ -0,0 +1,14 @@
import { Route } from '@angular/router';
import { UserRouteAccessService } from 'app/core';
import { SettingsComponent } from './settings.component';
export const settingsRoute: Route = {
path: 'settings',
component: SettingsComponent,
data: {
authorities: ['ROLE_USER'],
pageTitle: 'global.menu.account.settings'
},
canActivate: [UserRouteAccessService]
};

View File

@ -0,0 +1,54 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RouterModule } from '@angular/router';
import { JhiLanguageService } from 'ng-jhipster';
import { JhiLanguageHelper } from 'app/core';
import { HsadminNgSharedModule } from 'app/shared';
/* jhipster-needle-add-admin-module-import - JHipster will add admin modules imports here */
import {
adminState,
AuditsComponent,
UserMgmtComponent,
UserMgmtDetailComponent,
UserMgmtUpdateComponent,
UserMgmtDeleteDialogComponent,
LogsComponent,
JhiMetricsMonitoringComponent,
JhiHealthModalComponent,
JhiHealthCheckComponent,
JhiConfigurationComponent,
JhiDocsComponent
} from './';
@NgModule({
imports: [
HsadminNgSharedModule,
RouterModule.forChild(adminState)
/* jhipster-needle-add-admin-module - JHipster will add admin modules here */
],
declarations: [
AuditsComponent,
UserMgmtComponent,
UserMgmtDetailComponent,
UserMgmtUpdateComponent,
UserMgmtDeleteDialogComponent,
LogsComponent,
JhiConfigurationComponent,
JhiHealthCheckComponent,
JhiHealthModalComponent,
JhiDocsComponent,
JhiMetricsMonitoringComponent
],
providers: [{ provide: JhiLanguageService, useClass: JhiLanguageService }],
entryComponents: [UserMgmtDeleteDialogComponent, JhiHealthModalComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class HsadminNgAdminModule {
constructor(private languageService: JhiLanguageService, private languageHelper: JhiLanguageHelper) {
this.languageHelper.language.subscribe((languageKey: string) => {
if (languageKey !== undefined) {
this.languageService.changeLanguage(languageKey);
}
});
}
}

View File

@ -0,0 +1,18 @@
import { Routes } from '@angular/router';
import { auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, metricsRoute, userMgmtRoute } from './';
import { UserRouteAccessService } from 'app/core';
const ADMIN_ROUTES = [auditsRoute, configurationRoute, docsRoute, healthRoute, logsRoute, ...userMgmtRoute, metricsRoute];
export const adminState: Routes = [
{
path: '',
data: {
authorities: ['ROLE_ADMIN']
},
canActivate: [UserRouteAccessService],
children: ADMIN_ROUTES
}
];

View File

@ -0,0 +1,3 @@
export class AuditData {
constructor(public remoteAddress: string, public sessionId: string) {}
}

View File

@ -0,0 +1,5 @@
import { AuditData } from './audit-data.model';
export class Audit {
constructor(public data: AuditData, public principal: string, public timestamp: string, public type: string) {}
}

View File

@ -0,0 +1,52 @@
<div *ngIf="audits">
<h2 id="audits-page-heading" jhiTranslate="audits.title">Audits</h2>
<div class="row">
<div class="col-md-5">
<h4 jhiTranslate="audits.filter.title">Filter by date</h4>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" jhiTranslate="audits.filter.from">from</span>
</div>
<input type="date" class="form-control" name="start" [(ngModel)]="fromDate" (ngModelChange)="transition()" required/>
<div class="input-group-append">
<span class="input-group-text" jhiTranslate="audits.filter.to">To</span>
</div>
<input type="date" class="form-control" name="end" [(ngModel)]="toDate" (ngModelChange)="transition()" required/>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-sm table-striped">
<thead>
<tr jhiSort [(predicate)]="predicate" [(ascending)]="reverse" [callback]="transition.bind(this)">
<th jhiSortBy="auditEventDate"><span jhiTranslate="audits.table.header.date">Date</span><fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="principal"><span jhiTranslate="audits.table.header.principal">User</span><fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="auditEventType"><span jhiTranslate="audits.table.header.status">State</span><fa-icon [icon]="'sort'"></fa-icon></th>
<th><span jhiTranslate="audits.table.header.data">Extra data</span></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let audit of audits">
<td><span>{{audit.timestamp| date:'medium'}}</span></td>
<td><small>{{audit.principal}}</small></td>
<td>{{audit.type}}</td>
<td>
<span *ngIf="audit.data" ng-show="audit.data.message">{{audit.data.message}}</span>
<span *ngIf="audit.data" ng-show="audit.data.remoteAddress"><span jhiTranslate="audits.table.data.remoteAddress">Remote Address</span> {{audit.data.remoteAddress}}</span>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<div class="row justify-content-center">
<jhi-item-count [page]="page" [total]="totalItems" [itemsPerPage]="itemsPerPage"></jhi-item-count>
</div>
<div class="row justify-content-center">
<ngb-pagination [collectionSize]="totalItems" [(page)]="page" [pageSize]="itemsPerPage" [maxSize]="5" [rotate]="true" [boundaryLinks]="true" (pageChange)="loadPage(page)"></ngb-pagination>
</div>
</div>
</div>

View File

@ -0,0 +1,126 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { DatePipe } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { JhiParseLinks, JhiAlertService } from 'ng-jhipster';
import { ITEMS_PER_PAGE } from 'app/shared';
import { Audit } from './audit.model';
import { AuditsService } from './audits.service';
@Component({
selector: 'jhi-audit',
templateUrl: './audits.component.html'
})
export class AuditsComponent implements OnInit, OnDestroy {
audits: Audit[];
fromDate: string;
itemsPerPage: any;
links: any;
page: number;
routeData: any;
predicate: any;
previousPage: any;
reverse: boolean;
toDate: string;
totalItems: number;
constructor(
private auditsService: AuditsService,
private alertService: JhiAlertService,
private parseLinks: JhiParseLinks,
private activatedRoute: ActivatedRoute,
private datePipe: DatePipe,
private router: Router
) {
this.itemsPerPage = ITEMS_PER_PAGE;
this.routeData = this.activatedRoute.data.subscribe(data => {
this.page = data['pagingParams'].page;
this.previousPage = data['pagingParams'].page;
this.reverse = data['pagingParams'].ascending;
this.predicate = data['pagingParams'].predicate;
});
}
ngOnInit() {
this.today();
this.previousMonth();
this.loadAll();
}
ngOnDestroy() {
this.routeData.unsubscribe();
}
previousMonth() {
const dateFormat = 'yyyy-MM-dd';
let fromDate: Date = 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());
}
this.fromDate = this.datePipe.transform(fromDate, dateFormat);
}
today() {
const dateFormat = 'yyyy-MM-dd';
// Today + 1 day - needed if the current day must be included
const today: Date = new Date();
today.setDate(today.getDate() + 1);
const date = new Date(today.getFullYear(), today.getMonth(), today.getDate());
this.toDate = this.datePipe.transform(date, dateFormat);
}
loadAll() {
this.auditsService
.query({
page: this.page - 1,
size: this.itemsPerPage,
sort: this.sort(),
fromDate: this.fromDate,
toDate: this.toDate
})
.subscribe(
(res: HttpResponse<Audit[]>) => this.onSuccess(res.body, res.headers),
(res: HttpResponse<any>) => this.onError(res.body)
);
}
sort() {
const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')];
if (this.predicate !== 'id') {
result.push('id');
}
return result;
}
loadPage(page: number) {
if (page !== this.previousPage) {
this.previousPage = page;
this.transition();
}
}
transition() {
this.router.navigate(['/admin/audits'], {
queryParams: {
page: this.page,
sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc')
}
});
this.loadAll();
}
private onSuccess(data, headers) {
this.links = this.parseLinks.parse(headers.get('link'));
this.totalItems = headers.get('X-Total-Count');
this.audits = data;
}
private onError(error) {
this.alertService.error(error.error, error.message, null);
}
}

View File

@ -0,0 +1,17 @@
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Route } from '@angular/router';
import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster';
import { AuditsComponent } from './audits.component';
export const auditsRoute: Route = {
path: 'audits',
component: AuditsComponent,
resolve: {
pagingParams: JhiResolvePagingParams
},
data: {
pageTitle: 'audits.title',
defaultSort: 'auditEventDate,desc'
}
};

View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { createRequestOption } from 'app/shared';
import { SERVER_API_URL } from 'app/app.constants';
import { Audit } from './audit.model';
@Injectable({ providedIn: 'root' })
export class AuditsService {
constructor(private http: HttpClient) {}
query(req: any): Observable<HttpResponse<Audit[]>> {
const params: HttpParams = createRequestOption(req);
params.set('fromDate', req.fromDate);
params.set('toDate', req.toDate);
const requestURL = SERVER_API_URL + 'management/audits';
return this.http.get<Audit[]>(requestURL, {
params,
observe: 'response'
});
}
}

View File

@ -0,0 +1,46 @@
<div *ngIf="allConfiguration && configuration">
<h2 id="configuration-page-heading" jhiTranslate="configuration.title">Configuration</h2>
<span jhiTranslate="configuration.filter">Filter (by prefix)</span> <input type="text" [(ngModel)]="filter" class="form-control">
<h3>Spring configuration</h3>
<table class="table table-striped table-bordered table-responsive d-table">
<thead>
<tr>
<th class="w-40" (click)="orderProp = 'prefix'; reverse=!reverse"><span jhiTranslate="configuration.table.prefix">Prefix</span></th>
<th class="w-60" (click)="orderProp = 'properties'; reverse=!reverse"><span jhiTranslate="configuration.table.properties">Properties</span></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let entry of (configuration | pureFilter:filter:'prefix' | orderBy:orderProp:reverse)">
<td><span>{{entry.prefix}}</span></td>
<td>
<div class="row" *ngFor="let key of keys(entry.properties)">
<div class="col-md-4">{{key}}</div>
<div class="col-md-8">
<span class="float-right badge-secondary break">{{entry.properties[key] | json}}</span>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<div *ngFor="let key of keys(allConfiguration)">
<h4><span>{{key}}</span></h4>
<table class="table table-sm table-striped table-bordered table-responsive d-table">
<thead>
<tr>
<th class="w-40">Property</th>
<th class="w-60">Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of allConfiguration[key]">
<td class="break">{{item.key}}</td>
<td class="break">
<span class="float-right badge-secondary break">{{item.val}}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,43 @@
import { Component, OnInit } from '@angular/core';
import { JhiConfigurationService } from './configuration.service';
@Component({
selector: 'jhi-configuration',
templateUrl: './configuration.component.html'
})
export class JhiConfigurationComponent implements OnInit {
allConfiguration: any = null;
configuration: any = null;
configKeys: any[];
filter: string;
orderProp: string;
reverse: boolean;
constructor(private configurationService: JhiConfigurationService) {
this.configKeys = [];
this.filter = '';
this.orderProp = 'prefix';
this.reverse = false;
}
keys(dict): Array<string> {
return dict === undefined ? [] : Object.keys(dict);
}
ngOnInit() {
this.configurationService.get().subscribe(configuration => {
this.configuration = configuration;
for (const config of configuration) {
if (config.properties !== undefined) {
this.configKeys.push(Object.keys(config.properties));
}
}
});
this.configurationService.getEnv().subscribe(configuration => {
this.allConfiguration = configuration;
});
}
}

View File

@ -0,0 +1,11 @@
import { Route } from '@angular/router';
import { JhiConfigurationComponent } from './configuration.component';
export const configurationRoute: Route = {
path: 'jhi-configuration',
component: JhiConfigurationComponent,
data: {
pageTitle: 'configuration.title'
}
};

View File

@ -0,0 +1,67 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class JhiConfigurationService {
constructor(private http: HttpClient) {}
get(): Observable<any> {
return this.http.get(SERVER_API_URL + 'management/configprops', { observe: 'response' }).pipe(
map((res: HttpResponse<any>) => {
const properties: any[] = [];
const propertiesObject = this.getConfigPropertiesObjects(res.body);
for (const key in propertiesObject) {
if (propertiesObject.hasOwnProperty(key)) {
properties.push(propertiesObject[key]);
}
}
return properties.sort((propertyA, propertyB) => {
return propertyA.prefix === propertyB.prefix ? 0 : propertyA.prefix < propertyB.prefix ? -1 : 1;
});
})
);
}
getConfigPropertiesObjects(res: Object) {
// This code is for Spring Boot 2
if (res['contexts'] !== undefined) {
for (const key in res['contexts']) {
// If the key is not bootstrap, it will be the ApplicationContext Id
// For default app, it is baseName
// For microservice, it is baseName-1
if (!key.startsWith('bootstrap')) {
return res['contexts'][key]['beans'];
}
}
}
// by default, use the default ApplicationContext Id
return res['contexts']['hsadminNg']['beans'];
}
getEnv(): Observable<any> {
return this.http.get(SERVER_API_URL + 'management/env', { observe: 'response' }).pipe(
map((res: HttpResponse<any>) => {
const properties: any = {};
const propertySources = res.body['propertySources'];
for (const propertyObject of propertySources) {
const name = propertyObject['name'];
const detailProperties = propertyObject['properties'];
const vals: any[] = [];
for (const keyDetail in detailProperties) {
if (detailProperties.hasOwnProperty(keyDetail)) {
vals.push({ key: keyDetail, val: detailProperties[keyDetail]['value'] });
}
}
properties[name] = vals;
}
return properties;
})
);
}
}

View File

@ -0,0 +1,2 @@
<iframe src="swagger-ui/index.html" width="100%" height="900" seamless
target="_top" title="Swagger UI" class="border-0"></iframe>

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'jhi-docs',
templateUrl: './docs.component.html'
})
export class JhiDocsComponent {
constructor() {}
}

View File

@ -0,0 +1,11 @@
import { Route } from '@angular/router';
import { JhiDocsComponent } from './docs.component';
export const docsRoute: Route = {
path: 'docs',
component: JhiDocsComponent,
data: {
pageTitle: 'global.menu.admin.apidocs'
}
};

View File

@ -0,0 +1,36 @@
<div class="modal-header">
<h4 class="modal-title" id="showHealthLabel">
{{'health.indicator.' + baseName(currentHealth.name) | translate}}
{{subSystemName(currentHealth.name)}}
</h4>
<button aria-label="Close" data-dismiss="modal" class="close" type="button" (click)="activeModal.dismiss('closed')"><span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body pad">
<div *ngIf="currentHealth.details">
<h5 jhiTranslate="health.details.properties">Properties</h5>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th class="text-left" jhiTranslate="health.details.name">Name</th>
<th class="text-left" jhiTranslate="health.details.value">Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let entry of currentHealth.details.details | keys">
<td class="text-left">{{entry.key}}</td>
<td class="text-left">{{readableValue(entry.value)}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div *ngIf="currentHealth.error">
<h4 jhiTranslate="health.details.error">Error</h4>
<pre>{{currentHealth.error}}</pre>
</div>
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-secondary float-left" type="button" (click)="activeModal.dismiss('closed')">Done</button>
</div>

View File

@ -0,0 +1,41 @@
import { Component } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { JhiHealthService } from './health.service';
@Component({
selector: 'jhi-health-modal',
templateUrl: './health-modal.component.html'
})
export class JhiHealthModalComponent {
currentHealth: any;
constructor(private healthService: JhiHealthService, public activeModal: NgbActiveModal) {}
baseName(name) {
return this.healthService.getBaseName(name);
}
subSystemName(name) {
return this.healthService.getSubSystemName(name);
}
readableValue(value: number) {
if (this.currentHealth.name === 'diskSpace') {
// Should display storage space in an human readable unit
const val = value / 1073741824;
if (val > 1) {
// Value
return val.toFixed(2) + ' GB';
} else {
return (value / 1048576).toFixed(2) + ' MB';
}
}
if (typeof value === 'object') {
return JSON.stringify(value);
} else {
return value.toString();
}
}
}

View File

@ -0,0 +1,34 @@
<div>
<h2>
<span id="health-page-heading" jhiTranslate="health.title">Health Checks</span>
<button class="btn btn-primary float-right" (click)="refresh()">
<fa-icon [icon]="'sync'"></fa-icon> <span jhiTranslate="health.refresh.button">Refresh</span>
</button>
</h2>
<div class="table-responsive">
<table id="healthCheck" class="table table-striped">
<thead>
<tr>
<th jhiTranslate="health.table.service">Service Name</th>
<th class="text-center" jhiTranslate="health.table.status">Status</th>
<th class="text-center" jhiTranslate="health.details.details">Details</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let health of healthData">
<td>{{'health.indicator.' + baseName(health.name) | translate}} {{subSystemName(health.name)}}</td>
<td class="text-center">
<span class="badge" [ngClass]="getBadgeClass(health.status)" jhiTranslate="{{'health.status.' + health.status}}">
{{health.status}}
</span>
</td>
<td class="text-center">
<a class="hand" (click)="showHealth(health)" *ngIf="health.details || health.error">
<fa-icon [icon]="'eye'"></fa-icon>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,66 @@
import { Component, OnInit } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { JhiHealthService } from './health.service';
import { JhiHealthModalComponent } from './health-modal.component';
@Component({
selector: 'jhi-health',
templateUrl: './health.component.html'
})
export class JhiHealthCheckComponent implements OnInit {
healthData: any;
updatingHealth: boolean;
constructor(private modalService: NgbModal, private healthService: JhiHealthService) {}
ngOnInit() {
this.refresh();
}
baseName(name: string) {
return this.healthService.getBaseName(name);
}
getBadgeClass(statusState) {
if (statusState === 'UP') {
return 'badge-success';
} else {
return 'badge-danger';
}
}
refresh() {
this.updatingHealth = true;
this.healthService.checkHealth().subscribe(
health => {
this.healthData = this.healthService.transformHealthData(health);
this.updatingHealth = false;
},
error => {
if (error.status === 503) {
this.healthData = this.healthService.transformHealthData(error.error);
this.updatingHealth = false;
}
}
);
}
showHealth(health: any) {
const modalRef = this.modalService.open(JhiHealthModalComponent);
modalRef.componentInstance.currentHealth = health;
modalRef.result.then(
result => {
// Left blank intentionally, nothing to do here
},
reason => {
// Left blank intentionally, nothing to do here
}
);
}
subSystemName(name: string) {
return this.healthService.getSubSystemName(name);
}
}

View File

@ -0,0 +1,11 @@
import { Route } from '@angular/router';
import { JhiHealthCheckComponent } from './health.component';
export const healthRoute: Route = {
path: 'jhi-health',
component: JhiHealthCheckComponent,
data: {
pageTitle: 'health.title'
}
};

View File

@ -0,0 +1,133 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class JhiHealthService {
separator: string;
constructor(private http: HttpClient) {
this.separator = '.';
}
checkHealth(): Observable<any> {
return this.http.get(SERVER_API_URL + 'management/health');
}
transformHealthData(data): any {
const response = [];
this.flattenHealthData(response, null, data.details);
return response;
}
getBaseName(name): string {
if (name) {
const split = name.split('.');
return split[0];
}
}
getSubSystemName(name): string {
if (name) {
const split = name.split('.');
split.splice(0, 1);
const remainder = split.join('.');
return remainder ? ' - ' + remainder : '';
}
}
/* private methods */
private addHealthObject(result, isLeaf, healthObject, name): any {
const healthData: any = {
name
};
const details = {};
let hasDetails = false;
for (const key in healthObject) {
if (healthObject.hasOwnProperty(key)) {
const value = healthObject[key];
if (key === 'status' || key === 'error') {
healthData[key] = value;
} else {
if (!this.isHealthObject(value)) {
details[key] = value;
hasDetails = true;
}
}
}
}
// Add the details
if (hasDetails) {
healthData.details = details;
}
// Only add nodes if they provide additional information
if (isLeaf || hasDetails || healthData.error) {
result.push(healthData);
}
return healthData;
}
private flattenHealthData(result, path, data): any {
for (const key in data) {
if (data.hasOwnProperty(key)) {
const value = data[key];
if (this.isHealthObject(value)) {
if (this.hasSubSystem(value)) {
this.addHealthObject(result, false, value, this.getModuleName(path, key));
this.flattenHealthData(result, this.getModuleName(path, key), value);
} else {
this.addHealthObject(result, true, value, this.getModuleName(path, key));
}
}
}
}
return result;
}
private getModuleName(path, name): string {
let result;
if (path && name) {
result = path + this.separator + name;
} else if (path) {
result = path;
} else if (name) {
result = name;
} else {
result = '';
}
return result;
}
private hasSubSystem(healthObject): boolean {
let result = false;
for (const key in healthObject) {
if (healthObject.hasOwnProperty(key)) {
const value = healthObject[key];
if (value && value.status) {
result = true;
}
}
}
return result;
}
private isHealthObject(healthObject): boolean {
let result = false;
for (const key in healthObject) {
if (healthObject.hasOwnProperty(key)) {
if (key === 'status') {
result = true;
}
}
}
return result;
}
}

View File

@ -0,0 +1,27 @@
export * from './audits/audits.component';
export * from './audits/audits.service';
export * from './audits/audits.route';
export * from './audits/audit.model';
export * from './audits/audit-data.model';
export * from './configuration/configuration.component';
export * from './configuration/configuration.service';
export * from './configuration/configuration.route';
export * from './docs/docs.component';
export * from './docs/docs.route';
export * from './health/health.component';
export * from './health/health-modal.component';
export * from './health/health.service';
export * from './health/health.route';
export * from './logs/logs.component';
export * from './logs/logs.service';
export * from './logs/logs.route';
export * from './logs/log.model';
export * from './metrics/metrics.component';
export * from './metrics/metrics.service';
export * from './metrics/metrics.route';
export * from './user-management/user-management-update.component';
export * from './user-management/user-management-delete-dialog.component';
export * from './user-management/user-management-detail.component';
export * from './user-management/user-management.component';
export * from './user-management/user-management.route';
export * from './admin.route';

View File

@ -0,0 +1,3 @@
export class Log {
constructor(public name: string, public level: string) {}
}

View File

@ -0,0 +1,28 @@
<div class="table-responsive" *ngIf="loggers">
<h2 id="logs-page-heading" jhiTranslate="logs.title">Logs</h2>
<p jhiTranslate="logs.nbloggers" [translateValues]="{total: loggers.length}">There are {{ loggers.length }} loggers.</p>
<span jhiTranslate="logs.filter">Filter</span> <input type="text" [(ngModel)]="filter" class="form-control">
<table class="table table-sm table-striped table-bordered">
<thead>
<tr title="click to order">
<th (click)="orderProp = 'name'; reverse=!reverse"><span jhiTranslate="logs.table.name">Name</span></th>
<th (click)="orderProp = 'level'; reverse=!reverse"><span jhiTranslate="logs.table.level">Level</span></th>
</tr>
</thead>
<tr *ngFor="let logger of (loggers | pureFilter:filter:'name' | orderBy:orderProp:reverse)">
<td><small>{{logger.name | slice:0:140}}</small></td>
<td>
<button (click)="changeLevel(logger.name, 'TRACE')" [ngClass]="(logger.level=='TRACE') ? 'btn-primary' : 'btn-light'" class="btn btn-sm">TRACE</button>
<button (click)="changeLevel(logger.name, 'DEBUG')" [ngClass]="(logger.level=='DEBUG') ? 'btn-success' : 'btn-light'" class="btn btn-sm">DEBUG</button>
<button (click)="changeLevel(logger.name, 'INFO')" [ngClass]="(logger.level=='INFO') ? 'btn-info' : 'btn-light'" class="btn btn-sm">INFO</button>
<button (click)="changeLevel(logger.name, 'WARN')" [ngClass]="(logger.level=='WARN') ? 'btn-warning' : 'btn-light'" class="btn btn-sm">WARN</button>
<button (click)="changeLevel(logger.name, 'ERROR')" [ngClass]="(logger.level=='ERROR') ? 'btn-danger' : 'btn-light'" class="btn btn-sm">ERROR</button>
<button (click)="changeLevel(logger.name, 'OFF')" [ngClass]="(logger.level=='OFF') ? 'btn-secondary' : 'btn-light'" class="btn btn-sm">OFF</button>
</td>
</tr>
</table>
</div>

View File

@ -0,0 +1,32 @@
import { Component, OnInit } from '@angular/core';
import { Log } from './log.model';
import { LogsService } from './logs.service';
@Component({
selector: 'jhi-logs',
templateUrl: './logs.component.html'
})
export class LogsComponent implements OnInit {
loggers: Log[];
filter: string;
orderProp: string;
reverse: boolean;
constructor(private logsService: LogsService) {
this.filter = '';
this.orderProp = 'name';
this.reverse = false;
}
ngOnInit() {
this.logsService.findAll().subscribe(response => (this.loggers = response.body));
}
changeLevel(name: string, level: string) {
const log = new Log(name, level);
this.logsService.changeLevel(log).subscribe(() => {
this.logsService.findAll().subscribe(response => (this.loggers = response.body));
});
}
}

View File

@ -0,0 +1,11 @@
import { Route } from '@angular/router';
import { LogsComponent } from './logs.component';
export const logsRoute: Route = {
path: 'logs',
component: LogsComponent,
data: {
pageTitle: 'logs.title'
}
};

View File

@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
import { Log } from './log.model';
@Injectable({ providedIn: 'root' })
export class LogsService {
constructor(private http: HttpClient) {}
changeLevel(log: Log): Observable<HttpResponse<any>> {
return this.http.put(SERVER_API_URL + 'management/logs', log, { observe: 'response' });
}
findAll(): Observable<HttpResponse<Log[]>> {
return this.http.get<Log[]>(SERVER_API_URL + 'management/logs', { observe: 'response' });
}
}

View File

@ -0,0 +1,56 @@
<div>
<h2>
<span id="metrics-page-heading" jhiTranslate="metrics.title">Application Metrics</span>
<button class="btn btn-primary float-right" (click)="refresh()">
<fa-icon [icon]="'sync'"></fa-icon> <span jhiTranslate="metrics.refresh.button">Refresh</span>
</button>
</h2>
<h3 jhiTranslate="metrics.jvm.title">JVM Metrics</h3>
<div class="row" *ngIf="!updatingMetrics">
<jhi-jvm-memory
class="col-md-4"
[updating]="updatingMetrics"
[jvmMemoryMetrics]="metrics.jvm">
</jhi-jvm-memory>
<jhi-jvm-threads class="col-md-4" [threadData]="threadData"></jhi-jvm-threads>
<jhi-metrics-system
class="col-md-4"
[updating]="updatingMetrics"
[systemMetrics]="metrics.processMetrics">
</jhi-metrics-system>
</div>
<div *ngIf="isObjectExisting(metrics, 'garbageCollector')">
<h3 jhiTranslate="metrics.jvm.gc.title">Garbage collector statistics</h3>
<jhi-metrics-garbagecollector [updating]="updatingMetrics" [garbageCollectorMetrics]="metrics.garbageCollector"></jhi-metrics-garbagecollector>
</div>
<div class="well well-lg" *ngIf="updatingMetrics" jhiTranslate="metrics.updating">Updating...</div>
<jhi-metrics-request
*ngIf="isObjectExisting(metrics, 'http.server.requests')"
[updating]="updatingMetrics"
[requestMetrics]="metrics['http.server.requests']">
</jhi-metrics-request>
<div >
<jhi-metrics-endpoints-requests
*ngIf="isObjectExisting(metrics, 'services')"
[updating]="updatingMetrics"
[endpointsRequestsMetrics]="metrics.services">
</jhi-metrics-endpoints-requests>
<jhi-metrics-cache
*ngIf="isObjectExisting(metrics, 'cache')"
[updating]="updatingMetrics"
[cacheMetrics]="metrics.cache">
</jhi-metrics-cache>
<jhi-metrics-datasource
*ngIf="isObjectExistingAndNotEmpty(metrics, 'databases')"
[updating]="updatingMetrics"
[datasourceMetrics]="metrics.databases">
</jhi-metrics-datasource>
</div>

View File

@ -0,0 +1,42 @@
import { Component, OnInit } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { JhiMetricsService } from './metrics.service';
@Component({
selector: 'jhi-metrics',
templateUrl: './metrics.component.html'
})
export class JhiMetricsMonitoringComponent implements OnInit {
metrics: any = {};
threadData: any = {};
updatingMetrics = true;
JCACHE_KEY: string;
constructor(private modalService: NgbModal, private metricsService: JhiMetricsService) {
this.JCACHE_KEY = 'jcache.statistics';
}
ngOnInit() {
this.refresh();
}
refresh() {
this.updatingMetrics = true;
this.metricsService.getMetrics().subscribe(metrics => {
this.metrics = metrics;
this.metricsService.threadDump().subscribe(data => {
this.threadData = data.threads;
this.updatingMetrics = false;
});
});
}
isObjectExisting(metrics: any, key: string) {
return metrics && metrics[key];
}
isObjectExistingAndNotEmpty(metrics: any, key: string) {
return this.isObjectExisting(metrics, key) && JSON.stringify(metrics[key]) !== '{}';
}
}

View File

@ -0,0 +1,11 @@
import { Route } from '@angular/router';
import { JhiMetricsMonitoringComponent } from './metrics.component';
export const metricsRoute: Route = {
path: 'jhi-metrics',
component: JhiMetricsMonitoringComponent,
data: {
pageTitle: 'metrics.title'
}
};

View File

@ -0,0 +1,18 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class JhiMetricsService {
constructor(private http: HttpClient) {}
getMetrics(): Observable<any> {
return this.http.get(SERVER_API_URL + 'management/jhi-metrics');
}
threadDump(): Observable<any> {
return this.http.get(SERVER_API_URL + 'management/threaddump');
}
}

View File

@ -0,0 +1,19 @@
<form name="deleteForm" (ngSubmit)="confirmDelete(user.login)">
<div class="modal-header">
<h4 class="modal-title" jhiTranslate="entity.delete.title">Confirm delete operation</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"
(click)="clear()">&times;</button>
</div>
<div class="modal-body">
<jhi-alert-error></jhi-alert-error>
<p jhiTranslate="userManagement.delete.question" [translateValues]="{login: user.login}">Are you sure you want to delete this User?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="clear()">
<fa-icon [icon]="'ban'"></fa-icon>&nbsp;<span jhiTranslate="entity.action.cancel">Cancel</span>
</button>
<button type="submit" class="btn btn-danger">
<fa-icon [icon]="'times'"></fa-icon>&nbsp;<span jhiTranslate="entity.action.delete">Delete</span>
</button>
</div>
</form>

View File

@ -0,0 +1,29 @@
import { Component } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { JhiEventManager } from 'ng-jhipster';
import { User, UserService } from 'app/core';
@Component({
selector: 'jhi-user-mgmt-delete-dialog',
templateUrl: './user-management-delete-dialog.component.html'
})
export class UserMgmtDeleteDialogComponent {
user: User;
constructor(private userService: UserService, public activeModal: NgbActiveModal, private eventManager: JhiEventManager) {}
clear() {
this.activeModal.dismiss('cancel');
}
confirmDelete(login) {
this.userService.delete(login).subscribe(response => {
this.eventManager.broadcast({
name: 'userListModification',
content: 'Deleted a user'
});
this.activeModal.dismiss(true);
});
}
}

View File

@ -0,0 +1,49 @@
<div class="row justify-content-center">
<div class="col-8">
<div *ngIf="user">
<h2>
<span jhiTranslate="userManagement.detail.title">User</span> [<b>{{user.login}}</b>]
</h2>
<dl class="row-md jh-entity-details">
<dt><span jhiTranslate="userManagement.login">Login</span></dt>
<dd>
<span>{{user.login}}</span>
<jhi-boolean
[value]="user.activated"
[textTrue]="'userManagement.activated' | translate"
[textFalse]="'userManagement.deactivated' | translate">
</jhi-boolean>
</dd>
<dt><span jhiTranslate="userManagement.firstName">First Name</span></dt>
<dd>{{user.firstName}}</dd>
<dt><span jhiTranslate="userManagement.lastName">Last Name</span></dt>
<dd>{{user.lastName}}</dd>
<dt><span jhiTranslate="userManagement.email">Email</span></dt>
<dd>{{user.email}}</dd>
<dt><span jhiTranslate="userManagement.langKey">Lang Key</span></dt>
<dd>{{user.langKey}}</dd>
<dt><span jhiTranslate="userManagement.createdBy">Created By</span></dt>
<dd>{{user.createdBy}}</dd>
<dt><span jhiTranslate="userManagement.createdDate">Created Date</span></dt>
<dd>{{user.createdDate | date:'dd/MM/yy HH:mm' }}</dd>
<dt><span jhiTranslate="userManagement.lastModifiedBy">Last Modified By</span></dt>
<dd>{{user.lastModifiedBy}}</dd>
<dt><span jhiTranslate="userManagement.lastModifiedDate">Last Modified Date</span></dt>
<dd>{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}}</dd>
<dt><span jhiTranslate="userManagement.profiles">Profiles</span></dt>
<dd>
<ul class="list-unstyled">
<li *ngFor="let authority of user.authorities">
<span class="badge badge-info">{{authority}}</span>
</li>
</ul>
</dd>
</dl>
<button type="submit"
routerLink="../../"
class="btn btn-info">
<fa-icon [icon]="'arrow-left'"></fa-icon>&nbsp;<span jhiTranslate="entity.action.back"> Back</span>
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,20 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { User } from 'app/core';
@Component({
selector: 'jhi-user-mgmt-detail',
templateUrl: './user-management-detail.component.html'
})
export class UserMgmtDetailComponent implements OnInit {
user: User;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.data.subscribe(({ user }) => {
this.user = user.body ? user.body : user;
});
}
}

View File

@ -0,0 +1,124 @@
<div class="row justify-content-center">
<div class="col-8">
<form name="editForm" role="form" novalidate (ngSubmit)="save()" #editForm="ngForm">
<h2 id="myUserLabel" jhiTranslate="userManagement.home.createOrEditLabel">
Create or edit a User
</h2>
<div>
<jhi-alert-error></jhi-alert-error>
<div class="form-group" [hidden]="!user.id">
<label jhiTranslate="global.field.id">ID</label>
<input type="text" class="form-control" name="id"
[(ngModel)]="user.id" readonly>
</div>
<div class="form-group">
<label class="form-control-label" jhiTranslate="userManagement.login">Login</label>
<input type="text" class="form-control" name="login" #loginInput="ngModel"
[(ngModel)]="user.login" required minlength="1" maxlength="50" pattern="^[_.@A-Za-z0-9-]*$">
<div *ngIf="loginInput.dirty && loginInput.invalid">
<small class="form-text text-danger"
*ngIf="loginInput.errors.required" jhiTranslate="entity.validation.required">
This field is required.
</small>
<small class="form-text text-danger"
*ngIf="loginInput.errors.maxlength" jhiTranslate="entity.validation.maxlength"
[translateValues]="{max: 50}">
This field cannot be longer than 50 characters.
</small>
<small class="form-text text-danger"
*ngIf="loginInput.errors.pattern" jhiTranslate="entity.validation.patternLogin">
This field can only contain letters, digits and e-mail addresses.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" jhiTranslate="userManagement.firstName">First Name</label>
<input type="text" class="form-control" name="firstName" #firstNameInput="ngModel"
[(ngModel)]="user.firstName" maxlength="50">
<div *ngIf="firstNameInput.dirty && firstNameInput.invalid">
<small class="form-text text-danger"
*ngIf="firstNameInput.errors.maxlength" jhiTranslate="entity.validation.maxlength"
[translateValues]="{max: 50}">
This field cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label jhiTranslate="userManagement.lastName">Last Name</label>
<input type="text" class="form-control" name="lastName" #lastNameInput="ngModel"
[(ngModel)]="user.lastName" maxlength="50">
<div *ngIf="lastNameInput.dirty && lastNameInput.invalid">
<small class="form-text text-danger"
*ngIf="lastNameInput.errors.maxlength" jhiTranslate="entity.validation.maxlength"
[translateValues]="{max: 50}">
This field cannot be longer than 50 characters.
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" jhiTranslate="userManagement.email">Email</label>
<input type="email" class="form-control" name="email" #emailInput="ngModel"
[(ngModel)]="user.email" minlength="5" required maxlength="254" email>
<div *ngIf="emailInput.dirty && emailInput.invalid">
<small class="form-text text-danger"
*ngIf="emailInput.errors.required" jhiTranslate="entity.validation.required">
This field is required.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.maxlength" jhiTranslate="entity.validation.maxlength"
[translateValues]="{max: 100}">
This field cannot be longer than 100 characters.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.minlength" jhiTranslate="entity.validation.minlength"
[translateValues]="{min: 5}">
This field is required to be at least 5 characters.
</small>
<small class="form-text text-danger"
*ngIf="emailInput.errors.email" jhiTranslate="global.messages.validate.email.invalid">
Your email is invalid.
</small>
</div>
</div>
<div class="form-check">
<label class="form-check-label" for="activated">
<input class="form-check-input" [disabled]="user.id === null" type="checkbox" id="activated" name="activated" [(ngModel)]="user.activated">
<span jhiTranslate="userManagement.activated">Activated</span>
</label>
</div>
<div class="form-group" *ngIf="languages && languages.length > 0">
<label jhiTranslate="userManagement.langKey">Lang Key</label>
<select class="form-control" id="langKey" name="langKey" [(ngModel)]="user.langKey">
<option *ngFor="let language of languages" [value]="language">{{language | findLanguageFromKey}}</option>
</select>
</div>
<div class="form-group">
<label jhiTranslate="userManagement.profiles">Profiles</label>
<select class="form-control" multiple name="authority" [(ngModel)]="user.authorities">
<option *ngFor="let authority of authorities" [value]="authority">{{authority}}</option>
</select>
</div>
</div>
<div>
<button type="button" class="btn btn-secondary" (click)="previousState()">
<fa-icon [icon]="'ban'"></fa-icon>&nbsp;<span
jhiTranslate="entity.action.cancel">Cancel</span>
</button>
<button type="submit" [disabled]="editForm.form.invalid || isSaving" class="btn btn-primary">
<fa-icon [icon]="'save'"></fa-icon>&nbsp;<span jhiTranslate="entity.action.save">Save</span>
</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,58 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { JhiLanguageHelper, User, UserService } from 'app/core';
@Component({
selector: 'jhi-user-mgmt-update',
templateUrl: './user-management-update.component.html'
})
export class UserMgmtUpdateComponent implements OnInit {
user: User;
languages: any[];
authorities: any[];
isSaving: boolean;
constructor(
private languageHelper: JhiLanguageHelper,
private userService: UserService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.isSaving = false;
this.route.data.subscribe(({ user }) => {
this.user = user.body ? user.body : user;
});
this.authorities = [];
this.userService.authorities().subscribe(authorities => {
this.authorities = authorities;
});
this.languageHelper.getAll().then(languages => {
this.languages = languages;
});
}
previousState() {
window.history.back();
}
save() {
this.isSaving = true;
if (this.user.id !== null) {
this.userService.update(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError());
} else {
this.userService.create(this.user).subscribe(response => this.onSaveSuccess(response), () => this.onSaveError());
}
}
private onSaveSuccess(result) {
this.isSaving = false;
this.previousState();
}
private onSaveError() {
this.isSaving = false;
}
}

View File

@ -0,0 +1,79 @@
<div>
<h2>
<span id="user-management-page-heading" jhiTranslate="userManagement.home.title">Users</span>
<button class="btn btn-primary float-right jh-create-entity" [routerLink]="['./new']">
<fa-icon [icon]="'plus'"></fa-icon> <span jhiTranslate="userManagement.home.createLabel">Create a new User</span>
</button>
</h2>
<jhi-alert></jhi-alert>
<div class="table-responsive" *ngIf="users">
<table class="table table-striped">
<thead>
<tr jhiSort [(predicate)]="predicate" [(ascending)]="reverse" [callback]="transition.bind(this)">
<th jhiSortBy="id"><span jhiTranslate="global.field.id">ID</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="login"><span jhiTranslate="userManagement.login">Login</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="email"><span jhiTranslate="userManagement.email">Email</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th></th>
<th jhiSortBy="langKey"> <span jhiTranslate="userManagement.langKey">Lang Key</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th><span jhiTranslate="userManagement.profiles">Profiles</span></th>
<th jhiSortBy="createdDate"><span jhiTranslate="userManagement.createdDate">Created Date</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="lastModifiedBy"><span jhiTranslate="userManagement.lastModifiedBy">Last Modified By</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th jhiSortBy="lastModifiedDate"><span jhiTranslate="userManagement.lastModifiedDate">Last Modified Date</span> <fa-icon [icon]="'sort'"></fa-icon></th>
<th></th>
</tr>
</thead>
<tbody *ngIf ="users">
<tr *ngFor="let user of users; trackBy: trackIdentity">
<td><a [routerLink]="['./', user.login, 'view']">{{user.id}}</a></td>
<td>{{user.login}}</td>
<td>{{user.email}}</td>
<td>
<button class="btn btn-danger btn-sm" (click)="setActive(user, true)" *ngIf="!user.activated"
jhiTranslate="userManagement.deactivated">Deactivated</button>
<button class="btn btn-success btn-sm" (click)="setActive(user, false)" *ngIf="user.activated"
[disabled]="currentAccount.login === user.login" jhiTranslate="userManagement.activated">Activated</button>
</td>
<td>{{user.langKey}}</td>
<td>
<div *ngFor="let authority of user.authorities">
<span class="badge badge-info">{{ authority }}</span>
</div>
</td>
<td>{{user.createdDate | date:'dd/MM/yy HH:mm'}}</td>
<td>{{user.lastModifiedBy}}</td>
<td>{{user.lastModifiedDate | date:'dd/MM/yy HH:mm'}}</td>
<td class="text-right">
<div class="btn-group flex-btn-group-container">
<button type="submit"
[routerLink]="['./', user.login, 'view']"
class="btn btn-info btn-sm">
<fa-icon [icon]="'eye'"></fa-icon>
<span class="d-none d-md-inline" jhiTranslate="entity.action.view">View</span>
</button>
<button type="submit"
[routerLink]="['./', user.login, 'edit']"
queryParamsHandling="merge"
class="btn btn-primary btn-sm">
<fa-icon [icon]="'pencil-alt'"></fa-icon>
<span class="d-none d-md-inline" jhiTranslate="entity.action.edit">Edit</span>
</button>
<button type="button" (click)="deleteUser(user)"
class="btn btn-danger btn-sm" [disabled]="currentAccount.login === user.login">
<fa-icon [icon]="'times'"></fa-icon>
<span class="d-none d-md-inline" jhiTranslate="entity.action.delete">Delete</span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div *ngIf="users">
<div class="row justify-content-center">
<jhi-item-count [page]="page" [total]="totalItems" [itemsPerPage]="itemsPerPage"></jhi-item-count>
</div>
<div class="row justify-content-center">
<ngb-pagination [collectionSize]="totalItems" [(page)]="page" [pageSize]="itemsPerPage" [maxSize]="5" [rotate]="true" [boundaryLinks]="true" (pageChange)="loadPage(page)"></ngb-pagination>
</div>
</div>
</div>

View File

@ -0,0 +1,144 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ActivatedRoute, Router } from '@angular/router';
import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster';
import { ITEMS_PER_PAGE } from 'app/shared';
import { AccountService, UserService, User } from 'app/core';
import { UserMgmtDeleteDialogComponent } from 'app/admin';
@Component({
selector: 'jhi-user-mgmt',
templateUrl: './user-management.component.html'
})
export class UserMgmtComponent implements OnInit, OnDestroy {
currentAccount: any;
users: User[];
error: any;
success: any;
routeData: any;
links: any;
totalItems: any;
itemsPerPage: any;
page: any;
predicate: any;
previousPage: any;
reverse: any;
constructor(
private userService: UserService,
private alertService: JhiAlertService,
private accountService: AccountService,
private parseLinks: JhiParseLinks,
private activatedRoute: ActivatedRoute,
private router: Router,
private eventManager: JhiEventManager,
private modalService: NgbModal
) {
this.itemsPerPage = ITEMS_PER_PAGE;
this.routeData = this.activatedRoute.data.subscribe(data => {
this.page = data['pagingParams'].page;
this.previousPage = data['pagingParams'].page;
this.reverse = data['pagingParams'].ascending;
this.predicate = data['pagingParams'].predicate;
});
}
ngOnInit() {
this.accountService.identity().then(account => {
this.currentAccount = account;
this.loadAll();
this.registerChangeInUsers();
});
}
ngOnDestroy() {
this.routeData.unsubscribe();
}
registerChangeInUsers() {
this.eventManager.subscribe('userListModification', response => this.loadAll());
}
setActive(user, isActivated) {
user.activated = isActivated;
this.userService.update(user).subscribe(response => {
if (response.status === 200) {
this.error = null;
this.success = 'OK';
this.loadAll();
} else {
this.success = null;
this.error = 'ERROR';
}
});
}
loadAll() {
this.userService
.query({
page: this.page - 1,
size: this.itemsPerPage,
sort: this.sort()
})
.subscribe(
(res: HttpResponse<User[]>) => this.onSuccess(res.body, res.headers),
(res: HttpResponse<any>) => this.onError(res.body)
);
}
trackIdentity(index, item: User) {
return item.id;
}
sort() {
const result = [this.predicate + ',' + (this.reverse ? 'asc' : 'desc')];
if (this.predicate !== 'id') {
result.push('id');
}
return result;
}
loadPage(page: number) {
if (page !== this.previousPage) {
this.previousPage = page;
this.transition();
}
}
transition() {
this.router.navigate(['/admin/user-management'], {
queryParams: {
page: this.page,
sort: this.predicate + ',' + (this.reverse ? 'asc' : 'desc')
}
});
this.loadAll();
}
deleteUser(user: User) {
const modalRef = this.modalService.open(UserMgmtDeleteDialogComponent, { size: 'lg', backdrop: 'static' });
modalRef.componentInstance.user = user;
modalRef.result.then(
result => {
// Left blank intentionally, nothing to do here
},
reason => {
// Left blank intentionally, nothing to do here
}
);
}
private onSuccess(data, headers) {
this.links = this.parseLinks.parse(headers.get('link'));
this.totalItems = headers.get('X-Total-Count');
this.users = data;
}
private onError(error) {
this.alertService.error(error.error, error.message, null);
}
}

View File

@ -0,0 +1,68 @@
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Routes, CanActivate } from '@angular/router';
import { JhiPaginationUtil, JhiResolvePagingParams } from 'ng-jhipster';
import { AccountService, User, UserService } from 'app/core';
import { UserMgmtComponent } from './user-management.component';
import { UserMgmtDetailComponent } from './user-management-detail.component';
import { UserMgmtUpdateComponent } from './user-management-update.component';
@Injectable({ providedIn: 'root' })
export class UserResolve implements CanActivate {
constructor(private accountService: AccountService) {}
canActivate() {
return this.accountService.identity().then(account => this.accountService.hasAnyAuthority(['ROLE_ADMIN']));
}
}
@Injectable({ providedIn: 'root' })
export class UserMgmtResolve implements Resolve<any> {
constructor(private service: UserService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const id = route.params['login'] ? route.params['login'] : null;
if (id) {
return this.service.find(id);
}
return new User();
}
}
export const userMgmtRoute: Routes = [
{
path: 'user-management',
component: UserMgmtComponent,
resolve: {
pagingParams: JhiResolvePagingParams
},
data: {
pageTitle: 'userManagement.home.title',
defaultSort: 'id,asc'
}
},
{
path: 'user-management/:login/view',
component: UserMgmtDetailComponent,
resolve: {
user: UserMgmtResolve
},
data: {
pageTitle: 'userManagement.home.title'
}
},
{
path: 'user-management/new',
component: UserMgmtUpdateComponent,
resolve: {
user: UserMgmtResolve
}
},
{
path: 'user-management/:login/edit',
component: UserMgmtUpdateComponent,
resolve: {
user: UserMgmtResolve
}
}
];

View File

@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { errorRoute, navbarRoute } from './layouts';
import { DEBUG_INFO_ENABLED } from 'app/app.constants';
const LAYOUT_ROUTES = [navbarRoute, ...errorRoute];
@NgModule({
imports: [
RouterModule.forRoot(
[
{
path: 'admin',
loadChildren: './admin/admin.module#HsadminNgAdminModule'
},
...LAYOUT_ROUTES
],
{ useHash: true, enableTracing: DEBUG_INFO_ENABLED }
)
],
exports: [RouterModule]
})
export class HsadminNgAppRoutingModule {}

View File

@ -0,0 +1,8 @@
// These constants are injected via webpack environment variables.
// You can add more variables in webpack.common.js or in profile specific webpack.<dev|prod>.js files.
// If you change the values in the webpack config files, you need to re run webpack to update the application
export const VERSION = process.env.VERSION;
export const DEBUG_INFO_ENABLED: boolean = !!process.env.DEBUG_INFO_ENABLED;
export const SERVER_API_URL = process.env.SERVER_API_URL;
export const BUILD_TIMESTAMP = process.env.BUILD_TIMESTAMP;

View File

@ -0,0 +1,14 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { ProdConfig } from './blocks/config/prod.config';
import { HsadminNgAppModule } from './app.module';
ProdConfig();
if (module['hot']) {
module['hot'].accept();
}
platformBrowserDynamic()
.bootstrapModule(HsadminNgAppModule, { preserveWhitespaces: true })
.then(success => console.log(`Application started`))
.catch(err => console.error(err));

View File

@ -0,0 +1,72 @@
import './vendor.ts';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgbDatepickerConfig } from '@ng-bootstrap/ng-bootstrap';
import { Ng2Webstorage } from 'ngx-webstorage';
import { NgJhipsterModule } from 'ng-jhipster';
import { AuthInterceptor } from './blocks/interceptor/auth.interceptor';
import { AuthExpiredInterceptor } from './blocks/interceptor/auth-expired.interceptor';
import { ErrorHandlerInterceptor } from './blocks/interceptor/errorhandler.interceptor';
import { NotificationInterceptor } from './blocks/interceptor/notification.interceptor';
import { HsadminNgSharedModule } from 'app/shared';
import { HsadminNgCoreModule } from 'app/core';
import { HsadminNgAppRoutingModule } from './app-routing.module';
import { HsadminNgHomeModule } from './home/home.module';
import { HsadminNgAccountModule } from './account/account.module';
import { HsadminNgEntityModule } from './entities/entity.module';
import * as moment from 'moment';
// jhipster-needle-angular-add-module-import JHipster will add new module here
import { JhiMainComponent, NavbarComponent, FooterComponent, PageRibbonComponent, ActiveMenuDirective, ErrorComponent } from './layouts';
@NgModule({
imports: [
BrowserModule,
Ng2Webstorage.forRoot({ prefix: 'jhi', separator: '-' }),
NgJhipsterModule.forRoot({
// set below to true to make alerts look like toast
alertAsToast: false,
alertTimeout: 5000,
i18nEnabled: true,
defaultI18nLang: 'de'
}),
HsadminNgSharedModule.forRoot(),
HsadminNgCoreModule,
HsadminNgHomeModule,
HsadminNgAccountModule,
// jhipster-needle-angular-add-module JHipster will add new module here
HsadminNgEntityModule,
HsadminNgAppRoutingModule
],
declarations: [JhiMainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, ActiveMenuDirective, FooterComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthExpiredInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorHandlerInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: NotificationInterceptor,
multi: true
}
],
bootstrap: [JhiMainComponent]
})
export class HsadminNgAppModule {
constructor(private dpConfig: NgbDatepickerConfig) {
this.dpConfig.minDate = { year: moment().year() - 100, month: 1, day: 1 };
}
}

View File

@ -0,0 +1,9 @@
import { enableProdMode } from '@angular/core';
import { DEBUG_INFO_ENABLED } from 'app/app.constants';
export function ProdConfig() {
// disable debug data on prod profile to improve performance
if (!DEBUG_INFO_ENABLED) {
enableProdMode();
}
}

View File

@ -0,0 +1,14 @@
import { Injectable } from '@angular/core';
import { NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap';
import { ITEMS_PER_PAGE } from 'app/shared';
@Injectable({ providedIn: 'root' })
export class PaginationConfig {
// tslint:disable-next-line: no-unused-variable
constructor(private config: NgbPaginationConfig) {
config.boundaryLinks = true;
config.maxSize = 5;
config.pageSize = ITEMS_PER_PAGE;
config.size = 'sm';
}
}

View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { LoginService } from 'app/core/login/login.service';
@Injectable()
export class AuthExpiredInterceptor implements HttpInterceptor {
constructor(private loginService: LoginService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
tap(
(event: HttpEvent<any>) => {},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
this.loginService.logout();
}
}
}
)
);
}
}

View File

@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private localStorage: LocalStorageService, private sessionStorage: SessionStorageService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!request || !request.url || (/^http/.test(request.url) && !(SERVER_API_URL && request.url.startsWith(SERVER_API_URL)))) {
return next.handle(request);
}
const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken');
if (!!token) {
request = request.clone({
setHeaders: {
Authorization: 'Bearer ' + token
}
});
}
return next.handle(request);
}
}

View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { JhiEventManager } from 'ng-jhipster';
import { HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class ErrorHandlerInterceptor implements HttpInterceptor {
constructor(private eventManager: JhiEventManager) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
tap(
(event: HttpEvent<any>) => {},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (!(err.status === 401 && (err.message === '' || (err.url && err.url.includes('/api/account'))))) {
this.eventManager.broadcast({ name: 'hsadminNgApp.httpError', content: err });
}
}
}
)
);
}
}

View File

@ -0,0 +1,37 @@
import { JhiAlertService } from 'ng-jhipster';
import { HttpInterceptor, HttpRequest, HttpResponse, HttpHandler, HttpEvent } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class NotificationInterceptor implements HttpInterceptor {
constructor(private alertService: JhiAlertService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
tap(
(event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
const arr = event.headers.keys();
let alert = null;
let alertParams = null;
arr.forEach(entry => {
if (entry.toLowerCase().endsWith('app-alert')) {
alert = event.headers.get(entry);
} else if (entry.toLowerCase().endsWith('app-params')) {
alertParams = event.headers.get(entry);
}
});
if (alert) {
if (typeof alert === 'string') {
this.alertService.success(alert, { param: alertParams }, null);
}
}
}
},
(err: any) => {}
)
);
}
}

View File

@ -0,0 +1,114 @@
import { Injectable } from '@angular/core';
import { JhiLanguageService } from 'ng-jhipster';
import { SessionStorageService } from 'ngx-webstorage';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable, Subject } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
import { Account } from 'app/core/user/account.model';
@Injectable({ providedIn: 'root' })
export class AccountService {
private userIdentity: any;
private authenticated = false;
private authenticationState = new Subject<any>();
constructor(private languageService: JhiLanguageService, private sessionStorage: SessionStorageService, private http: HttpClient) {}
fetch(): Observable<HttpResponse<Account>> {
return this.http.get<Account>(SERVER_API_URL + 'api/account', { observe: 'response' });
}
save(account: any): Observable<HttpResponse<any>> {
return this.http.post(SERVER_API_URL + 'api/account', account, { observe: 'response' });
}
authenticate(identity) {
this.userIdentity = identity;
this.authenticated = identity !== null;
this.authenticationState.next(this.userIdentity);
}
hasAnyAuthority(authorities: string[]): boolean {
if (!this.authenticated || !this.userIdentity || !this.userIdentity.authorities) {
return false;
}
for (let i = 0; i < authorities.length; i++) {
if (this.userIdentity.authorities.includes(authorities[i])) {
return true;
}
}
return false;
}
hasAuthority(authority: string): Promise<boolean> {
if (!this.authenticated) {
return Promise.resolve(false);
}
return this.identity().then(
id => {
return Promise.resolve(id.authorities && id.authorities.includes(authority));
},
() => {
return Promise.resolve(false);
}
);
}
identity(force?: boolean): Promise<any> {
if (force) {
this.userIdentity = undefined;
}
// check and see if we have retrieved the userIdentity data from the server.
// if we have, reuse it by immediately resolving
if (this.userIdentity) {
return Promise.resolve(this.userIdentity);
}
// retrieve the userIdentity data from the server, update the identity object, and then resolve.
return this.fetch()
.toPromise()
.then(response => {
const account = response.body;
if (account) {
this.userIdentity = account;
this.authenticated = true;
// After retrieve the account info, the language will be changed to
// the user's preferred language configured in the account setting
const langKey = this.sessionStorage.retrieve('locale') || this.userIdentity.langKey;
this.languageService.changeLanguage(langKey);
} else {
this.userIdentity = null;
this.authenticated = false;
}
this.authenticationState.next(this.userIdentity);
return this.userIdentity;
})
.catch(err => {
this.userIdentity = null;
this.authenticated = false;
this.authenticationState.next(this.userIdentity);
return null;
});
}
isAuthenticated(): boolean {
return this.authenticated;
}
isIdentityResolved(): boolean {
return this.userIdentity !== undefined;
}
getAuthenticationState(): Observable<any> {
return this.authenticationState.asObservable();
}
getImageUrl(): string {
return this.isIdentityResolved() ? this.userIdentity.imageUrl : null;
}
}

View File

@ -0,0 +1,59 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { SERVER_API_URL } from 'app/app.constants';
@Injectable({ providedIn: 'root' })
export class AuthServerProvider {
constructor(private http: HttpClient, private $localStorage: LocalStorageService, private $sessionStorage: SessionStorageService) {}
getToken() {
return this.$localStorage.retrieve('authenticationToken') || this.$sessionStorage.retrieve('authenticationToken');
}
login(credentials): Observable<any> {
const data = {
username: credentials.username,
password: credentials.password,
rememberMe: credentials.rememberMe
};
return this.http.post(SERVER_API_URL + 'api/authenticate', data, { observe: 'response' }).pipe(map(authenticateSuccess.bind(this)));
function authenticateSuccess(resp) {
const bearerToken = resp.headers.get('Authorization');
if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') {
const jwt = bearerToken.slice(7, bearerToken.length);
this.storeAuthenticationToken(jwt, credentials.rememberMe);
return jwt;
}
}
}
loginWithToken(jwt, rememberMe) {
if (jwt) {
this.storeAuthenticationToken(jwt, rememberMe);
return Promise.resolve(jwt);
} else {
return Promise.reject('auth-jwt-service Promise reject'); // Put appropriate error message here
}
}
storeAuthenticationToken(jwt, rememberMe) {
if (rememberMe) {
this.$localStorage.store('authenticationToken', jwt);
} else {
this.$sessionStorage.store('authenticationToken', jwt);
}
}
logout(): Observable<any> {
return new Observable(observer => {
this.$localStorage.clear('authenticationToken');
this.$sessionStorage.clear('authenticationToken');
observer.complete();
});
}
}

View File

@ -0,0 +1,11 @@
import { Injectable } from '@angular/core';
import { CookieService } from 'ngx-cookie';
@Injectable({ providedIn: 'root' })
export class CSRFService {
constructor(private cookieService: CookieService) {}
getCSRF(name = 'XSRF-TOKEN') {
return this.cookieService.get(name);
}
}

View File

@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { SessionStorageService } from 'ngx-webstorage';
@Injectable({ providedIn: 'root' })
export class StateStorageService {
constructor(private $sessionStorage: SessionStorageService) {}
getPreviousState() {
return this.$sessionStorage.retrieve('previousState');
}
resetPreviousState() {
this.$sessionStorage.clear('previousState');
}
storePreviousState(previousStateName, previousStateParams) {
const previousState = { name: previousStateName, params: previousStateParams };
this.$sessionStorage.store('previousState', previousState);
}
getDestinationState() {
return this.$sessionStorage.retrieve('destinationState');
}
storeUrl(url: string) {
this.$sessionStorage.store('previousUrl', url);
}
getUrl() {
return this.$sessionStorage.retrieve('previousUrl');
}
storeDestinationState(destinationState, destinationStateParams, fromState) {
const destinationInfo = {
destination: {
name: destinationState.name,
data: destinationState.data
},
params: destinationStateParams,
from: {
name: fromState.name
}
};
this.$sessionStorage.store('destinationState', destinationInfo);
}
}

View File

@ -0,0 +1,52 @@
import { Injectable, isDevMode } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { AccountService } from '../';
import { LoginModalService } from '../login/login-modal.service';
import { StateStorageService } from './state-storage.service';
@Injectable({ providedIn: 'root' })
export class UserRouteAccessService implements CanActivate {
constructor(
private router: Router,
private loginModalService: LoginModalService,
private accountService: AccountService,
private stateStorageService: StateStorageService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Promise<boolean> {
const authorities = route.data['authorities'];
// We need to call the checkLogin / and so the accountService.identity() function, to ensure,
// that the client has a principal too, if they already logged in by the server.
// This could happen on a page refresh.
return this.checkLogin(authorities, state.url);
}
checkLogin(authorities: string[], url: string): Promise<boolean> {
return this.accountService.identity().then(account => {
if (!authorities || authorities.length === 0) {
return true;
}
if (account) {
const hasAnyAuthority = this.accountService.hasAnyAuthority(authorities);
if (hasAnyAuthority) {
return true;
}
if (isDevMode()) {
console.error('User has not any of required authorities: ', authorities);
}
return false;
}
this.stateStorageService.storeUrl(url);
this.router.navigate(['accessdenied']).then(() => {
// only show the login dialog, if the user hasn't logged in yet
if (!account) {
this.loginModalService.open();
}
});
return false;
});
}
}

View File

@ -0,0 +1,24 @@
import { NgModule, LOCALE_ID } from '@angular/core';
import { DatePipe, registerLocaleData } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { Title } from '@angular/platform-browser';
import locale from '@angular/common/locales/de';
@NgModule({
imports: [HttpClientModule],
exports: [],
declarations: [],
providers: [
Title,
{
provide: LOCALE_ID,
useValue: 'de'
},
DatePipe
]
})
export class HsadminNgCoreModule {
constructor() {
registerLocaleData(locale);
}
}

View File

@ -0,0 +1,13 @@
export * from './auth/csrf.service';
export * from './auth/state-storage.service';
export * from './auth/account.service';
export * from './auth/auth-jwt.service';
export * from './language/language.helper';
export * from './language/language.constants';
export * from './user/account.model';
export * from './user/user.model';
export * from './auth/user-route-access-service';
export * from './login/login-modal.service';
export * from './login/login.service';
export * from './user/user.service';
export * from './core.module';

View File

@ -0,0 +1,9 @@
/*
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)
*/
export const LANGUAGES: string[] = [
'de',
'en'
// jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array
];

View File

@ -0,0 +1,65 @@
import { Injectable, RendererFactory2, Renderer2 } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Router, ActivatedRouteSnapshot } from '@angular/router';
import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { LANGUAGES } from 'app/core/language/language.constants';
@Injectable({ providedIn: 'root' })
export class JhiLanguageHelper {
renderer: Renderer2 = null;
private _language: BehaviorSubject<string>;
constructor(
private translateService: TranslateService,
private titleService: Title,
private router: Router,
rootRenderer: RendererFactory2
) {
this._language = new BehaviorSubject<string>(this.translateService.currentLang);
this.renderer = rootRenderer.createRenderer(document.querySelector('html'), null);
this.init();
}
getAll(): Promise<any> {
return Promise.resolve(LANGUAGES);
}
get language(): Observable<string> {
return this._language.asObservable();
}
/**
* Update the window title using params in the following
* order:
* 1. titleKey parameter
* 2. $state.$current.data.pageTitle (current state page title)
* 3. 'global.title'
*/
updateTitle(titleKey?: string) {
if (!titleKey) {
titleKey = this.getPageTitle(this.router.routerState.snapshot.root);
}
this.translateService.get(titleKey).subscribe(title => {
this.titleService.setTitle(title);
});
}
private init() {
this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
this._language.next(this.translateService.currentLang);
this.renderer.setAttribute(document.querySelector('html'), 'lang', this.translateService.currentLang);
this.updateTitle();
});
}
private getPageTitle(routeSnapshot: ActivatedRouteSnapshot) {
let title: string = routeSnapshot.data && routeSnapshot.data['pageTitle'] ? routeSnapshot.data['pageTitle'] : 'hsadminNgApp';
if (routeSnapshot.firstChild) {
title = this.getPageTitle(routeSnapshot.firstChild) || title;
}
return title;
}
}

View File

@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { JhiLoginModalComponent } from 'app/shared/login/login.component';
@Injectable({ providedIn: 'root' })
export class LoginModalService {
private isOpen = false;
constructor(private modalService: NgbModal) {}
open(): NgbModalRef {
if (this.isOpen) {
return;
}
this.isOpen = true;
const modalRef = this.modalService.open(JhiLoginModalComponent);
modalRef.result.then(
result => {
this.isOpen = false;
},
reason => {
this.isOpen = false;
}
);
return modalRef;
}
}

View File

@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { AccountService } from 'app/core/auth/account.service';
import { AuthServerProvider } from 'app/core/auth/auth-jwt.service';
@Injectable({ providedIn: 'root' })
export class LoginService {
constructor(private accountService: AccountService, private authServerProvider: AuthServerProvider) {}
login(credentials, callback?) {
const cb = callback || function() {};
return new Promise((resolve, reject) => {
this.authServerProvider.login(credentials).subscribe(
data => {
this.accountService.identity(true).then(account => {
resolve(data);
});
return cb();
},
err => {
this.logout();
reject(err);
return cb(err);
}
);
});
}
loginWithToken(jwt, rememberMe) {
return this.authServerProvider.loginWithToken(jwt, rememberMe);
}
logout() {
this.authServerProvider.logout().subscribe();
this.accountService.authenticate(null);
}
}

View File

@ -0,0 +1,12 @@
export class Account {
constructor(
public activated: boolean,
public authorities: string[],
public email: string,
public firstName: string,
public langKey: string,
public lastName: string,
public login: string,
public imageUrl: string
) {}
}

View File

@ -0,0 +1,47 @@
export interface IUser {
id?: any;
login?: string;
firstName?: string;
lastName?: string;
email?: string;
activated?: boolean;
langKey?: string;
authorities?: any[];
createdBy?: string;
createdDate?: Date;
lastModifiedBy?: string;
lastModifiedDate?: Date;
password?: string;
}
export class User implements IUser {
constructor(
public id?: any,
public login?: string,
public firstName?: string,
public lastName?: string,
public email?: string,
public activated?: boolean,
public langKey?: string,
public authorities?: any[],
public createdBy?: string,
public createdDate?: Date,
public lastModifiedBy?: string,
public lastModifiedDate?: Date,
public password?: string
) {
this.id = id ? id : null;
this.login = login ? login : null;
this.firstName = firstName ? firstName : null;
this.lastName = lastName ? lastName : null;
this.email = email ? email : null;
this.activated = activated ? activated : false;
this.langKey = langKey ? langKey : null;
this.authorities = authorities ? authorities : null;
this.createdBy = createdBy ? createdBy : null;
this.createdDate = createdDate ? createdDate : null;
this.lastModifiedBy = lastModifiedBy ? lastModifiedBy : null;
this.lastModifiedDate = lastModifiedDate ? lastModifiedDate : null;
this.password = password ? password : null;
}
}

View File

@ -0,0 +1,39 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared/util/request-util';
import { IUser } from './user.model';
@Injectable({ providedIn: 'root' })
export class UserService {
public resourceUrl = SERVER_API_URL + 'api/users';
constructor(private http: HttpClient) {}
create(user: IUser): Observable<HttpResponse<IUser>> {
return this.http.post<IUser>(this.resourceUrl, user, { observe: 'response' });
}
update(user: IUser): Observable<HttpResponse<IUser>> {
return this.http.put<IUser>(this.resourceUrl, user, { observe: 'response' });
}
find(login: string): Observable<HttpResponse<IUser>> {
return this.http.get<IUser>(`${this.resourceUrl}/${login}`, { observe: 'response' });
}
query(req?: any): Observable<HttpResponse<IUser[]>> {
const options = createRequestOption(req);
return this.http.get<IUser[]>(this.resourceUrl, { params: options, observe: 'response' });
}
delete(login: string): Observable<HttpResponse<any>> {
return this.http.delete(`${this.resourceUrl}/${login}`, { observe: 'response' });
}
authorities(): Observable<string[]> {
return this.http.get<string[]>(SERVER_API_URL + 'api/users/authorities');
}
}

View File

@ -0,0 +1,15 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [
RouterModule.forChild([
/* jhipster-needle-add-entity-route - JHipster will add entity modules routes here */
])
],
declarations: [],
entryComponents: [],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class HsadminNgEntityModule {}

View File

@ -0,0 +1,41 @@
<div class="row">
<div class="col-md-3">
<span class="hipster img-fluid rounded"></span>
</div>
<div class="col-md-9">
<h1 class="display-4" jhiTranslate="home.title">Welcome, Java Hipster!</h1>
<p class="lead" jhiTranslate="home.subtitle">This is your homepage</p>
<div [ngSwitch]="isAuthenticated()">
<div class="alert alert-success" *ngSwitchCase="true">
<span id="home-logged-message" *ngIf="account" jhiTranslate="home.logged.message"
[translateValues]="{username: account.login}"> You are logged in as user "{{account.login}}". </span>
</div>
<div class="alert alert-warning" *ngSwitchCase="false">
<span jhiTranslate="global.messages.info.authenticated.prefix">If you want to </span>
<a class="alert-link" (click)="login()" jhiTranslate="global.messages.info.authenticated.link">sign in</a><span jhiTranslate="global.messages.info.authenticated.suffix">, you can try the default accounts:<br/>- Administrator (login="admin" and password="admin") <br/>- User (login="user" and password="user").</span>
</div>
<div class="alert alert-warning" *ngSwitchCase="false">
<span jhiTranslate="global.messages.info.register.noaccount">You don't have an account yet?</span>&nbsp;
<a class="alert-link" routerLink="register" jhiTranslate="global.messages.info.register.link">Register a new account</a>
</div>
</div>
<p jhiTranslate="home.question">
If you have any question on JHipster:
</p>
<ul>
<li><a href="https://www.jhipster.tech/" target="_blank" rel="noopener" jhiTranslate="home.link.homepage">JHipster homepage</a></li>
<li><a href="http://stackoverflow.com/tags/jhipster/info" target="_blank" rel="noopener" jhiTranslate="home.link.stackoverflow">JHipster on Stack Overflow</a></li>
<li><a href="https://github.com/jhipster/generator-jhipster/issues?state=open" target="_blank" rel="noopener" jhiTranslate="home.link.bugtracker">JHipster bug tracker</a></li>
<li><a href="https://gitter.im/jhipster/generator-jhipster" target="_blank" rel="noopener" jhiTranslate="home.link.chat">JHipster public chat room</a></li>
<li><a href="https://twitter.com/java_hipster" target="_blank" rel="noopener" jhiTranslate="home.link.follow">follow @java_hipster on Twitter</a></li>
</ul>
<p>
<span jhiTranslate="home.like">If you like JHipster, don't forget to give us a star on</span> <a href="https://github.com/jhipster/generator-jhipster" target="_blank" rel="noopener" jhiTranslate="home.github">GitHub</a>!
</p>
</div>
</div>

View File

@ -0,0 +1,44 @@
import { Component, OnInit } from '@angular/core';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { JhiEventManager } from 'ng-jhipster';
import { LoginModalService, AccountService, Account } from 'app/core';
@Component({
selector: 'jhi-home',
templateUrl: './home.component.html',
styleUrls: ['home.css']
})
export class HomeComponent implements OnInit {
account: Account;
modalRef: NgbModalRef;
constructor(
private accountService: AccountService,
private loginModalService: LoginModalService,
private eventManager: JhiEventManager
) {}
ngOnInit() {
this.accountService.identity().then((account: Account) => {
this.account = account;
});
this.registerAuthenticationSuccess();
}
registerAuthenticationSuccess() {
this.eventManager.subscribe('authenticationSuccess', message => {
this.accountService.identity().then(account => {
this.account = account;
});
});
}
isAuthenticated() {
return this.accountService.isAuthenticated();
}
login() {
this.modalRef = this.loginModalService.open();
}
}

View File

@ -0,0 +1,23 @@
/* ==========================================================================
Main page styles
========================================================================== */
.hipster {
display: inline-block;
width: 347px;
height: 497px;
background: url('../../content/images/jhipster_family_member_3.svg') 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 (-moz-min-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-resolution: 192dpi),
only screen and (min-resolution: 2dppx) {
.hipster {
background: url('../../content/images/jhipster_family_member_3.svg') no-repeat center top;
background-size: contain;
}
}

View File

@ -0,0 +1,12 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HsadminNgSharedModule } from 'app/shared';
import { HOME_ROUTE, HomeComponent } from './';
@NgModule({
imports: [HsadminNgSharedModule, RouterModule.forChild([HOME_ROUTE])],
declarations: [HomeComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class HsadminNgHomeModule {}

View File

@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { HomeComponent } from './';
export const HOME_ROUTE: Route = {
path: '',
component: HomeComponent,
data: {
authorities: [],
pageTitle: 'home.title'
}
};

View File

@ -0,0 +1,3 @@
export * from './home.component';
export * from './home.route';
export * from './home.module';

Some files were not shown because too many files have changed in this diff Show More