SPA: Fix delete basket http call that was not working
This commit is contained in:
parent
6d5ff94cad
commit
ab20a93118
@ -1,5 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Response, Headers } from '@angular/http';
|
import { Response, Headers } from '@angular/http';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { DataService } from '../shared/services/data.service';
|
import { DataService } from '../shared/services/data.service';
|
||||||
import { SecurityService } from '../shared/services/security.service';
|
import { SecurityService } from '../shared/services/security.service';
|
||||||
@ -22,7 +23,7 @@ export class BasketService {
|
|||||||
items: []
|
items: []
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private service: DataService, private authService: SecurityService, private basketEvents: BasketWrapperService) {
|
constructor(private service: DataService, private authService: SecurityService, private basketEvents: BasketWrapperService, private router: Router) {
|
||||||
this.basket.items = [];
|
this.basket.items = [];
|
||||||
|
|
||||||
// Init:
|
// Init:
|
||||||
@ -35,7 +36,9 @@ export class BasketService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.basketEvents.orderCreated$.subscribe(x => this.dropBasket());
|
this.basketEvents.orderCreated$.subscribe(x => {
|
||||||
|
this.dropBasket();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setBasket(item): Observable<boolean> {
|
setBasket(item): Observable<boolean> {
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'appc-page-heading',
|
|
||||||
template: `<h4>{{text}}</h4>`
|
|
||||||
})
|
|
||||||
export class PageHeadingComponent {
|
|
||||||
@Input() text: string;
|
|
||||||
constructor() { }
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import {
|
|
||||||
fakeAsync,
|
|
||||||
tick,
|
|
||||||
TestBed
|
|
||||||
} from '@angular/core/testing';
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
import { By } from '@angular/platform-browser/src/dom/debug/by';
|
|
||||||
|
|
||||||
// Load the implementations that should be tested
|
|
||||||
import { XLargeDirective } from './x-large.directive';
|
|
||||||
|
|
||||||
describe('x-large directive', () => {
|
|
||||||
// Create a test component to test directives
|
|
||||||
@Component({
|
|
||||||
template: '<div x-large>Content</div>'
|
|
||||||
})
|
|
||||||
class TestComponent { }
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [
|
|
||||||
XLargeDirective,
|
|
||||||
TestComponent
|
|
||||||
]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sent font-size to x-large', fakeAsync(() => {
|
|
||||||
TestBed.compileComponents().then(() => {
|
|
||||||
|
|
||||||
const fixture = TestBed.createComponent(TestComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
tick();
|
|
||||||
const element = fixture.debugElement.query(By.css('div'));
|
|
||||||
|
|
||||||
// expect(element.nativeElement.style.fontSize).toBe('x-large');
|
|
||||||
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
@ -1,18 +0,0 @@
|
|||||||
import { Directive, ElementRef, Renderer } from '@angular/core';
|
|
||||||
/*
|
|
||||||
* Directive
|
|
||||||
* XLarge is a simple directive to show how one is made
|
|
||||||
*/
|
|
||||||
@Directive({
|
|
||||||
selector: '[appdXlarge]' // using [ ] means selecting attributes
|
|
||||||
})
|
|
||||||
export class XLargeDirective {
|
|
||||||
constructor(element: ElementRef, renderer: Renderer) {
|
|
||||||
// simple DOM manipulation to set font size to x-large
|
|
||||||
// `nativeElement` is the direct reference to the DOM element
|
|
||||||
// element.nativeElement.style.fontSize = 'x-large';
|
|
||||||
|
|
||||||
// for server/webworker support use the renderer
|
|
||||||
renderer.setElementStyle(element.nativeElement, 'fontSize', 'x-large');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
export class ControlBase<T>{
|
|
||||||
value: T;
|
|
||||||
key: string;
|
|
||||||
label: string;
|
|
||||||
placeholder: string;
|
|
||||||
required: boolean;
|
|
||||||
minlength: number;
|
|
||||||
maxlength: number;
|
|
||||||
order: number;
|
|
||||||
type: string;
|
|
||||||
class: string;
|
|
||||||
|
|
||||||
constructor(options: {
|
|
||||||
value?: T,
|
|
||||||
key?: string,
|
|
||||||
label?: string,
|
|
||||||
placeholder?: string,
|
|
||||||
required?: boolean,
|
|
||||||
minlength?: number,
|
|
||||||
maxlength?: number,
|
|
||||||
order?: number,
|
|
||||||
type?: string,
|
|
||||||
class?: string;
|
|
||||||
} = {}) {
|
|
||||||
this.value = options.value;
|
|
||||||
this.key = options.key || '';
|
|
||||||
this.label = options.label || '';
|
|
||||||
this.placeholder = options.placeholder || '';
|
|
||||||
this.required = !!options.required;
|
|
||||||
this.minlength = options.minlength;
|
|
||||||
this.maxlength = options.maxlength;
|
|
||||||
this.order = options.order === undefined ? 1 : options.order;
|
|
||||||
this.type = options.type || '';
|
|
||||||
this.class = options.class || '';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { ControlBase } from './control-base';
|
|
||||||
|
|
||||||
export class ControlCheckbox extends ControlBase<string> {
|
|
||||||
type: string;
|
|
||||||
|
|
||||||
constructor(options: any = {}) {
|
|
||||||
super(options);
|
|
||||||
this.type = 'checkbox';
|
|
||||||
this.value = options.value || false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { ControlBase } from './control-base';
|
|
||||||
|
|
||||||
export class ControlDropdown extends ControlBase<string> {
|
|
||||||
options: { key: string, value: string }[] = [];
|
|
||||||
|
|
||||||
constructor(options: any = {}) {
|
|
||||||
super(options);
|
|
||||||
this.type = 'dropdown';
|
|
||||||
this.options = options.options || [];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { ControlBase } from './control-base';
|
|
||||||
|
|
||||||
export class ControlTextbox extends ControlBase<boolean> {
|
|
||||||
constructor(options: any = {}) {
|
|
||||||
super(options);
|
|
||||||
this.type = options.type || 'textbox';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<!--{{f.controls[control.key] | json}}-->
|
|
||||||
<div #f="ngForm" [formGroup]="form" [ngSwitch]="control.type" class="form-group {{control.class}}" [class.has-danger]="invalid"
|
|
||||||
[class.has-success]="valid" [class.form-check]="control.type === 'checkbox'">
|
|
||||||
|
|
||||||
<label *ngSwitchCase="'dropdown'" [attr.for]="control.key" class="col-form-label">{{control.label}}</label>
|
|
||||||
<select *ngSwitchCase="'dropdown'" [id]="control.key" [formControlName]="control.key" [class.form-control-success]="valid"
|
|
||||||
[class.form-control-danger]="invalid" class="form-control">
|
|
||||||
<option *ngFor="let opt of control.options" [value]="opt.key">{{opt.value}}</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<label *ngSwitchCase="'checkbox'" [attr.for]="control.key" class="form-check-label">
|
|
||||||
<input #ck *ngSwitchCase="'checkbox'" (change)="control.value = ck.checked" [id]="control.key" [formControlName]="control.key"
|
|
||||||
[type]="control.type" class="form-check-input">
|
|
||||||
{{control.label}}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<!--This is not the switch case because of multiple control types-->
|
|
||||||
<label *ngIf="control.type === 'textbox' || control.type === 'email' || control.type === 'password'" [attr.for]="control.key" class="col-form-label">{{control.label}}</label>
|
|
||||||
<input *ngIf="control.type === 'textbox' || control.type === 'email' || control.type === 'password'" [id]="control.key" [formControlName]="control.key" [type]="control.type"
|
|
||||||
[placeholder]="control.placeholder" [class.form-control-success]="valid" [class.form-control-danger]="invalid" class="form-control">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<appc-control-error-message [form]="f" [control]="control"></appc-control-error-message>
|
|
||||||
|
|
||||||
</div>
|
|
@ -1,26 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
import { FormGroup } from '@angular/forms';
|
|
||||||
import { ControlBase } from './control-base';
|
|
||||||
import { ErrorMessageComponent } from './error-message.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'appc-dynamic-control',
|
|
||||||
templateUrl: './dynamic-form-control.component.html'
|
|
||||||
})
|
|
||||||
export class DynamicFormControlComponent {
|
|
||||||
@Input() control;
|
|
||||||
@Input() form;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.control = undefined;
|
|
||||||
this.form = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
get valid() {
|
|
||||||
return this.form.controls[this.control.key].valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
get invalid() {
|
|
||||||
return !this.form.controls[this.control.key].valid && this.form.controls[this.control.key].touched;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
<form class="{{formClass}}" (ngSubmit)="onSubmit()" [formGroup]="form" novalidate role="form">
|
|
||||||
<appc-dynamic-control *ngFor="let ctrl of controls" [control]="ctrl" [form]="form"></appc-dynamic-control>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary pull-right" [disabled]="!form.valid">{{btnText}}</button>
|
|
||||||
</form>
|
|
@ -1,30 +0,0 @@
|
|||||||
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
|
||||||
import { FormGroup } from '@angular/forms';
|
|
||||||
|
|
||||||
import { ControlBase } from './control-base';
|
|
||||||
import { FormControlService } from './form-control.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'appc-dynamic-form',
|
|
||||||
templateUrl: './dynamic-form.component.html'
|
|
||||||
})
|
|
||||||
export class DynamicFormComponent implements OnInit {
|
|
||||||
|
|
||||||
@Input() controls: ControlBase<any>[] = [];
|
|
||||||
@Input() btnText: string = 'Submit'; // Default value at least
|
|
||||||
@Input() formClass: string = 'form-horizontal';
|
|
||||||
// Note: don't keep name of output events as same as native events such as submit etc.
|
|
||||||
@Output() formsubmit: EventEmitter<any> = new EventEmitter<any>();
|
|
||||||
form: FormGroup;
|
|
||||||
|
|
||||||
constructor(private _controlService: FormControlService) { }
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
let sortedControls = this.controls.sort((a, b) => a.order - b.order);
|
|
||||||
this.form = this._controlService.toControlGroup(sortedControls);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
this.formsubmit.emit(this.form.value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import { Component, Host, Input } from '@angular/core';
|
|
||||||
import { FormGroupDirective } from '@angular/forms';
|
|
||||||
|
|
||||||
import { ControlBase } from './control-base';
|
|
||||||
import { ValidationService } from './validation.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'appc-control-error-message',
|
|
||||||
template: `<div *ngIf="errorMessage" class="form-control-feedback"> {{errorMessage}} </div>`
|
|
||||||
})
|
|
||||||
export class ErrorMessageComponent {
|
|
||||||
@Input() control: ControlBase<any>;
|
|
||||||
@Input() form: FormGroupDirective;
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
get errorMessage() {
|
|
||||||
let c = this.form.form.get(this.control.key);
|
|
||||||
for (let propertyName in c.errors) {
|
|
||||||
if (c.errors.hasOwnProperty(propertyName) && c.touched) {
|
|
||||||
return ValidationService.getValidatorErrorMessage(propertyName, this.control.minlength || this.control.maxlength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
<div class="alert alert-danger" *ngIf="errors?.length > 0">
|
|
||||||
<ul>
|
|
||||||
<li *ngFor="let error of errors">
|
|
||||||
{{error}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
@ -1,11 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'appc-error-summary',
|
|
||||||
templateUrl: './error-summary.component.html'
|
|
||||||
})
|
|
||||||
export class ErrorSummaryComponent {
|
|
||||||
@Input() errors: string | string[];
|
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
|
||||||
|
|
||||||
import { ControlBase } from './control-base';
|
|
||||||
import { ValidationService } from './validation.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FormControlService {
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
toControlGroup(controls: ControlBase<any>[]) {
|
|
||||||
let group: any = {};
|
|
||||||
|
|
||||||
controls.forEach(control => {
|
|
||||||
let validators = [];
|
|
||||||
// Required
|
|
||||||
if (control.required) {
|
|
||||||
validators.push(Validators.required);
|
|
||||||
}
|
|
||||||
// Minlength
|
|
||||||
if (control.minlength) {
|
|
||||||
validators.push(Validators.minLength(control.minlength));
|
|
||||||
}
|
|
||||||
// Maxlength
|
|
||||||
if (control.maxlength) {
|
|
||||||
validators.push(Validators.minLength(control.maxlength));
|
|
||||||
}
|
|
||||||
// Email
|
|
||||||
if (control.type === 'email') {
|
|
||||||
validators.push(ValidationService.emailValidator);
|
|
||||||
}
|
|
||||||
// Password
|
|
||||||
if (control.type === 'password') {
|
|
||||||
validators.push(ValidationService.passwordValidator);
|
|
||||||
}
|
|
||||||
group[control.key] = new FormControl(control.value || '', validators);
|
|
||||||
});
|
|
||||||
|
|
||||||
return new FormGroup(group);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
export class ValidationService {
|
|
||||||
|
|
||||||
static getValidatorErrorMessage(code: string, fieldLength: number) {
|
|
||||||
let config: any = {
|
|
||||||
'required': 'This is a required field',
|
|
||||||
'minlength': 'Minimum length is ' + fieldLength,
|
|
||||||
'maxlength': 'Maximum length is ' + fieldLength,
|
|
||||||
'invalidCreditCard': 'Invalid credit card number',
|
|
||||||
'invalidEmailAddress': 'Invalid email address',
|
|
||||||
'invalidPassword': 'Password must be at least 6 characters long, and contain a number and special character.'
|
|
||||||
};
|
|
||||||
return config[code];
|
|
||||||
}
|
|
||||||
|
|
||||||
static creditCardValidator(control: any) {
|
|
||||||
// Visa, MasterCard, American Express, Diners Club, Discover, JCB
|
|
||||||
if (control.value.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) {
|
|
||||||
return undefined;
|
|
||||||
} else {
|
|
||||||
return { 'invalidCreditCard': true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static emailValidator(control: any) {
|
|
||||||
// RFC 2822 compliant regex
|
|
||||||
if (control.value.match(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/)) {
|
|
||||||
return undefined;
|
|
||||||
} else {
|
|
||||||
return { 'invalidEmailAddress': true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static passwordValidator(control: any) {
|
|
||||||
// {6,100} - Assert password is between 6 and 100 characters
|
|
||||||
// (?=.*[0-9]) - Assert a string has at least one number
|
|
||||||
if (control.value.match(/^(?=.*[0-9])[a-zA-Z0-9!"@#$%^&*]{6,100}$/)) {
|
|
||||||
return undefined;
|
|
||||||
} else {
|
|
||||||
return { 'invalidPassword': true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -42,7 +42,7 @@ export class DataService {
|
|||||||
}).catch(this.handleError);
|
}).catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(url: string, params?: any): Observable<Response> {
|
delete(url: string, params?: any) {
|
||||||
let options: RequestOptionsArgs = {};
|
let options: RequestOptionsArgs = {};
|
||||||
|
|
||||||
if (this.securityService) {
|
if (this.securityService) {
|
||||||
@ -51,12 +51,13 @@ export class DataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('data.service deleting');
|
console.log('data.service deleting');
|
||||||
return this.http.delete(url, options).map(
|
//return this.http.delete(url, options).subscribe(
|
||||||
(res: Response) => {
|
// return res;
|
||||||
console.log('response from server in delete operation');
|
// );
|
||||||
console.log(res);
|
|
||||||
return res;
|
this.http.delete(url, options).subscribe((res) => {
|
||||||
}).catch(this.handleError);
|
console.log('deleted');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError(error: any) {
|
private handleError(error: any) {
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UtilityService {
|
|
||||||
|
|
||||||
private _router: Router;
|
|
||||||
|
|
||||||
constructor(router: Router) {
|
|
||||||
this._router = router;
|
|
||||||
}
|
|
||||||
|
|
||||||
convertDateTime(date: Date) {
|
|
||||||
let _formattedDate = new Date(date.toString());
|
|
||||||
return _formattedDate.toDateString();
|
|
||||||
}
|
|
||||||
|
|
||||||
navigate(path: string) {
|
|
||||||
this._router.navigate([path]);
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateToSignIn() {
|
|
||||||
this.navigate('/login');
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,17 +5,8 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { HttpModule, JsonpModule } from '@angular/http';
|
import { HttpModule, JsonpModule } from '@angular/http';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
import { PageHeadingComponent } from './directives/page-heading.directive';
|
|
||||||
import { DynamicFormComponent } from './forms/dynamic-form.component';
|
|
||||||
import { DynamicFormControlComponent } from './forms/dynamic-form-control.component';
|
|
||||||
import { ErrorMessageComponent } from './forms/error-message.component';
|
|
||||||
import { ErrorSummaryComponent } from './forms/error-summary.component';
|
|
||||||
import { FormControlService } from './forms/form-control.service';
|
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { DataService } from './services/data.service';
|
import { DataService } from './services/data.service';
|
||||||
import { UtilityService } from './services/utility.service';
|
|
||||||
import { UppercasePipe } from './pipes/uppercase.pipe';
|
|
||||||
import { BasketWrapperService} from './services/basket.wrapper.service';
|
import { BasketWrapperService} from './services/basket.wrapper.service';
|
||||||
import { SecurityService } from './services/security.service';
|
import { SecurityService } from './services/security.service';
|
||||||
|
|
||||||
@ -36,12 +27,6 @@ import { Identity } from './components/identity/identity';
|
|||||||
JsonpModule
|
JsonpModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
DynamicFormComponent,
|
|
||||||
DynamicFormControlComponent,
|
|
||||||
ErrorMessageComponent,
|
|
||||||
ErrorSummaryComponent,
|
|
||||||
PageHeadingComponent,
|
|
||||||
UppercasePipe,
|
|
||||||
Pager,
|
Pager,
|
||||||
Header,
|
Header,
|
||||||
Identity
|
Identity
|
||||||
@ -54,14 +39,6 @@ import { Identity } from './components/identity/identity';
|
|||||||
RouterModule,
|
RouterModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
// Providers, Components, directive, pipes
|
// Providers, Components, directive, pipes
|
||||||
DynamicFormComponent,
|
|
||||||
DynamicFormControlComponent,
|
|
||||||
ErrorSummaryComponent,
|
|
||||||
ErrorMessageComponent,
|
|
||||||
//FooterComponent,
|
|
||||||
//HeaderComponent,
|
|
||||||
PageHeadingComponent,
|
|
||||||
UppercasePipe,
|
|
||||||
Pager,
|
Pager,
|
||||||
Header,
|
Header,
|
||||||
Identity
|
Identity
|
||||||
@ -74,8 +51,6 @@ export class SharedModule {
|
|||||||
providers: [
|
providers: [
|
||||||
// Providers
|
// Providers
|
||||||
DataService,
|
DataService,
|
||||||
FormControlService,
|
|
||||||
UtilityService,
|
|
||||||
BasketWrapperService,
|
BasketWrapperService,
|
||||||
SecurityService
|
SecurityService
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user