rsanchez
2017-03-22 60c65f2110f65221bc3a71b2887667e78c53c53e
#3527 fix - Added pack/license actions and a lot of bugfixing
19 files modified
changed files
securis/src/main/java/net/curisit/securis/DevFilter.java patch | view | blame | history
securis/src/main/webapp/package.json patch | view | blame | history
securis/src/main/webapp/src/app/app.module.ts patch | view | blame | history
securis/src/main/webapp/src/app/common/default.requests.options.ts patch | view | blame | history
securis/src/main/webapp/src/app/forms/base.ts patch | view | blame | history
securis/src/main/webapp/src/app/forms/license.form.component.ts patch | view | blame | history
securis/src/main/webapp/src/app/forms/license.form.html patch | view | blame | history
securis/src/main/webapp/src/app/forms/pack.form.component.ts patch | view | blame | history
securis/src/main/webapp/src/app/forms/pack.form.html patch | view | blame | history
securis/src/main/webapp/src/app/forms/user.form.component.ts patch | view | blame | history
securis/src/main/webapp/src/app/forms/user.form.html patch | view | blame | history
securis/src/main/webapp/src/app/listing/license.list.component.html patch | view | blame | history
securis/src/main/webapp/src/app/listing/license.list.component.ts patch | view | blame | history
securis/src/main/webapp/src/app/listing/pack.list.component.html patch | view | blame | history
securis/src/main/webapp/src/app/listing/pack.list.component.ts patch | view | blame | history
securis/src/main/webapp/src/app/resources/licenses.ts patch | view | blame | history
securis/src/main/webapp/src/app/resources/packs.ts patch | view | blame | history
securis/src/main/webapp/src/lang/messages_en.json patch | view | blame | history
securis/src/main/webapp/systemjs.config.js patch | view | blame | history
securis/src/main/java/net/curisit/securis/DevFilter.java
....@@ -35,7 +35,7 @@
3535 //res.addHeader("Access-Control-Request-Headers", "*");
3636 res.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
3737 res.addHeader("Access-Control-Allow-Headers", "X-SECURIS-TOKEN, Content-Type");
38
- res.addHeader("Access-Control-Expose-Headers", "X-SECURIS-ERROR-MSG, X-SECURIS-ERROR-CODE, Content-Type");
38
+ res.addHeader("Access-Control-Expose-Headers", "X-SECURIS-ERROR-MSG, X-SECURIS-ERROR-CODE, Content-Type, Content-Disposition");
3939
4040 // LOG.info("Added header to: " + res.getHeaderNames());
4141 if (!req.getMethod().equals("OPTIONS")) {
securis/src/main/webapp/package.json
....@@ -39,6 +39,7 @@
3939 "angular-2-local-storage": "^1.0.1",
4040 "angular-in-memory-web-api": "~0.2.4",
4141 "core-js": "^2.4.1",
42
+ "file-saver": "^1.3.3",
4243 "hammerjs": "^2.0.8",
4344 "ng2-toastr": "^1.5.1",
4445 "rxjs": "^5.0.1",
....@@ -46,6 +47,7 @@
4647 "zone.js": "^0.7.4"
4748 },
4849 "devDependencies": {
50
+ "@types/file-saver": "0.0.0",
4951 "@types/jasmine": "2.5.36",
5052 "@types/node": "^6.0.46",
5153 "canonical-path": "0.0.2",
securis/src/main/webapp/src/app/app.module.ts
....@@ -35,11 +35,11 @@
3535
3636 import { LoginFormComponent } from './forms/login.form.component';
3737 import { LicenseFormComponent } from './forms/license.form.component';
38
+import { ApplicationFormComponent } from './forms/application.form.component';
39
+import { PackFormComponent } from "./forms/pack.form.component";
3840 import { LicenseTypeFormComponent } from './forms/licensetype.form.component';
3941 import { OrganizationFormComponent } from './forms/organization.form.component';
4042 import { UserFormComponent } from './forms/user.form.component';
41
-import { ApplicationFormComponent } from './forms/application.form.component';
42
-import { PackFormComponent } from "./forms/pack.form.component";
4343
4444
4545 import { appRoutes, appRoutingProviders } from './app.routes';
securis/src/main/webapp/src/app/common/default.requests.options.ts
....@@ -23,11 +23,6 @@
2323
2424 // Set the default 'Content-Type' header
2525 this.headers.set('Content-Type', 'application/json');
26
- let token = this.store.get<string>('token');
27
- if (token) {
28
- this.headers.set('X-SECURIS-TOKEN', token);
29
-
30
- }
3126
3227 }
3328 }
....@@ -35,11 +30,15 @@
3530 @Injectable()
3631 export class ApiXHRBackend extends XHRBackend {
3732
38
- constructor(_browserXHR: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy) {
33
+ constructor(_browserXHR: BrowserXhr, _baseResponseOptions: ResponseOptions, _xsrfStrategy: XSRFStrategy, private store: LocalStorageService) {
3934 super(_browserXHR, _baseResponseOptions, _xsrfStrategy);
4035 }
4136
4237 createConnection(request: Request): XHRConnection {
38
+ let token = this.store.get<string>('token');
39
+ if (token) {
40
+ request.headers.set('X-SECURIS-TOKEN', token);
41
+ }
4342 if (!request.url.endsWith('.js') && !request.url.endsWith('.json') && !request.url.endsWith('.html') && !request.url.endsWith('.svg')){
4443 request.url = 'http://localhost:8080/securis/' + request.url; // prefix base url
4544 }
securis/src/main/webapp/src/app/forms/base.ts
....@@ -56,8 +56,8 @@
5656 protected abstract init(): void;
5757 protected abstract goBack(): void;
5858
59
- save() {
60
- var command = this.isNew ? this.resourceServices.create(this.data) : this.resourceServices.modify(this.data.id, this.data);
59
+ save(fieldId : string = 'id') {
60
+ var command = this.isNew ? this.resourceServices.create(this.data) : this.resourceServices.modify(this.data[fieldId], this.data);
6161 command.subscribe(
6262 data => {
6363 this.toaster.success(this.$L.get('{} saved sucessfully', this.resourceName.capitalize()));
....@@ -94,7 +94,7 @@
9494 this.form_title = this.$L.get('{} data', this.resourceName.capitalize());
9595 this.isNew = true;
9696 !!this.route && this.route.params.subscribe(params => {
97
- var eleId = +params[idparam]; // (+) converts string 'id' to a number
97
+ var eleId = params[idparam];
9898 if (!eleId) {
9999 this.data = {};
100100 Object.keys(default_values).forEach((k : string) => this.data[k] = default_values[k]);
securis/src/main/webapp/src/app/forms/license.form.component.ts
....@@ -50,7 +50,22 @@
5050 reader.readAsText(file);
5151 this.requestFileUploader.clear();
5252 }
53
+
54
+
55
+ licenseAction(action: string) {
56
+ return this.licenses[action](this.data.id).subscribe(
57
+ (actionResponse : any) => {
58
+ this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
59
+ this.reload();
60
+ },
61
+ (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
62
+ );
63
+ }
64
+
5365
66
+ canBeDeleted() : boolean {
67
+ return !this.isNew && this.licenses.isActionAvailable('delete', this.data);
68
+ }
5469
5570 requestFileUploaded(file: File) : void {
5671 console.log(file);
securis/src/main/webapp/src/app/forms/license.form.html
....@@ -39,7 +39,7 @@
3939 <field-readonly [value]="data.activation_code" label="field.activation_code" flex></field-readonly>
4040 </div>
4141 <div layout="row" layout-fill layout-padding *ngIf="!isNew">
42
- <field-readonly [value]="data.expiration_date | date: 'dateMedium'" label="field.expiration_date" flex></field-readonly>
42
+ <field-readonly [value]="data.expiration_date | date: 'mediumDate'" label="field.expiration_date" flex></field-readonly>
4343 <field-readonly [value]="licenses.getStatusName(data.status)" label="field.status" flex></field-readonly>
4444 </div>
4545 <div layout="row" layout-fill layout-padding>
....@@ -59,7 +59,7 @@
5959 <span i18n="field.email"></span>
6060 </md-placeholder>
6161 </md-input-container>
62
- <error-checker [fieldName]="$L.get('field.full_name')" [formField]="form.controls.email"></error-checker>
62
+ <error-checker [fieldName]="$L.get('field.email')" [formField]="form.controls.email"></error-checker>
6363 </div>
6464 </div>
6565 <div layout="row" layout-fill layout-padding>
....@@ -99,7 +99,16 @@
9999 <md-divider></md-divider>
100100 <md-card-actions>
101101 <div layout="row" layout-align="start center" class="margin">
102
+ <button *ngIf="canBeDeleted()" md-raised-button color="warn" (click)="delete(data.id)">Delete</button>
102103 <span flex></span>
104
+ <button md-icon-button [mdMenuTriggerFor]="licMenu" aria-label="License menu">
105
+ <md-icon>more_vert</md-icon>
106
+ </button>
107
+ <md-menu #licMenu="mdMenu">
108
+ <button md-menu-item *ngFor="let action of license_menu_options" (click)="licenseAction(action.command)" [disabled]="!licenses.isActionAvailable(action.command, data)">
109
+ <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
110
+ </button>
111
+ </md-menu>
103112 <button [disabled]="!form.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
104113 <button md-button (click)="goBack()">Cancel</button>
105114 </div>
securis/src/main/webapp/src/app/forms/pack.form.component.ts
....@@ -1,7 +1,7 @@
11 import { Http } from '@angular/http';
22 import { ToastsManager } from 'ng2-toastr/ng2-toastr';
33
4
-import { PacksService, PACK_STATUS } from '../resources/packs';
4
+import { PacksService, PACK_STATUS, PACK_ACTIONS } from '../resources/packs';
55 import { LicenseTypesService } from '../resources/license_types';
66 import { LocaleService } from '../common/i18n';
77 import { TdDataTableService, TdDataTableSortingOrder, ITdDataTableSortChangeEvent, ITdDataTableColumn } from '@covalent/core';
....@@ -21,7 +21,7 @@
2121
2222 organizations : IComboOption[];
2323 licensetypes : IComboOption[];
24
-
24
+ pack_menu_options = PACK_ACTIONS;
2525 constructor(private http: Http,
2626 private licenseTypes: LicenseTypesService,
2727 private packs: PacksService,
....@@ -65,11 +65,27 @@
6565 );
6666 }
6767
68
+ packAction(action: string) {
69
+ return this.packs[action](this.data.id).subscribe(
70
+ (actionResponse : any) => {
71
+ this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
72
+ this.reload();
73
+ },
74
+ (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
75
+ );
76
+ }
77
+
6878 changeOrg(event: any) {
69
- console.log(event);
7079 console.log(this.data.organization_id);
7180 }
72
-
81
+
82
+ canBeDeleted(event: any) : boolean{
83
+ return !this.isNew && this.packs.isActionAvailable('delete', this.data);
84
+ }
85
+
86
+ convertToEpoch(str: string) : number {
87
+ return new Date(str).getTime();
88
+ }
7389
7490 ngAfterViewInit(): void {
7591 this.init();
securis/src/main/webapp/src/app/forms/pack.form.html
....@@ -48,7 +48,8 @@
4848 <div layout="row" layout-fill layout-padding>
4949 <div layout="column" layout-fill flex>
5050 <md-input-container flex>
51
- <input mdInput type="date" [(ngModel)]="data.init_valid_date" name="init_valid_date" required />
51
+ <input mdInput type="date" [ngModel]="data.init_valid_date | date:'yyyy-MM-dd'"
52
+ (ngModelChange)="data.init_valid_date = $event" name="init_valid_date" required />
5253 <md-placeholder>
5354 <span i18n="field.end_valid_date"></span>
5455 </md-placeholder>
....@@ -57,7 +58,8 @@
5758 </div>
5859 <div layout="column" layout-fill flex>
5960 <md-input-container flex>
60
- <input mdInput type="date" [(ngModel)]="data.end_valid_date" name="end_valid_date" required />
61
+ <input mdInput type="date" [ngModel]="data.end_valid_date | date:'yyyy-MM-dd'"
62
+ (ngModelChange)="data.end_valid_date = $event" name="end_valid_date" required />
6163 <md-placeholder>
6264 <span i18n="field.end_valid_date"></span>
6365 </md-placeholder>
....@@ -133,7 +135,17 @@
133135 <md-divider></md-divider>
134136 <md-card-actions>
135137 <div layout="row" layout-align="start center" class="margin">
138
+ <button *ngIf="canBeDeleted()" md-raised-button color="warn" (click)="delete(data.id)">Delete</button>
136139 <span flex></span>
140
+
141
+ <button md-icon-button [mdMenuTriggerFor]="packMenu" aria-label="Pack menu">
142
+ <md-icon>more_vert</md-icon>
143
+ </button>
144
+ <md-menu #packMenu="mdMenu">
145
+ <button md-menu-item *ngFor="let action of pack_menu_options" (click)="packAction(action.command)" [disabled]="!packs.isActionAvailable(action.command, data)">
146
+ <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
147
+ </button>
148
+ </md-menu>
137149 <button [disabled]="!form.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
138150 <button md-button (click)="goBack()">Cancel</button>
139151 </div>
securis/src/main/webapp/src/app/forms/user.form.component.ts
....@@ -9,6 +9,7 @@
99 import { TdMediaService } from '@covalent/core';
1010 import { FormBase, IComboOption } from './base';
1111 import { ActivatedRoute, Router } from '@angular/router';
12
+import { OrganizationsService } from "../resources/organizations";
1213
1314 var user_example = {
1415 username: 'rym',
....@@ -27,10 +28,14 @@
2728 templateUrl: 'src/app/forms/user.form.html'
2829 })
2930 export class UserFormComponent extends FormBase {
30
-
31
+ allOrganizations: IComboOption[];
32
+ orgNames: string[] = [];
33
+ allRoles: any[] = [{"id":1, "code": "advance", "label":"Advance"}, {"id":2, "code": "admin","label":"Admin"}];
34
+ user_orgs: string[] = [];
35
+ user_roles: any = {};
3136 constructor(private http: Http,
3237 private users: UsersService,
33
- private applications: ApplicationsService,
38
+ private organizations: OrganizationsService,
3439 router: Router,
3540 toaster: ToastsManager,
3641 route: ActivatedRoute,
....@@ -39,16 +44,62 @@
3944 super($L, router, route, toaster, users, $L.get('user'), dialogs);
4045 }
4146
42
-
47
+ save() : void {
48
+ this.data.organizations_ids = [];
49
+ this.data.roles = [];
50
+ this.user_orgs.forEach(orgName => {
51
+ var selectedOrg = this.allOrganizations.find(org => org.label === orgName);
52
+ this.data.organizations_ids.push(selectedOrg.id);
53
+ });
54
+ this.user_roles.advance && this.data.roles.push(1);
55
+ this.user_roles.admin && this.data.roles.push(2);
56
+ super.save('username');
57
+ }
58
+
59
+ canBeDeleted() {
60
+ return this.data && this.data.username !== 'admin' && this.data.username !== '_client';
61
+ }
62
+
63
+ loadCombos() : void {
64
+ this.organizations.get()
65
+ .map(list => list.map((org : any) => <IComboOption>{id: org.id, label: org.name}))
66
+ .subscribe(
67
+ data => {
68
+ this.allOrganizations = (<IComboOption[]>data).sort((e1, e2) => e1.label.localeCompare(e2.label));
69
+ this.orgNames = this.allOrganizations.map(org => org.label);
70
+ this._loadOrgs();
71
+ },
72
+ err => console.error('Error loading organizations')
73
+ );
74
+ }
75
+
4376 goBack(): void {
4477 this.router.navigate([`users`]);
4578 }
46
-
79
+ _loadOrgs() {
80
+ if (this.data && this.data.organizations_ids && this.allOrganizations && this.allOrganizations.length > 0) {
81
+ this.data.organizations_ids.forEach((orgId : number) => {
82
+ var selectedOrg = this.allOrganizations.find(org => org.id === orgId);
83
+ this.user_orgs.push(selectedOrg.label);
84
+ });
85
+ }
86
+ }
4787 init() : void {
88
+ this.loadCombos();
89
+ this.user_orgs = [];
90
+ this.user_roles = {};
4891 super.setFirstFocus();
4992 super.reset();
5093 super.prepareInitialData('username', {
51
- metadata: []
94
+ organizations_ids: [],
95
+ roles: []
96
+ }, (data) => {
97
+ this._loadOrgs();
98
+ data.roles.forEach((roleId : number) => {
99
+ var selectedRole = this.allRoles.find(r => r.id === roleId);
100
+ this.user_roles[selectedRole.code] = true;
101
+ });
102
+
52103 });
53104 }
54105
securis/src/main/webapp/src/app/forms/user.form.html
....@@ -8,17 +8,15 @@
88 <button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
99 </md-toolbar>
1010 <!--
11
- code: 'CICS',
12
- creation_timestamp: 1418384439000,
13
- description: 'Wellbore integrity analysis software',
14
- id: 1,
15
- license_filename: 'config_server.lic',
16
- name: 'CurisIntegrity',
17
- metadata:
18
- [ { key: 'max_docs',
19
- value: '250000',
20
- readonly: true,
21
- mandatory: true } ]
11
+ username: 'rym',
12
+ roles: [ 1 ],
13
+ lastLogin: 1488885433000,
14
+ modificationTimestamp: 1479898458000,
15
+ email: 'rbouchair@curistec.com',
16
+ first_name: 'Rym',
17
+ last_name: 'Bouchair',
18
+ creation_timestamp: 1479898458000,
19
+ organizations_ids: [ 1, 2, 5, 6, 7, 8 ]
2220 }
2321 -->
2422 <div class="margin" layout-align-gt-xs="center start" layout-fill="" layout-gt-xs="row">
....@@ -31,59 +29,80 @@
3129 <form #form="ngForm" class="inset">
3230 <div layout="column" layout-align="start center">
3331 <div layout="row" layout-fill layout-padding>
34
- <field-readonly [value]="data.id" label="field.id" flex="15" *ngIf="!isNew"></field-readonly>
3532 <div layout="column" layout-fill flex>
3633 <md-input-container>
37
- <input #firstField mdInput maxLength="50" type="text" [(ngModel)]="data.code" name="code" required [readonly]="!isNew" />
34
+ <input #firstField mdInput maxLength="50" type="text" [(ngModel)]="data.username" name="username" required [readonly]="!isNew" />
3835 <md-placeholder>
39
- <span i18n="field.code"></span>
36
+ <span i18n="field.username"></span>
4037 </md-placeholder>
4138 </md-input-container>
42
- <error-checker [fieldName]="getFieldName('code')" [formField]="form.controls.code"></error-checker>
39
+ <error-checker [fieldName]="getFieldName('username')" [formField]="form.controls.username"></error-checker>
40
+ </div>
41
+ <div layout="column" layout-fill flex>
42
+ <md-input-container flex>
43
+ <input mdInput type="password" [(ngModel)]="data.password" name="password" [required]="isNew" />
44
+ <md-placeholder>
45
+ <span i18n="field.password"></span>
46
+ </md-placeholder>
47
+ </md-input-container>
48
+ <error-checker [fieldName]="getFieldName('password')" [formField]="form.controls.password"></error-checker>
4349 </div>
4450 </div>
4551 <div layout="row" layout-fill layout-padding>
4652 <div layout="column" layout-fill flex>
4753 <md-input-container flex>
48
- <input mdInput type="text" [(ngModel)]="data.name" name="name" required />
54
+ <input mdInput type="text" [(ngModel)]="data.first_name" name="first_name" required />
4955 <md-placeholder>
50
- <span i18n="field.name"></span>
56
+ <span i18n="field.first_name"></span>
5157 </md-placeholder>
5258 </md-input-container>
53
- <error-checker [fieldName]="getFieldName('name')" [formField]="form.controls.name"></error-checker>
59
+ <error-checker [fieldName]="getFieldName('first_name')" [formField]="form.controls.first_name"></error-checker>
5460 </div>
5561 <div layout="column" layout-fill flex>
5662 <md-input-container flex>
57
- <input mdInput type="text" [(ngModel)]="data.license_filename" name="license_filename" required />
63
+ <input mdInput type="text" [(ngModel)]="data.last_name" name="last_name" />
5864 <md-placeholder>
59
- <span i18n="field.license_filename"></span>
65
+ <span i18n="field.last_name"></span>
6066 </md-placeholder>
6167 </md-input-container>
62
- <error-checker [fieldName]="getFieldName('license_filename')" [formField]="form.controls.license_filename"></error-checker>
68
+ <error-checker [fieldName]="getFieldName('last_name')" [formField]="form.controls.last_name"></error-checker>
6369 </div>
6470 </div>
6571 <div layout="row" layout-fill layout-padding>
6672 <div layout="column" layout-fill flex>
6773 <md-input-container flex>
68
- <textarea mdInput type="text" type="text" [(ngModel)]="data.description" name="description" maxlength="1024"></textarea>
74
+ <input mdInput type="email" [(ngModel)]="data.email" name="email" required maxlength="200" />
6975 <md-placeholder>
70
- <span i18n="field.description"></span>
76
+ <span i18n="field.email"></span>
7177 </md-placeholder>
72
- <md-hint align="end">(max 1024)</md-hint>
7378 </md-input-container>
79
+ <error-checker [fieldName]="$L.get('field.email')" [formField]="form.controls.email"></error-checker>
80
+ </div>
81
+ </div>
82
+ <div layout="row" layout-fill layout-padding >
83
+ <td-chips flex [mdTooltip]="$L.get('Organizations that user can access')" [placeholder]="$L.get('Select organizations')"
84
+ [items]="orgNames" [(ngModel)]="user_orgs" name="user_orgs" requireMatch>
85
+ </td-chips>
86
+ <div layout="column" layout-fill flex="25">
87
+ <md-checkbox [(ngModel)]="user_roles.advance" name="advance_role" [mdTooltip]="$L.get('Role {}', 'advance')">
88
+ <span i18n>Advance</span>
89
+ </md-checkbox>
90
+ <md-checkbox [(ngModel)]="user_roles.admin" name="admin_role" [mdTooltip]="$L.get('Role {}', 'admin')">
91
+ <span i18n>Admin</span>
92
+ </md-checkbox>
7493 </div>
7594 </div>
7695 <div layout="row" layout-fill layout-padding *ngIf="!isNew">
96
+ <field-readonly [value]="data.lastLogin || '' | timeAgo" label="field.lastLogin" flex></field-readonly>
7797 <field-readonly [value]="data.creation_timestamp | date: 'medium'" label="field.creation_timestamp" flex></field-readonly>
7898 </div>
79
- <metadata-manager addOrDelete="true" editKeys="true" [metadata]="data.metadata" ></metadata-manager>
8099 </div>
81100 </form>
82101 </md-card-content>
83102 <md-divider></md-divider>
84103 <md-card-actions>
85104 <div layout="row" layout-align="start center" class="margin">
86
- <button *ngIf="!isNew" md-raised-button color="warn" (click)="delete(data.id)">Delete</button>
105
+ <button *ngIf="!isNew" [disabled]="!canBeDeleted()" md-raised-button color="warn" (click)="delete(data.username)">Delete</button>
87106 <span flex></span>
88107 <button [disabled]="!form.form.valid" md-raised-button color="primary" (click)="save()">Save</button>
89108 <button md-button (click)="goBack()">Cancel</button>
securis/src/main/webapp/src/app/listing/license.list.component.html
....@@ -40,9 +40,9 @@
4040 <span style="white-space: nowrap">{{value}}</span>
4141 </div>
4242 </template>
43
- <template tdDataTableTemplate="status" let-row="row">
43
+ <template tdDataTableTemplate="status" let-row="row" let-value="value">
4444 <div layout="row" layout-align="start center">
45
- <md-icon [style.color]="licenses.getStatusColor(row.status)">brightness_1</md-icon>&nbsp;<span>{{licenses.getStatusName(row.status)}}</span>
45
+ <md-chip selected [mdTooltip]="licenses.getStatusName(value)" [style.background-color]="licenses.getStatusColor(value)" >{{value}}</md-chip>
4646 </div>
4747 </template>
4848 <template tdDataTableTemplate="email" let-row="row" let-value="value">
....@@ -63,7 +63,7 @@
6363 <md-icon>more_vert</md-icon>
6464 </button>
6565 <md-menu #licenseMenu="mdMenu">
66
- <button md-menu-item *ngFor="let action of license_menu_options" (click)="licenseAction(action.command, row)" [disabled]="!isActionAvailable(row)">
66
+ <button md-menu-item *ngFor="let action of license_menu_options" (click)="licenseAction(action.command, row)" [disabled]="!isActionAvailable(action.command, row)">
6767 <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
6868 </button>
6969 </md-menu>
....@@ -74,4 +74,4 @@
7474 <span i18n td-paging-bar-label hide-xs>Rows per page:</span> {{pagingBar.range}} <span hide-xs>of {{pagingBar.total}}</span>
7575 </td-paging-bar>
7676 </div>
77
-</td-layout-card-over>
77
+</td-layout-card-over>
securis/src/main/webapp/src/app/listing/license.list.component.ts
....@@ -5,9 +5,10 @@
55 import { Component, AfterViewInit, ViewChild } from '@angular/core';
66 import { TdMediaService } from '@covalent/core';
77 import { Location } from '@angular/common';
8
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
89
910 import { LocaleService } from '../common/i18n';
10
-import { LicensesService } from '../resources/licenses';
11
+import { LicensesService, LICENSE_ACTIONS } from '../resources/licenses';
1112 import { PacksService } from '../resources/packs';
1213 import { LicenseFormComponent } from '../forms/license.form.component';
1314 import { ListingBase } from './base';
....@@ -43,22 +44,30 @@
4344 { name: 'menu', label: '' }
4445 ];
4546
46
- license_menu_options : any[] = [{
47
- icon: 'edit',
48
- command: 'edit',
49
- name: 'Edit'
50
- },{
51
- icon: 'cancel',
52
- command: 'cancel',
53
- name: 'Cancel'
54
- }]
47
+ license_menu_options = LICENSE_ACTIONS;
5548
56
- licenseAction(action: any) {
57
- console.log(action.command);
49
+ licenseAction(action: string, license: any) {
50
+ return this.licenses[action](license.id).subscribe(
51
+ (actionResponse : any) => {
52
+ this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
53
+ this.reload(this.pack.id);
54
+ },
55
+ (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
56
+ );
5857 }
5958
60
- isActionAvailable(pack : any) : boolean {
61
- return true;
59
+ reload(packId: number) : void {
60
+ this.licenses.getByPack(packId).subscribe(
61
+ list => {
62
+ this.data = list;
63
+ this.refresh();
64
+ },
65
+ err => console.error(err)
66
+ );
67
+ }
68
+
69
+ isActionAvailable(action: string, license : any) : boolean {
70
+ return this.licenses.isActionAvailable(action, license);
6271 }
6372
6473 constructor( _dataTableService: TdDataTableService,
....@@ -66,6 +75,7 @@
6675 private $L: LocaleService,
6776 private router: Router,
6877 private location: Location,
78
+ private toaster: ToastsManager,
6979 private route: ActivatedRoute,
7080 private dialog: MdDialog,
7181 private licenseForm: LicenseFormComponent,
....@@ -75,22 +85,6 @@
7585 }
7686
7787 ngOnInit(): void {
78
- this.route.params.subscribe(params => {
79
- var packId = +params['packId']; // (+) converts string 'id' to a number
80
- this.licenses.getByPack(packId).subscribe(
81
- list => {
82
- this.data = list;
83
- this.refresh();
84
- },
85
- err => console.error(err)
86
- );
87
- this.packs.get(packId).subscribe(
88
- packData => {
89
- this.pack = packData;
90
- },
91
- err => console.error(err)
92
- );
93
- });
9488 }
9589
9690 goBack() : void {
....@@ -111,7 +105,16 @@
111105
112106 ngAfterViewInit(): void {
113107 this.media.broadcast();
114
-
108
+ this.route.params.subscribe(params => {
109
+ var packId = +params['packId']; // (+) converts string 'id' to a number
110
+ this.reload(packId);
111
+ this.packs.get(packId).subscribe(
112
+ packData => {
113
+ this.pack = packData;
114
+ },
115
+ err => console.error(err)
116
+ );
117
+ });
115118 }
116119 }
117120
securis/src/main/webapp/src/app/listing/pack.list.component.html
....@@ -33,6 +33,11 @@
3333 <span style="white-space: nowrap">{{value}}</span>
3434 </div>
3535 </template>
36
+ <template tdDataTableTemplate="status" let-row="row" let-value="value">
37
+ <div layout="row" layout-align="start center">
38
+ <md-chip selected [mdTooltip]="$L.get('pack.status.' +value)" [style.background-color]="packs.getStatusColor(value)" >{{value}}</md-chip>
39
+ </div>
40
+ </template>
3641 <template tdDataTableTemplate="menu" let-row="row" let-index="index">
3742 <div layout="row" layout-align="end center">
3843 <button md-icon-button (click)="edit(row.id)" color="primary"><md-icon>edit</md-icon></button>
....@@ -41,7 +46,7 @@
4146 </button>
4247
4348 <md-menu #packMenu="mdMenu">
44
- <button md-menu-item *ngFor="let action of pack_menu_options" (click)="packAction(action.command, row)" [disabled]="!isActionAvailable(row)">
49
+ <button md-menu-item *ngFor="let action of pack_menu_options" (click)="packAction(action.command, row)" [disabled]="!packs.isActionAvailable(action.command, row)">
4550 <md-icon *ngIf="!!action.icon">{{ action.icon }}</md-icon> {{ action.name }}
4651 </button>
4752 </md-menu>
securis/src/main/webapp/src/app/listing/pack.list.component.ts
....@@ -1,4 +1,5 @@
11 import { Router, ActivatedRoute } from '@angular/router';
2
+import { ToastsManager } from 'ng2-toastr/ng2-toastr';
23 import { MdDialog, MdDialogConfig } from '@angular/material';
34 import {
45 ITdDataTableColumn,
....@@ -10,7 +11,7 @@
1011 import { IPageChangeEvent } from '@covalent/core';
1112 import { Component, ViewChild, AfterViewInit } from '@angular/core';
1213 import { TdMediaService } from '@covalent/core';
13
-import { PacksService } from '../resources/packs';
14
+import { PacksService, PACK_ACTIONS } from '../resources/packs';
1415 import { PackFormComponent } from '../forms/pack.form.component';
1516 import { LocaleService } from '../common/i18n';
1617 import { ListingBase } from './base';
....@@ -57,17 +58,11 @@
5758 { name: 'licensetype_code', label: 'License type' },
5859 { name: 'organization_name', label: 'Organization' },
5960 { name: 'used_licenses', label: 'Licenses', tooltip: 'Initial/Available pack licenses' },
61
+ { name: 'status', label: 'Status', tooltip: 'Pack status' },
6062 { name: 'menu', label: '' }
6163 ];
6264
63
- pack_menu_options : any[] = [{
64
- command: 'edit',
65
- name: 'Edit'
66
- },{
67
- command: 'cancel',
68
- name: 'Cancel'
69
- }]
70
-
65
+ pack_menu_options = PACK_ACTIONS;
7166
7267 constructor(_dataTableService: TdDataTableService,
7368 private media: TdMediaService,
....@@ -75,25 +70,30 @@
7570 private route: ActivatedRoute,
7671 private dialog: MdDialog,
7772 private $L: LocaleService,
73
+ private toaster: ToastsManager,
7874 private packForm: PackFormComponent,
7975 private packs: PacksService) {
8076 super(_dataTableService);
81
- this.packs.get().subscribe(
82
- (list : any[]) => {
83
- this.data = list;
84
- this.refresh();
85
- },
86
- (err: any) => console.error(err)
87
- );
8877 }
8978
90
-
91
- packAction(action: any) {
92
- console.log(action.command);
79
+ reload() : void {
80
+ this.packs.get().subscribe(
81
+ (list : any[]) => {
82
+ this.data = list;
83
+ this.refresh();
84
+ },
85
+ (err: any) => console.error(err)
86
+ );
9387 }
9488
95
- isActionAvailable(pack : any) : boolean {
96
- return true;
89
+ packAction(action: string, pack: any) {
90
+ return this.packs[action](pack.id).subscribe(
91
+ (actionResponse : any) => {
92
+ this.toaster.success(this.$L.get('Action "{}" executed successfully', action));
93
+ this.reload();
94
+ },
95
+ (err : any) => this.toaster.error(this.$L.get('Action "{}" failed', action))
96
+ );
9797 }
9898
9999 showLicenses(pack: any) : void {
....@@ -115,8 +115,8 @@
115115 }
116116
117117 ngAfterViewInit(): void {
118
+ this.reload();
118119 this.media.broadcast();
119
-
120120 }
121121 }
122122
securis/src/main/webapp/src/app/resources/licenses.ts
....@@ -1,26 +1,9 @@
11 import { LocaleService } from '../common/i18n';
22 import { Observable } from 'rxjs/Rx';
33 import { Injectable } from '@angular/core';
4
-import { Http, RequestOptions } from '@angular/http';
4
+import { Http, RequestOptions, ResponseContentType, Response } from '@angular/http';
55 import { SeCurisResourceServices } from './base';
6
-
7
-var lic_example = {
8
- id: 101,
9
- activation_code: 'f3e2d27e-7f81-4ac7-87ba-b9e38b4fdbb8',
10
- code: 'CITR01-436-1',
11
- code_suffix: 1,
12
- created_by_id: '_client',
13
- creation_timestamp: 1445898088000,
14
- email: 'GQuercia@trican.ca',
15
- expiration_date: 1487523828000,
16
- full_name: 'George Quercia',
17
- licenseData: '{"appCode":"CICS","appName":"CurisIntegrity","licenseCode":"CITR01-436-1","activationCode":"f3e2d27e-7f81-4ac7-87ba-b9e38b4fdbb8","expirationDate":1487523828416,"arch":"amd64","osName":"Windows 7","macAddresses":["C4-D9-87-5D-53-72","C4-D9-87-5D-53-76","FC-15-B4-EB-70-F9"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f","metadata":{"a2Mode":"false","datasetPrefix":"TR","extendedMode":"false","maxConcurrentInstances":"-1","maxInstances":"3","maxUsers":"0","maxWellLifeLines":"50","timeThreshold":"0"},"signature":"cjyLYFyhXpWWsMNnG6ER9mtCREgw02aQDnXPSQQWZtiLWbu/GyHZzK+1msLhwuKMGYG6I90s5wp82HVIqhIheHOsov3JfnHgNtYzf3BdkqUinwPFuDqPqkXz5Sjb6bouWkmvTI1TN/s4U2DJOXVnYN4FnYl0/dBTcU9RP4NZlQxMu6oFuRrZSMfdMCxEJYZAU62SWgTSurkdmHhFgwRjIwsOXRWHYsr6vGT//yILI7UvMGbMc6dRCGwyJLPNi4nXwF9PRMLinB7fYK8HxKylTJx2O7bvWCZd6EOdwi6gRI/0HhOqZ7E4DzBDrqEnsHeuH4L47DfRdIMGDnA492F+mg=="}',
18
- modification_timestamp: 1484931828000,
19
- pack_code: 'CITR01',
20
- pack_id: 12,
21
- request_data: '{"appCode":"CICS","activationCode":"f3e2d27e-7f81-4ac7-87ba-b9e38b4fdbb8","arch":"amd64","osName":"Windows 7","macAddresses":["C4-D9-87-5D-53-72","C4-D9-87-5D-53-76","FC-15-B4-EB-70-F9"],"crcLogo":"10f6379e0e1c00ebc403160307e3c5d0aba0727c9cae0bf1ac7cd19d84fdc80f"}',
22
- status: 'AC'
23
-}
6
+import * as saveAsFile from "file-saver";
247
258 export const LIC_STATUS = {
269 CREATED: 'CR',
....@@ -41,6 +24,7 @@
4124 'CA': '#a21717'
4225 };
4326
27
+
4428 /**
4529 * These transitions could be get from server, class License.Status, but
4630 * we copy them for simplicity, this info won't change easily
....@@ -56,6 +40,37 @@
5640 cancel: [LIC_STATUS.REQUESTED, LIC_STATUS.EXPIRED, LIC_STATUS.PREACTIVE, LIC_STATUS.ACTIVE],
5741 'delete': [LIC_STATUS.CREATED, LIC_STATUS.CANCELLED, LIC_STATUS.BLOCKED]
5842 }
43
+
44
+export const LICENSE_ACTIONS : any[] = [{
45
+/* command: 'add_request',
46
+ icon: 'add_to_photos',
47
+ name: 'Add request'
48
+ },{ */
49
+ command: 'activate',
50
+ icon: 'play_circle_outline',
51
+ name: 'Activate'
52
+ },{
53
+ command: 'send',
54
+ icon: 'send',
55
+ name: 'Send'
56
+ },{
57
+ command: 'download',
58
+ icon: 'file_download',
59
+ name: 'Download'
60
+ },{
61
+ command: 'block',
62
+ icon: 'do_not_disturb_on',
63
+ name: 'Block'
64
+ },{
65
+ command: 'unblock',
66
+ icon: 'do_not_disturb_off',
67
+ name: 'Unblock'
68
+ },{
69
+ command: 'cancel',
70
+ icon: 'cancel',
71
+ name: 'Cancel'
72
+ }]
73
+
5974
6075 @Injectable()
6176 export class LicensesService extends SeCurisResourceServices {
....@@ -73,19 +88,36 @@
7388 return super.action(id, "activate");
7489 }
7590
91
+ public block(id: number) {
92
+ return super.action(id, "block");
93
+ }
94
+
95
+ public unblock(id: number) {
96
+ return super.action(id, "unblock");
97
+ }
98
+
99
+ public send(id: number) {
100
+ return super.action(id, "send");
101
+ }
102
+
76103 public cancel(id: number) {
77104 return super.action(id, "cancel");
78105 }
79106
80
- public putonhold(id: number) {
81
- return super.action(id, "putonhold");
107
+ public download(id: number) {
108
+ let url = `${this.resource}/${id}/download`;
109
+ return this.http.get(url).map((response : Response) => {
110
+ let filename = JSON.parse(response.headers.get('Content-Disposition').match(/".*"$/g)[0]);
111
+ let content = JSON.stringify(response.json(), null, 2);
112
+ saveAsFile( new Blob([ content ], { type : 'application/octet-stream' }), filename);
113
+ return Observable.of(true);
114
+ }).catch(err => super.processErrorResponse(err));
82115 }
83116
84117 public isActionAvailable(action:string, lic:any) {
85118 var validStatuses = LIC_ACTIONS_BY_STATUS[action];
86119 return lic && validStatuses && validStatuses.indexOf(lic.status) !== -1;
87120 }
88
-
89121
90122 getStatusName(statusCode: string): string {
91123 return this.$L.get(`pack.status.${statusCode}`, this.$L.get('Unknown'));
securis/src/main/webapp/src/app/resources/packs.ts
....@@ -57,6 +57,21 @@
5757 'delete': [PACK_STATUS.CREATED, PACK_STATUS.CANCELLED]
5858 }
5959
60
+export const PACK_ACTIONS : any[] = [{
61
+ command: 'activate',
62
+ icon: 'play_circle_outline',
63
+ name: 'Activate'
64
+ },{
65
+ command: 'putonhold',
66
+ icon: 'pause_circle_outline',
67
+ name: 'Put on hold'
68
+ },{
69
+ command: 'cancel',
70
+ icon: 'cancel',
71
+ name: 'Cancel'
72
+ }]
73
+
74
+
6075
6176 @Injectable()
6277 export class PacksService extends SeCurisResourceServices {
securis/src/main/webapp/src/lang/messages_en.json
....@@ -20,11 +20,17 @@
2020 "field.metadata": "Metadata",
2121 "field.key": "Parameter",
2222 "field.value": "Value",
23
+ "field.username": "Username",
24
+ "field.password": "Password",
25
+ "field.first_name": "Firstname",
26
+ "field.last_name": "Lastname",
2327 "field.created_by": "Created by",
2428 "field.creation_date": "Creation date",
29
+ "field.expiration_date": "Expiration date",
2530 "field.request_data": "Request data",
26
- "field.full_name": "Full name",
31
+ "field.full_name": "Fullname",
2732 "field.email": "Email",
33
+ "field.lastLogin": "Last login",
2834 "field.creation_timestamp": "Creation timestamp",
2935 "field.comments": "Comments",
3036 "field.mandatory": "Required",
securis/src/main/webapp/systemjs.config.js
....@@ -16,6 +16,7 @@
1616 // other libraries
1717 'rxjs': 'npm:rxjs',
1818 'ng2-toastr': 'npm:ng2-toastr',
19
+ 'file-saver': 'npm:file-saver/FileSaver.js',
1920 'angular-2-local-storage': 'npm:angular-2-local-storage/dist',
2021 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
2122 }