]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Refactor a little bit client canonical URL
authorChocobozzz <me@florianbigard.com>
Tue, 8 Dec 2020 09:53:41 +0000 (10:53 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Tue, 8 Dec 2020 10:15:11 +0000 (11:15 +0100)
server/lib/client-html.ts
server/models/account/account.ts
server/models/video/video-channel.ts
server/tests/client.ts
shared/extra-utils/server/servers.ts

index 211ac3342ac58ef69e72a9c96d47420315e7d055..d97d2318017a3696d310aae4aa23e343ce1bda83 100644 (file)
@@ -117,7 +117,16 @@ export class ClientHtml {
     const schemaType = 'VideoObject'
 
     customHtml = ClientHtml.addTags(customHtml, {
-      url, originUrl, siteName, title, description, image, embed, ogType, twitterCard, schemaType
+      url,
+      originUrl,
+      siteName,
+      title,
+      description,
+      image,
+      embed,
+      ogType,
+      twitterCard,
+      schemaType
     })
 
     return customHtml
@@ -168,7 +177,17 @@ export class ClientHtml {
     const schemaType = 'ItemList'
 
     customHtml = ClientHtml.addTags(customHtml, {
-      url, originUrl, siteName, embed, title, description, image, list, ogType, twitterCard, schemaType
+      url,
+      originUrl,
+      siteName,
+      embed,
+      title,
+      description,
+      image,
+      list,
+      ogType,
+      twitterCard,
+      schemaType
     })
 
     return customHtml
@@ -216,7 +235,7 @@ export class ClientHtml {
     let customHtml = ClientHtml.addTitleTag(html, escapeHTML(entity.getDisplayName()))
     customHtml = ClientHtml.addDescriptionTag(customHtml, escapeHTML(entity.description))
 
-    const url = entity.Actor.url
+    const url = entity.getLocalUrl()
     const originUrl = entity.Actor.url
     const siteName = escapeHTML(CONFIG.INSTANCE.NAME)
     const title = escapeHTML(entity.getDisplayName())
@@ -232,7 +251,17 @@ export class ClientHtml {
     const twitterCard = 'summary'
     const schemaType = 'ProfilePage'
 
-    customHtml = ClientHtml.addTags(customHtml, { url, originUrl, title, siteName, description, image, ogType, twitterCard, schemaType })
+    customHtml = ClientHtml.addTags(customHtml, {
+      url,
+      originUrl,
+      title,
+      siteName,
+      description,
+      image,
+      ogType,
+      twitterCard,
+      schemaType
+    })
 
     return customHtml
   }
index 1162643bec2c7939c823846f824714e7072b35a0..8c244d432bae114bd19e6e30218fc092f04f0b34 100644 (file)
@@ -1,3 +1,5 @@
+import * as Bluebird from 'bluebird'
+import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize'
 import {
   AllowNull,
   BeforeDestroy,
@@ -15,27 +17,33 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
+import { ModelCache } from '@server/models/model-cache'
 import { Account, AccountSummary } from '../../../shared/models/actors'
 import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts'
+import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants'
 import { sendDeleteActor } from '../../lib/activitypub/send'
+import {
+  MAccount,
+  MAccountActor,
+  MAccountAP,
+  MAccountDefault,
+  MAccountFormattable,
+  MAccountSummaryFormattable,
+  MChannelActor
+} from '../../types/models'
 import { ActorModel } from '../activitypub/actor'
+import { ActorFollowModel } from '../activitypub/actor-follow'
 import { ApplicationModel } from '../application/application'
+import { AvatarModel } from '../avatar/avatar'
 import { ServerModel } from '../server/server'
+import { ServerBlocklistModel } from '../server/server-blocklist'
 import { getSort, throwIfNotValid } from '../utils'
+import { VideoModel } from '../video/video'
 import { VideoChannelModel } from '../video/video-channel'
 import { VideoCommentModel } from '../video/video-comment'
-import { UserModel } from './user'
-import { AvatarModel } from '../avatar/avatar'
 import { VideoPlaylistModel } from '../video/video-playlist'
-import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants'
-import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize'
 import { AccountBlocklistModel } from './account-blocklist'
-import { ServerBlocklistModel } from '../server/server-blocklist'
-import { ActorFollowModel } from '../activitypub/actor-follow'
-import { MAccountActor, MAccountAP, MAccountDefault, MAccountFormattable, MAccountSummaryFormattable, MAccount } from '../../types/models'
-import * as Bluebird from 'bluebird'
-import { ModelCache } from '@server/models/model-cache'
-import { VideoModel } from '../video/video'
+import { UserModel } from './user'
 
 export enum ScopeNames {
   SUMMARY = 'SUMMARY'
@@ -441,6 +449,10 @@ export class AccountModel extends Model<AccountModel> {
     return this.name
   }
 
+  getLocalUrl (this: MAccountActor | MChannelActor) {
+    return WEBSERVER.URL + `/accounts/` + this.Actor.preferredUsername
+  }
+
   isBlocked () {
     return this.BlockedAccounts && this.BlockedAccounts.length !== 0
   }
index 202dc513f4515a1016dd2fd047f471a11cf254fd..0c8aef18ff8e98540faa5175500f8ebec2a377d8 100644 (file)
@@ -18,6 +18,7 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
+import { MAccountActor } from '@server/types/models'
 import { ActivityPubActor } from '../../../shared/models/activitypub'
 import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos'
 import {
@@ -628,6 +629,10 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
     })
   }
 
+  getLocalUrl (this: MAccountActor | MChannelActor) {
+    return WEBSERVER.URL + `/video-channels/` + this.Actor.preferredUsername
+  }
+
   getDisplayName () {
     return this.name
   }
index 7bcb999eacd09520dffb3a7e0fd647d7ba78e697..7572fd34a5bb48c7c3b558a946bd59b517f2c670 100644 (file)
@@ -8,20 +8,21 @@ import {
   addVideoInPlaylist,
   cleanupTests,
   createVideoPlaylist,
+  doubleFollow,
+  flushAndRunMultipleServers,
   getAccount,
   getCustomConfig,
   getVideosList,
   makeHTMLRequest,
   ServerInfo,
+  setAccessTokensToServers,
   setDefaultVideoChannel,
   updateCustomConfig,
   updateCustomSubConfig,
-  uploadVideo,
   updateMyUser,
   updateVideoChannel,
-  doubleFollow,
-  flushAndRunMultipleServers,
-  setAccessTokensToServers
+  uploadVideo,
+  waitJobs
 } from '../../shared/extra-utils'
 import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
 
@@ -35,10 +36,7 @@ function checkIndexTags (html: string, title: string, description: string, css:
 
 describe('Test a client controllers', function () {
   let servers: ServerInfo[] = []
-  let server: ServerInfo
   let account: Account
-  let videoUUID: string
-  let videoOriginalUrl: string
 
   const videoName = 'my super name for server 1'
   const videoDescription = 'my super description for server 1'
@@ -53,32 +51,25 @@ describe('Test a client controllers', function () {
     this.timeout(120000)
 
     servers = await flushAndRunMultipleServers(2)
-    const server = servers[0]
 
     await setAccessTokensToServers(servers)
 
-    {
-      const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
-      videoUUID = res.body.video.uuid
-      videoOriginalUrl = res.body.video.url
-    }
-
     await doubleFollow(servers[0], servers[1])
 
-    await setDefaultVideoChannel([ server ])
+    await setDefaultVideoChannel(servers)
 
-    await updateVideoChannel(server.url, server.accessToken, server.videoChannel.name, { description: channelDescription })
+    await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
 
     // Video
 
     const videoAttributes = { name: videoName, description: videoDescription }
-    await uploadVideo(server.url, server.accessToken, videoAttributes)
+    await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
 
-    const resVideosRequest = await getVideosList(server.url)
+    const resVideosRequest = await getVideosList(servers[0].url)
     const videos = resVideosRequest.body.data
     expect(videos.length).to.equal(1)
 
-    server.video = videos[0]
+    servers[0].video = videos[0]
 
     // Playlist
 
@@ -86,54 +77,56 @@ describe('Test a client controllers', function () {
       displayName: playlistName,
       description: playlistDescription,
       privacy: VideoPlaylistPrivacy.PUBLIC,
-      videoChannelId: server.videoChannel.id
+      videoChannelId: servers[0].videoChannel.id
     }
 
-    const resVideoPlaylistRequest = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs })
+    const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
 
     const playlist = resVideoPlaylistRequest.body.videoPlaylist
     const playlistId = playlist.id
     playlistUUID = playlist.uuid
 
     await addVideoInPlaylist({
-      url: server.url,
-      token: server.accessToken,
+      url: servers[0].url,
+      token: servers[0].accessToken,
       playlistId,
-      elementAttrs: { videoId: server.video.id }
+      elementAttrs: { videoId: servers[0].video.id }
     })
 
     // Account
 
-    await updateMyUser({ url: server.url, accessToken: server.accessToken, description: 'my account description' })
+    await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
 
-    const resAccountRequest = await getAccount(server.url, `${server.user.username}@${server.host}`)
+    const resAccountRequest = await getAccount(servers[0].url, `${servers[0].user.username}@${servers[0].host}`)
     account = resAccountRequest.body
+
+    await waitJobs(servers)
   })
 
   describe('oEmbed', function () {
     it('Should have valid oEmbed discovery tags for videos', async function () {
-      const path = '/videos/watch/' + server.video.uuid
-      const res = await request(server.url)
+      const path = '/videos/watch/' + servers[0].video.uuid
+      const res = await request(servers[0].url)
         .get(path)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
-      const port = server.port
+      const port = servers[0].port
 
       const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
-        `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${server.video.uuid}" ` +
-        `title="${server.video.name}" />`
+        `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
+        `title="${servers[0].video.name}" />`
 
       expect(res.text).to.contain(expectedLink)
     })
 
     it('Should have valid oEmbed discovery tags for a playlist', async function () {
-      const res = await request(server.url)
+      const res = await request(servers[0].url)
         .get('/videos/watch/playlist/' + playlistUUID)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
-      const port = server.port
+      const port = servers[0].port
 
       const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
         `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` +
@@ -146,55 +139,55 @@ describe('Test a client controllers', function () {
   describe('Open Graph', function () {
 
     it('Should have valid Open Graph tags on the account page', async function () {
-      const res = await request(server.url)
-        .get('/accounts/' + server.user.username)
+      const res = await request(servers[0].url)
+        .get('/accounts/' + servers[0].user.username)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
       expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
       expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
       expect(res.text).to.contain('<meta property="og:type" content="website" />')
-      expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/accounts/${server.user.username}" />`)
+      expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
     })
 
     it('Should have valid Open Graph tags on the channel page', async function () {
-      const res = await request(server.url)
-        .get('/video-channels/' + server.videoChannel.name)
+      const res = await request(servers[0].url)
+        .get('/video-channels/' + servers[0].videoChannel.name)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
-      expect(res.text).to.contain(`<meta property="og:title" content="${server.videoChannel.displayName}" />`)
+      expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
       expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
       expect(res.text).to.contain('<meta property="og:type" content="website" />')
-      expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/video-channels/${server.videoChannel.name}" />`)
+      expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
     })
 
     it('Should have valid Open Graph tags on the watch page with video id', async function () {
-      const res = await request(server.url)
-        .get('/videos/watch/' + server.video.id)
+      const res = await request(servers[0].url)
+        .get('/videos/watch/' + servers[0].video.id)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
       expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
       expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
       expect(res.text).to.contain('<meta property="og:type" content="video" />')
-      expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`)
+      expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
     })
 
     it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
-      const res = await request(server.url)
-        .get('/videos/watch/' + server.video.uuid)
+      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(`<meta property="og:title" content="${videoName}" />`)
       expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
       expect(res.text).to.contain('<meta property="og:type" content="video" />')
-      expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`)
+      expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
     })
 
     it('Should have valid Open Graph tags on the watch playlist page', async function () {
-      const res = await request(server.url)
+      const res = await request(servers[0].url)
         .get('/videos/watch/playlist/' + playlistUUID)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
@@ -202,15 +195,15 @@ describe('Test a client controllers', function () {
       expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
       expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
       expect(res.text).to.contain('<meta property="og:type" content="video" />')
-      expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/playlist/${playlistUUID}" />`)
+      expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
     })
   })
 
   describe('Twitter card', async function () {
 
     it('Should have valid twitter card on the watch video page', async function () {
-      const res = await request(server.url)
-        .get('/videos/watch/' + server.video.uuid)
+      const res = await request(servers[0].url)
+        .get('/videos/watch/' + servers[0].video.uuid)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
@@ -221,7 +214,7 @@ describe('Test a client controllers', function () {
     })
 
     it('Should have valid twitter card on the watch playlist page', async function () {
-      const res = await request(server.url)
+      const res = await request(servers[0].url)
         .get('/videos/watch/playlist/' + playlistUUID)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
@@ -233,7 +226,7 @@ describe('Test a client controllers', function () {
     })
 
     it('Should have valid twitter card on the account page', async function () {
-      const res = await request(server.url)
+      const res = await request(servers[0].url)
         .get('/accounts/' + account.name)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
@@ -245,35 +238,35 @@ describe('Test a client controllers', function () {
     })
 
     it('Should have valid twitter card on the channel page', async function () {
-      const res = await request(server.url)
-        .get('/video-channels/' + server.videoChannel.name)
+      const res = await request(servers[0].url)
+        .get('/video-channels/' + servers[0].videoChannel.name)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
       expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
       expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
-      expect(res.text).to.contain(`<meta property="twitter:title" content="${server.videoChannel.displayName}" />`)
+      expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
       expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
     })
 
     it('Should have valid twitter card if Twitter is whitelisted', async function () {
-      const res1 = await getCustomConfig(server.url, server.accessToken)
+      const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken)
       const config = res1.body
       config.services.twitter = {
         username: '@Kuja',
         whitelisted: true
       }
-      await updateCustomConfig(server.url, server.accessToken, config)
+      await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
 
-      const resVideoRequest = await request(server.url)
-        .get('/videos/watch/' + server.video.uuid)
+      const resVideoRequest = 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('<meta property="twitter:card" content="player" />')
       expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
 
-      const resVideoPlaylistRequest = await request(server.url)
+      const resVideoPlaylistRequest = await request(servers[0].url)
         .get('/videos/watch/playlist/' + playlistUUID)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
@@ -281,7 +274,7 @@ describe('Test a client controllers', function () {
       expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
       expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
 
-      const resAccountRequest = await request(server.url)
+      const resAccountRequest = await request(servers[0].url)
         .get('/accounts/' + account.name)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
@@ -289,8 +282,8 @@ describe('Test a client controllers', function () {
       expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
       expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
 
-      const resChannelRequest = await request(server.url)
-        .get('/video-channels/' + server.videoChannel.name)
+      const resChannelRequest = await request(servers[0].url)
+        .get('/video-channels/' + servers[0].videoChannel.name)
         .set('Accept', 'text/html')
         .expect(HttpStatusCode.OK_200)
 
@@ -302,14 +295,14 @@ describe('Test a client controllers', function () {
   describe('Index HTML', function () {
 
     it('Should have valid index html tags (title, description...)', async function () {
-      const res = await makeHTMLRequest(server.url, '/videos/trending')
+      const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
 
       const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
       checkIndexTags(res.text, 'PeerTube', description, '')
     })
 
     it('Should update the customized configuration and have the correct index html tags', async function () {
-      await updateCustomSubConfig(server.url, server.accessToken, {
+      await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
         instance: {
           name: 'PeerTube updated',
           shortDescription: 'my short description',
@@ -324,24 +317,39 @@ describe('Test a client controllers', function () {
         }
       })
 
-      const res = await makeHTMLRequest(server.url, '/videos/trending')
+      const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
 
       checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
     })
 
     it('Should have valid index html updated tags (title, description...)', async function () {
-      const res = await makeHTMLRequest(server.url, '/videos/trending')
+      const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
 
       checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
     })
 
     it('Should use the original video URL for the canonical tag', async function () {
-      const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + videoUUID)
-      expect(res.text).to.contain(`<link rel="canonical" href="${videoOriginalUrl}" />`)
+      const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid)
+      expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
+    })
+
+    it('Should use the original account URL for the canonical tag', async function () {
+      const res = await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)
+      expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
+    })
+
+    it('Should use the original channel URL for the canonical tag', async function () {
+      const res = await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)
+      expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
+    })
+
+    it('Should use the original playlist URL for the canonical tag', async function () {
+      const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID)
+      expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`)
     })
   })
 
   after(async function () {
-    await cleanupTests([ server ])
+    await cleanupTests(servers)
   })
 })
index 4ad3eb14a5fab7092da0940e1d39df5679c2c311..e88482e49c1cf125a734c649d0e8c8a061d4bbcf 100644 (file)
@@ -42,6 +42,7 @@ interface ServerInfo {
     id: number
     uuid: string
     name?: string
+    url?: string
     account?: {
       name: string
     }