diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 75f12fb..f4a576a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -6,24 +6,22 @@ import { UserListComponent } from './user-list/user-list.component'; import { ErrorMetadataService } from './services/error-metadata.service'; import { HighlightTextPipe } from './pipes/highlight-text.pipe'; -import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; -import { UserListInterceptorService } from './mocks/user-list-interceptor.service'; +import { FilterLocationidPipe } from './pipes/filter-locationid.pipe'; @NgModule({ - declarations: [ - AppComponent, - UserListComponent, - HighlightTextPipe - ], - imports: [ - BrowserModule, - AppRoutingModule, - HttpClientModule - ], - providers: [ - // { provide: ErrorHandler, useClass: ErrorMetadataService }, - { provide: HTTP_INTERCEPTORS, useClass: UserListInterceptorService, multi: true } - ], - bootstrap: [AppComponent] + declarations: [ + AppComponent, + UserListComponent, + HighlightTextPipe, + FilterLocationidPipe + ], + imports: [ + BrowserModule, + AppRoutingModule + ], + providers: [ + { provide: ErrorHandler, useClass: ErrorMetadataService } + ], + bootstrap: [AppComponent] }) export class AppModule { } diff --git a/src/app/mocks/user-list-interceptor.service.spec.ts b/src/app/mocks/user-list-interceptor.service.spec.ts index 1668494..dccec07 100644 --- a/src/app/mocks/user-list-interceptor.service.spec.ts +++ b/src/app/mocks/user-list-interceptor.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; - -import { UserListInterceptorService } from './user-list-interceptor.service'; - -describe('UserListInterceptorService', () => { - let service: UserListInterceptorService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(UserListInterceptorService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); +import { TestBed } from '@angular/core/testing'; + +import { UserListInterceptorService } from './user-list-interceptor.service'; + +describe('UserListInterceptorService', () => { + let service: UserListInterceptorService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UserListInterceptorService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/mocks/user-list-interceptor.service.ts b/src/app/mocks/user-list-interceptor.service.ts index 71e9900..e1a315d 100644 --- a/src/app/mocks/user-list-interceptor.service.ts +++ b/src/app/mocks/user-list-interceptor.service.ts @@ -1,41 +1,50 @@ -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - -@Injectable({ - providedIn: 'root' -}) -export class UserListInterceptorService implements HttpInterceptor { - private readonly API_URL = '/mock/api/filter'; - private readonly STORAGE_KEY = 'MOCK_API_FILTER'; - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - - if (request.url === this.API_URL && request.method === 'GET') { - return this.getFilter(); - } - - if (request.url === this.API_URL && request.method === 'PUT') { - return this.setFilter(request.body); - } - - return next.handle(request); - } - - private getFilter(): Observable> { - return new Observable(observer => { - observer.next(new HttpResponse({ - status: 200, - body: window.localStorage.getItem(this.STORAGE_KEY) - })); - - observer.complete(); - }); - } - - private setFilter(filter: string): Observable> { - window.localStorage.setItem(this.STORAGE_KEY, filter); - return this.getFilter(); - } - -} +import { + HttpEvent, + HttpHandler, + HttpInterceptor, + HttpRequest, + HttpResponse, +} from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class UserListInterceptorService implements HttpInterceptor { + private readonly API_URL = '/mock/api/filter'; + private readonly STORAGE_KEY = 'MOCK_API_FILTER'; + + intercept( + request: HttpRequest, + next: HttpHandler, + ): Observable> { + if (request.url === this.API_URL && request.method === 'GET') { + return this.getFilter(); + } + + if (request.url === this.API_URL && request.method === 'PUT') { + return this.setFilter(request.body); + } + + return next.handle(request); + } + + private getFilter(): Observable> { + return new Observable((observer) => { + observer.next( + new HttpResponse({ + status: 200, + body: window.localStorage.getItem(this.STORAGE_KEY), + }), + ); + + observer.complete(); + }); + } + + private setFilter(filter: string): Observable> { + window.localStorage.setItem(this.STORAGE_KEY, filter); + return this.getFilter(); + } +} diff --git a/src/app/pipes/filter-locationid.pipe.spec.ts b/src/app/pipes/filter-locationid.pipe.spec.ts new file mode 100644 index 0000000..aa72284 --- /dev/null +++ b/src/app/pipes/filter-locationid.pipe.spec.ts @@ -0,0 +1,8 @@ +import { FilterLocationidPipe } from './filter-locationid.pipe'; + +describe('FilterLocationidPipe', () => { + it('create an instance', () => { + const pipe = new FilterLocationidPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/pipes/filter-locationid.pipe.ts b/src/app/pipes/filter-locationid.pipe.ts new file mode 100644 index 0000000..7342748 --- /dev/null +++ b/src/app/pipes/filter-locationid.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { User } from '../user/user'; + +@Pipe({ + name: 'filterLocationid', +}) +export class FilterLocationidPipe implements PipeTransform { + transform(users: User[] | null, ...ids: number[]): User[] | null { + if (users === null || ids.length === 0) { + return users; + } + + return users.filter((user) => ids.some((id) => user.locationId === id)); + } +} diff --git a/src/app/pipes/highlight-text.pipe.ts b/src/app/pipes/highlight-text.pipe.ts index 8ce4cff..1f3cd6e 100644 --- a/src/app/pipes/highlight-text.pipe.ts +++ b/src/app/pipes/highlight-text.pipe.ts @@ -1,20 +1,17 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ - name: 'highlightText' + name: 'highlightText', }) export class HighlightTextPipe implements PipeTransform { + transform(value: string, filter: string): string { + if (filter.length === 0) return value; - transform(value: string, filter: string): string { - if (filter.length === 0) { - return value; - } + const search = new RegExp(filter, 'ig'); //i => ignore case, g => global + return value.replace(search, (match) => { + return `${match}`; + }); + } +} - const search = new RegExp(filter, 'ig'); - - return value.replace(search, (match) => { - return `${match}`; - }); - } - -} +//cross site scripting, angular security diff --git a/src/app/user-list/user-list.component.html b/src/app/user-list/user-list.component.html index c3f1dda..8e93473 100644 --- a/src/app/user-list/user-list.component.html +++ b/src/app/user-list/user-list.component.html @@ -1,11 +1,27 @@
- + - +
    -
  • +
diff --git a/src/app/user-list/user-list.component.ts b/src/app/user-list/user-list.component.ts index b0f9f0c..e260917 100644 --- a/src/app/user-list/user-list.component.ts +++ b/src/app/user-list/user-list.component.ts @@ -1,34 +1,33 @@ import { Component, OnInit } from '@angular/core'; import { User } from '../user/user'; import { UserListService } from './user-list.service'; +import { WebStorageService } from '../services/web-storage.service'; import { WebStorageService } from '../services/web-storage.service'; @Component({ - selector: 'app-user-list', - templateUrl: './user-list.component.html', - styleUrls: ['./user-list.component.css'] + selector: 'app-user-list', + templateUrl: './user-list.component.html', + styleUrls: ['./user-list.component.css'], }) export class UserListComponent implements OnInit { public users: Promise | null = null; constructor( private userListService: UserListService, - private webStorageService: WebStorageService - ) { } + private webStorage: WebStorageService, + ) {} public async ngOnInit(): Promise { - this.webStorageService.getRemote().subscribe(filtered => { - this.users = (filtered === null) ? this.userListService.getAll() : this.userListService.filter(filtered); - }, error => { - console.error('ngOnInit Error', error); - }); + const filtered = this.webStorage.get('USERS'); + this.users = + filtered === null + ? await this.userListService.getAll() + : JSON.parse(filtered); } public async update(text: string): Promise { - this.webStorageService.setRemote(text).subscribe(filtered => { - this.users = (filtered === null) ? this.userListService.getAll() : this.userListService.filter(filtered); - }); + this.users = await this.userListService.filter(text); + this.webStorage.set('USERS', JSON.stringify(this.users)); } - } diff --git a/src/styles.css b/src/styles.css index 36858da..7768bd5 100644 --- a/src/styles.css +++ b/src/styles.css @@ -14,4 +14,4 @@ body { .highlight-text { background: yellow; -} \ No newline at end of file +}