# Conflicts:
#	dmp-admin/src/app/routes.ts
#	dmp-frontend/package.json
This commit is contained in:
annampak 2018-02-02 13:00:30 +02:00
commit 8653c06111
108 changed files with 5592 additions and 1999 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';
@ -128,8 +126,6 @@ import { UnauthorizedModule } from './unauthorized/unauthorized.module';
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

@ -52,7 +52,8 @@ const routes: Routes = [
},
{ path: 'form', loadChildren: './dataset-profile-form/dataset-profile.module#DatasetProfileModule', canActivate: [AuthGuard]},
{ path: "unauthorized", loadChildren: './unauthorized/unauthorized.module#UnauthorizedModule' } ,
{ path: "login", component: MainSignInComponent }
{ path: "login", component: MainSignInComponent },
{ 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

@ -28,7 +28,7 @@ public class DashBoardController extends BaseController{
}
@RequestMapping(method = RequestMethod.GET, value = { "/dashboard/getStatistics" }, produces="application/json")
public ResponseEntity<ResponseItem<DashBoardStatistics>> getStatistics(Principal principal){
public ResponseEntity<ResponseItem<DashBoardStatistics>> getStatistics(){
try {
DashBoardStatistics statistics = new DashBoardManager().getStatistics(this.getApiContext().getDatabaseRepository().getDatasetDao(), this.getApiContext().getDatabaseRepository().getDmpDao()
, this.getApiContext().getDatabaseRepository().getProjectDao());
@ -38,5 +38,18 @@ public class DashBoardController extends BaseController{
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<DashBoardStatistics>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
}
@RequestMapping(method = RequestMethod.GET, value = { "/dashboard/me/getStatistics" }, produces="application/json")
public ResponseEntity<ResponseItem<DashBoardStatistics>> getStatistics(Principal principal){
try {
DashBoardStatistics statistics = new DashBoardManager().getMeStatistics(this.getApiContext().getDatabaseRepository().getDatasetDao(), this.getApiContext().getDatabaseRepository().getDmpDao()
, this.getApiContext().getDatabaseRepository().getProjectDao(),principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DashBoardStatistics>().status(ApiMessageCode.NO_MESSAGE).payload(statistics));
}
catch(Exception ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<DashBoardStatistics>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
}

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

@ -1,8 +1,15 @@
package eu.eudat.dao;
public interface DatabaseAccessLayer<T, I> {
import eu.eudat.entities.DataEntity;
import eu.eudat.queryable.QueryableList;
public interface DatabaseAccessLayer<T extends DataEntity<T>, I> {
T createOrUpdate(T item);
T find(I id);
void delete(T item);
QueryableList<T> asQueryable();
}

View File

@ -1,6 +1,7 @@
package eu.eudat.dao.entities;
import java.util.UUID;
import eu.eudat.dao.DatabaseAccess;
import eu.eudat.dao.databaselayer.service.DatabaseService;
import eu.eudat.entities.DatasetProfile;
@ -17,47 +18,61 @@ import org.springframework.stereotype.Component;
public class DMPDaoImpl extends DatabaseAccess<DMP> implements DMPDao {
@Autowired
public DMPDaoImpl(DatabaseService<DMP> databaseService) {
this.setDatabaseService(databaseService);
}
@Autowired
public DMPDaoImpl(DatabaseService<DMP> databaseService) {
this.setDatabaseService(databaseService);
}
@Override
public QueryableList<DMP> getWithCriteria(DataManagementPlanCriteria criteria) {
QueryableList<DMP> query = getDatabaseService().getQueryable(DMP.getHints(),DMP.class);
if(criteria.getLike()!=null&&!criteria.getLike().isEmpty())query.where((builder, root) -> builder.like(root.get("label"),"%"+criteria.getLike()+"%"));
if(criteria.getPeriodEnd()!=null)query.where((builder, root) -> builder.lessThan(root.get("created"),criteria.getPeriodEnd()));
if(criteria.getPeriodStart()!=null)query.where((builder, root) -> builder.greaterThan(root.get("created"),criteria.getPeriodStart()));
if(criteria.getProjects()!=null&&!criteria.getProjects().isEmpty())query.where(((builder, root) -> root.get("project").in(criteria.getProjectEntities())));
return query;
}
@Override
public QueryableList<DMP> getWithCriteria(DataManagementPlanCriteria criteria) {
QueryableList<DMP> query = getDatabaseService().getQueryable(DMP.getHints(), DMP.class);
if (criteria.getLike() != null && !criteria.getLike().isEmpty())
query.where((builder, root) -> builder.like(root.get("label"), "%" + criteria.getLike() + "%"));
if (criteria.getPeriodEnd() != null)
query.where((builder, root) -> builder.lessThan(root.get("created"), criteria.getPeriodEnd()));
if (criteria.getPeriodStart() != null)
query.where((builder, root) -> builder.greaterThan(root.get("created"), criteria.getPeriodStart()));
if (criteria.getProjects() != null && !criteria.getProjects().isEmpty())
query.where(((builder, root) -> root.get("project").in(criteria.getProjectEntities())));
return query;
}
public QueryableList<DMP> getAuthenticated(QueryableList<DMP> query,UserInfo principal) {
query.where((builder, root) -> builder.or(builder.equal(root.get("creator"),principal),builder.isMember(principal,root.get("users"))));
return query;
}
public QueryableList<DMP> getAuthenticated(QueryableList<DMP> query, UserInfo principal) {
query.where((builder, root) -> builder.or(builder.equal(root.get("creator"), principal), builder.isMember(principal, root.get("users"))));
return query;
}
@Override
public DMP createOrUpdate(DMP item) {
return this.getDatabaseService().createOrUpdate(item,DMP.class);
}
@Override
public DMP createOrUpdate(DMP item) {
return this.getDatabaseService().createOrUpdate(item, DMP.class);
}
@Override
public DMP find(UUID id) {
return getDatabaseService().getQueryable(DMP.class).where((builder, root) -> builder.equal((root.get("id")),id)).getSingle();
}
@Override
public DMP find(UUID id) {
return getDatabaseService().getQueryable(DMP.class).where((builder, root) -> builder.equal((root.get("id")), id)).getSingle();
}
@Override
public QueryableList<DMP> getUserDmps(DatasetWizardAutocompleteRequest datasetWizardAutocompleteRequest, UserInfo userInfo) {
QueryableList<DMP> query = getDatabaseService().getQueryable(DMP.class).where((builder, root) -> builder.or(builder.equal(root.get("creator"),userInfo),builder.isMember(userInfo,root.get("users"))));
if(datasetWizardAutocompleteRequest.getCriteria().getLike()!=null&&!datasetWizardAutocompleteRequest.getCriteria().getLike().isEmpty()){
query.where((builder, root) -> builder.like(root.get("label"),"%"+datasetWizardAutocompleteRequest.getCriteria().getLike()+"%"));
}
return query;
}
@Override
public QueryableList<DMP> getUserDmps(DatasetWizardAutocompleteRequest datasetWizardAutocompleteRequest, UserInfo userInfo) {
QueryableList<DMP> query = getDatabaseService().getQueryable(DMP.class).where((builder, root) -> builder.or(builder.equal(root.get("creator"), userInfo), builder.isMember(userInfo, root.get("users"))));
if (datasetWizardAutocompleteRequest.getCriteria().getLike() != null && !datasetWizardAutocompleteRequest.getCriteria().getLike().isEmpty()) {
query.where((builder, root) -> builder.like(root.get("label"), "%" + datasetWizardAutocompleteRequest.getCriteria().getLike() + "%"));
}
return query;
}
@Override
public Long count() {
return this.getDatabaseService().count(DMP.class);
}
@Override
public Long count() {
return this.getDatabaseService().count(DMP.class);
}
@Override
public void delete(DMP item) {
this.getDatabaseService().delete(item);
}
@Override
public QueryableList<DMP> asQueryable() {
return this.getDatabaseService().getQueryable(DMP.class);
}
}

View File

@ -36,4 +36,14 @@ 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);
}
@Override
public QueryableList<DataRepository> asQueryable() {
return this.getDatabaseService().getQueryable(DataRepository.class);
}
}

View File

@ -51,4 +51,14 @@ 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);
}
@Override
public QueryableList<Dataset> asQueryable() {
return this.getDatabaseService().getQueryable(Dataset.class);
}
}

View File

@ -40,4 +40,14 @@ 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);
}
@Override
public QueryableList<DatasetProfile> asQueryable() {
return this.getDatabaseService().getQueryable(DatasetProfile.class);
}
}

View File

@ -36,4 +36,14 @@ 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);
}
@Override
public QueryableList<ExternalDataset> asQueryable() {
return this.getDatabaseService().getQueryable(ExternalDataset.class);
}
}

View File

@ -35,4 +35,13 @@ 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);
}
@Override
public QueryableList<Invitation> asQueryable() {
return this.getDatabaseService().getQueryable(Invitation.class);
}
}

View File

@ -37,4 +37,14 @@ 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);
}
@Override
public QueryableList<Organisation> asQueryable() {
return this.getDatabaseService().getQueryable(Organisation.class);
}
}

View File

@ -3,8 +3,10 @@ package eu.eudat.dao.entities;
import java.util.UUID;
import eu.eudat.dao.DatabaseAccessLayer;
import eu.eudat.entities.Dataset;
import eu.eudat.entities.Organisation;
import eu.eudat.entities.Project;
import eu.eudat.entities.UserInfo;
import eu.eudat.models.criteria.ProjectCriteria;
import eu.eudat.queryable.QueryableList;
@ -12,5 +14,7 @@ public interface ProjectDao extends DatabaseAccessLayer<Project, UUID> {
QueryableList<Project> getWithCriteria(ProjectCriteria criteria);
QueryableList<Project> getAuthenticated(QueryableList<Project> query, UserInfo principal);
Long count();
}

View File

@ -3,11 +3,10 @@ package eu.eudat.dao.entities;
import java.util.UUID;
import eu.eudat.dao.DatabaseAccess;
import eu.eudat.dao.databaselayer.service.DatabaseService;
import eu.eudat.entities.Organisation;
import eu.eudat.entities.*;
import eu.eudat.models.criteria.ProjectCriteria;
import eu.eudat.queryable.QueryableList;
import eu.eudat.entities.Project;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -43,4 +42,19 @@ 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);
}
@Override
public QueryableList<Project> asQueryable() {
return this.getDatabaseService().getQueryable(Project.class);
}
public QueryableList<Project> getAuthenticated(QueryableList<Project> query, UserInfo principal) {
query.where((builder, root) -> builder.equal(root.get("creator"), principal));
return query;
}
}

View File

@ -36,4 +36,14 @@ 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);
}
@Override
public QueryableList<Registry> asQueryable() {
return this.getDatabaseService().getQueryable(Registry.class);
}
}

View File

@ -36,4 +36,14 @@ 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);
}
@Override
public QueryableList<Researcher> asQueryable() {
return this.getDatabaseService().getQueryable(Researcher.class);
}
}

View File

@ -36,4 +36,14 @@ 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);
}
@Override
public QueryableList<Service> asQueryable() {
return this.getDatabaseService().getQueryable(Service.class);
}
}

View File

@ -1,5 +1,6 @@
package eu.eudat.dao.entities;
import java.util.Arrays;
import java.util.UUID;
import eu.eudat.dao.DatabaseAccess;
@ -22,21 +23,32 @@ public class UserInfoDaoImpl extends DatabaseAccess<UserInfo> implements UserInf
@Override
public QueryableList<UserInfo> getWithCriteria(UserInfoCriteria criteria) {
QueryableList<UserInfo> users = this.getDatabaseService().getQueryable(UserInfo.class);
if (criteria.getAppRoles() != null && !criteria.getAppRoles().isEmpty())
users.where((builder, root) -> root.join("userRoles").get("role").in(criteria.getAppRoles()));
if (criteria.getLike() != null)
users.where((builder, root) -> builder.or(builder.like(root.get("name"), "%" + criteria.getLike() + "%"), builder.like(root.get("email"), "%" + criteria.getLike() + "%")));
if(criteria.getEmail()!=null)
users.where((builder, root) -> builder.equal(root.get("email"),criteria.getEmail()));
if (criteria.getEmail() != null)
users.where((builder, root) -> builder.equal(root.get("email"), criteria.getEmail()));
return users;
}
@Override
public UserInfo createOrUpdate(UserInfo item) {
return this.getDatabaseService().createOrUpdate(item,UserInfo.class);
return this.getDatabaseService().createOrUpdate(item, UserInfo.class);
}
@Override
public UserInfo find(UUID id) {
return this.getDatabaseService().getQueryable(UserInfo.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingle();
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);
}
@Override
public QueryableList<UserInfo> asQueryable() {
return this.getDatabaseService().getQueryable(UserInfo.class);
}
}

View File

@ -3,6 +3,8 @@ package eu.eudat.dao.entities;
import eu.eudat.dao.DatabaseAccessLayer;
import eu.eudat.entities.UserInfo;
import eu.eudat.entities.UserRole;
import eu.eudat.models.criteria.UserRoleCriteria;
import eu.eudat.queryable.QueryableList;
import java.util.List;
import java.util.UUID;
@ -10,5 +12,6 @@ import java.util.UUID;
public interface UserRoleDao extends DatabaseAccessLayer<UserRole, UUID> {
QueryableList<UserRole> getWithCriteria(UserRoleCriteria criteria);
List<UserRole> getUserRoles(UserInfo userInfo);
}

View File

@ -5,6 +5,8 @@ import eu.eudat.dao.DatabaseAccessLayer;
import eu.eudat.dao.databaselayer.service.DatabaseService;
import eu.eudat.entities.UserInfo;
import eu.eudat.entities.UserRole;
import eu.eudat.models.criteria.UserRoleCriteria;
import eu.eudat.queryable.QueryableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -13,7 +15,7 @@ import java.util.UUID;
@Component("userRoleDao")
public class UserRoleDaoImpl extends DatabaseAccess<UserRole> implements UserRoleDao{
public class UserRoleDaoImpl extends DatabaseAccess<UserRole> implements UserRoleDao {
@Autowired
public UserRoleDaoImpl(DatabaseService<UserRole> databaseService) {
@ -22,16 +24,36 @@ public class UserRoleDaoImpl extends DatabaseAccess<UserRole> implements UserRo
@Override
public UserRole createOrUpdate(UserRole item) {
return this.getDatabaseService().createOrUpdate(item,UserRole.class);
return this.getDatabaseService().createOrUpdate(item, UserRole.class);
}
@Override
public UserRole find(UUID id) {
return this.getDatabaseService().getQueryable(UserRole.class).where((builder, root) -> builder.equal(root.get("id"),id)).getSingleOrDefault();
return this.getDatabaseService().getQueryable(UserRole.class).where((builder, root) -> builder.equal(root.get("id"), id)).getSingleOrDefault();
}
@Override
public List<UserRole> getUserRoles(UserInfo userInfo) {
return this.getDatabaseService().getQueryable(UserRole.class).where((builder, root) -> builder.equal(root.get("userInfo"),userInfo)).toList();
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);
}
@Override
public QueryableList<UserRole> getWithCriteria(UserRoleCriteria criteria) {
QueryableList<UserRole> query = this.getDatabaseService().getQueryable(UserRole.class);
if (criteria.getLike() != null)
query.where((builder, root) -> builder.equal(root.get("userInfo").get("name"), criteria.getLike()));
if (criteria.getAppRoles() != null && !criteria.getAppRoles().isEmpty())
query.where((builder, root) -> root.get("role").in(criteria.getAppRoles()));
return query;
}
@Override
public QueryableList<UserRole> asQueryable() {
return this.getDatabaseService().getQueryable(UserRole.class);
}
}

View File

@ -5,6 +5,7 @@ import eu.eudat.dao.databaselayer.service.DatabaseService;
import eu.eudat.entities.Credential;
import eu.eudat.entities.UserInfo;
import eu.eudat.models.login.Credentials;
import eu.eudat.queryable.QueryableList;
import eu.eudat.security.validators.TokenValidatorFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -39,4 +40,14 @@ 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);
}
@Override
public QueryableList<Credential> asQueryable() {
return this.getDatabaseService().getQueryable(Credential.class);
}
}

View File

@ -1,11 +1,13 @@
package eu.eudat.dao.entities.security;
import eu.eudat.dao.DatabaseAccessLayer;
import eu.eudat.entities.Credential;
import eu.eudat.entities.UserToken;
import java.util.UUID;
public interface UserTokenDao {
public interface UserTokenDao extends DatabaseAccessLayer<UserToken,UUID> {
UserToken createOrUpdate(UserToken item);

View File

@ -3,6 +3,7 @@ package eu.eudat.dao.entities.security;
import eu.eudat.dao.DatabaseAccess;
import eu.eudat.dao.databaselayer.service.DatabaseService;
import eu.eudat.entities.UserToken;
import eu.eudat.queryable.QueryableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -31,4 +32,9 @@ public class UserTokenDaoImpl extends DatabaseAccess<UserToken> implements UserT
public void delete(UserToken userToken) {
this.getDatabaseService().delete(userToken);
}
@Override
public QueryableList<UserToken> asQueryable() {
return this.getDatabaseService().getQueryable(UserToken.class);
}
}

View File

@ -62,10 +62,10 @@ public class UserInfo implements DataEntity<UserInfo>{
private Set<DMP> dmps;
@OneToMany(mappedBy="userInfo",fetch = FetchType.LAZY)
Set<Credential> credentials = new HashSet<>();
private Set<Credential> credentials = new HashSet<>();
@OneToMany(mappedBy="userInfo",fetch = FetchType.LAZY)
Set<UserRole> userRoles = new HashSet<>();
@OneToMany(mappedBy="userInfo",fetch = FetchType.EAGER)
private Set<UserRole> userRoles = new HashSet<>();
public Set<DMP> getDmps() {
return dmps;
@ -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

@ -3,16 +3,34 @@ package eu.eudat.managers;
import eu.eudat.dao.entities.DMPDao;
import eu.eudat.dao.entities.DatasetDao;
import eu.eudat.dao.entities.ProjectDao;
import eu.eudat.entities.DMP;
import eu.eudat.entities.Dataset;
import eu.eudat.entities.Project;
import eu.eudat.entities.UserInfo;
import eu.eudat.models.dashboard.DashBoardStatistics;
import eu.eudat.models.security.Principal;
import java.lang.reflect.Array;
import java.util.Arrays;
public class DashBoardManager {
public DashBoardStatistics getStatistics(DatasetDao datasetRepository,DMPDao dataManagementPlanRepository,ProjectDao projectRepository){
DashBoardStatistics statistics = new DashBoardStatistics();
statistics.setTotalDataManagementPlanCount(dataManagementPlanRepository.count());
statistics.setTotalDataSetCount(datasetRepository.count());
statistics.setTotalProjectCount(projectRepository.count());
return statistics;
}
public DashBoardStatistics getStatistics(DatasetDao datasetRepository, DMPDao dataManagementPlanRepository, ProjectDao projectRepository) {
DashBoardStatistics statistics = new DashBoardStatistics();
statistics.setTotalDataManagementPlanCount(dataManagementPlanRepository.count());
statistics.setTotalDataSetCount(datasetRepository.count());
statistics.setTotalProjectCount(projectRepository.count());
return statistics;
}
public DashBoardStatistics getMeStatistics(DatasetDao datasetRepository, DMPDao dataManagementPlanRepository, ProjectDao projectRepository, Principal principal) {
DashBoardStatistics statistics = new DashBoardStatistics();
UserInfo user = new UserInfo();
user.setId(principal.getId());
statistics.setTotalDataManagementPlanCount(dataManagementPlanRepository.asQueryable().where((builder, root) -> builder.equal(root.get("creator").get("id"), principal.getId())).count());
statistics.setTotalDataSetCount(datasetRepository.asQueryable().where((builder, root) -> builder.equal(root.get("creator").get("id"), principal.getId())).count());
statistics.setTotalProjectCount(projectRepository.asQueryable().where((builder, root) -> builder.equal(root.get("creationUser").get("id"), principal.getId())).count());
return statistics;
}
}

View File

@ -38,6 +38,7 @@ public class UserManager {
public static DataTableData<UserListingModel> getPaged(UserInfoDao userInfoDao, UserInfoTableRequestItem userInfoTableRequestItem) throws Exception {
QueryableList<eu.eudat.entities.UserInfo> users = userInfoDao.getWithCriteria(userInfoTableRequestItem.getCriteria());
QueryableList<eu.eudat.entities.UserInfo> pagedUsers = PaginationManager.applyPaging(users, userInfoTableRequestItem);
List<UserListingModel> modelUsers = new DomainModelConverter<eu.eudat.entities.UserInfo, UserListingModel>().fromDataModel(pagedUsers.toList(), UserListingModel.class);
DataTableData<UserListingModel> dataTableData = new DataTableData<>();
dataTableData.setData(modelUsers);
@ -47,8 +48,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

@ -2,9 +2,20 @@ package eu.eudat.models.criteria;
import eu.eudat.entities.UserInfo;
import java.util.List;
public class UserInfoCriteria extends Criteria<UserInfo> {
private String email;
private List<Integer> appRoles;
public List<Integer> getAppRoles() {
return appRoles;
}
public void setAppRoles(List<Integer> appRoles) {
this.appRoles = appRoles;
}
public String getEmail() {
return email;

View File

@ -0,0 +1,20 @@
package eu.eudat.models.criteria;
import eu.eudat.entities.UserRole;
import java.util.List;
/**
* Created by ikalyvas on 2/1/2018.
*/
public class UserRoleCriteria extends Criteria<UserRole> {
private List<Integer> appRoles;
public List<Integer> getAppRoles() {
return appRoles;
}
public void setAppRoles(List<Integer> appRoles) {
this.appRoles = appRoles;
}
}

View File

@ -1,8 +1,12 @@
package eu.eudat.models.userinfo;
import eu.eudat.models.criteria.UserInfoCriteria;
import eu.eudat.models.criteria.UserRoleCriteria;
import eu.eudat.models.helpers.requests.TableRequest;
import java.util.List;
public class UserInfoTableRequestItem extends TableRequest<UserInfoCriteria> {
}

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

@ -10,7 +10,7 @@ import javax.xml.crypto.Data;
import java.util.List;
import java.util.Set;
public interface QueryableList<T extends DataEntity<T>> {
public interface QueryableList<T extends DataEntity<T>> {
QueryableList<T> where(SinglePredicate<T> predicate);
<R> List<R> select(SelectPredicate<T, R> predicate);
@ -36,4 +36,5 @@ public interface QueryableList<T extends DataEntity<T>> {
QueryableList<T> withHint(String hint);
Long count();
}

View File

@ -22,7 +22,7 @@ public class QueryableHibernateList<T extends DataEntity<T>> implements Queryabl
private CriteriaQuery<T> query;
private Class<T> tClass;
private Root<T> root;
private List<Predicate> predicates = new LinkedList<Predicate>();
private List<SinglePredicate<T>> predicates = new LinkedList<>();
private List<Order> orderings = new LinkedList<>();
private List<Selection> fields = new LinkedList<>();
private Integer length;
@ -75,7 +75,7 @@ public class QueryableHibernateList<T extends DataEntity<T>> implements Queryabl
}
public QueryableList<T> where(SinglePredicate<T> predicate) {
this.predicates.add(predicate.applyPredicate(this.manager.getCriteriaBuilder(), this.root));
this.predicates.add(predicate);
return this;
}
@ -106,14 +106,23 @@ public class QueryableHibernateList<T extends DataEntity<T>> implements Queryabl
public Long count() {
CriteriaBuilder criteriaBuilder = this.manager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(this.tClass)));
criteriaQuery.where(this.predicates.toArray(new Predicate[this.predicates.size()]));
Root<T> root = criteriaQuery.from(tClass);
criteriaQuery.select(criteriaBuilder.count(root));
criteriaQuery.where(this.generateWherePredicates(this.predicates, root));
return this.manager.createQuery(criteriaQuery).getSingleResult();
}
private Predicate[] generateWherePredicates(List<SinglePredicate<T>> singlePredicates, Root<T> root) {
List<Predicate> predicates = new LinkedList<>();
for (SinglePredicate<T> singlePredicate : singlePredicates) {
predicates.add(singlePredicate.applyPredicate(this.manager.getCriteriaBuilder(), root));
}
return predicates.toArray(new Predicate[predicates.size()]);
}
public List<T> toList() {
this.query.where(this.predicates.toArray(new Predicate[this.predicates.size()]));
this.query.where(this.generateWherePredicates(this.predicates, this.root));
if (!this.orderings.isEmpty()) this.query.orderBy(this.orderings);
TypedQuery<T> typedQuery = this.manager.createQuery(this.query);
if (this.offset != null) typedQuery.setFirstResult(this.offset);
@ -126,18 +135,13 @@ public class QueryableHibernateList<T extends DataEntity<T>> implements Queryabl
}
public T getSingle() {
Predicate[] array = new Predicate[this.predicates.size()];
this.predicates.toArray(array);
this.query.where(array);
this.query.where(this.generateWherePredicates(this.predicates, this.root));
TypedQuery<T> typedQuery = this.manager.createQuery(this.query);
return typedQuery.getSingleResult();
}
public T getSingleOrDefault() {
Predicate[] array = new Predicate[this.predicates.size()];
this.predicates.toArray(array);
this.query.where(array);
this.query.where(this.generateWherePredicates(this.predicates, this.root));
TypedQuery<T> typedQuery = this.manager.createQuery(this.query);
List<T> results = typedQuery.getResultList();

View File

@ -782,7 +782,7 @@
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": {
"core-js": "2.5.0",
"core-js": "2.4.1",
"regenerator-runtime": "0.11.1"
}
},
@ -1618,9 +1618,9 @@
}
},
"core-js": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz",
"integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY="
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
"integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4="
},
"core-object": {
"version": "3.1.5",

View File

@ -27,7 +27,7 @@
"@ngx-translate/core": "^9.0.1",
"@ngx-translate/http-loader": "^2.0.0",
"core-js": "^2.4.1",
"rxjs": "5.5.6",
"rxjs": "^5.5.6",
"zone.js": "^0.8.17"
},
"devDependencies": {

View File

@ -13,8 +13,8 @@ const appRoutes: Routes = [
{ path: 'form', loadChildren: './dataset-profile-form/dataset-profile.module#DatasetProfileModule', 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 '../../login/Principal';
export class UserCriteria extends BaseCriteria {
public label: String;
public appRoles: 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
Admin = 2,
Manager = 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="like"
(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="appRoles"
(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.appRoles = item.appRoles;
return this.criteria;
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
like: [this.criteria.label, context.getValidation('label').validators],
appRoles: [this.criteria.appRoles, context.getValidation('appRoles').validators],
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'label' });
validationArray.push({ key: 'appRoles' });
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

@ -4,6 +4,7 @@
<button mat-button class="navbar-button" routerLink="/projects">{{'NAV-BAR.PROJECTS' | translate}}</button>
<button mat-button class="navbar-button" routerLink="/dmps">{{'NAV-BAR.DMPS' | translate}}</button>
<button mat-button class="navbar-button" routerLink="/datasets">{{'NAV-BAR.DATASETS' | translate}}</button>
<button *ngIf="isAdmin()" mat-button class="navbar-button" routerLink="/users">{{'NAV-BAR.USERS' | translate}}</button>
</div>
<span class="navbar-spacer"></span>
<div *ngIf="isAuthenticated()">

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%;
}

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