diff options
21 files changed, 213 insertions, 389 deletions
diff --git a/client/src/app/+page-not-found/page-not-found.component.ts b/client/src/app/+page-not-found/page-not-found.component.ts index 94b4c8d27..695568898 100644 --- a/client/src/app/+page-not-found/page-not-found.component.ts +++ b/client/src/app/+page-not-found/page-not-found.component.ts | |||
@@ -3,6 +3,7 @@ import { Title } from '@angular/platform-browser' | |||
3 | import { Router } from '@angular/router' | 3 | import { Router } from '@angular/router' |
4 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 4 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
5 | 5 | ||
6 | |||
6 | @Component({ | 7 | @Component({ |
7 | selector: 'my-page-not-found', | 8 | selector: 'my-page-not-found', |
8 | templateUrl: './page-not-found.component.html', | 9 | templateUrl: './page-not-found.component.html', |
@@ -10,7 +11,7 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | |||
10 | }) | 11 | }) |
11 | export class PageNotFoundComponent implements OnInit { | 12 | export class PageNotFoundComponent implements OnInit { |
12 | status = HttpStatusCode.NOT_FOUND_404 | 13 | status = HttpStatusCode.NOT_FOUND_404 |
13 | type: string | 14 | type: 'video' | 'other' = 'other' |
14 | 15 | ||
15 | public constructor ( | 16 | public constructor ( |
16 | private titleService: Title, | 17 | private titleService: Title, |
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 4619c4046..444b6f134 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts | |||
@@ -5,7 +5,8 @@ import { MenuGuards } from '@app/core/routing/menu-guard.service' | |||
5 | import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n' | 5 | import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n' |
6 | import { MetaGuard, PreloadSelectedModulesList } from './core' | 6 | import { MetaGuard, PreloadSelectedModulesList } from './core' |
7 | import { EmptyComponent } from './empty.component' | 7 | import { EmptyComponent } from './empty.component' |
8 | import { RootComponent } from './root.component' | 8 | import { USER_USERNAME_REGEX_CHARACTERS } from './shared/form-validators/user-validators' |
9 | import { ActorRedirectGuard } from './shared/shared-main' | ||
9 | 10 | ||
10 | const routes: Routes = [ | 11 | const routes: Routes = [ |
11 | { | 12 | { |
@@ -17,7 +18,8 @@ const routes: Routes = [ | |||
17 | }, | 18 | }, |
18 | { | 19 | { |
19 | path: 'home', | 20 | path: 'home', |
20 | loadChildren: () => import('./+home/home.module').then(m => m.HomeModule) | 21 | loadChildren: () => import('./+home/home.module').then(m => m.HomeModule), |
22 | canActivateChild: [ MetaGuard ] | ||
21 | }, | 23 | }, |
22 | { | 24 | { |
23 | path: 'my-account', | 25 | path: 'my-account', |
@@ -94,18 +96,22 @@ const routes: Routes = [ | |||
94 | { | 96 | { |
95 | matcher: (url): UrlMatchResult => { | 97 | matcher: (url): UrlMatchResult => { |
96 | // Matches /@:actorName | 98 | // Matches /@:actorName |
97 | if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) { | 99 | const regex = new RegExp(`^@(${USER_USERNAME_REGEX_CHARACTERS}+)$`) |
98 | return { | 100 | if (url.length !== 1) return null |
99 | consumed: url, | 101 | |
100 | posParams: { | 102 | const matchResult = url[0].path.match(regex) |
101 | actorName: new UrlSegment(url[0].path.substr(1), {}) | 103 | if (!matchResult) return null |
102 | } | 104 | |
105 | return { | ||
106 | consumed: url, | ||
107 | posParams: { | ||
108 | actorName: new UrlSegment(matchResult[1], {}) | ||
103 | } | 109 | } |
104 | } | 110 | } |
105 | |||
106 | return null | ||
107 | }, | 111 | }, |
108 | component: RootComponent | 112 | pathMatch: 'full', |
113 | canActivate: [ ActorRedirectGuard ], | ||
114 | component: EmptyComponent | ||
109 | }, | 115 | }, |
110 | { | 116 | { |
111 | path: '', | 117 | path: '', |
diff --git a/client/src/app/shared/form-validators/user-validators.ts b/client/src/app/shared/form-validators/user-validators.ts index fee37e95f..976c97b87 100644 --- a/client/src/app/shared/form-validators/user-validators.ts +++ b/client/src/app/shared/form-validators/user-validators.ts | |||
@@ -1,12 +1,14 @@ | |||
1 | import { Validators } from '@angular/forms' | 1 | import { Validators } from '@angular/forms' |
2 | import { BuildFormValidator } from './form-validator.model' | 2 | import { BuildFormValidator } from './form-validator.model' |
3 | 3 | ||
4 | export const USER_USERNAME_REGEX_CHARACTERS = '[a-z0-9][a-z0-9._]' | ||
5 | |||
4 | export const USER_USERNAME_VALIDATOR: BuildFormValidator = { | 6 | export const USER_USERNAME_VALIDATOR: BuildFormValidator = { |
5 | VALIDATORS: [ | 7 | VALIDATORS: [ |
6 | Validators.required, | 8 | Validators.required, |
7 | Validators.minLength(1), | 9 | Validators.minLength(1), |
8 | Validators.maxLength(50), | 10 | Validators.maxLength(50), |
9 | Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) | 11 | Validators.pattern(new RegExp(`^${USER_USERNAME_REGEX_CHARACTERS}*$`)) |
10 | ], | 12 | ], |
11 | MESSAGES: { | 13 | MESSAGES: { |
12 | 'required': $localize`Username is required.`, | 14 | 'required': $localize`Username is required.`, |
diff --git a/client/src/app/shared/shared-main/account/actor.service.ts b/client/src/app/shared/shared-main/account/actor.service.ts deleted file mode 100644 index 464ed4519..000000000 --- a/client/src/app/shared/shared-main/account/actor.service.ts +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | import { Observable, ReplaySubject } from 'rxjs' | ||
2 | import { catchError, map, tap } from 'rxjs/operators' | ||
3 | import { HttpClient } from '@angular/common/http' | ||
4 | import { Injectable } from '@angular/core' | ||
5 | import { RestExtractor } from '@app/core' | ||
6 | import { Account as ServerAccount, VideoChannel as ServerVideoChannel } from '@shared/models' | ||
7 | import { environment } from '../../../../environments/environment' | ||
8 | |||
9 | type KeysOfUnion<T> = T extends T ? keyof T: never | ||
10 | type ServerActor = KeysOfUnion<ServerAccount | ServerVideoChannel> | ||
11 | |||
12 | @Injectable() | ||
13 | export class ActorService { | ||
14 | static BASE_ACTOR_API_URL = environment.apiUrl + '/api/v1/actors/' | ||
15 | |||
16 | actorLoaded = new ReplaySubject<string>(1) | ||
17 | |||
18 | constructor ( | ||
19 | private authHttp: HttpClient, | ||
20 | private restExtractor: RestExtractor | ||
21 | ) {} | ||
22 | |||
23 | getActorType (actorName: string): Observable<string> { | ||
24 | return this.authHttp.get<ServerActor>(ActorService.BASE_ACTOR_API_URL + actorName) | ||
25 | .pipe( | ||
26 | map(actorHash => { | ||
27 | if (actorHash[ 'userId' ]) { | ||
28 | return 'Account' | ||
29 | } | ||
30 | |||
31 | return 'VideoChannel' | ||
32 | }), | ||
33 | tap(actor => this.actorLoaded.next(actor)), | ||
34 | catchError(res => this.restExtractor.handleError(res)) | ||
35 | ) | ||
36 | } | ||
37 | } | ||
diff --git a/client/src/app/shared/shared-main/account/index.ts b/client/src/app/shared/shared-main/account/index.ts index c6cdcd574..b80ddb9f5 100644 --- a/client/src/app/shared/shared-main/account/index.ts +++ b/client/src/app/shared/shared-main/account/index.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | export * from './account.model' | 1 | export * from './account.model' |
2 | export * from './account.service' | 2 | export * from './account.service' |
3 | export * from './actor.model' | 3 | export * from './actor.model' |
4 | export * from './actor.service' | ||
diff --git a/client/src/app/shared/shared-main/index.ts b/client/src/app/shared/shared-main/index.ts index a4d813c06..3a7fd4c34 100644 --- a/client/src/app/shared/shared-main/index.ts +++ b/client/src/app/shared/shared-main/index.ts | |||
@@ -5,6 +5,9 @@ export * from './date' | |||
5 | export * from './feeds' | 5 | export * from './feeds' |
6 | export * from './loaders' | 6 | export * from './loaders' |
7 | export * from './misc' | 7 | export * from './misc' |
8 | export * from './peertube-modal' | ||
9 | export * from './plugins' | ||
10 | export * from './router' | ||
8 | export * from './users' | 11 | export * from './users' |
9 | export * from './video' | 12 | export * from './video' |
10 | export * from './video-caption' | 13 | export * from './video-caption' |
diff --git a/client/src/app/shared/shared-main/router/actor-redirect-guard.service.ts b/client/src/app/shared/shared-main/router/actor-redirect-guard.service.ts new file mode 100644 index 000000000..49d61f945 --- /dev/null +++ b/client/src/app/shared/shared-main/router/actor-redirect-guard.service.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import { forkJoin, of } from 'rxjs' | ||
2 | import { catchError, map } from 'rxjs/operators' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router' | ||
5 | import { AccountService } from '../account' | ||
6 | import { VideoChannelService } from '../video-channel' | ||
7 | |||
8 | @Injectable() | ||
9 | export class ActorRedirectGuard implements CanActivate { | ||
10 | |||
11 | constructor ( | ||
12 | private router: Router, | ||
13 | private accountService: AccountService, | ||
14 | private channelService: VideoChannelService | ||
15 | ) {} | ||
16 | |||
17 | canActivate (route: ActivatedRouteSnapshot) { | ||
18 | const actorName = route.params.actorName | ||
19 | |||
20 | return forkJoin([ | ||
21 | this.accountService.getAccount(actorName).pipe(this.orUndefined()), | ||
22 | this.channelService.getVideoChannel(actorName).pipe(this.orUndefined()) | ||
23 | ]).pipe( | ||
24 | map(([ account, channel ]) => { | ||
25 | if (!account && !channel) { | ||
26 | this.router.navigate([ '/404' ]) | ||
27 | return false | ||
28 | } | ||
29 | |||
30 | if (account) { | ||
31 | this.router.navigate([ `/a/${actorName}` ], { skipLocationChange: true }) | ||
32 | } | ||
33 | |||
34 | if (channel) { | ||
35 | this.router.navigate([ `/c/${actorName}` ], { skipLocationChange: true }) | ||
36 | } | ||
37 | |||
38 | return true | ||
39 | }) | ||
40 | ) | ||
41 | } | ||
42 | |||
43 | private orUndefined () { | ||
44 | return catchError(() => of(undefined)) | ||
45 | } | ||
46 | } | ||
diff --git a/client/src/app/shared/shared-main/router/index.ts b/client/src/app/shared/shared-main/router/index.ts new file mode 100644 index 000000000..f4000b674 --- /dev/null +++ b/client/src/app/shared/shared-main/router/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './actor-redirect-guard.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 f06f25ca5..c8dd01429 100644 --- a/client/src/app/shared/shared-main/shared-main.module.ts +++ b/client/src/app/shared/shared-main/shared-main.module.ts | |||
@@ -4,7 +4,7 @@ import { CommonModule, DatePipe } from '@angular/common' | |||
4 | import { HttpClientModule } from '@angular/common/http' | 4 | import { HttpClientModule } from '@angular/common/http' |
5 | import { NgModule } from '@angular/core' | 5 | import { NgModule } from '@angular/core' |
6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' | 6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' |
7 | import { RouterModule } from '@angular/router' | 7 | import { ActivatedRouteSnapshot, RouterModule } from '@angular/router' |
8 | import { | 8 | import { |
9 | NgbButtonsModule, | 9 | NgbButtonsModule, |
10 | NgbCollapseModule, | 10 | NgbCollapseModule, |
@@ -17,7 +17,7 @@ import { | |||
17 | import { LoadingBarModule } from '@ngx-loading-bar/core' | 17 | import { LoadingBarModule } from '@ngx-loading-bar/core' |
18 | import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' | 18 | import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' |
19 | import { SharedGlobalIconModule } from '../shared-icons' | 19 | import { SharedGlobalIconModule } from '../shared-icons' |
20 | import { AccountService, ActorService } from './account' | 20 | import { AccountService } from './account' |
21 | import { | 21 | import { |
22 | AutofocusDirective, | 22 | AutofocusDirective, |
23 | BytesPipe, | 23 | BytesPipe, |
@@ -39,6 +39,7 @@ import { UserHistoryService, UserNotificationsComponent, UserNotificationService | |||
39 | import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' | 39 | import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' |
40 | import { VideoCaptionService } from './video-caption' | 40 | import { VideoCaptionService } from './video-caption' |
41 | import { VideoChannelService } from './video-channel' | 41 | import { VideoChannelService } from './video-channel' |
42 | import { ActorRedirectGuard } from './router' | ||
42 | 43 | ||
43 | @NgModule({ | 44 | @NgModule({ |
44 | imports: [ | 45 | imports: [ |
@@ -161,7 +162,6 @@ import { VideoChannelService } from './video-channel' | |||
161 | AUTH_INTERCEPTOR_PROVIDER, | 162 | AUTH_INTERCEPTOR_PROVIDER, |
162 | 163 | ||
163 | AccountService, | 164 | AccountService, |
164 | ActorService, | ||
165 | 165 | ||
166 | UserHistoryService, | 166 | UserHistoryService, |
167 | UserNotificationService, | 167 | UserNotificationService, |
@@ -175,7 +175,9 @@ import { VideoChannelService } from './video-channel' | |||
175 | 175 | ||
176 | VideoChannelService, | 176 | VideoChannelService, |
177 | 177 | ||
178 | CustomPageService | 178 | CustomPageService, |
179 | |||
180 | ActorRedirectGuard | ||
179 | ] | 181 | ] |
180 | }) | 182 | }) |
181 | export class SharedMainModule { } | 183 | export class SharedMainModule { } |
diff --git a/server/controllers/api/actor.ts b/server/controllers/api/actor.ts deleted file mode 100644 index da7f2eb91..000000000 --- a/server/controllers/api/actor.ts +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | import * as express from 'express' | ||
2 | import { JobQueue } from '../../lib/job-queue' | ||
3 | import { asyncMiddleware } from '../../middlewares' | ||
4 | import { actorNameWithHostGetValidator } from '../../middlewares/validators' | ||
5 | |||
6 | const actorRouter = express.Router() | ||
7 | |||
8 | actorRouter.get('/:actorName', | ||
9 | asyncMiddleware(actorNameWithHostGetValidator), | ||
10 | getActor | ||
11 | ) | ||
12 | |||
13 | // --------------------------------------------------------------------------- | ||
14 | |||
15 | export { | ||
16 | actorRouter | ||
17 | } | ||
18 | |||
19 | // --------------------------------------------------------------------------- | ||
20 | |||
21 | function getActor (req: express.Request, res: express.Response) { | ||
22 | let accountOrVideoChannel | ||
23 | |||
24 | if (res.locals.account) { | ||
25 | accountOrVideoChannel = res.locals.account | ||
26 | } | ||
27 | |||
28 | if (res.locals.videoChannel) { | ||
29 | accountOrVideoChannel = res.locals.videoChannel | ||
30 | } | ||
31 | |||
32 | if (accountOrVideoChannel.isOutdated()) { | ||
33 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: accountOrVideoChannel.Actor.url } }) | ||
34 | } | ||
35 | |||
36 | return res.json(accountOrVideoChannel.toFormattedJSON()) | ||
37 | } | ||
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 9ffcf1337..28378654a 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -16,7 +16,6 @@ import { pluginRouter } from './plugins' | |||
16 | import { searchRouter } from './search' | 16 | import { searchRouter } from './search' |
17 | import { serverRouter } from './server' | 17 | import { serverRouter } from './server' |
18 | import { usersRouter } from './users' | 18 | import { usersRouter } from './users' |
19 | import { actorRouter } from './actor' | ||
20 | import { videoChannelRouter } from './video-channel' | 19 | import { videoChannelRouter } from './video-channel' |
21 | import { videoPlaylistRouter } from './video-playlist' | 20 | import { videoPlaylistRouter } from './video-playlist' |
22 | import { videosRouter } from './videos' | 21 | import { videosRouter } from './videos' |
@@ -41,7 +40,6 @@ apiRouter.use('/bulk', bulkRouter) | |||
41 | apiRouter.use('/oauth-clients', oauthClientsRouter) | 40 | apiRouter.use('/oauth-clients', oauthClientsRouter) |
42 | apiRouter.use('/config', configRouter) | 41 | apiRouter.use('/config', configRouter) |
43 | apiRouter.use('/users', usersRouter) | 42 | apiRouter.use('/users', usersRouter) |
44 | apiRouter.use('/actors', actorRouter) | ||
45 | apiRouter.use('/accounts', accountsRouter) | 43 | apiRouter.use('/accounts', accountsRouter) |
46 | apiRouter.use('/video-channels', videoChannelRouter) | 44 | apiRouter.use('/video-channels', videoChannelRouter) |
47 | apiRouter.use('/video-playlists', videoPlaylistRouter) | 45 | apiRouter.use('/video-playlists', videoPlaylistRouter) |
diff --git a/server/helpers/custom-validators/actor.ts b/server/helpers/custom-validators/actor.ts deleted file mode 100644 index ad129e080..000000000 --- a/server/helpers/custom-validators/actor.ts +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | import { isAccountNameValid } from './accounts' | ||
2 | import { isVideoChannelNameValid } from './video-channels' | ||
3 | |||
4 | function isActorNameValid (value: string) { | ||
5 | return isAccountNameValid(value) || isVideoChannelNameValid(value) | ||
6 | } | ||
7 | |||
8 | export { | ||
9 | isActorNameValid | ||
10 | } | ||
diff --git a/server/helpers/middlewares/video-channels.ts b/server/helpers/middlewares/video-channels.ts index e30ea90b3..602555921 100644 --- a/server/helpers/middlewares/video-channels.ts +++ b/server/helpers/middlewares/video-channels.ts | |||
@@ -3,22 +3,22 @@ import { MChannelBannerAccountDefault } from '@server/types/models' | |||
3 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | 3 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' |
4 | import { VideoChannelModel } from '../../models/video/video-channel' | 4 | import { VideoChannelModel } from '../../models/video/video-channel' |
5 | 5 | ||
6 | async function doesLocalVideoChannelNameExist (name: string, res: express.Response, sendNotFound = true) { | 6 | async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { |
7 | const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) | 7 | const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) |
8 | 8 | ||
9 | return processVideoChannelExist(videoChannel, res, sendNotFound) | 9 | return processVideoChannelExist(videoChannel, res) |
10 | } | 10 | } |
11 | 11 | ||
12 | async function doesVideoChannelIdExist (id: number, res: express.Response, sendNotFound = true) { | 12 | async function doesVideoChannelIdExist (id: number, res: express.Response) { |
13 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) | 13 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) |
14 | 14 | ||
15 | return processVideoChannelExist(videoChannel, res, sendNotFound) | 15 | return processVideoChannelExist(videoChannel, res) |
16 | } | 16 | } |
17 | 17 | ||
18 | async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response, sendNotFound = true) { | 18 | async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) { |
19 | const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain) | 19 | const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain) |
20 | 20 | ||
21 | return processVideoChannelExist(videoChannel, res, sendNotFound) | 21 | return processVideoChannelExist(videoChannel, res) |
22 | } | 22 | } |
23 | 23 | ||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
@@ -29,12 +29,10 @@ export { | |||
29 | doesVideoChannelNameWithHostExist | 29 | doesVideoChannelNameWithHostExist |
30 | } | 30 | } |
31 | 31 | ||
32 | function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, res: express.Response, sendNotFound = true) { | 32 | function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, res: express.Response) { |
33 | if (!videoChannel) { | 33 | if (!videoChannel) { |
34 | if (sendNotFound) { | 34 | res.status(HttpStatusCode.NOT_FOUND_404) |
35 | res.status(HttpStatusCode.NOT_FOUND_404) | 35 | .json({ error: 'Video channel not found' }) |
36 | .json({ error: 'Video channel not found' }) | ||
37 | } | ||
38 | 36 | ||
39 | return false | 37 | return false |
40 | } | 38 | } |
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 2f6bce1c7..3c09332b5 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -208,14 +208,12 @@ class ClientHtml { | |||
208 | } | 208 | } |
209 | 209 | ||
210 | static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) { | 210 | static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) { |
211 | const accountModel = await AccountModel.loadByNameWithHost(nameWithHost) | 211 | const [ account, channel ] = await Promise.all([ |
212 | AccountModel.loadByNameWithHost(nameWithHost), | ||
213 | VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost) | ||
214 | ]) | ||
212 | 215 | ||
213 | if (accountModel) { | 216 | return this.getAccountOrChannelHTMLPage(() => Promise.resolve(account || channel), req, res) |
214 | return this.getAccountOrChannelHTMLPage(() => new Promise(resolve => resolve(accountModel)), req, res) | ||
215 | } else { | ||
216 | const videoChannelModelPromise = VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost) | ||
217 | return this.getAccountOrChannelHTMLPage(() => videoChannelModelPromise, req, res) | ||
218 | } | ||
219 | } | 217 | } |
220 | 218 | ||
221 | static async getEmbedHTML () { | 219 | static async getEmbedHTML () { |
diff --git a/server/middlewares/validators/actor.ts b/server/middlewares/validators/actor.ts deleted file mode 100644 index 99b529dd6..000000000 --- a/server/middlewares/validators/actor.ts +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | import * as express from 'express' | ||
2 | import { param } from 'express-validator' | ||
3 | import { isActorNameValid } from '../../helpers/custom-validators/actor' | ||
4 | import { logger } from '../../helpers/logger' | ||
5 | import { areValidationErrors } from './utils' | ||
6 | import { | ||
7 | doesAccountNameWithHostExist, | ||
8 | doesLocalAccountNameExist, | ||
9 | doesVideoChannelNameWithHostExist, | ||
10 | doesLocalVideoChannelNameExist | ||
11 | } from '../../helpers/middlewares' | ||
12 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
13 | |||
14 | const localActorValidator = [ | ||
15 | param('actorName').custom(isActorNameValid).withMessage('Should have a valid actor name'), | ||
16 | |||
17 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
18 | logger.debug('Checking localActorValidator parameters', { parameters: req.params }) | ||
19 | |||
20 | if (areValidationErrors(req, res)) return | ||
21 | |||
22 | const isAccount = await doesLocalAccountNameExist(req.params.actorName, res, false) | ||
23 | const isVideoChannel = await doesLocalVideoChannelNameExist(req.params.actorName, res, false) | ||
24 | |||
25 | if (!isAccount || !isVideoChannel) { | ||
26 | res.status(HttpStatusCode.NOT_FOUND_404) | ||
27 | .json({ error: 'Actor not found' }) | ||
28 | } | ||
29 | |||
30 | return next() | ||
31 | } | ||
32 | ] | ||
33 | |||
34 | const actorNameWithHostGetValidator = [ | ||
35 | param('actorName').exists().withMessage('Should have an actor name with host'), | ||
36 | |||
37 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
38 | logger.debug('Checking actorNameWithHostGetValidator parameters', { parameters: req.params }) | ||
39 | |||
40 | if (areValidationErrors(req, res)) return | ||
41 | |||
42 | const isAccount = await doesAccountNameWithHostExist(req.params.actorName, res, false) | ||
43 | const isVideoChannel = await doesVideoChannelNameWithHostExist(req.params.actorName, res, false) | ||
44 | |||
45 | if (!isAccount && !isVideoChannel) { | ||
46 | res.status(HttpStatusCode.NOT_FOUND_404) | ||
47 | .json({ error: 'Actor not found' }) | ||
48 | } | ||
49 | |||
50 | return next() | ||
51 | } | ||
52 | ] | ||
53 | |||
54 | // --------------------------------------------------------------------------- | ||
55 | |||
56 | export { | ||
57 | localActorValidator, | ||
58 | actorNameWithHostGetValidator | ||
59 | } | ||
diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index 3e1a1e5ce..24faeea3e 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | export * from './abuse' | 1 | export * from './abuse' |
2 | export * from './account' | 2 | export * from './account' |
3 | export * from './actor' | ||
4 | export * from './actor-image' | 3 | export * from './actor-image' |
5 | export * from './blocklist' | 4 | export * from './blocklist' |
6 | export * from './oembed' | 5 | export * from './oembed' |
diff --git a/server/tests/api/check-params/actors.ts b/server/tests/api/check-params/actors.ts deleted file mode 100644 index 3a03edc39..000000000 --- a/server/tests/api/check-params/actors.ts +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import 'mocha' | ||
4 | |||
5 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../../shared/extra-utils' | ||
6 | import { getActor } from '../../../../shared/extra-utils/actors/actors' | ||
7 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | ||
8 | |||
9 | describe('Test actors API validators', function () { | ||
10 | let server: ServerInfo | ||
11 | |||
12 | // --------------------------------------------------------------- | ||
13 | |||
14 | before(async function () { | ||
15 | this.timeout(30000) | ||
16 | |||
17 | server = await flushAndRunServer(1) | ||
18 | }) | ||
19 | |||
20 | describe('When getting an actor', function () { | ||
21 | it('Should return 404 with a non existing actorName', async function () { | ||
22 | await getActor(server.url, 'arfaze', HttpStatusCode.NOT_FOUND_404) | ||
23 | }) | ||
24 | |||
25 | it('Should return 200 with an existing accountName', async function () { | ||
26 | await getActor(server.url, 'root', HttpStatusCode.OK_200) | ||
27 | }) | ||
28 | |||
29 | it('Should return 200 with an existing channelName', async function () { | ||
30 | await getActor(server.url, 'root_channel', HttpStatusCode.OK_200) | ||
31 | }) | ||
32 | }) | ||
33 | |||
34 | after(async function () { | ||
35 | await cleanupTests([ server ]) | ||
36 | }) | ||
37 | }) | ||
diff --git a/server/tests/client.ts b/server/tests/client.ts index d9a472fdd..f33e5c1da 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -2,8 +2,10 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { omit } from 'lodash' | ||
5 | import * as request from 'supertest' | 6 | import * as request from 'supertest' |
6 | import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models' | 7 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
8 | import { Account, CustomConfig, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models' | ||
7 | import { | 9 | import { |
8 | addVideoInPlaylist, | 10 | addVideoInPlaylist, |
9 | cleanupTests, | 11 | cleanupTests, |
@@ -14,6 +16,7 @@ import { | |||
14 | getConfig, | 16 | getConfig, |
15 | getCustomConfig, | 17 | getCustomConfig, |
16 | getVideosList, | 18 | getVideosList, |
19 | makeGetRequest, | ||
17 | makeHTMLRequest, | 20 | makeHTMLRequest, |
18 | ServerInfo, | 21 | ServerInfo, |
19 | setAccessTokensToServers, | 22 | setAccessTokensToServers, |
@@ -25,8 +28,6 @@ import { | |||
25 | uploadVideo, | 28 | uploadVideo, |
26 | waitJobs | 29 | waitJobs |
27 | } from '../../shared/extra-utils' | 30 | } from '../../shared/extra-utils' |
28 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | ||
29 | import { omit } from 'lodash' | ||
30 | 31 | ||
31 | const expect = chai.expect | 32 | const expect = chai.expect |
32 | 33 | ||
@@ -144,52 +145,36 @@ describe('Test a client controllers', function () { | |||
144 | 145 | ||
145 | describe('Open Graph', function () { | 146 | describe('Open Graph', function () { |
146 | 147 | ||
147 | it('Should have valid Open Graph tags on the account page', async function () { | 148 | async function accountPageTest (path: string) { |
148 | const accountPageTests = (res) => { | 149 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
149 | expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) | 150 | const text = res.text |
150 | expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`) | ||
151 | expect(res.text).to.contain('<meta property="og:type" content="website" />') | ||
152 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`) | ||
153 | } | ||
154 | 151 | ||
155 | accountPageTests(await request(servers[0].url) | 152 | expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) |
156 | .get('/accounts/' + servers[0].user.username) | 153 | expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`) |
157 | .set('Accept', 'text/html') | 154 | expect(text).to.contain('<meta property="og:type" content="website" />') |
158 | .expect(HttpStatusCode.OK_200)) | 155 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`) |
156 | } | ||
159 | 157 | ||
160 | accountPageTests(await request(servers[0].url) | 158 | async function channelPageTest (path: string) { |
161 | .get('/a/' + servers[0].user.username) | 159 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
162 | .set('Accept', 'text/html') | 160 | const text = res.text |
163 | .expect(HttpStatusCode.OK_200)) | ||
164 | 161 | ||
165 | accountPageTests(await request(servers[0].url) | 162 | expect(text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`) |
166 | .get('/@' + servers[0].user.username) | 163 | expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) |
167 | .set('Accept', 'text/html') | 164 | expect(text).to.contain('<meta property="og:type" content="website" />') |
168 | .expect(HttpStatusCode.OK_200)) | 165 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`) |
166 | } | ||
167 | |||
168 | it('Should have valid Open Graph tags on the account page', async function () { | ||
169 | await accountPageTest('/accounts/' + servers[0].user.username) | ||
170 | await accountPageTest('/a/' + servers[0].user.username) | ||
171 | await accountPageTest('/@' + servers[0].user.username) | ||
169 | }) | 172 | }) |
170 | 173 | ||
171 | it('Should have valid Open Graph tags on the channel page', async function () { | 174 | it('Should have valid Open Graph tags on the channel page', async function () { |
172 | const channelPageOGtests = (res) => { | 175 | await channelPageTest('/video-channels/' + servers[0].videoChannel.name) |
173 | expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`) | 176 | await channelPageTest('/c/' + servers[0].videoChannel.name) |
174 | expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) | 177 | await channelPageTest('/@' + servers[0].videoChannel.name) |
175 | expect(res.text).to.contain('<meta property="og:type" content="website" />') | ||
176 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`) | ||
177 | } | ||
178 | |||
179 | channelPageOGtests(await request(servers[0].url) | ||
180 | .get('/video-channels/' + servers[0].videoChannel.name) | ||
181 | .set('Accept', 'text/html') | ||
182 | .expect(HttpStatusCode.OK_200)) | ||
183 | |||
184 | channelPageOGtests(await request(servers[0].url) | ||
185 | .get('/c/' + servers[0].videoChannel.name) | ||
186 | .set('Accept', 'text/html') | ||
187 | .expect(HttpStatusCode.OK_200)) | ||
188 | |||
189 | channelPageOGtests(await request(servers[0].url) | ||
190 | .get('/@' + servers[0].videoChannel.name) | ||
191 | .set('Accept', 'text/html') | ||
192 | .expect(HttpStatusCode.OK_200)) | ||
193 | }) | 178 | }) |
194 | 179 | ||
195 | it('Should have valid Open Graph tags on the watch page with video id', async function () { | 180 | it('Should have valid Open Graph tags on the watch page with video id', async function () { |
@@ -231,142 +216,125 @@ describe('Test a client controllers', function () { | |||
231 | 216 | ||
232 | describe('Twitter card', async function () { | 217 | describe('Twitter card', async function () { |
233 | 218 | ||
234 | it('Should have valid twitter card on the watch video page', async function () { | 219 | describe('Not whitelisted', function () { |
235 | const res = await request(servers[0].url) | ||
236 | .get('/videos/watch/' + servers[0].video.uuid) | ||
237 | .set('Accept', 'text/html') | ||
238 | .expect(HttpStatusCode.OK_200) | ||
239 | 220 | ||
240 | expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') | 221 | async function accountPageTest (path: string) { |
241 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 222 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
242 | expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) | 223 | const text = res.text |
243 | expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) | ||
244 | }) | ||
245 | 224 | ||
246 | it('Should have valid twitter card on the watch playlist page', async function () { | 225 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') |
247 | const res = await request(servers[0].url) | 226 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
248 | .get('/videos/watch/playlist/' + playlistUUID) | 227 | expect(text).to.contain(`<meta property="twitter:title" content="${account.name}" />`) |
249 | .set('Accept', 'text/html') | 228 | expect(text).to.contain(`<meta property="twitter:description" content="${account.description}" />`) |
250 | .expect(HttpStatusCode.OK_200) | 229 | } |
251 | 230 | ||
252 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | 231 | async function channelPageTest (path: string) { |
253 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 232 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
254 | expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) | 233 | const text = res.text |
255 | expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`) | ||
256 | }) | ||
257 | 234 | ||
258 | it('Should have valid twitter card on the account page', async function () { | 235 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') |
259 | const accountPageTests = (res) => { | 236 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
260 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | 237 | expect(text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`) |
261 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 238 | expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) |
262 | expect(res.text).to.contain(`<meta property="twitter:title" content="${account.name}" />`) | ||
263 | expect(res.text).to.contain(`<meta property="twitter:description" content="${account.description}" />`) | ||
264 | } | 239 | } |
265 | 240 | ||
266 | accountPageTests(await request(servers[0].url) | 241 | it('Should have valid twitter card on the watch video page', async function () { |
267 | .get('/accounts/' + account.name) | 242 | const res = await request(servers[0].url) |
268 | .set('Accept', 'text/html') | 243 | .get('/videos/watch/' + servers[0].video.uuid) |
269 | .expect(HttpStatusCode.OK_200)) | 244 | .set('Accept', 'text/html') |
245 | .expect(HttpStatusCode.OK_200) | ||
270 | 246 | ||
271 | accountPageTests(await request(servers[0].url) | 247 | expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') |
272 | .get('/a/' + account.name) | 248 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
273 | .set('Accept', 'text/html') | 249 | expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) |
274 | .expect(HttpStatusCode.OK_200)) | 250 | expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) |
251 | }) | ||
275 | 252 | ||
276 | accountPageTests(await request(servers[0].url) | 253 | it('Should have valid twitter card on the watch playlist page', async function () { |
277 | .get('/@' + account.name) | 254 | const res = await request(servers[0].url) |
278 | .set('Accept', 'text/html') | 255 | .get('/videos/watch/playlist/' + playlistUUID) |
279 | .expect(HttpStatusCode.OK_200)) | 256 | .set('Accept', 'text/html') |
280 | }) | 257 | .expect(HttpStatusCode.OK_200) |
281 | 258 | ||
282 | it('Should have valid twitter card on the channel page', async function () { | ||
283 | const channelPageTests = (res) => { | ||
284 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | 259 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') |
285 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 260 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
286 | expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`) | 261 | expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) |
287 | expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) | 262 | expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`) |
288 | } | 263 | }) |
289 | |||
290 | channelPageTests(await request(servers[0].url) | ||
291 | .get('/video-channels/' + servers[0].videoChannel.name) | ||
292 | .set('Accept', 'text/html') | ||
293 | .expect(HttpStatusCode.OK_200)) | ||
294 | 264 | ||
295 | channelPageTests(await request(servers[0].url) | 265 | it('Should have valid twitter card on the account page', async function () { |
296 | .get('/c/' + servers[0].videoChannel.name) | 266 | await accountPageTest('/accounts/' + account.name) |
297 | .set('Accept', 'text/html') | 267 | await accountPageTest('/a/' + account.name) |
298 | .expect(HttpStatusCode.OK_200)) | 268 | await accountPageTest('/@' + account.name) |
269 | }) | ||
299 | 270 | ||
300 | channelPageTests(await request(servers[0].url) | 271 | it('Should have valid twitter card on the channel page', async function () { |
301 | .get('/@' + servers[0].videoChannel.name) | 272 | await channelPageTest('/video-channels/' + servers[0].videoChannel.name) |
302 | .set('Accept', 'text/html') | 273 | await channelPageTest('/c/' + servers[0].videoChannel.name) |
303 | .expect(HttpStatusCode.OK_200)) | 274 | await channelPageTest('/@' + servers[0].videoChannel.name) |
275 | }) | ||
304 | }) | 276 | }) |
305 | 277 | ||
306 | it('Should have valid twitter card if Twitter is whitelisted', async function () { | 278 | describe('Whitelisted', function () { |
307 | const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken) | ||
308 | const config = res1.body | ||
309 | config.services.twitter = { | ||
310 | username: '@Kuja', | ||
311 | whitelisted: true | ||
312 | } | ||
313 | await updateCustomConfig(servers[0].url, servers[0].accessToken, config) | ||
314 | |||
315 | const resVideoRequest = await request(servers[0].url) | ||
316 | .get('/videos/watch/' + servers[0].video.uuid) | ||
317 | .set('Accept', 'text/html') | ||
318 | .expect(HttpStatusCode.OK_200) | ||
319 | 279 | ||
320 | expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />') | 280 | before(async function () { |
321 | expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | 281 | const res = await getCustomConfig(servers[0].url, servers[0].accessToken) |
282 | const config = res.body as CustomConfig | ||
283 | config.services.twitter = { | ||
284 | username: '@Kuja', | ||
285 | whitelisted: true | ||
286 | } | ||
322 | 287 | ||
323 | const resVideoPlaylistRequest = await request(servers[0].url) | 288 | await updateCustomConfig(servers[0].url, servers[0].accessToken, config) |
324 | .get('/videos/watch/playlist/' + playlistUUID) | 289 | }) |
325 | .set('Accept', 'text/html') | ||
326 | .expect(HttpStatusCode.OK_200) | ||
327 | 290 | ||
328 | expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />') | 291 | async function accountPageTest (path: string) { |
329 | expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | 292 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
293 | const text = res.text | ||
330 | 294 | ||
331 | const accountTests = (res) => { | 295 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') |
332 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | 296 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
333 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
334 | } | 297 | } |
335 | 298 | ||
336 | accountTests(await request(servers[0].url) | 299 | async function channelPageTest (path: string) { |
337 | .get('/accounts/' + account.name) | 300 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
338 | .set('Accept', 'text/html') | 301 | const text = res.text |
339 | .expect(HttpStatusCode.OK_200)) | ||
340 | 302 | ||
341 | accountTests(await request(servers[0].url) | 303 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') |
342 | .get('/a/' + account.name) | 304 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
343 | .set('Accept', 'text/html') | 305 | } |
344 | .expect(HttpStatusCode.OK_200)) | ||
345 | 306 | ||
346 | accountTests(await request(servers[0].url) | 307 | it('Should have valid twitter card on the watch video page', async function () { |
347 | .get('/@' + account.name) | 308 | const res = await request(servers[0].url) |
348 | .set('Accept', 'text/html') | 309 | .get('/videos/watch/' + servers[0].video.uuid) |
349 | .expect(HttpStatusCode.OK_200)) | 310 | .set('Accept', 'text/html') |
311 | .expect(HttpStatusCode.OK_200) | ||
350 | 312 | ||
351 | const channelTests = (res) => { | 313 | expect(res.text).to.contain('<meta property="twitter:card" content="player" />') |
352 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | ||
353 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | 314 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
354 | } | 315 | }) |
355 | 316 | ||
356 | channelTests(await request(servers[0].url) | 317 | it('Should have valid twitter card on the watch playlist page', async function () { |
357 | .get('/video-channels/' + servers[0].videoChannel.name) | 318 | const res = await request(servers[0].url) |
358 | .set('Accept', 'text/html') | 319 | .get('/videos/watch/playlist/' + playlistUUID) |
359 | .expect(HttpStatusCode.OK_200)) | 320 | .set('Accept', 'text/html') |
321 | .expect(HttpStatusCode.OK_200) | ||
360 | 322 | ||
361 | channelTests(await request(servers[0].url) | 323 | expect(res.text).to.contain('<meta property="twitter:card" content="player" />') |
362 | .get('/c/' + servers[0].videoChannel.name) | 324 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
363 | .set('Accept', 'text/html') | 325 | }) |
364 | .expect(HttpStatusCode.OK_200)) | ||
365 | 326 | ||
366 | channelTests(await request(servers[0].url) | 327 | it('Should have valid twitter card on the account page', async function () { |
367 | .get('/@' + servers[0].videoChannel.name) | 328 | await accountPageTest('/accounts/' + account.name) |
368 | .set('Accept', 'text/html') | 329 | await accountPageTest('/a/' + account.name) |
369 | .expect(HttpStatusCode.OK_200)) | 330 | await accountPageTest('/@' + account.name) |
331 | }) | ||
332 | |||
333 | it('Should have valid twitter card on the channel page', async function () { | ||
334 | await channelPageTest('/video-channels/' + servers[0].videoChannel.name) | ||
335 | await channelPageTest('/c/' + servers[0].videoChannel.name) | ||
336 | await channelPageTest('/@' + servers[0].videoChannel.name) | ||
337 | }) | ||
370 | }) | 338 | }) |
371 | }) | 339 | }) |
372 | 340 | ||
diff --git a/shared/extra-utils/actors/actors.ts b/shared/extra-utils/actors/actors.ts deleted file mode 100644 index 4a4aba775..000000000 --- a/shared/extra-utils/actors/actors.ts +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { makeGetRequest } from '../requests/requests' | ||
4 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
5 | |||
6 | function getActor (url: string, actorName: string, statusCodeExpected = HttpStatusCode.OK_200) { | ||
7 | const path = '/api/v1/actors/' + actorName | ||
8 | |||
9 | return makeGetRequest({ | ||
10 | url, | ||
11 | path, | ||
12 | statusCodeExpected | ||
13 | }) | ||
14 | } | ||
15 | |||
16 | export { | ||
17 | getActor | ||
18 | } | ||
diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 9f5b5bb28..3bc09ead5 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | export * from './actors/actors' | ||
2 | export * from './bulk/bulk' | 1 | export * from './bulk/bulk' |
3 | 2 | ||
4 | export * from './cli/cli' | 3 | export * from './cli/cli' |
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 8b5cddf4a..38e24d897 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts | |||
@@ -26,6 +26,7 @@ function makeGetRequest (options: { | |||
26 | contentType?: string | 26 | contentType?: string |
27 | range?: string | 27 | range?: string |
28 | redirects?: number | 28 | redirects?: number |
29 | accept?: string | ||
29 | }) { | 30 | }) { |
30 | if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 | 31 | if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 |
31 | if (options.contentType === undefined) options.contentType = 'application/json' | 32 | if (options.contentType === undefined) options.contentType = 'application/json' |
@@ -36,6 +37,7 @@ function makeGetRequest (options: { | |||
36 | if (options.token) req.set('Authorization', 'Bearer ' + options.token) | 37 | if (options.token) req.set('Authorization', 'Bearer ' + options.token) |
37 | if (options.query) req.query(options.query) | 38 | if (options.query) req.query(options.query) |
38 | if (options.range) req.set('Range', options.range) | 39 | if (options.range) req.set('Range', options.range) |
40 | if (options.accept) req.set('Accept', options.accept) | ||
39 | if (options.redirects) req.redirects(options.redirects) | 41 | if (options.redirects) req.redirects(options.redirects) |
40 | 42 | ||
41 | return req.expect(options.statusCodeExpected) | 43 | return req.expect(options.statusCodeExpected) |