From 69e076ddb0deda9e4120bab095d3369bb19fbd1e Mon Sep 17 00:00:00 2001 From: Kimsible Date: Wed, 28 Apr 2021 22:17:02 +0200 Subject: Refactor client @actorName matcher with new API route --- client/src/app/+actors/actors.component.ts | 41 --------------------- client/src/app/app-routing.module.ts | 20 ++++++++--- client/src/app/root.component.ts | 42 ++++++++++++++++++++++ .../shared/shared-main/account/actor.service.ts | 41 +++++++++++++++++++++ client/src/app/shared/shared-main/account/index.ts | 1 + .../app/shared/shared-main/shared-main.module.ts | 3 +- 6 files changed, 102 insertions(+), 46 deletions(-) delete mode 100644 client/src/app/+actors/actors.component.ts create mode 100644 client/src/app/root.component.ts create mode 100644 client/src/app/shared/shared-main/account/actor.service.ts (limited to 'client/src') diff --git a/client/src/app/+actors/actors.component.ts b/client/src/app/+actors/actors.component.ts deleted file mode 100644 index 74fbe7dea..000000000 --- a/client/src/app/+actors/actors.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, OnInit } from '@angular/core' -import { empty } from 'rxjs' -import { catchError } from 'rxjs/operators' -import { RestExtractor } from '@app/core' - -import { ActivatedRoute, Router } from '@angular/router' -import { AccountService } from '@app/shared/shared-main/account' - -@Component({ - selector: 'my-actor', - template: '' -}) -export class ActorsComponent implements OnInit { - constructor ( - private accountService: AccountService, - private route: ActivatedRoute, - private restExtractor: RestExtractor, - private router: Router - ) { - } - - ngOnInit () { - const accountOrChannelName = this.route.snapshot.params['actorName'].replace('@', '') - - this.accountService - .getAccount(accountOrChannelName) - .pipe( - catchError(res => { - if (res.status === 404 && res.message === 'Account not found') { - this.router.navigateByUrl(`/video-channels/${accountOrChannelName}`) - return empty() - } - - return this.restExtractor.handleError(res) - }) - ) - .subscribe(() => { - this.router.navigateByUrl(`/accounts/${accountOrChannelName}`) - }) - } -} diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index c0a2d29e4..23fd52e8b 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -1,11 +1,11 @@ import { NgModule } from '@angular/core' -import { RouteReuseStrategy, RouterModule, Routes } from '@angular/router' +import { RouteReuseStrategy, RouterModule, Routes, UrlMatchResult, UrlSegment } from '@angular/router' import { CustomReuseStrategy } from '@app/core/routing/custom-reuse-strategy' import { MenuGuards } from '@app/core/routing/menu-guard.service' import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n' import { PreloadSelectedModulesList } from './core' import { EmptyComponent } from './empty.component' -import { ActorsComponent } from './+actors/actors.component' +import { RootComponent } from './root.component' const routes: Routes = [ { @@ -75,8 +75,20 @@ const routes: Routes = [ redirectTo: 'video-channels' }, { - path: ':actorName', - component: ActorsComponent + matcher: (url): UrlMatchResult => { + // Matches /@:actorName + if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) { + return { + consumed: url, + posParams: { + actorName: new UrlSegment(url[0].path.substr(1), {}) + } + } + } + + return null + }, + component: RootComponent }, { path: '', diff --git a/client/src/app/root.component.ts b/client/src/app/root.component.ts new file mode 100644 index 000000000..c65f59448 --- /dev/null +++ b/client/src/app/root.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit } from '@angular/core' +import { catchError, distinctUntilChanged, map, switchMap } from 'rxjs/operators' +import { ActivatedRoute, Router } from '@angular/router' +import { RestExtractor } from '@app/core' +import { ActorService } from '@app/shared/shared-main/account' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' + +@Component({ + selector: 'my-root', + template: '' +}) +export class RootComponent implements OnInit { + constructor ( + private actorService: ActorService, + private route: ActivatedRoute, + private restExtractor: RestExtractor, + private router: Router + ) { + } + + ngOnInit () { + this.route.params + .pipe( + map(params => params[ 'actorName' ]), + distinctUntilChanged(), + switchMap(actorName => this.actorService.getActor(actorName)), + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [ + HttpStatusCode.BAD_REQUEST_400, + HttpStatusCode.NOT_FOUND_404 + ])) + ) + .subscribe(actor => { + if (actor.constructor.name === 'Account') { + this.router.navigateByUrl(`/accounts/${actor.name}`) + } + + if (actor.constructor.name === 'VideoChannel') { + this.router.navigateByUrl(`/video-channels/${actor.name}`) + } + }) + } +} diff --git a/client/src/app/shared/shared-main/account/actor.service.ts b/client/src/app/shared/shared-main/account/actor.service.ts new file mode 100644 index 000000000..a789b6f5b --- /dev/null +++ b/client/src/app/shared/shared-main/account/actor.service.ts @@ -0,0 +1,41 @@ +import { Observable, ReplaySubject } from 'rxjs' +import { catchError, map, tap } from 'rxjs/operators' +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { RestExtractor } from '@app/core' +import { Account as ServerAccount, VideoChannel as ServerVideoChannel } from '@shared/models' +import { environment } from '../../../../environments/environment' +import { Account } from './account.model' +import { VideoChannel } from '../video-channel/video-channel.model' + +@Injectable() +export class ActorService { + static BASE_ACTOR_API_URL = environment.apiUrl + '/api/v1/actors/' + + actorLoaded = new ReplaySubject(1) + + constructor ( + private authHttp: HttpClient, + private restExtractor: RestExtractor + ) {} + + getActor (actorName: string): Observable { + return this.authHttp.get(ActorService.BASE_ACTOR_API_URL + actorName) + .pipe( + map(actorHash => { + const isAccount = /\/accounts\/.+/.test(actorHash.url) + const isVideoChannel = /\/video-channels\/.+/.test(actorHash.url) + + if (isAccount) { + return new Account(actorHash) + } + + if (isVideoChannel) { + return new VideoChannel(actorHash) + } + }), + tap(actor => this.actorLoaded.next(actor)), + catchError(res => this.restExtractor.handleError(res)) + ) + } +} diff --git a/client/src/app/shared/shared-main/account/index.ts b/client/src/app/shared/shared-main/account/index.ts index b80ddb9f5..c6cdcd574 100644 --- a/client/src/app/shared/shared-main/account/index.ts +++ b/client/src/app/shared/shared-main/account/index.ts @@ -1,3 +1,4 @@ export * from './account.model' export * from './account.service' export * from './actor.model' +export * from './actor.service' diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts index 772198cb2..05a5d77c7 100644 --- a/client/src/app/shared/shared-main/shared-main.module.ts +++ b/client/src/app/shared/shared-main/shared-main.module.ts @@ -17,7 +17,7 @@ import { import { LoadingBarModule } from '@ngx-loading-bar/core' import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' import { SharedGlobalIconModule } from '../shared-icons' -import { AccountService } from './account' +import { AccountService, ActorService } from './account' import { AutofocusDirective, BytesPipe, @@ -160,6 +160,7 @@ import { VideoChannelService } from './video-channel' AUTH_INTERCEPTOR_PROVIDER, AccountService, + ActorService, UserHistoryService, UserNotificationService, -- cgit v1.2.3