no message

This commit is contained in:
Ioannis Kalyvas 2018-02-01 16:04:36 +02:00
parent 86db30e5f3
commit 9f324b9f19
94 changed files with 5322 additions and 1918 deletions

File diff suppressed because it is too large Load Diff

View File

@ -12,17 +12,17 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^4.2.4",
"@angular/cdk": "^5.1.1",
"@angular/common": "^4.2.4",
"@angular/compiler": "^4.2.4",
"@angular/core": "^4.2.4",
"@angular/forms": "^4.2.4",
"@angular/http": "^4.2.4",
"@angular/material": "^5.1.1",
"@angular/platform-browser": "^4.2.4",
"@angular/platform-browser-dynamic": "^4.2.4",
"@angular/router": "^4.2.4",
"@angular/animations": "^5.1.1",
"@angular/cdk": "^5.0.1",
"@angular/common": "5.1.1",
"@angular/compiler": "5.1.1",
"@angular/core": "5.1.1",
"@angular/forms": "5.1.1",
"@angular/http": "5.1.1",
"@angular/material": "^5.0.1",
"@angular/platform-browser": "5.1.1",
"@angular/platform-browser-dynamic": "5.1.1",
"@angular/router": "5.1.1",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.5",
"angular-datatables": "^4.4.0",
"angular2-datatable": "^0.6.0",
@ -33,15 +33,15 @@
"jquery": "^3.2.1",
"ng2-bootstrap-modal": "^1.0.1",
"ng2-simple-global": "^1.2.5",
"ngx-contextmenu": "^1.3.5",
"ngx-webstorage": "^1.8.0",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
"zone.js": "^0.8.14",
"@ngx-translate/core": "^9.0.1",
"@ngx-translate/http-loader": "^2.0.0"
},
"devDependencies": {
"@angular/cli": "1.3.1",
"@angular/compiler-cli": "^4.2.4",
"@angular/language-service": "^4.2.4",
"@angular/cli": "1.6.5",
"@angular/compiler-cli": "^5.1.1",
"@angular/language-service": "^5.1.1",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/jquery": "^3.2.12",
@ -58,6 +58,6 @@
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.3.2",
"typescript": "~2.3.3"
"typescript": "2.4.2"
}
}

View File

@ -0,0 +1,6 @@
export const HostConfiguration = {
Server: 'http://192.168.32.67:8080/', //'http://dl043.madgik.di.uoa.gr:8080/'
App: 'localhost:4200/' // 'http://dl043.madgik.di.uoa.gr:8080/'
//CASHost: 'https://login-devel.uoa.gr/login',
//Service: 'http://elkefinman/login'
}

View File

@ -20,8 +20,6 @@ import { DataTableModule } from "angular2-datatable";
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DialogService } from "ng2-bootstrap-modal";
import { ReactiveFormsModule } from '@angular/forms';
import { ContextMenuModule } from 'ngx-contextmenu';
import { Ng2Webstorage } from 'ngx-webstorage';
import { RestBase } from './services/rest-base';
import { TokenService } from './services/login/token.service';
@ -127,8 +125,6 @@ import { DatasetProfileModule } from './dataset-profile-form/dataset-profile.mod
DataTableModule,
FormsModule,
ReactiveFormsModule,
ContextMenuModule,
Ng2Webstorage,
NgbModule.forRoot(),
AppRouting
],

View File

@ -28,6 +28,6 @@ export class RadioBoxComponent implements OnInit{
(<FormArray>this.form.get("data").get("options")).push(radioListOptions.buildForm());
this.data.options = [];
this.data.options.push(radioListOptions);
this.dataModel.data = new JsonSerializer<RadioBoxData>().fromJSONObject(this.data,RadioBoxData);
this.dataModel.data = JsonSerializer.fromJSONObject(this.data,RadioBoxData);
}
}

View File

@ -29,6 +29,6 @@ export class WordlistComponent implements OnInit{
(<FormArray>this.form.get("data").get("options")).push(wordListOptions.buildForm());
this.data.options = [];
this.data.options.push(wordListOptions);
this.dataModel.data = new JsonSerializer<WordListData>().fromJSONObject(this.data,WordListData);
this.dataModel.data = JsonSerializer.fromJSONObject(this.data,WordListData);
}
}

View File

@ -0,0 +1,19 @@
import { CommonModule } from '@angular/common';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { MaterialModule } from '../material/material.module';
@NgModule({
imports: [
CommonModule,
MaterialModule,
]
})
export class CoreModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
]
};
}
}

View File

@ -0,0 +1,3 @@
export class Criteria {
public Like: string;
}

View File

@ -0,0 +1,7 @@
import { Criteria } from './Criteria';
import { Principal } from '../../models/login/Principal';
export class UserCriteria extends Criteria {
public Label: String;
public Roles: Principal.AppRole[];
}

View File

@ -0,0 +1,45 @@
import { UserListingModel } from '../../shared/components/criteria/models/errormodel/users/userListingModel';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { DataTableRequest } from '../../models/data-table/dataTableRequest';
import { DataTableData } from '../../models/data-table/dataTableData';
import { MyHttpService } from 'app/utilities/httpservice/myhttpservice.service';
import { HostConfiguration } from 'app/app.constants';
@Injectable()
export class UserReferenceService {
private actionUrl: string;
private headers: HttpHeaders;
constructor(private http: MyHttpService) {
this.actionUrl = HostConfiguration.Server + 'api/user/';
this.headers = new HttpHeaders();
this.headers = this.headers.set('Content-Type', 'application/json');
this.headers = this.headers.set('Accept', 'application/json');
}
// formatItem(utilities: Utilities, item: ConfigurationModel): ConfigurationModel {
// item.validFrom = new Date(item.validFrom);
// item.validTo = new Date(item.validTo);
// return item
// }
getPaged(dataTableRequest: DataTableRequest): Observable<DataTableData<UserListingModel>> {
return this.http.post<DataTableData<UserListingModel>>(this.actionUrl + 'getPaged', JSON.stringify(dataTableRequest), { headers: this.headers });
}
updateRoles(itemToUpdate: UserListingModel): Observable<UserListingModel> {
return this.http.post<UserListingModel>(this.actionUrl + 'updateRoles', JSON.stringify(itemToUpdate), { headers: this.headers });
}
delete(id: String): Observable<any> {
return this.http.delete<any>(this.actionUrl + id, { headers: this.headers });
}
}

View File

@ -57,7 +57,7 @@ export class SectionFormComponent {
keepPageSelectionValid(pagesJson: Array<any>) {
let selectedPage = this.form.get("page").value as String;
let pages: Array<Page> = new JsonSerializer<Page>().fromJSONArray(pagesJson, Page);
let pages: Array<Page> = JsonSerializer.fromJSONArray(pagesJson, Page);
if (pages.find(elem => elem.id === selectedPage) === undefined)
this.form.get("page").reset();
}

View File

@ -1,6 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { DatasetProfileService } from '../../services/dataset-profile.service';
import { ContextMenuComponent } from 'ngx-contextmenu';
import { ReactiveFormsModule } from '@angular/forms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@ -130,6 +129,4 @@ export class DatasetprofileEditorComponent implements OnInit {
}
@ViewChild(ContextMenuComponent) public basicMenu: ContextMenuComponent;
}

View File

@ -1,6 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { DmpProfileService } from '../../services/dmpprofile-service';
import { ContextMenuComponent } from 'ngx-contextmenu';
import { ReactiveFormsModule } from '@angular/forms';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@ -128,9 +127,6 @@ export class DmpProfileEditorComponent implements OnInit {
}
@ViewChild(ContextMenuComponent) public basicMenu: ContextMenuComponent;
}

View File

@ -0,0 +1,27 @@
import { NativeDateAdapter } from '@angular/material';
export class LocalizedDateAdapter extends NativeDateAdapter {
parse(value: any): Date | null {
const invalidDate = new Date(NaN);
if (typeof value === 'string') {
if (value === '') { return null; } else {
const splitted = value.split('/');
if (splitted.length !== 3) { return invalidDate; } else {
const day = Number(splitted[0]);
const month = Number(splitted[1]) - 1;
const year = Number(splitted[2]);
if (day < 1 || day > 31 || month < 0 || month > 11 || year < 1 || year > 9999) { return invalidDate; }
return new Date(year, month, day);
}
}
} else {
const dateValue = typeof value === 'number' ? value : Date.parse(value);
return isNaN(dateValue) ? invalidDate : new Date(dateValue);
}
}
}

View File

@ -0,0 +1,97 @@
import { NgModule } from '@angular/core';
import {
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatDialogModule,
MatDatepickerModule,
MatNativeDateModule,
MatInputModule,
MatFormFieldModule,
MatSnackBarModule,
MatAutocompleteModule,
MatExpansionModule,
MatSelectModule,
MatOptionModule,
MatCardModule,
MatProgressBarModule,
MatProgressSpinnerModule,
DateAdapter,
MatTooltipModule,
MatTabsModule
} from '@angular/material';
import { CdkTableModule } from '@angular/cdk/table';
import { LocalizedDateAdapter } from './date/LocalizedDateAdapter';
import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar-notification.component';
@NgModule({
imports: [
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatTableModule,
MatPaginatorModule,
CdkTableModule,
MatSortModule,
MatDialogModule,
MatDatepickerModule,
MatNativeDateModule,
MatInputModule,
MatFormFieldModule,
MatSnackBarModule,
MatAutocompleteModule,
MatExpansionModule,
MatSelectModule,
MatOptionModule,
MatCardModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatTooltipModule,
MatTabsModule
],
exports: [
MatToolbarModule,
MatIconModule,
MatSidenavModule,
MatButtonModule,
MatTableModule,
MatPaginatorModule,
CdkTableModule,
MatSortModule,
MatDialogModule,
MatDatepickerModule,
MatNativeDateModule,
MatInputModule,
MatFormFieldModule,
MatSnackBarModule,
MatAutocompleteModule,
MatExpansionModule,
MatSelectModule,
MatOptionModule,
MatCardModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatTooltipModule,
MatTabsModule
],
providers: [
{ provide: DateAdapter, useClass: LocalizedDateAdapter },
],
entryComponents: [
SnackBarNotificationComponent
]
})
export class MaterialModule {
constructor(dateAdapter: DateAdapter<LocalizedDateAdapter>) {
dateAdapter.setLocale('el-GR');
}
}

View File

@ -22,7 +22,7 @@ export class RadioBoxData extends DataField<RadioBoxData>{
}
fromJSONObject(item:any):RadioBoxData{
this.options = new JsonSerializer<ListingItem>().fromJSONArray(item.options,ListingItem);
this.options = JsonSerializer.fromJSONArray(item.options,ListingItem);
this.label = item.label
return this;
}

View File

@ -25,7 +25,7 @@ export class WordListData extends DataField<WordListData>{
fromJSONObject(item:any):WordListData{
this.type = item.type;
this.options = new JsonSerializer<ListingItem>().fromJSONArray(item.options,ListingItem);
this.options = JsonSerializer.fromJSONArray(item.options,ListingItem);
this.label = item.label;
return this;
}

View File

@ -13,8 +13,8 @@ export class DatasetProfileModel extends BaseModel implements Serializable<Datas
public label: string;
fromJSONObject(item:any):DatasetProfileModel{
this.sections = new JsonSerializer<Section>().fromJSONArray(item.sections, Section);
this.pages = new JsonSerializer<Page>().fromJSONArray(item.pages, Page);
this.sections = JsonSerializer.fromJSONArray(item.sections, Section);
this.pages = JsonSerializer.fromJSONArray(item.pages, Page);
this.label = item.label;
return this;
}

View File

@ -34,23 +34,23 @@ export class Field extends BaseModel implements Serializable<Field>, FormGenerat
fromJSONObject(item: any): Field {
this.id = item.id;
this.title = item.title;
this.defaultValue = new JsonSerializer<DefaultValue>().fromJSONObject(item.defaultValue, DefaultValue);
this.defaultValue = JsonSerializer.fromJSONObject(item.defaultValue, DefaultValue);
this.page = item.page;
// this.multiplicity = new JsonSerializer<Multiplicity>().fromJSONObject(item.multiplicity, Multiplicity);
this.ordinal = item.ordinal;
this.validations = item.validations;
this.viewStyle = new JsonSerializer<ViewStyle>().fromJSONObject(item.viewStyle, ViewStyle);
this.visible = new JsonSerializer<Visibility>().fromJSONObject(item.visible, Visibility);
this.viewStyle = JsonSerializer.fromJSONObject(item.viewStyle, ViewStyle);
this.visible = JsonSerializer.fromJSONObject(item.visible, Visibility);
if (item.data) {
if (this.viewStyle.renderStyle === "combobox") {
if (item.data.type === "autocomplete") this.data = new JsonSerializer<AutocompleteData>().fromJSONObject(item.data, AutocompleteData);
if (item.data.type === "wordlist") this.data = new JsonSerializer<WordListData>().fromJSONObject(item.data, WordListData);
if (item.data.type === "autocomplete") this.data = JsonSerializer.fromJSONObject(item.data, AutocompleteData);
if (item.data.type === "wordlist") this.data = JsonSerializer.fromJSONObject(item.data, WordListData);
} else {
if (this.viewStyle.renderStyle === "radiobox") this.data = new JsonSerializer<RadioBoxData>().fromJSONObject(item.data, RadioBoxData);
if (this.viewStyle.renderStyle === "checkBox") this.data = new JsonSerializer<CheckBoxData>().fromJSONObject(item.data, CheckBoxData);
if (this.viewStyle.renderStyle === "textarea") this.data = new JsonSerializer<TextArea>().fromJSONObject(item.data, TextArea);
if (this.viewStyle.renderStyle === "freetext") this.data = new JsonSerializer<FreeTextData>().fromJSONObject(item.data, FreeTextData);
if (this.viewStyle.renderStyle === "booleanDecision") this.data = new JsonSerializer<BooleanDecisionData>().fromJSONObject(item.data, BooleanDecisionData);
if (this.viewStyle.renderStyle === "radiobox") this.data = JsonSerializer.fromJSONObject(item.data, RadioBoxData);
if (this.viewStyle.renderStyle === "checkBox") this.data = JsonSerializer.fromJSONObject(item.data, CheckBoxData);
if (this.viewStyle.renderStyle === "textarea") this.data = JsonSerializer.fromJSONObject(item.data, TextArea);
if (this.viewStyle.renderStyle === "freetext") this.data = JsonSerializer.fromJSONObject(item.data, FreeTextData);
if (this.viewStyle.renderStyle === "booleanDecision") this.data = JsonSerializer.fromJSONObject(item.data, BooleanDecisionData);
}
}
return this;

View File

@ -29,7 +29,7 @@ export class FieldGroup extends BaseModel implements Serializable<FieldGroup>, F
this.defaultVisibility = item.defaultVisibility;
this.page = item.page;
this.ordinal = item.ordinal;
this.compositeFields = new JsonSerializer<FieldSet>().fromJSONArray(item.compositeFields, FieldSet);
this.compositeFields = JsonSerializer.fromJSONArray(item.compositeFields, FieldSet);
return this;
}

View File

@ -17,8 +17,8 @@ export class FieldSet extends BaseModel implements Serializable<FieldSet> {
fromJSONObject(item:any):FieldSet{
this.fields = new JsonSerializer<Field>().fromJSONArray(item.fields,Field);
this.multiplicity = new JsonSerializer<Multiplicity>().fromJSONObject(item.multiplicity, Multiplicity);
this.fields = JsonSerializer.fromJSONArray(item.fields,Field);
this.multiplicity = JsonSerializer.fromJSONObject(item.multiplicity, Multiplicity);
this.id = item.id;
this.ordinal = item.ordinal;
this.title = item.title;

View File

@ -18,7 +18,7 @@ export class Section extends BaseModel implements Serializable<Section>, FormGen
public fieldSets: Array<FieldSet> = new Array<FieldSet>();
fromJSONObject(item: any): Section {
this.sections = new JsonSerializer<Section>().fromJSONArray(item.sections, Section);
this.sections = JsonSerializer.fromJSONArray(item.sections, Section);
//this.fieldGroups = new JsonSerializer<FieldGroup>().fromJSONArray(item.fieldGroups, FieldGroup);
this.page = item.page;
this.defaultVisibility = item.defaultVisibility;
@ -26,7 +26,7 @@ export class Section extends BaseModel implements Serializable<Section>, FormGen
this.title = item.title;
this.description = item.description;
this.ordinal = item.ordinal;
this.fieldSets = new JsonSerializer<FieldSet>().fromJSONArray(item.fieldSets, FieldSet);
this.fieldSets = JsonSerializer.fromJSONArray(item.fieldSets, FieldSet);
return this;
}

View File

@ -10,7 +10,7 @@ export class Visibility extends BaseModel implements Serializable<Visibility>, F
public style:string;
fromJSONObject(item:any):Visibility{
this.rules = new JsonSerializer<Rule>().fromJSONArray(item.rules, Rule);
this.rules = JsonSerializer.fromJSONArray(item.rules, Rule);
this.style = item.style;
return this;

View File

@ -0,0 +1,4 @@
export class DataTableData<T> {
data = new Array<T>();
totalCount = 0;
}

View File

@ -0,0 +1,12 @@
import { UserCriteria } from '../../core/criteria/UserCriteria';
export class DataTableRequest {
offset = 0;
length = 0;
userCriteria: UserCriteria;
constructor(offset: number, length: number) {
this.length = length;
this.offset = offset;
}
}

View File

@ -0,0 +1,13 @@
/**
* An object used to get page information from the server
*/
export class Page {
// The number of elements in the page
size = 0;
// The total number of elements
totalElements = 0;
// The total number of pages
totalPages = 0;
// The current page number
pageNumber = 0;
}

View File

@ -0,0 +1,9 @@
import { Page } from './page';
/**
* An array of data with an associated page object used for paging
*/
export class PagedData<T> {
data = new Array<T>();
page = new Page();
}

View File

@ -43,7 +43,9 @@ const routes: Routes = [
component: MainWindowComponent,
canActivate: [AuthGuard]
},
{ path: 'form', loadChildren: './dataset-profile-form/dataset-profile.module#DatasetProfileModule', canActivate: [AuthGuard]}
{ path: 'form', loadChildren: './dataset-profile-form/dataset-profile.module#DatasetProfileModule', canActivate: [AuthGuard]},
{ path: 'user-management', loadChildren: './users/users.module#UsersModule', canActivate: [AuthGuard]}
];
@NgModule({

View File

@ -1,6 +1,5 @@
import { Injectable, Inject} from '@angular/core';
import { Observable } from 'rxjs';
import {LocalStorageService} from 'ngx-webstorage';
import 'rxjs/add/operator/map';
import { DOCUMENT } from '@angular/platform-browser';
@ -13,59 +12,59 @@ declare function sign_out_google(): any;
export class TokenService {
constructor (private storage : LocalStorageService, @Inject(DOCUMENT) private document) {
constructor (@Inject(DOCUMENT) private document) {
var csrfToken : string = jQuery(document).find('meta[name="csrf-token"]').attr('content');
this.setCSRFToken(csrfToken);
}
getCSRFToken() : string{
return this.storage.retrieve('csrf-token');
return localStorage.retrieve('csrf-token');
}
setCSRFToken(csrfToken : string){
this.storage.store('csrf-token',csrfToken);
localStorage.store('csrf-token',csrfToken);
}
getProvider() : TokenProvider {
return this.storage.retrieve('provider');
return localStorage.retrieve('provider');
}
setProvider(provider : TokenProvider){
this.storage.store('provider',provider);
localStorage.store('provider',provider);
}
getToken() : string{
return this.storage.retrieve('token');
return localStorage.retrieve('token');
}
setToken(token : string){
this.storage.store('token',token);
localStorage.store('token',token);
}
isLoggedIn(){
return this.storage.retrieve('loggedIn');
return localStorage.retrieve('loggedIn');
}
setLoggedIn(boolStatus){
this.storage.store('loggedIn',boolStatus);
localStorage.store('loggedIn',boolStatus);
}
getEmail(){
return this.storage.retrieve('email');
return localStorage.retrieve('email');
}
setEmail(email){
this.storage.store('email',email);
localStorage.store('email',email);
}
getUsername(){
return this.storage.retrieve('username');
return localStorage.retrieve('username');
}
setUsername(username){
this.storage.store('username',username);
localStorage.store('username',username);
}

View File

@ -0,0 +1,102 @@
import { CriteriaErrorModel } from '../models/errormodel/criteriaErrorModel';
import { Component, OnInit, Input } from '@angular/core';
import { FormControl, FormGroup, NgForm, FormArray, AbstractControl } from '@angular/forms';
@Component({
selector: 'base-criteria-component',
template: '',
providers: [
]
})
export class BaseCriteriaComponent implements OnInit {
public refreshCallback: Function = null;
public formGroup: FormGroup = null;
constructor(
public baseErrorModel?: CriteriaErrorModel,
) {
}
ngOnInit() {
if (this.baseErrorModel == null) { this.baseErrorModel = new CriteriaErrorModel(); }
}
controlModified(): void {
this.clearErrorModel();
if (!this.isFormValid()) { return; }
if (this.refreshCallback != null) { this.refreshCallback(); }
}
public isFormValid(): boolean {
this.touchAllFormFields(this.formGroup);
this.validateAllFormFields(this.formGroup);
return this.formGroup.valid;
}
public getFormData(): any {
return this.formGroup.value;
}
public getFormControl(controlName: string): AbstractControl {
return this.formGroup.get(controlName);
}
public disableFormFields(formControl: AbstractControl) {
formControl.disable();
}
public validateAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.updateValueAndValidity({ emitEvent: false })
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.validateAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.validateAllFormFields(item);
})
}
}
public touchAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.markAsTouched();
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.touchAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.touchAllFormFields(item);
})
}
}
setRefreshCallback(callback: Function): void {
this.refreshCallback = callback;
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: CriteriaErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = (<any>errorModel)[item];
})
}
public clearErrorModel() {
Object.keys(this.baseErrorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = '';
})
}
}

View File

@ -0,0 +1,3 @@
export class BaseErrorModel {
}

View File

@ -0,0 +1,5 @@
import { BaseErrorModel } from './BaseErrorModel';
export class CriteriaErrorModel extends BaseErrorModel {
public Like: String;
}

View File

@ -0,0 +1,6 @@
import { CriteriaErrorModel } from '../criteriaErrorModel';
export class UserCriteriaErrorModel extends CriteriaErrorModel {
public Label: String;
public Roles: String;
}

View File

@ -0,0 +1,6 @@
import { BaseErrorModel } from "app/shared/components/criteria/models/errormodel/BaseErrorModel";
export class UserErrorModel extends BaseErrorModel {
public Roles: String;
}

View File

@ -0,0 +1,16 @@
import { Serializable } from '../../../../../../models/interfaces/Serializable';
import { TranslateService } from '@ngx-translate/core';
import { Principal } from 'app/models/login/Principal';
export class UserListingModel implements Serializable<UserListingModel> {
public id: String;
public label: String;
public roles: Principal.AppRole[];
fromJSONObject(item: any): UserListingModel {
this.id = item.id;
this.label = item.label;
this.roles = item.roles;
return this;
}
}

View File

@ -0,0 +1,24 @@
<form class="user-roles-criteria" [formGroup]="formGroup">
<mat-card class="mat-card">
<div class="row">
<div class="col-sm-6 col-md-8">
<mat-form-field>
<input matInput
placeholder="{{'CRITERIA.USERS.LABEL'| translate}}"
formControlName="label"
(ngModelChange)="controlModified()">
</mat-form-field>
</div>
<div class="col-sm-6 col-md-4">
<mat-form-field>
<mat-select placeholder="{{'CRITERIA.USERS.ROLE' | translate}}"
formControlName="roles"
(change)="controlModified()"
multiple>
<mat-option *ngFor="let role of getPrincipalAppRoleValues()" [value]="role">{{getPrincipalAppRoleWithLanguage(role)}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</mat-card>
</form>

View File

@ -0,0 +1,10 @@
.user-roles-criteria {
mat-form-field {
padding-bottom: 5px;
width: 100%;
}
mat-card {
padding-bottom: 0px;
}
}

View File

@ -0,0 +1,82 @@
import { TranslateService } from '@ngx-translate/core';
import { Validation, ValidationContext } from '../../../../utilities/validators/ValidationContext';
import { UserCriteria } from '../../../../core/criteria/UserCriteria';
import { Component, OnInit } from '@angular/core';
import { BaseCriteriaComponent } from '../base/base-criteria.component';
import { Principal } from '../../../../models/login/Principal';
import { FormBuilder, FormGroup } from '@angular/forms';
import { UserCriteriaErrorModel } from 'app/shared/components/criteria/models/errormodel/users/userCriteriaErrorModel';
@Component({
selector: 'users-criteria-component',
templateUrl: './users-criteria.component.html',
styleUrls: ['./users-criteria.component.scss'],
})
export class UsersCriteriaComponent extends BaseCriteriaComponent implements OnInit {
public role: Principal.AppRole;
public criteria: UserCriteria = new UserCriteria();
constructor(
public language: TranslateService,
public errorModel: UserCriteriaErrorModel,
public formBuilder: FormBuilder
) {
super(errorModel);
}
ngOnInit() {
super.ngOnInit();
if (this.criteria == null) { this.criteria = new UserCriteria(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
}
setCriteria(criteria: UserCriteria): void {
this.criteria = criteria;
this.formGroup = this.buildForm();
}
public fromJSONObject(item: any): UserCriteria {
this.criteria = new UserCriteria();
this.criteria.Label = item.Label;
this.criteria.Roles = item.Roles;
return this.criteria;
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
label: [this.criteria.Label, context.getValidation('label').validators],
roles: [this.criteria.Roles, context.getValidation('roles').validators],
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'label' });
validationArray.push({ key: 'roles' });
validationContext.validation = validationArray;
return validationContext;
}
getPrincipalAppRoleValues(): Number[] {
let keys: string[] = Object.keys(Principal.AppRole);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getPrincipalAppRoleWithLanguage(role: Principal.AppRole): string {
let result = '';
// this.language.get(new Utilities().convertFromPrincipalAppRole(role)).subscribe((value: string) => {
// result = value;
// });
return result;
}
}

View File

@ -0,0 +1,20 @@
import { TranslateService } from '@ngx-translate/core';
import { Component, Inject } from '@angular/core';
import { MAT_SNACK_BAR_DATA } from '@angular/material';
@Component({
selector: 'snack-bar-notification',
templateUrl: 'snack-bar-notification.html'
})
export class SnackBarNotificationComponent {
message: string;
constructor( @Inject(MAT_SNACK_BAR_DATA) public data: any) {
this.parseMessage(data.message, data.language);
}
parseMessage(message: any, language: TranslateService): void {
language.get(message).subscribe((value: string) => {
this.message = value;
});
}
}

View File

@ -0,0 +1 @@
{{message}}

View File

@ -0,0 +1,35 @@
import { SnackBarNotificationComponent } from './notification/snack-bar-notification.component';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { MaterialModule } from '../material/material.module';
import { TranslateModule } from '@ngx-translate/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CoreModule } from '../core/core.module';
@NgModule({
imports: [
CommonModule,
RouterModule,
MaterialModule,
CoreModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
],
declarations: [
SnackBarNotificationComponent,
],
exports: [
SnackBarNotificationComponent,
TranslateModule,
FormsModule,
ReactiveFormsModule,
],
entryComponents: [
]
})
export class SharedModule { }

View File

@ -1,243 +0,0 @@
export const TestModel = {
"sections": [
{
"id": "sumData",
"defaultVisibility": "true",
"page": "1",
"title": "1 Data Summary",
"description": " Fill in the fields to describe your data model ",
"sections": [],
"fieldGroups":
[
{
"id": "dataSummaryGroup",
"defaultVisibility": "true",
"page": "1",
"title": "Data Summary",
"description": "",
"extendedDescription": "",
"compositeFields": [
{
"multiplicity":{
"min":0,
"max":3
},
"fields":
[
{
"id": "dataSummary",
"defaultVisibility": "true",
"title": "",
"description": "",
"extendedDescription": "",
"viewStyle": "checkBox",
"rules":[
{
"ruleType":"fieldValue",
"target":"metadataStandarsA211",
"ruleStyle":"boolean",
"value":"true",
"valueType":"boolean"
},
{
"ruleType":"fieldValue",
"target":"freeOfChargeGroupCommentA213",
"ruleStyle":"boolean",
"value":"true",
"valueType":"boolean"
},
{
"ruleType":"fieldValue",
"target":"standardisedVocabulariesA212",
"ruleStyle":"boolean",
"value":"true",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}
]
}
]
}
]
},
{
"id": "fairData",
"ordinal": "2",
"defaultVisibility": "true",
"page": "1",
"title": "2 Fair Data",
"sections": [
{
"id": "dataMetadata",
"defaultVisibility": "true",
"page": "1",
"title": "2.1 Making data findable, including provisions for metadata",
"sections": [],
"fieldGroups": [
{
"id": "FindDataMetadataGroup",
"section": "dataMetadata",
"defaultVisibility": "true",
"page": "1",
"title": "Making data findable, including provisions for metadata",
"description": "Making data findable, including provisions for metadata",
"extendedDescription": "FieldGroup Description",
"compositeFields": [
{
"fields":
[
{
"id": "useMetadataQ211",
"defaultVisibility": "true",
"title": "Q2.1.1 Will you use metadata to describe the data?",
"description": "User can select from a list of metadata standards. If they cannot find the standard in the list provided then they should choose \"not listed\". Selecting this will result in a field in which the user can insert the URL to the description of the metadata scheme used. A \"comments\" box should exist to allow users to add comments. They may select more than one metadata standard. They may specify more than one URL when selecting \"not listed\". They are also presented with a field in which to specify the location of the metadata service. Users can select the \"no metadata\" button to specify no metadata will be used to describe the data.",
"extendedDescription": "FieldGroup Description",
"viewStyle": "booleanDesicion",
"rules":[
{
"ruleType":"fieldValue",
"target":"noMetadata",
"ruleStyle":"boolean",
"value":"true",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}
]
},
{
"fields":
[
{
"id": "metadataStandarsA211",
"defaultVisibility": "false",
"title": "Metadata standards",
"description": "The data will be described by metadata that follows the metadata standards described in <url1>, <url2>, ? The data will be described by metadata that follows the metadata schema described in <not-listed-url1>, <not-listed-url2>. The metadata will be stored in the service located at <metadata-repo-url>",
"extendedDescription": "",
"viewStyle": "combobox",
"rules":[],
"multiplicity":{
"min":0,
"max":1
}
}]
},
{
"fields":
[
{
"id": "notlistedA211",
"defaultVisibility": "false",
"title": "Not listed",
"description": "",
"extendedDescription": "",
"viewStyle": "checkBox",
"rules":[
{
"ruleType":"fieldValue",
"target":"",
"ruleStyle":"boolean",
"value":"",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}]
},
{
"fields":
[
{
"id": "notlistedUrlA211",
"defaultVisibility": "false",
"title": "Url",
"description": "URL to the description of the metadata scheme used",
"extendedDescription": "",
"viewStyle": "freetext",
"rules":[
{
"ruleType":"fieldValue",
"target":"",
"ruleStyle":"boolean",
"value":"",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}]
},
{
"fields":
[
{
"id": "notlistedCommentA211",
"defaultVisibility": "false",
"title": "Comments",
"description": "",
"extendedDescription": "",
"viewStyle": "freetext",
"rules":[
{
"ruleType":"fieldValue",
"target":"",
"ruleStyle":"boolean",
"value":"",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}]
},
{
"fields":
[
{
"id": "noMetadata",
"defaultVisibility": "false",
"title": "The data will not be described by any metadata.",
"description": "",
"extendedDescription": "",
"viewStyle": "checkBox",
"rules":[
{
"ruleType":"fieldValue",
"target":"",
"ruleStyle":"boolean",
"value":"",
"valueType":"boolean"
}
],
"multiplicity":{
"min":0,
"max":1
}
}
]
}
]
}
]
}
]
}
]
}

View File

@ -0,0 +1,16 @@
<form class="user-role-editor" [formGroup]="formGroup" (ngSubmit)="formSubmit()">
<mat-form-field class="roles-width-80">
<mat-select formControlName="roles"
multiple required>
<mat-option *ngFor="let role of getPrincipalAppRoleValues()" [value]="role">{{getPrincipalAppRoleWithLanguage(role)}}</mat-option>
</mat-select>
<mat-error *ngIf="getFormControl('roles').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<button *ngIf="!this.nowEditing" mat-icon-button color="primary" type="button" (click)="editItem()">
<mat-icon class="mat-24">edit</mat-icon>
</button>
<button *ngIf="this.nowEditing" mat-icon-button color="primary" type="submit">
<mat-icon class="mat-24">save</mat-icon>
</button>
</form>

View File

@ -0,0 +1,3 @@
.roles-width-80 {
width: 80%;
}

View File

@ -0,0 +1,166 @@
import { UserReferenceService } from '../../../core/services/user-reference-data.service';
import { TranslateService } from '@ngx-translate/core';
import { Component, OnInit, Input } from '@angular/core';
import { FormControl, FormGroup, NgForm, FormArray, AbstractControl, FormBuilder } from '@angular/forms';
import { ValidationContext, Validation } from '../../../utilities/validators/ValidationContext';
import { Principal } from '../../../models/login/Principal';
import { MatSnackBar } from '@angular/material';
import { UserListingModel } from 'app/shared/components/criteria/models/errormodel/users/userListingModel';
import { UserErrorModel } from 'app/shared/components/criteria/models/errormodel/users/userErrorModel';
import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar-notification.component';
@Component({
selector: 'user-role-editor-component',
templateUrl: './user-role-editor.component.html',
styleUrls: ['./user-role-editor.component.scss'],
providers: [
UserReferenceService
]
})
export class UserRoleEditorComponent implements OnInit {
@Input() public item: UserListingModel;
private formGroup: FormGroup = null;
private nowEditing = false;
constructor(
private language: TranslateService,
private userService: UserReferenceService,
private errorModel: UserErrorModel,
private formBuilder: FormBuilder,
private snackBar: MatSnackBar
) {
}
ngOnInit() {
if (this.errorModel == null) { this.errorModel = new UserErrorModel(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
roles: new FormControl({ value: this.item.roles, disabled: true }, context.getValidation('roles').validators)
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'roles' });
validationContext.validation = validationArray;
return validationContext;
}
formSubmit(): void {
this.clearErrorModel();
const modifiedItem = new UserListingModel().fromJSONObject(this.item);
modifiedItem.roles = this.getFormControl('roles').value;
if (!this.isFormValid()) { return; }
this.userService.updateRoles(modifiedItem).subscribe(
(res) => this.onCallbackSuccess(),
(error) => this.onCallbackError(error)
);
}
editItem(): void {
this.formGroup.enable();
this.nowEditing = true;
}
isFormValid(): boolean {
this.touchAllFormFields(this.formGroup);
this.validateAllFormFields(this.formGroup);
return this.formGroup.valid;
}
getFormData(): any {
return this.formGroup.value;
}
getFormControl(controlName: string): AbstractControl {
return this.formGroup.get(controlName);
}
validateAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.updateValueAndValidity({ emitEvent: false })
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.validateAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.validateAllFormFields(item);
})
}
}
touchAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.markAsTouched();
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.touchAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.touchAllFormFields(item);
})
}
}
setErrorModel(errorModel: UserErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.errorModel)[item] = (<any>errorModel)[item];
})
}
clearErrorModel() {
Object.keys(this.errorModel).forEach(item => {
(<any>this.errorModel)[item] = '';
})
}
onCallbackSuccess() {
this.nowEditing = false;
this.formGroup.disable();
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE', language: this.language },
duration: 3000,
extraClasses: ['snackbar-success']
});
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
this.validateAllFormFields(this.formGroup);
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE', language: this.language },
duration: 3000,
extraClasses: ['snackbar-warning']
});
}
getPrincipalAppRoleValues(): Number[] {
let keys: string[] = Object.keys(Principal.AppRole);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getPrincipalAppRoleWithLanguage(role: Principal.AppRole): string {
let result = '';
/* this.language.get(new Utilities().convertFromPrincipalAppRole(role)).subscribe((value: string) => {
result = value;
}); */
return result;
}
}

View File

@ -0,0 +1,33 @@
<div class="container-fluid">
<h3>{{'USERS.LISTING.TITLE' | translate}}</h3>
<users-criteria-component></users-criteria-component>
<mat-card class="mat-card">
<mat-progress-bar *ngIf="dataSource?.isLoadingResults" mode="query"></mat-progress-bar>
<mat-table [dataSource]="dataSource" matSort>
<!-- Column Definition: Label -->
<ng-container cdkColumnDef="label">
<mat-header-cell *matHeaderCellDef>{{'USERS.LISTING.LABEL' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.label}}</mat-cell>
</ng-container>
<!-- Column Definition: Roles -->
<ng-container cdkColumnDef="roles">
<mat-header-cell *matHeaderCellDef>{{'USERS.LISTING.ROLES' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">
<user-role-editor-component [item]="row"></user-role-editor-component>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator #paginator
[length]="dataSource?.totalCount"
[pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</mat-card>
</div>

View File

@ -0,0 +1,12 @@
.mat-card {
overflow: auto;
padding: 0px;
mat-table {
margin: 24px;
}
mat-progress-bar {
position: absolute;
}
}

View File

@ -0,0 +1,139 @@
import { DataTableRequest } from '../../models/data-table/dataTableRequest';
import { UserReferenceService } from '../../core/services/user-reference-data.service';
import { Observable } from 'rxjs/Rx';
import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { UsersCriteriaComponent } from '../../shared/components/criteria/users/users-criteria.component';
import { Router } from '@angular/router';
import { UserCriteria } from '../../core/criteria/UserCriteria';
import { Principal } from '../../models/login/Principal';
import { MatPaginator, MatSort, MatSnackBar } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { DataSource } from '@angular/cdk/table';
import { UserListingModel } from 'app/shared/components/criteria/models/errormodel/users/userListingModel';
import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar-notification.component';
import { UserCriteriaErrorModel } from 'app/shared/components/criteria/models/errormodel/users/userCriteriaErrorModel';
import { UserErrorModel } from 'app/shared/components/criteria/models/errormodel/users/userErrorModel';
export class UsersDataSource extends DataSource<UserListingModel> {
totalCount = 0;
isLoadingResults = false;
constructor(
private _service: UserReferenceService,
private _paginator: MatPaginator,
private _sort: MatSort,
private _languageService: TranslateService,
private _snackBar: MatSnackBar,
private _criteria: UsersCriteriaComponent
) {
super();
//this._paginator.page.subscribe((pageEvent: PageEvent) => {
// this.store.dispatch(new LoadPhotosRequestAction(pageEvent.pageIndex, pageEvent.pageSize))
//})
}
connect(): Observable<UserListingModel[]> {
const displayDataChanges = [
this._paginator.page
//this._sort.matSortChange
];
// If the user changes the sort order, reset back to the first page.
//this._sort.matSortChange.subscribe(() => {
// this._paginator.pageIndex = 0;
//})
return Observable.merge(...displayDataChanges)
.startWith(null)
.switchMap(() => {
setTimeout(() => {
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
const request = new DataTableRequest(startIndex, this._paginator.pageSize);
request.userCriteria = this._criteria.getFormData();
return this._service.getPaged(request);
})
.catch((error: any) => {
this._snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService },
duration: 3000,
extraClasses: ['snackbar-warning']
});
this._criteria.onCallbackError(error);
return Observable.of(null);
})
.map(result => {
setTimeout(() => {
this.isLoadingResults = false;
});
return result;
})
.map(result => {
if (!result) { return []; }
if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
//result.data.forEach((element: any) => {
// const roles: String[] = [];
// element.roles.forEach((role: any) => {
// this._languageService.get(this._utilities.convertFromPrincipalAppRole(role)).subscribe(
// value => roles.push(value)
// );
// });
// element.roles = roles;
//});
return result.data;
});
}
disconnect() {
// No-op
}
}
@Component({
selector: 'app-users-component',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss'],
providers: [
UserReferenceService,
UserCriteriaErrorModel,
UserErrorModel
],
})
export class UsersComponent implements OnInit, AfterViewInit {
@ViewChild(MatPaginator) _paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(UsersCriteriaComponent) criteria: UsersCriteriaComponent;
dataSource: UsersDataSource | null;
displayedColumns: String[] = ['label', 'roles'];
constructor(private userService: UserReferenceService, private router: Router, private languageService: TranslateService, public snackBar: MatSnackBar) {
}
ngOnInit() {
//this.refresh(); //called on ngAfterViewInit with default criteria
}
ngAfterViewInit() {
setTimeout(() => {
this.criteria.setRefreshCallback(() => this.refresh());
this.criteria.setCriteria(this.getDefaultCriteria());
this.criteria.controlModified();
});
}
refresh() {
this.dataSource = new UsersDataSource(this.userService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria, );
}
getDefaultCriteria(): UserCriteria {
const defaultCriteria = new UserCriteria();
return defaultCriteria;
}
}

View File

@ -0,0 +1,32 @@
import { UsersCriteriaComponent } from '../shared/components/criteria/users/users-criteria.component';
import { SharedModule } from '../shared/shared.module';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { UsersComponent } from './components/users.component';
import { UsersRoutes } from './users.routes';
import { MaterialModule } from '../material/material.module';
import { UserRoleEditorComponent } from './components/roles/user-role-editor.component';
@NgModule({
imports: [
CommonModule,
UsersRoutes,
SharedModule,
MaterialModule
],
declarations: [
UsersComponent,
UsersCriteriaComponent,
UserRoleEditorComponent
],
exports: [
UsersComponent
]
})
export class UsersModule { }

View File

@ -0,0 +1,8 @@
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './components/users.component';
const routes: Routes = [
{ path: 'users', component: UsersComponent }
];
export const UsersRoutes = RouterModule.forChild(routes);

View File

@ -0,0 +1,25 @@
import { MyHttpService } from './myhttpservice.service';
import { CommonModule } from '@angular/common';
import { NgModule, ModuleWithProviders } from '@angular/core';
import { MaterialModule } from '../../material/material.module';
import { CoreModule } from '../../core/core.module';
import { AuthService } from 'app/services/auth/auth.service';
@NgModule({
imports: [
CommonModule,
MaterialModule,
CoreModule.forRoot()
]
})
export class MyHttpModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: MyHttpModule,
providers: [
AuthService,
MyHttpService
]
};
}
}

View File

@ -0,0 +1,84 @@
import { Injectable } from '@angular/core';
import { Http, RequestOptions, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Router, ActivatedRoute, RouterStateSnapshot } from '@angular/router';
import { MatSnackBar } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { AuthService } from 'app/services/auth/auth.service';
import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar-notification.component';
@Injectable()
export class MyHttpService {
constructor(
protected http: HttpClient,
private router: Router,
private authService: AuthService,
public language: TranslateService,
public snackBar: MatSnackBar,
) {
}
get<T>(url: string, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.get(url, this.buildRequestOptions(options)));
}
post<T>(url: string, body: any, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.post(url, body, this.buildRequestOptions(options)));
}
put<T>(url: string, body: any, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.put(url, body, this.buildRequestOptions(options)));
}
delete<T>(url: string, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.delete(url, this.buildRequestOptions(options)));
}
patch<T>(url: string, body: any, options?: any): Observable<T> {
return this.interceptRepsonse(this.http.patch(url, body, this.buildRequestOptions(options)));
}
head<T>(url: string, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.head(url, this.buildRequestOptions(options)));
}
options<T>(url: string, options?: any): Observable<T> {
return this.interceptRepsonse<T>(this.http.options(url, this.buildRequestOptions(options)));
}
protected buildRequestOptions(options?: any): Object {
if (options == null) {
options = new RequestOptions();
}
if (options.headers == null) {
options.headers = new Headers();
}
if (!options.headers.has('Content-Type')) {
options.headers = options.headers.set('Content-Type', 'application/json');
}
if (!options.headers.has('Content-Type')) {
options.headers = options.headers.set('Content-Type', 'application/json');
}
if (!options.headers.has('AuthToken')) {
const principal = this.authService.current();
if (principal) {
options.headers = options.headers.set('AuthToken', principal.token);
}
}
return options;
}
private interceptRepsonse<T>(observable: Observable<Object>): Observable<T> {
return observable
.catch((error) => {
if (error.status === 401) {
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-LOGOUT', language: this.language },
duration: 3000,
extraClasses: ['snackbar-success']
})
this.router.navigate(['/unauthorized']);
//this.notification.httpError(error);
return Observable.of<T>();
} else {
return Observable.throw(error);
}
});
}
}

View File

@ -0,0 +1,9 @@
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { BaseErrorModel } from 'app/shared/components/criteria/models/errormodel/BaseErrorModel';
export function BackendErrorValidator(errorModel: BaseErrorModel, propertyName: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
const error: string = (<any>errorModel)[propertyName];
return error ? { 'backendError': { value: error } } : null;
};
}

View File

@ -0,0 +1,20 @@
import { ValidatorFn } from '@angular/forms';
export class ValidationContext {
validation: Validation[];
getValidation(key: string): Validation {
for (let i = 0; i < this.validation.length; i++) {
if (this.validation[i].key === key) {
return this.validation[i];
}
}
throw new Error('Key Was Not Found In The Validation Context');
}
}
export class Validation {
key: string;
validators?: ValidatorFn[] = new Array<ValidatorFn>();
descendantValidations?: ValidationContext;
}

View File

@ -26,6 +26,7 @@ import static eu.eudat.types.Authorities.USER;
@RestController
@CrossOrigin
@RequestMapping(value = "user")
public class Users extends BaseController {
@Autowired
@ -33,7 +34,7 @@ public class Users extends BaseController {
super(apiContext);
}
@RequestMapping(method = RequestMethod.POST, value = {"/users/getPaged"}, consumes = "application/json", produces = "application/json")
@RequestMapping(method = RequestMethod.POST, value = {"/getPaged"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataTableData<UserListingModel>>> getPaged(@Valid @RequestBody UserInfoTableRequestItem userInfoTableRequestItem, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) {
try {
@ -46,9 +47,9 @@ public class Users extends BaseController {
}
@Transactional
@RequestMapping(method = RequestMethod.POST, value = {"/users/editRoles"}, consumes = "application/json", produces = "application/json")
@RequestMapping(method = RequestMethod.POST, value = {"/updateRoles"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<UserListingModel>> editRoles(@Valid @RequestBody UserListingModel userListingModel, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) {
ResponseEntity<ResponseItem<UserListingModel>> updateRoles(@Valid @RequestBody UserListingModel userListingModel, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) {
try {
UserManager.editRoles(this.getApiContext(), userListingModel);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UserListingModel>().status(ApiMessageCode.NO_MESSAGE));

View File

@ -5,4 +5,6 @@ public interface DatabaseAccessLayer<T, I> {
T createOrUpdate(T item);
T find(I id);
void delete(T item);
}

View File

@ -60,4 +60,9 @@ public class DMPDaoImpl extends DatabaseAccess<DMP> implements DMPDao {
public Long count() {
return this.getDatabaseService().count(DMP.class);
}
@Override
public void delete(DMP item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -36,4 +36,9 @@ public class DataRepositoryDaoImpl extends DatabaseAccess<DataRepository> implem
public DataRepository createOrUpdate(DataRepository item) {
return getDatabaseService().createOrUpdate(item, DataRepository.class);
}
@Override
public void delete(DataRepository item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -51,4 +51,9 @@ public class DatasetDaoImpl extends DatabaseAccess<Dataset> implements DatasetDa
public Long count() {
return this.getDatabaseService().count(Dataset.class);
}
@Override
public void delete(Dataset item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -40,4 +40,9 @@ public class DatasetProfileDaoImpl extends DatabaseAccess<DatasetProfile> implem
public QueryableList<DatasetProfile> getAll() {
return getDatabaseService().getQueryable(DatasetProfile.class);
}
@Override
public void delete(DatasetProfile item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -36,4 +36,9 @@ public class ExternalDatasetDaoImpl extends DatabaseAccess<ExternalDataset> impl
public ExternalDataset find(UUID id) {
return this.getDatabaseService().getQueryable(ExternalDataset.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(ExternalDataset item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -35,4 +35,8 @@ public class InvitationDaoImpl extends DatabaseAccess<Invitation> implements Inv
return this.getDatabaseService().getQueryable(Invitation.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(Invitation item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -37,4 +37,9 @@ public class OrganisationDaoImpl extends DatabaseAccess<Organisation> implements
public Organisation find(UUID id) {
return this.getDatabaseService().getQueryable(Organisation.class).where((builder, root) -> builder.equal(root.get("id"), id)).getSingle();
}
@Override
public void delete(Organisation item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -43,4 +43,9 @@ public class ProjectDaoImpl extends DatabaseAccess<Project> implements ProjectDa
public Long count() {
return this.getDatabaseService().count(Project.class);
}
@Override
public void delete(Project item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -36,4 +36,9 @@ public class RegistryDaoImpl extends DatabaseAccess<Registry> implements Registr
public Registry find(UUID id) {
return this.getDatabaseService().getQueryable(Registry.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(Registry item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -36,4 +36,9 @@ public class ResearcherDaoImpl extends DatabaseAccess<Researcher> implements Res
public Researcher find(UUID id) {
return this.getDatabaseService().getQueryable(Researcher.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(Researcher item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -36,4 +36,9 @@ public class ServiceDaoImpl extends DatabaseAccess<Service> implements ServiceDa
public Service find(UUID id) {
return this.getDatabaseService().getQueryable(Service.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(Service item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -39,4 +39,8 @@ public class UserInfoDaoImpl extends DatabaseAccess<UserInfo> implements UserInf
return this.getDatabaseService().getQueryable(UserInfo.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
}
@Override
public void delete(UserInfo item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -34,4 +34,9 @@ public class UserRoleDaoImpl extends DatabaseAccess<UserRole> implements UserRo
public List<UserRole> getUserRoles(UserInfo userInfo) {
return this.getDatabaseService().getQueryable(UserRole.class).where((builder, root) -> builder.equal(root.get("userInfo"),userInfo)).toList();
}
@Override
public void delete(UserRole item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -39,4 +39,9 @@ public class CredentialDaoImpl extends DatabaseAccess<Credential> implements Cre
builder.equal(root.get("provider"), TokenValidatorFactoryImpl.LoginProvider.NATIVELOGIN.getValue())
))).getSingleOrDefault();
}
@Override
public void delete(Credential item) {
this.getDatabaseService().delete(item);
}
}

View File

@ -169,6 +169,7 @@ public class UserInfo implements DataEntity<UserInfo>{
this.email = entity.getEmail();
this.additionalinfo = entity.getAdditionalinfo();
this.lastloggedin = entity.getLastloggedin();
this.userRoles = entity.getUserRoles();
}
@Override

View File

@ -47,8 +47,7 @@ public class UserManager {
public static void editRoles(ApiContext apiContext, UserListingModel user) {
eu.eudat.entities.UserInfo userInfo = apiContext.getDatabaseRepository().getUserInfoDao().find(user.getId());
userInfo.getUserRoles().removeAll(userInfo.getUserRoles());
userInfo = apiContext.getDatabaseRepository().getUserInfoDao().createOrUpdate(userInfo);
userInfo.getUserRoles().stream().forEach(item -> apiContext.getDatabaseRepository().getUserRoleDao().delete(item));
for (Integer role : user.getAppRoles()) {
UserRole userRole = new UserRole();
userRole.setRole(role);

View File

@ -104,6 +104,7 @@ public class UserListingModel implements DataModel<eu.eudat.entities.UserInfo> {
@Override
public void fromDataModel(UserInfo entity) throws InstantiationException, IllegalAccessException {
this.id = entity.getId();
this.email = entity.getEmail();
this.usertype = entity.getUsertype();
this.verified_email = entity.getVerified_email();

View File

@ -12,8 +12,8 @@ const appRoutes: Routes = [
{ path: "dmps", loadChildren: './dmps/dmps.module#DataManagementPlanModule',canActivate: [AuthGuard] },
{ path: 'welcome', component: HomepageComponent, canActivate: [AuthGuard] },
{ path: '', redirectTo: '/welcome', pathMatch: 'full' },
{ path: "unauthorized", loadChildren: './unauthorized/unauthorized.module#UnauthorizedModule' }
{ path: "unauthorized", loadChildren: './unauthorized/unauthorized.module#UnauthorizedModule' },
{ path: "users", loadChildren: './users/users.module#UsersModule' }
];
@NgModule({

View File

@ -0,0 +1,9 @@
import { BaseCriteria } from '../BaseCriteria';
import { Principal } from "@app/models/login/Principal";
export class UserCriteria extends BaseCriteria {
public Label: String;
public Roles: Principal.AppRole[];
}

View File

@ -0,0 +1,6 @@
import { BaseCriteriaErrorModel } from '../BaseCriteriaErrorModel';
export class UserCriteriaErrorModel extends BaseCriteriaErrorModel {
public Label: String;
public Roles: String;
}

View File

@ -20,7 +20,8 @@ export class Principal implements Serializable<Principal> {
export namespace Principal {
export enum AppRole {
Admin = 0,
User = 1
Manager = 2,
Admin = 1,
User = 0,
}
}

View File

@ -0,0 +1,6 @@
import { BaseErrorModel } from "@app/models/error/BaseErrorModel";
export class UserErrorModel extends BaseErrorModel {
public Roles: String;
}

View File

@ -0,0 +1,16 @@
import { Serializable } from '../Serializable';
import { TranslateService } from '@ngx-translate/core';
import { Principal } from 'app/models/login/Principal';
export class UserListingModel implements Serializable<UserListingModel> {
public id: String;
public name: String;
public appRoles: Principal.AppRole[];
fromJSONObject(item: any): UserListingModel {
this.id = item.id;
this.name = item.name;
this.appRoles = item.appRoles;
return this;
}
}

View File

@ -0,0 +1,46 @@
import { UserListingModel } from '../../models/users/UserListingModel';
import { UserCriteria } from '../../models/criteria/users/UserCriteria';
import { BaseHttpService } from '../../utilities/cite-http-service-module/base-http.service';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { DataTableRequest } from '../../models/data-table/dataTableRequest';
import { DataTableData } from '../../models/data-table/dataTableData';
import { HostConfiguration } from 'app/app.constants';
@Injectable()
export class UserReferenceService {
private actionUrl: string;
private headers: HttpHeaders;
constructor(private http: BaseHttpService) {
this.actionUrl = HostConfiguration.Server + '/user/';
this.headers = new HttpHeaders();
this.headers = this.headers.set('Content-Type', 'application/json');
this.headers = this.headers.set('Accept', 'application/json');
}
// formatItem(utilities: Utilities, item: ConfigurationModel): ConfigurationModel {
// item.validFrom = new Date(item.validFrom);
// item.validTo = new Date(item.validTo);
// return item
// }
getPaged(dataTableRequest: DataTableRequest<UserCriteria>): Observable<DataTableData<UserListingModel>> {
return this.http.post<DataTableData<UserListingModel>>(this.actionUrl + 'getPaged', JSON.stringify(dataTableRequest), { headers: this.headers });
}
updateRoles(itemToUpdate: UserListingModel): Observable<UserListingModel> {
return this.http.post<UserListingModel>(this.actionUrl + 'updateRoles', JSON.stringify(itemToUpdate), { headers: this.headers });
}
delete(id: String): Observable<any> {
return this.http.delete<any>(this.actionUrl + id, { headers: this.headers });
}
}

View File

@ -13,29 +13,90 @@ import { BaseCriteriaErrorModel } from '../../../../models/criteria/BaseCriteria
export class BaseCriteriaComponent implements OnInit {
public refreshCallback: Function = null;
public baseErrorModel: BaseCriteriaErrorModel = new BaseCriteriaErrorModel();
public formGroup: FormGroup = null;
constructor(baseErrorModel: BaseCriteriaErrorModel) {
this.baseErrorModel = baseErrorModel;
}
constructor(
public baseErrorModel?: BaseCriteriaErrorModel,
) {
}
ngOnInit() {
}
ngOnInit() {
if (this.baseErrorModel == null) { this.baseErrorModel = new BaseCriteriaErrorModel(); }
}
setRefreshCallback(callback: Function): void {
this.refreshCallback = callback;
}
controlModified(): void {
this.clearErrorModel();
if (!this.isFormValid()) { return; }
if (this.refreshCallback != null) { this.refreshCallback(); }
}
public setErrorModel(errorModel: BaseCriteriaErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = (<any>errorModel)[item];
})
}
public isFormValid(): boolean {
this.touchAllFormFields(this.formGroup);
this.validateAllFormFields(this.formGroup);
return this.formGroup.valid;
}
public clearErrorModel() {
Object.keys(this.baseErrorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = '';
})
}
public getFormData(): any {
return this.formGroup.value;
}
public getFormControl(controlName: string): AbstractControl {
return this.formGroup.get(controlName);
}
public disableFormFields(formControl: AbstractControl) {
formControl.disable();
}
public validateAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.updateValueAndValidity({ emitEvent: false })
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.validateAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.validateAllFormFields(item);
})
}
}
public touchAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.markAsTouched();
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.touchAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.touchAllFormFields(item);
})
}
}
setRefreshCallback(callback: Function): void {
this.refreshCallback = callback;
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: BaseCriteriaErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = (<any>errorModel)[item];
})
}
public clearErrorModel() {
Object.keys(this.baseErrorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = '';
})
}
}

View File

@ -0,0 +1,24 @@
<form class="user-roles-criteria" [formGroup]="formGroup">
<mat-card class="mat-card">
<div class="row">
<div class="col-sm-6 col-md-8">
<mat-form-field>
<input matInput
placeholder="{{'CRITERIA.USERS.LABEL'| translate}}"
formControlName="label"
(ngModelChange)="controlModified()">
</mat-form-field>
</div>
<div class="col-sm-6 col-md-4">
<mat-form-field>
<mat-select placeholder="{{'CRITERIA.USERS.ROLE' | translate}}"
formControlName="roles"
(change)="controlModified()"
multiple>
<mat-option *ngFor="let role of getPrincipalAppRoleValues()" [value]="role">{{getPrincipalAppRoleWithLanguage(role)}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</mat-card>
</form>

View File

@ -0,0 +1,10 @@
.user-roles-criteria {
mat-form-field {
padding-bottom: 5px;
width: 100%;
}
mat-card {
padding-bottom: 0px;
}
}

View File

@ -0,0 +1,83 @@
import { Utilities } from '../../../../utilities/utilities';
import { UserCriteriaErrorModel } from '../../../../models/criteria/users/UserCriteriaErrorModel';
import { UserCriteria } from '../../../../models/criteria/users/UserCriteria';
import { TranslateService } from '@ngx-translate/core';
import { Validation, ValidationContext } from '../../../../utilities/validators/ValidationContext';
import { Component, OnInit } from '@angular/core';
import { BaseCriteriaComponent } from '../base/base-criteria.component';
import { Principal } from '../../../../models/login/Principal';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'users-criteria-component',
templateUrl: './users-criteria.component.html',
styleUrls: ['./users-criteria.component.scss'],
})
export class UsersCriteriaComponent extends BaseCriteriaComponent implements OnInit {
public role: Principal.AppRole;
public criteria: UserCriteria = new UserCriteria();
constructor(
public language: TranslateService,
public errorModel: UserCriteriaErrorModel,
public formBuilder: FormBuilder
) {
super(errorModel);
}
ngOnInit() {
super.ngOnInit();
if (this.criteria == null) { this.criteria = new UserCriteria(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
}
setCriteria(criteria: UserCriteria): void {
this.criteria = criteria;
this.formGroup = this.buildForm();
}
public fromJSONObject(item: any): UserCriteria {
this.criteria = new UserCriteria();
this.criteria.Label = item.Label;
this.criteria.Roles = item.Roles;
return this.criteria;
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
label: [this.criteria.Label, context.getValidation('label').validators],
roles: [this.criteria.Roles, context.getValidation('roles').validators],
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'label' });
validationArray.push({ key: 'roles' });
validationContext.validation = validationArray;
return validationContext;
}
getPrincipalAppRoleValues(): Number[] {
let keys: string[] = Object.keys(Principal.AppRole);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getPrincipalAppRoleWithLanguage(role: Principal.AppRole): string {
let result = '';
this.language.get(new Utilities().convertFromPrincipalAppRole(role)).subscribe((value: string) => {
result = value;
});
return result;
}
}

View File

@ -0,0 +1,16 @@
<form class="user-role-editor" [formGroup]="formGroup" (ngSubmit)="formSubmit()">
<mat-form-field class="roles-width-80">
<mat-select formControlName="appRoles"
multiple required>
<mat-option *ngFor="let role of getPrincipalAppRoleValues()" [value]="role">{{getPrincipalAppRoleWithLanguage(role)}}</mat-option>
</mat-select>
<mat-error *ngIf="getFormControl('appRoles').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<button *ngIf="!this.nowEditing" mat-icon-button color="primary" type="button" (click)="editItem()">
<mat-icon class="mat-24">edit</mat-icon>
</button>
<button *ngIf="this.nowEditing" mat-icon-button color="primary" type="submit">
<mat-icon class="mat-24">save</mat-icon>
</button>
</form>

View File

@ -0,0 +1,3 @@
.roles-width-80 {
width: 80%;
}

View File

@ -0,0 +1,167 @@
import { Utilities } from '../../../utilities/utilities';
import { UserErrorModel } from '../../../models/users/UserErrorModel';
import { UserListingModel } from '../../../models/users/UserListingModel';
import { UserReferenceService } from '../../../services/user-reference/user-reference-data.service';
import { SnackBarNotificationComponent } from '../../../shared/components/notificaiton/snack-bar-notification.component';
import { TranslateService } from '@ngx-translate/core';
import { Component, OnInit, Input } from '@angular/core';
import { FormControl, FormGroup, NgForm, FormArray, AbstractControl, FormBuilder } from '@angular/forms';
import { ValidationContext, Validation } from '../../../utilities/validators/ValidationContext';
import { Principal } from '../../../models/login/Principal';
import { MatSnackBar } from '@angular/material';
@Component({
selector: 'user-role-editor-component',
templateUrl: './user-role-editor.component.html',
styleUrls: ['./user-role-editor.component.scss'],
providers: [
UserReferenceService
]
})
export class UserRoleEditorComponent implements OnInit {
@Input() public item: UserListingModel;
private formGroup: FormGroup = null;
private nowEditing = false;
constructor(
private language: TranslateService,
private userService: UserReferenceService,
private errorModel: UserErrorModel,
private formBuilder: FormBuilder,
private snackBar: MatSnackBar
) {
}
ngOnInit() {
if (this.errorModel == null) { this.errorModel = new UserErrorModel(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
appRoles: new FormControl({ value: this.item.appRoles, disabled: true }, context.getValidation('appRoles').validators)
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'appRoles' });
validationContext.validation = validationArray;
return validationContext;
}
formSubmit(): void {
this.clearErrorModel();
const modifiedItem = new UserListingModel().fromJSONObject(this.item);
modifiedItem.appRoles = this.getFormControl('appRoles').value;
if (!this.isFormValid()) { return; }
this.userService.updateRoles(modifiedItem).subscribe(
(res) => this.onCallbackSuccess(),
(error) => this.onCallbackError(error)
);
}
editItem(): void {
this.formGroup.enable();
this.nowEditing = true;
}
isFormValid(): boolean {
this.touchAllFormFields(this.formGroup);
this.validateAllFormFields(this.formGroup);
return this.formGroup.valid;
}
getFormData(): any {
return this.formGroup.value;
}
getFormControl(controlName: string): AbstractControl {
return this.formGroup.get(controlName);
}
validateAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.updateValueAndValidity({ emitEvent: false })
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.validateAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.validateAllFormFields(item);
})
}
}
touchAllFormFields(formControl: AbstractControl) {
if (formControl instanceof FormControl) {
formControl.markAsTouched();
} else if (formControl instanceof FormGroup) {
Object.keys(formControl.controls).forEach(item => {
const control = formControl.get(item);
this.touchAllFormFields(control);
})
} else if (formControl instanceof FormArray) {
formControl.controls.forEach(item => {
this.touchAllFormFields(item);
})
}
}
setErrorModel(errorModel: UserErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.errorModel)[item] = (<any>errorModel)[item];
})
}
clearErrorModel() {
Object.keys(this.errorModel).forEach(item => {
(<any>this.errorModel)[item] = '';
})
}
onCallbackSuccess() {
this.nowEditing = false;
this.formGroup.disable();
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE', language: this.language },
duration: 3000,
extraClasses: ['snackbar-success']
});
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
this.validateAllFormFields(this.formGroup);
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE', language: this.language },
duration: 3000,
extraClasses: ['snackbar-warning']
});
}
getPrincipalAppRoleValues(): Number[] {
let keys: string[] = Object.keys(Principal.AppRole);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getPrincipalAppRoleWithLanguage(role: Principal.AppRole): string {
let result = '';
this.language.get(new Utilities().convertFromPrincipalAppRole(role)).subscribe((value: string) => {
result = value;
});
return result;
}
}

View File

@ -0,0 +1,33 @@
<div class="container-fluid">
<h3>{{'USERS.LISTING.TITLE' | translate}}</h3>
<users-criteria-component></users-criteria-component>
<mat-card class="mat-card">
<mat-progress-bar *ngIf="dataSource?.isLoadingResults" mode="query"></mat-progress-bar>
<mat-table [dataSource]="dataSource" matSort>
<!-- Column Definition: Label -->
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef>{{'USERS.LISTING.LABEL' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<!-- Column Definition: Roles -->
<ng-container cdkColumnDef="roles">
<mat-header-cell *matHeaderCellDef>{{'USERS.LISTING.ROLES' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">
<user-role-editor-component [item]="row"></user-role-editor-component>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator #paginator
[length]="dataSource?.totalCount"
[pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</mat-card>
</div>

View File

@ -0,0 +1,12 @@
.mat-card {
overflow: auto;
padding: 0px;
mat-table {
margin: 24px;
}
mat-progress-bar {
position: absolute;
}
}

View File

@ -0,0 +1,139 @@
import { DataTableRequest } from '../../models/data-table/DataTableRequest';
import { UserErrorModel } from '../../models/users/UserErrorModel';
import { UserReferenceService } from '../../services/user-reference/user-reference-data.service';
import { UserListingModel } from '../../models/users/UserListingModel';
import { SnackBarNotificationComponent } from '../../shared/components/notificaiton/snack-bar-notification.component';
import { UserCriteria } from '../../models/criteria/users/UserCriteria';
import { UserCriteriaErrorModel } from '../../models/criteria/users/UserCriteriaErrorModel';
import { Observable } from 'rxjs/Rx';
import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { UsersCriteriaComponent } from '../../shared/components/criteria/users/users-criteria.component';
import { Router } from '@angular/router';
import { Principal } from '../../models/login/Principal';
import { MatPaginator, MatSort, MatSnackBar } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { DataSource } from '@angular/cdk/table';
export class UsersDataSource extends DataSource<UserListingModel> {
totalCount = 0;
isLoadingResults = false;
constructor(
private _service: UserReferenceService,
private _paginator: MatPaginator,
private _sort: MatSort,
private _languageService: TranslateService,
private _snackBar: MatSnackBar,
private _criteria: UsersCriteriaComponent
) {
super();
//this._paginator.page.subscribe((pageEvent: PageEvent) => {
// this.store.dispatch(new LoadPhotosRequestAction(pageEvent.pageIndex, pageEvent.pageSize))
//})
}
connect(): Observable<UserListingModel[]> {
const displayDataChanges = [
this._paginator.page
//this._sort.matSortChange
];
// If the user changes the sort order, reset back to the first page.
//this._sort.matSortChange.subscribe(() => {
// this._paginator.pageIndex = 0;
//})
return Observable.merge(...displayDataChanges)
.startWith(null)
.switchMap(() => {
setTimeout(() => {
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
const request = new DataTableRequest<UserCriteria>(startIndex, this._paginator.pageSize);
request.criteria = this._criteria.getFormData();
return this._service.getPaged(request);
})
.catch((error: any) => {
this._snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService },
duration: 3000,
extraClasses: ['snackbar-warning']
});
this._criteria.onCallbackError(error);
return Observable.of(null);
})
.map(result => {
setTimeout(() => {
this.isLoadingResults = false;
});
return result;
})
.map(result => {
if (!result) { return []; }
if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
//result.data.forEach((element: any) => {
// const roles: String[] = [];
// element.roles.forEach((role: any) => {
// this._languageService.get(this._utilities.convertFromPrincipalAppRole(role)).subscribe(
// value => roles.push(value)
// );
// });
// element.roles = roles;
//});
return result.data;
});
}
disconnect() {
// No-op
}
}
@Component({
selector: 'app-users-component',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss'],
providers: [
UserReferenceService,
UserCriteriaErrorModel,
UserErrorModel
],
})
export class UsersComponent implements OnInit, AfterViewInit {
@ViewChild(MatPaginator) _paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(UsersCriteriaComponent) criteria: UsersCriteriaComponent;
dataSource: UsersDataSource | null;
displayedColumns: String[] = ['name', 'roles'];
constructor(private userService: UserReferenceService, private router: Router, private languageService: TranslateService, public snackBar: MatSnackBar) {
}
ngOnInit() {
//this.refresh(); //called on ngAfterViewInit with default criteria
}
ngAfterViewInit() {
setTimeout(() => {
this.criteria.setRefreshCallback(() => this.refresh());
this.criteria.setCriteria(this.getDefaultCriteria());
this.criteria.controlModified();
});
}
refresh() {
this.dataSource = new UsersDataSource(this.userService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria, );
}
getDefaultCriteria(): UserCriteria {
const defaultCriteria = new UserCriteria();
return defaultCriteria;
}
}

View File

@ -0,0 +1,51 @@
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { UsersCriteriaComponent } from '../shared/components/criteria/users/users-criteria.component';
import { MaterialModule } from '../shared/material/material.module';
import { SharedModule } from '../shared/shared.module';
import { CommonModule } from '@angular/common';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { UsersComponent } from './components/users.component';
import { UsersRoutes } from './users.routes';
import { UserRoleEditorComponent } from './components/roles/user-role-editor.component';
@NgModule({
imports: [
CommonModule,
UsersRoutes,
SharedModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
ReactiveFormsModule,
MaterialModule
],
declarations: [
UsersComponent,
UsersCriteriaComponent,
UserRoleEditorComponent
],
exports: [
UsersComponent
]
})
export class UsersModule {
constructor(private translate: TranslateService) {
translate.setDefaultLang('en');
translate.use('en');
}
}
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, 'assets/lang/', '.json');
}

View File

@ -0,0 +1,8 @@
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './components/users.component';
const routes: Routes = [
{ path: '', component: UsersComponent }
];
export const UsersRoutes = RouterModule.forChild(routes);

View File

@ -0,0 +1,15 @@
import { Injectable } from '@angular/core';
import { FormBuilder, FormArray, FormGroup } from '@angular/forms';
import { Principal } from '../models/login/Principal';
@Injectable()
export class Utilities {
convertFromPrincipalAppRole(status: Principal.AppRole): string {
switch (status) {
case Principal.AppRole.Admin: return 'TYPES.APP-ROLE.ADMIN'
case Principal.AppRole.User: return 'TYPES.APP-ROLE.USER'
case Principal.AppRole.Manager: return 'TYPES.APP-ROLE.MANAGER'
}
}
}

View File

@ -149,7 +149,11 @@
"DMP": {
"LIKE": "Search",
"PROJECTS": "Projects"
}
},
"USERS": {
"LABEL": "Label",
"ROLE": "Role"
}
},
"DATASET-EDITOR": {
"TITLE": {
@ -179,5 +183,19 @@
"SEND-INVITATION": "Send Invitations",
"CANCEL": "Cancel"
}
}
},
"USERS": {
"LISTING": {
"TITLE": "Users",
"LABEL": "Label",
"ROLES": "Roles"
}
},
"TYPES": {
"APP-ROLE": {
"ADMIN": "Admin",
"USER": "User",
"MANAGER": "Manager"
}
}
}