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' import { Router } from '@angular/router' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' + @Component({ selector: 'my-page-not-found', templateUrl: './page-not-found.component.html', @@ -10,7 +11,7 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' }) export class PageNotFoundComponent implements OnInit { status = HttpStatusCode.NOT_FOUND_404 - type: string + type: 'video' | 'other' = 'other' public constructor ( 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' import { POSSIBLE_LOCALES } from '@shared/core-utils/i18n' import { MetaGuard, PreloadSelectedModulesList } from './core' import { EmptyComponent } from './empty.component' -import { RootComponent } from './root.component' +import { USER_USERNAME_REGEX_CHARACTERS } from './shared/form-validators/user-validators' +import { ActorRedirectGuard } from './shared/shared-main' const routes: Routes = [ { @@ -17,7 +18,8 @@ const routes: Routes = [ }, { path: 'home', - loadChildren: () => import('./+home/home.module').then(m => m.HomeModule) + loadChildren: () => import('./+home/home.module').then(m => m.HomeModule), + canActivateChild: [ MetaGuard ] }, { path: 'my-account', @@ -94,18 +96,22 @@ const routes: Routes = [ { 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), {}) - } + const regex = new RegExp(`^@(${USER_USERNAME_REGEX_CHARACTERS}+)$`) + if (url.length !== 1) return null + + const matchResult = url[0].path.match(regex) + if (!matchResult) return null + + return { + consumed: url, + posParams: { + actorName: new UrlSegment(matchResult[1], {}) } } - - return null }, - component: RootComponent + pathMatch: 'full', + canActivate: [ ActorRedirectGuard ], + component: EmptyComponent }, { 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 @@ import { Validators } from '@angular/forms' import { BuildFormValidator } from './form-validator.model' +export const USER_USERNAME_REGEX_CHARACTERS = '[a-z0-9][a-z0-9._]' + export const USER_USERNAME_VALIDATOR: BuildFormValidator = { VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(50), - Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) + Validators.pattern(new RegExp(`^${USER_USERNAME_REGEX_CHARACTERS}*$`)) ], MESSAGES: { '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 @@ -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' - -type KeysOfUnion = T extends T ? keyof T: never -type ServerActor = KeysOfUnion - -@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 - ) {} - - getActorType (actorName: string): Observable { - return this.authHttp.get(ActorService.BASE_ACTOR_API_URL + actorName) - .pipe( - map(actorHash => { - if (actorHash[ 'userId' ]) { - return 'Account' - } - - return 'VideoChannel' - }), - 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 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 @@ 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/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' export * from './feeds' export * from './loaders' export * from './misc' +export * from './peertube-modal' +export * from './plugins' +export * from './router' export * from './users' export * from './video' 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 @@ +import { forkJoin, of } from 'rxjs' +import { catchError, map } from 'rxjs/operators' +import { Injectable } from '@angular/core' +import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router' +import { AccountService } from '../account' +import { VideoChannelService } from '../video-channel' + +@Injectable() +export class ActorRedirectGuard implements CanActivate { + + constructor ( + private router: Router, + private accountService: AccountService, + private channelService: VideoChannelService + ) {} + + canActivate (route: ActivatedRouteSnapshot) { + const actorName = route.params.actorName + + return forkJoin([ + this.accountService.getAccount(actorName).pipe(this.orUndefined()), + this.channelService.getVideoChannel(actorName).pipe(this.orUndefined()) + ]).pipe( + map(([ account, channel ]) => { + if (!account && !channel) { + this.router.navigate([ '/404' ]) + return false + } + + if (account) { + this.router.navigate([ `/a/${actorName}` ], { skipLocationChange: true }) + } + + if (channel) { + this.router.navigate([ `/c/${actorName}` ], { skipLocationChange: true }) + } + + return true + }) + ) + } + + private orUndefined () { + return catchError(() => of(undefined)) + } +} 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' import { HttpClientModule } from '@angular/common/http' import { NgModule } from '@angular/core' import { FormsModule, ReactiveFormsModule } from '@angular/forms' -import { RouterModule } from '@angular/router' +import { ActivatedRouteSnapshot, RouterModule } from '@angular/router' import { NgbButtonsModule, NgbCollapseModule, @@ -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, ActorService } from './account' +import { AccountService } from './account' import { AutofocusDirective, BytesPipe, @@ -39,6 +39,7 @@ import { UserHistoryService, UserNotificationsComponent, UserNotificationService import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' import { VideoCaptionService } from './video-caption' import { VideoChannelService } from './video-channel' +import { ActorRedirectGuard } from './router' @NgModule({ imports: [ @@ -161,7 +162,6 @@ import { VideoChannelService } from './video-channel' AUTH_INTERCEPTOR_PROVIDER, AccountService, - ActorService, UserHistoryService, UserNotificationService, @@ -175,7 +175,9 @@ import { VideoChannelService } from './video-channel' VideoChannelService, - CustomPageService + CustomPageService, + + ActorRedirectGuard ] }) 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 @@ -import * as express from 'express' -import { JobQueue } from '../../lib/job-queue' -import { asyncMiddleware } from '../../middlewares' -import { actorNameWithHostGetValidator } from '../../middlewares/validators' - -const actorRouter = express.Router() - -actorRouter.get('/:actorName', - asyncMiddleware(actorNameWithHostGetValidator), - getActor -) - -// --------------------------------------------------------------------------- - -export { - actorRouter -} - -// --------------------------------------------------------------------------- - -function getActor (req: express.Request, res: express.Response) { - let accountOrVideoChannel - - if (res.locals.account) { - accountOrVideoChannel = res.locals.account - } - - if (res.locals.videoChannel) { - accountOrVideoChannel = res.locals.videoChannel - } - - if (accountOrVideoChannel.isOutdated()) { - JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: accountOrVideoChannel.Actor.url } }) - } - - return res.json(accountOrVideoChannel.toFormattedJSON()) -} 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' import { searchRouter } from './search' import { serverRouter } from './server' import { usersRouter } from './users' -import { actorRouter } from './actor' import { videoChannelRouter } from './video-channel' import { videoPlaylistRouter } from './video-playlist' import { videosRouter } from './videos' @@ -41,7 +40,6 @@ apiRouter.use('/bulk', bulkRouter) apiRouter.use('/oauth-clients', oauthClientsRouter) apiRouter.use('/config', configRouter) apiRouter.use('/users', usersRouter) -apiRouter.use('/actors', actorRouter) apiRouter.use('/accounts', accountsRouter) apiRouter.use('/video-channels', videoChannelRouter) 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 @@ -import { isAccountNameValid } from './accounts' -import { isVideoChannelNameValid } from './video-channels' - -function isActorNameValid (value: string) { - return isAccountNameValid(value) || isVideoChannelNameValid(value) -} - -export { - isActorNameValid -} 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' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' import { VideoChannelModel } from '../../models/video/video-channel' -async function doesLocalVideoChannelNameExist (name: string, res: express.Response, sendNotFound = true) { +async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) - return processVideoChannelExist(videoChannel, res, sendNotFound) + return processVideoChannelExist(videoChannel, res) } -async function doesVideoChannelIdExist (id: number, res: express.Response, sendNotFound = true) { +async function doesVideoChannelIdExist (id: number, res: express.Response) { const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) - return processVideoChannelExist(videoChannel, res, sendNotFound) + return processVideoChannelExist(videoChannel, res) } -async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response, sendNotFound = true) { +async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) { const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain) - return processVideoChannelExist(videoChannel, res, sendNotFound) + return processVideoChannelExist(videoChannel, res) } // --------------------------------------------------------------------------- @@ -29,12 +29,10 @@ export { doesVideoChannelNameWithHostExist } -function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, res: express.Response, sendNotFound = true) { +function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, res: express.Response) { if (!videoChannel) { - if (sendNotFound) { - res.status(HttpStatusCode.NOT_FOUND_404) - .json({ error: 'Video channel not found' }) - } + res.status(HttpStatusCode.NOT_FOUND_404) + .json({ error: 'Video channel not found' }) return false } 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 { } static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) { - const accountModel = await AccountModel.loadByNameWithHost(nameWithHost) + const [ account, channel ] = await Promise.all([ + AccountModel.loadByNameWithHost(nameWithHost), + VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost) + ]) - if (accountModel) { - return this.getAccountOrChannelHTMLPage(() => new Promise(resolve => resolve(accountModel)), req, res) - } else { - const videoChannelModelPromise = VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost) - return this.getAccountOrChannelHTMLPage(() => videoChannelModelPromise, req, res) - } + return this.getAccountOrChannelHTMLPage(() => Promise.resolve(account || channel), req, res) } 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 @@ -import * as express from 'express' -import { param } from 'express-validator' -import { isActorNameValid } from '../../helpers/custom-validators/actor' -import { logger } from '../../helpers/logger' -import { areValidationErrors } from './utils' -import { - doesAccountNameWithHostExist, - doesLocalAccountNameExist, - doesVideoChannelNameWithHostExist, - doesLocalVideoChannelNameExist -} from '../../helpers/middlewares' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -const localActorValidator = [ - param('actorName').custom(isActorNameValid).withMessage('Should have a valid actor name'), - - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking localActorValidator parameters', { parameters: req.params }) - - if (areValidationErrors(req, res)) return - - const isAccount = await doesLocalAccountNameExist(req.params.actorName, res, false) - const isVideoChannel = await doesLocalVideoChannelNameExist(req.params.actorName, res, false) - - if (!isAccount || !isVideoChannel) { - res.status(HttpStatusCode.NOT_FOUND_404) - .json({ error: 'Actor not found' }) - } - - return next() - } -] - -const actorNameWithHostGetValidator = [ - param('actorName').exists().withMessage('Should have an actor name with host'), - - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking actorNameWithHostGetValidator parameters', { parameters: req.params }) - - if (areValidationErrors(req, res)) return - - const isAccount = await doesAccountNameWithHostExist(req.params.actorName, res, false) - const isVideoChannel = await doesVideoChannelNameWithHostExist(req.params.actorName, res, false) - - if (!isAccount && !isVideoChannel) { - res.status(HttpStatusCode.NOT_FOUND_404) - .json({ error: 'Actor not found' }) - } - - return next() - } -] - -// --------------------------------------------------------------------------- - -export { - localActorValidator, - actorNameWithHostGetValidator -} 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 @@ export * from './abuse' export * from './account' -export * from './actor' export * from './actor-image' export * from './blocklist' 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 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import 'mocha' - -import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../../shared/extra-utils' -import { getActor } from '../../../../shared/extra-utils/actors/actors' -import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' - -describe('Test actors API validators', function () { - let server: ServerInfo - - // --------------------------------------------------------------- - - before(async function () { - this.timeout(30000) - - server = await flushAndRunServer(1) - }) - - describe('When getting an actor', function () { - it('Should return 404 with a non existing actorName', async function () { - await getActor(server.url, 'arfaze', HttpStatusCode.NOT_FOUND_404) - }) - - it('Should return 200 with an existing accountName', async function () { - await getActor(server.url, 'root', HttpStatusCode.OK_200) - }) - - it('Should return 200 with an existing channelName', async function () { - await getActor(server.url, 'root_channel', HttpStatusCode.OK_200) - }) - }) - - after(async function () { - await cleanupTests([ server ]) - }) -}) 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 @@ import 'mocha' import * as chai from 'chai' +import { omit } from 'lodash' import * as request from 'supertest' -import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' +import { Account, CustomConfig, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models' import { addVideoInPlaylist, cleanupTests, @@ -14,6 +16,7 @@ import { getConfig, getCustomConfig, getVideosList, + makeGetRequest, makeHTMLRequest, ServerInfo, setAccessTokensToServers, @@ -25,8 +28,6 @@ import { uploadVideo, waitJobs } from '../../shared/extra-utils' -import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' -import { omit } from 'lodash' const expect = chai.expect @@ -144,52 +145,36 @@ describe('Test a client controllers', function () { describe('Open Graph', function () { + async function accountPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text + + expect(text).to.contain(``) + expect(text).to.contain(``) + expect(text).to.contain('') + expect(text).to.contain(``) + } + + async function channelPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text + + expect(text).to.contain(``) + expect(text).to.contain(``) + expect(text).to.contain('') + expect(text).to.contain(``) + } + it('Should have valid Open Graph tags on the account page', async function () { - const accountPageTests = (res) => { - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) - expect(res.text).to.contain('') - expect(res.text).to.contain(``) - } - - accountPageTests(await request(servers[0].url) - .get('/accounts/' + servers[0].user.username) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - accountPageTests(await request(servers[0].url) - .get('/a/' + servers[0].user.username) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - accountPageTests(await request(servers[0].url) - .get('/@' + servers[0].user.username) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + await accountPageTest('/accounts/' + servers[0].user.username) + await accountPageTest('/a/' + servers[0].user.username) + await accountPageTest('/@' + servers[0].user.username) }) it('Should have valid Open Graph tags on the channel page', async function () { - const channelPageOGtests = (res) => { - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) - expect(res.text).to.contain('') - expect(res.text).to.contain(``) - } - - channelPageOGtests(await request(servers[0].url) - .get('/video-channels/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - channelPageOGtests(await request(servers[0].url) - .get('/c/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - channelPageOGtests(await request(servers[0].url) - .get('/@' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + await channelPageTest('/video-channels/' + servers[0].videoChannel.name) + await channelPageTest('/c/' + servers[0].videoChannel.name) + await channelPageTest('/@' + servers[0].videoChannel.name) }) 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 () { describe('Twitter card', async function () { - it('Should have valid twitter card on the watch video page', async function () { - const res = await request(servers[0].url) - .get('/videos/watch/' + servers[0].video.uuid) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200) + describe('Not whitelisted', function () { - expect(res.text).to.contain('') - expect(res.text).to.contain('') - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) - }) + async function accountPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text - it('Should have valid twitter card on the watch playlist page', async function () { - const res = await request(servers[0].url) - .get('/videos/watch/playlist/' + playlistUUID) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200) + expect(text).to.contain('') + expect(text).to.contain('') + expect(text).to.contain(``) + expect(text).to.contain(``) + } - expect(res.text).to.contain('') - expect(res.text).to.contain('') - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) - }) + async function channelPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text + + expect(text).to.contain('') + expect(text).to.contain('') + expect(text).to.contain(``) + expect(text).to.contain(``) + } + + it('Should have valid twitter card on the watch video page', async function () { + const res = await request(servers[0].url) + .get('/videos/watch/' + servers[0].video.uuid) + .set('Accept', 'text/html') + .expect(HttpStatusCode.OK_200) + + expect(res.text).to.contain('') + expect(res.text).to.contain('') + expect(res.text).to.contain(``) + expect(res.text).to.contain(``) + }) + + it('Should have valid twitter card on the watch playlist page', async function () { + const res = await request(servers[0].url) + .get('/videos/watch/playlist/' + playlistUUID) + .set('Accept', 'text/html') + .expect(HttpStatusCode.OK_200) - it('Should have valid twitter card on the account page', async function () { - const accountPageTests = (res) => { expect(res.text).to.contain('') expect(res.text).to.contain('') - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) - } + expect(res.text).to.contain(``) + expect(res.text).to.contain(``) + }) - accountPageTests(await request(servers[0].url) - .get('/accounts/' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + it('Should have valid twitter card on the account page', async function () { + await accountPageTest('/accounts/' + account.name) + await accountPageTest('/a/' + account.name) + await accountPageTest('/@' + account.name) + }) - accountPageTests(await request(servers[0].url) - .get('/a/' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - accountPageTests(await request(servers[0].url) - .get('/@' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + it('Should have valid twitter card on the channel page', async function () { + await channelPageTest('/video-channels/' + servers[0].videoChannel.name) + await channelPageTest('/c/' + servers[0].videoChannel.name) + await channelPageTest('/@' + servers[0].videoChannel.name) + }) }) - it('Should have valid twitter card on the channel page', async function () { - const channelPageTests = (res) => { - expect(res.text).to.contain('') - expect(res.text).to.contain('') - expect(res.text).to.contain(``) - expect(res.text).to.contain(``) + describe('Whitelisted', function () { + + before(async function () { + const res = await getCustomConfig(servers[0].url, servers[0].accessToken) + const config = res.body as CustomConfig + config.services.twitter = { + username: '@Kuja', + whitelisted: true + } + + await updateCustomConfig(servers[0].url, servers[0].accessToken, config) + }) + + async function accountPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text + + expect(text).to.contain('') + expect(text).to.contain('') } - channelPageTests(await request(servers[0].url) - .get('/video-channels/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + async function channelPageTest (path: string) { + const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) + const text = res.text - channelPageTests(await request(servers[0].url) - .get('/c/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - channelPageTests(await request(servers[0].url) - .get('/@' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - }) - - it('Should have valid twitter card if Twitter is whitelisted', async function () { - const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken) - const config = res1.body - config.services.twitter = { - username: '@Kuja', - whitelisted: true + expect(text).to.contain('') + expect(text).to.contain('') } - await updateCustomConfig(servers[0].url, servers[0].accessToken, config) - const resVideoRequest = await request(servers[0].url) - .get('/videos/watch/' + servers[0].video.uuid) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200) + it('Should have valid twitter card on the watch video page', async function () { + const res = await request(servers[0].url) + .get('/videos/watch/' + servers[0].video.uuid) + .set('Accept', 'text/html') + .expect(HttpStatusCode.OK_200) - expect(resVideoRequest.text).to.contain('') - expect(resVideoRequest.text).to.contain('') - - const resVideoPlaylistRequest = await request(servers[0].url) - .get('/videos/watch/playlist/' + playlistUUID) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200) - - expect(resVideoPlaylistRequest.text).to.contain('') - expect(resVideoPlaylistRequest.text).to.contain('') - - const accountTests = (res) => { - expect(res.text).to.contain('') + expect(res.text).to.contain('') expect(res.text).to.contain('') - } + }) - accountTests(await request(servers[0].url) - .get('/accounts/' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + it('Should have valid twitter card on the watch playlist page', async function () { + const res = await request(servers[0].url) + .get('/videos/watch/playlist/' + playlistUUID) + .set('Accept', 'text/html') + .expect(HttpStatusCode.OK_200) - accountTests(await request(servers[0].url) - .get('/a/' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - accountTests(await request(servers[0].url) - .get('/@' + account.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - const channelTests = (res) => { - expect(res.text).to.contain('') + expect(res.text).to.contain('') expect(res.text).to.contain('') - } + }) - channelTests(await request(servers[0].url) - .get('/video-channels/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + it('Should have valid twitter card on the account page', async function () { + await accountPageTest('/accounts/' + account.name) + await accountPageTest('/a/' + account.name) + await accountPageTest('/@' + account.name) + }) - channelTests(await request(servers[0].url) - .get('/c/' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) - - channelTests(await request(servers[0].url) - .get('/@' + servers[0].videoChannel.name) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200)) + it('Should have valid twitter card on the channel page', async function () { + await channelPageTest('/video-channels/' + servers[0].videoChannel.name) + await channelPageTest('/c/' + servers[0].videoChannel.name) + await channelPageTest('/@' + servers[0].videoChannel.name) + }) }) }) 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 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { makeGetRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getActor (url: string, actorName: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/actors/' + actorName - - return makeGetRequest({ - url, - path, - statusCodeExpected - }) -} - -export { - getActor -} 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 @@ -export * from './actors/actors' export * from './bulk/bulk' 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: { contentType?: string range?: string redirects?: number + accept?: string }) { if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 if (options.contentType === undefined) options.contentType = 'application/json' @@ -36,6 +37,7 @@ function makeGetRequest (options: { if (options.token) req.set('Authorization', 'Bearer ' + options.token) if (options.query) req.query(options.query) if (options.range) req.set('Range', options.range) + if (options.accept) req.set('Accept', options.accept) if (options.redirects) req.redirects(options.redirects) return req.expect(options.statusCodeExpected)