aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/lib/client-html.ts37
-rw-r--r--server/models/account/account.ts32
-rw-r--r--server/models/video/video-channel.ts5
-rw-r--r--server/tests/client.ts148
-rw-r--r--shared/extra-utils/server/servers.ts1
5 files changed, 139 insertions, 84 deletions
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index 211ac3342..d97d23180 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -117,7 +117,16 @@ export class ClientHtml {
117 const schemaType = 'VideoObject' 117 const schemaType = 'VideoObject'
118 118
119 customHtml = ClientHtml.addTags(customHtml, { 119 customHtml = ClientHtml.addTags(customHtml, {
120 url, originUrl, siteName, title, description, image, embed, ogType, twitterCard, schemaType 120 url,
121 originUrl,
122 siteName,
123 title,
124 description,
125 image,
126 embed,
127 ogType,
128 twitterCard,
129 schemaType
121 }) 130 })
122 131
123 return customHtml 132 return customHtml
@@ -168,7 +177,17 @@ export class ClientHtml {
168 const schemaType = 'ItemList' 177 const schemaType = 'ItemList'
169 178
170 customHtml = ClientHtml.addTags(customHtml, { 179 customHtml = ClientHtml.addTags(customHtml, {
171 url, originUrl, siteName, embed, title, description, image, list, ogType, twitterCard, schemaType 180 url,
181 originUrl,
182 siteName,
183 embed,
184 title,
185 description,
186 image,
187 list,
188 ogType,
189 twitterCard,
190 schemaType
172 }) 191 })
173 192
174 return customHtml 193 return customHtml
@@ -216,7 +235,7 @@ export class ClientHtml {
216 let customHtml = ClientHtml.addTitleTag(html, escapeHTML(entity.getDisplayName())) 235 let customHtml = ClientHtml.addTitleTag(html, escapeHTML(entity.getDisplayName()))
217 customHtml = ClientHtml.addDescriptionTag(customHtml, escapeHTML(entity.description)) 236 customHtml = ClientHtml.addDescriptionTag(customHtml, escapeHTML(entity.description))
218 237
219 const url = entity.Actor.url 238 const url = entity.getLocalUrl()
220 const originUrl = entity.Actor.url 239 const originUrl = entity.Actor.url
221 const siteName = escapeHTML(CONFIG.INSTANCE.NAME) 240 const siteName = escapeHTML(CONFIG.INSTANCE.NAME)
222 const title = escapeHTML(entity.getDisplayName()) 241 const title = escapeHTML(entity.getDisplayName())
@@ -232,7 +251,17 @@ export class ClientHtml {
232 const twitterCard = 'summary' 251 const twitterCard = 'summary'
233 const schemaType = 'ProfilePage' 252 const schemaType = 'ProfilePage'
234 253
235 customHtml = ClientHtml.addTags(customHtml, { url, originUrl, title, siteName, description, image, ogType, twitterCard, schemaType }) 254 customHtml = ClientHtml.addTags(customHtml, {
255 url,
256 originUrl,
257 title,
258 siteName,
259 description,
260 image,
261 ogType,
262 twitterCard,
263 schemaType
264 })
236 265
237 return customHtml 266 return customHtml
238 } 267 }
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 1162643be..8c244d432 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -1,3 +1,5 @@
1import * as Bluebird from 'bluebird'
2import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize'
1import { 3import {
2 AllowNull, 4 AllowNull,
3 BeforeDestroy, 5 BeforeDestroy,
@@ -15,27 +17,33 @@ import {
15 Table, 17 Table,
16 UpdatedAt 18 UpdatedAt
17} from 'sequelize-typescript' 19} from 'sequelize-typescript'
20import { ModelCache } from '@server/models/model-cache'
18import { Account, AccountSummary } from '../../../shared/models/actors' 21import { Account, AccountSummary } from '../../../shared/models/actors'
19import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts' 22import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts'
23import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants'
20import { sendDeleteActor } from '../../lib/activitypub/send' 24import { sendDeleteActor } from '../../lib/activitypub/send'
25import {
26 MAccount,
27 MAccountActor,
28 MAccountAP,
29 MAccountDefault,
30 MAccountFormattable,
31 MAccountSummaryFormattable,
32 MChannelActor
33} from '../../types/models'
21import { ActorModel } from '../activitypub/actor' 34import { ActorModel } from '../activitypub/actor'
35import { ActorFollowModel } from '../activitypub/actor-follow'
22import { ApplicationModel } from '../application/application' 36import { ApplicationModel } from '../application/application'
37import { AvatarModel } from '../avatar/avatar'
23import { ServerModel } from '../server/server' 38import { ServerModel } from '../server/server'
39import { ServerBlocklistModel } from '../server/server-blocklist'
24import { getSort, throwIfNotValid } from '../utils' 40import { getSort, throwIfNotValid } from '../utils'
41import { VideoModel } from '../video/video'
25import { VideoChannelModel } from '../video/video-channel' 42import { VideoChannelModel } from '../video/video-channel'
26import { VideoCommentModel } from '../video/video-comment' 43import { VideoCommentModel } from '../video/video-comment'
27import { UserModel } from './user'
28import { AvatarModel } from '../avatar/avatar'
29import { VideoPlaylistModel } from '../video/video-playlist' 44import { VideoPlaylistModel } from '../video/video-playlist'
30import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants'
31import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize'
32import { AccountBlocklistModel } from './account-blocklist' 45import { AccountBlocklistModel } from './account-blocklist'
33import { ServerBlocklistModel } from '../server/server-blocklist' 46import { UserModel } from './user'
34import { ActorFollowModel } from '../activitypub/actor-follow'
35import { MAccountActor, MAccountAP, MAccountDefault, MAccountFormattable, MAccountSummaryFormattable, MAccount } from '../../types/models'
36import * as Bluebird from 'bluebird'
37import { ModelCache } from '@server/models/model-cache'
38import { VideoModel } from '../video/video'
39 47
40export enum ScopeNames { 48export enum ScopeNames {
41 SUMMARY = 'SUMMARY' 49 SUMMARY = 'SUMMARY'
@@ -441,6 +449,10 @@ export class AccountModel extends Model<AccountModel> {
441 return this.name 449 return this.name
442 } 450 }
443 451
452 getLocalUrl (this: MAccountActor | MChannelActor) {
453 return WEBSERVER.URL + `/accounts/` + this.Actor.preferredUsername
454 }
455
444 isBlocked () { 456 isBlocked () {
445 return this.BlockedAccounts && this.BlockedAccounts.length !== 0 457 return this.BlockedAccounts && this.BlockedAccounts.length !== 0
446 } 458 }
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index 202dc513f..0c8aef18f 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -18,6 +18,7 @@ import {
18 Table, 18 Table,
19 UpdatedAt 19 UpdatedAt
20} from 'sequelize-typescript' 20} from 'sequelize-typescript'
21import { MAccountActor } from '@server/types/models'
21import { ActivityPubActor } from '../../../shared/models/activitypub' 22import { ActivityPubActor } from '../../../shared/models/activitypub'
22import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' 23import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos'
23import { 24import {
@@ -628,6 +629,10 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
628 }) 629 })
629 } 630 }
630 631
632 getLocalUrl (this: MAccountActor | MChannelActor) {
633 return WEBSERVER.URL + `/video-channels/` + this.Actor.preferredUsername
634 }
635
631 getDisplayName () { 636 getDisplayName () {
632 return this.name 637 return this.name
633 } 638 }
diff --git a/server/tests/client.ts b/server/tests/client.ts
index 7bcb999ea..7572fd34a 100644
--- a/server/tests/client.ts
+++ b/server/tests/client.ts
@@ -8,20 +8,21 @@ import {
8 addVideoInPlaylist, 8 addVideoInPlaylist,
9 cleanupTests, 9 cleanupTests,
10 createVideoPlaylist, 10 createVideoPlaylist,
11 doubleFollow,
12 flushAndRunMultipleServers,
11 getAccount, 13 getAccount,
12 getCustomConfig, 14 getCustomConfig,
13 getVideosList, 15 getVideosList,
14 makeHTMLRequest, 16 makeHTMLRequest,
15 ServerInfo, 17 ServerInfo,
18 setAccessTokensToServers,
16 setDefaultVideoChannel, 19 setDefaultVideoChannel,
17 updateCustomConfig, 20 updateCustomConfig,
18 updateCustomSubConfig, 21 updateCustomSubConfig,
19 uploadVideo,
20 updateMyUser, 22 updateMyUser,
21 updateVideoChannel, 23 updateVideoChannel,
22 doubleFollow, 24 uploadVideo,
23 flushAndRunMultipleServers, 25 waitJobs
24 setAccessTokensToServers
25} from '../../shared/extra-utils' 26} from '../../shared/extra-utils'
26import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' 27import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
27 28
@@ -35,10 +36,7 @@ function checkIndexTags (html: string, title: string, description: string, css:
35 36
36describe('Test a client controllers', function () { 37describe('Test a client controllers', function () {
37 let servers: ServerInfo[] = [] 38 let servers: ServerInfo[] = []
38 let server: ServerInfo
39 let account: Account 39 let account: Account
40 let videoUUID: string
41 let videoOriginalUrl: string
42 40
43 const videoName = 'my super name for server 1' 41 const videoName = 'my super name for server 1'
44 const videoDescription = 'my super description for server 1' 42 const videoDescription = 'my super description for server 1'
@@ -53,32 +51,25 @@ describe('Test a client controllers', function () {
53 this.timeout(120000) 51 this.timeout(120000)
54 52
55 servers = await flushAndRunMultipleServers(2) 53 servers = await flushAndRunMultipleServers(2)
56 const server = servers[0]
57 54
58 await setAccessTokensToServers(servers) 55 await setAccessTokensToServers(servers)
59 56
60 {
61 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
62 videoUUID = res.body.video.uuid
63 videoOriginalUrl = res.body.video.url
64 }
65
66 await doubleFollow(servers[0], servers[1]) 57 await doubleFollow(servers[0], servers[1])
67 58
68 await setDefaultVideoChannel([ server ]) 59 await setDefaultVideoChannel(servers)
69 60
70 await updateVideoChannel(server.url, server.accessToken, server.videoChannel.name, { description: channelDescription }) 61 await updateVideoChannel(servers[0].url, servers[0].accessToken, servers[0].videoChannel.name, { description: channelDescription })
71 62
72 // Video 63 // Video
73 64
74 const videoAttributes = { name: videoName, description: videoDescription } 65 const videoAttributes = { name: videoName, description: videoDescription }
75 await uploadVideo(server.url, server.accessToken, videoAttributes) 66 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
76 67
77 const resVideosRequest = await getVideosList(server.url) 68 const resVideosRequest = await getVideosList(servers[0].url)
78 const videos = resVideosRequest.body.data 69 const videos = resVideosRequest.body.data
79 expect(videos.length).to.equal(1) 70 expect(videos.length).to.equal(1)
80 71
81 server.video = videos[0] 72 servers[0].video = videos[0]
82 73
83 // Playlist 74 // Playlist
84 75
@@ -86,54 +77,56 @@ describe('Test a client controllers', function () {
86 displayName: playlistName, 77 displayName: playlistName,
87 description: playlistDescription, 78 description: playlistDescription,
88 privacy: VideoPlaylistPrivacy.PUBLIC, 79 privacy: VideoPlaylistPrivacy.PUBLIC,
89 videoChannelId: server.videoChannel.id 80 videoChannelId: servers[0].videoChannel.id
90 } 81 }
91 82
92 const resVideoPlaylistRequest = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs }) 83 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
93 84
94 const playlist = resVideoPlaylistRequest.body.videoPlaylist 85 const playlist = resVideoPlaylistRequest.body.videoPlaylist
95 const playlistId = playlist.id 86 const playlistId = playlist.id
96 playlistUUID = playlist.uuid 87 playlistUUID = playlist.uuid
97 88
98 await addVideoInPlaylist({ 89 await addVideoInPlaylist({
99 url: server.url, 90 url: servers[0].url,
100 token: server.accessToken, 91 token: servers[0].accessToken,
101 playlistId, 92 playlistId,
102 elementAttrs: { videoId: server.video.id } 93 elementAttrs: { videoId: servers[0].video.id }
103 }) 94 })
104 95
105 // Account 96 // Account
106 97
107 await updateMyUser({ url: server.url, accessToken: server.accessToken, description: 'my account description' }) 98 await updateMyUser({ url: servers[0].url, accessToken: servers[0].accessToken, description: 'my account description' })
108 99
109 const resAccountRequest = await getAccount(server.url, `${server.user.username}@${server.host}`) 100 const resAccountRequest = await getAccount(servers[0].url, `${servers[0].user.username}@${servers[0].host}`)
110 account = resAccountRequest.body 101 account = resAccountRequest.body
102
103 await waitJobs(servers)
111 }) 104 })
112 105
113 describe('oEmbed', function () { 106 describe('oEmbed', function () {
114 it('Should have valid oEmbed discovery tags for videos', async function () { 107 it('Should have valid oEmbed discovery tags for videos', async function () {
115 const path = '/videos/watch/' + server.video.uuid 108 const path = '/videos/watch/' + servers[0].video.uuid
116 const res = await request(server.url) 109 const res = await request(servers[0].url)
117 .get(path) 110 .get(path)
118 .set('Accept', 'text/html') 111 .set('Accept', 'text/html')
119 .expect(HttpStatusCode.OK_200) 112 .expect(HttpStatusCode.OK_200)
120 113
121 const port = server.port 114 const port = servers[0].port
122 115
123 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + 116 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
124 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${server.video.uuid}" ` + 117 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
125 `title="${server.video.name}" />` 118 `title="${servers[0].video.name}" />`
126 119
127 expect(res.text).to.contain(expectedLink) 120 expect(res.text).to.contain(expectedLink)
128 }) 121 })
129 122
130 it('Should have valid oEmbed discovery tags for a playlist', async function () { 123 it('Should have valid oEmbed discovery tags for a playlist', async function () {
131 const res = await request(server.url) 124 const res = await request(servers[0].url)
132 .get('/videos/watch/playlist/' + playlistUUID) 125 .get('/videos/watch/playlist/' + playlistUUID)
133 .set('Accept', 'text/html') 126 .set('Accept', 'text/html')
134 .expect(HttpStatusCode.OK_200) 127 .expect(HttpStatusCode.OK_200)
135 128
136 const port = server.port 129 const port = servers[0].port
137 130
138 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + 131 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
139 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` + 132 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` +
@@ -146,55 +139,55 @@ describe('Test a client controllers', function () {
146 describe('Open Graph', function () { 139 describe('Open Graph', function () {
147 140
148 it('Should have valid Open Graph tags on the account page', async function () { 141 it('Should have valid Open Graph tags on the account page', async function () {
149 const res = await request(server.url) 142 const res = await request(servers[0].url)
150 .get('/accounts/' + server.user.username) 143 .get('/accounts/' + servers[0].user.username)
151 .set('Accept', 'text/html') 144 .set('Accept', 'text/html')
152 .expect(HttpStatusCode.OK_200) 145 .expect(HttpStatusCode.OK_200)
153 146
154 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`) 147 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
155 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`) 148 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
156 expect(res.text).to.contain('<meta property="og:type" content="website" />') 149 expect(res.text).to.contain('<meta property="og:type" content="website" />')
157 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/accounts/${server.user.username}" />`) 150 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
158 }) 151 })
159 152
160 it('Should have valid Open Graph tags on the channel page', async function () { 153 it('Should have valid Open Graph tags on the channel page', async function () {
161 const res = await request(server.url) 154 const res = await request(servers[0].url)
162 .get('/video-channels/' + server.videoChannel.name) 155 .get('/video-channels/' + servers[0].videoChannel.name)
163 .set('Accept', 'text/html') 156 .set('Accept', 'text/html')
164 .expect(HttpStatusCode.OK_200) 157 .expect(HttpStatusCode.OK_200)
165 158
166 expect(res.text).to.contain(`<meta property="og:title" content="${server.videoChannel.displayName}" />`) 159 expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
167 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`) 160 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
168 expect(res.text).to.contain('<meta property="og:type" content="website" />') 161 expect(res.text).to.contain('<meta property="og:type" content="website" />')
169 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/video-channels/${server.videoChannel.name}" />`) 162 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
170 }) 163 })
171 164
172 it('Should have valid Open Graph tags on the watch page with video id', async function () { 165 it('Should have valid Open Graph tags on the watch page with video id', async function () {
173 const res = await request(server.url) 166 const res = await request(servers[0].url)
174 .get('/videos/watch/' + server.video.id) 167 .get('/videos/watch/' + servers[0].video.id)
175 .set('Accept', 'text/html') 168 .set('Accept', 'text/html')
176 .expect(HttpStatusCode.OK_200) 169 .expect(HttpStatusCode.OK_200)
177 170
178 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) 171 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
179 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`) 172 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
180 expect(res.text).to.contain('<meta property="og:type" content="video" />') 173 expect(res.text).to.contain('<meta property="og:type" content="video" />')
181 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`) 174 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
182 }) 175 })
183 176
184 it('Should have valid Open Graph tags on the watch page with video uuid', async function () { 177 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
185 const res = await request(server.url) 178 const res = await request(servers[0].url)
186 .get('/videos/watch/' + server.video.uuid) 179 .get('/videos/watch/' + servers[0].video.uuid)
187 .set('Accept', 'text/html') 180 .set('Accept', 'text/html')
188 .expect(HttpStatusCode.OK_200) 181 .expect(HttpStatusCode.OK_200)
189 182
190 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) 183 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
191 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`) 184 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`)
192 expect(res.text).to.contain('<meta property="og:type" content="video" />') 185 expect(res.text).to.contain('<meta property="og:type" content="video" />')
193 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/${server.video.uuid}" />`) 186 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
194 }) 187 })
195 188
196 it('Should have valid Open Graph tags on the watch playlist page', async function () { 189 it('Should have valid Open Graph tags on the watch playlist page', async function () {
197 const res = await request(server.url) 190 const res = await request(servers[0].url)
198 .get('/videos/watch/playlist/' + playlistUUID) 191 .get('/videos/watch/playlist/' + playlistUUID)
199 .set('Accept', 'text/html') 192 .set('Accept', 'text/html')
200 .expect(HttpStatusCode.OK_200) 193 .expect(HttpStatusCode.OK_200)
@@ -202,15 +195,15 @@ describe('Test a client controllers', function () {
202 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`) 195 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
203 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`) 196 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
204 expect(res.text).to.contain('<meta property="og:type" content="video" />') 197 expect(res.text).to.contain('<meta property="og:type" content="video" />')
205 expect(res.text).to.contain(`<meta property="og:url" content="${server.url}/videos/watch/playlist/${playlistUUID}" />`) 198 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
206 }) 199 })
207 }) 200 })
208 201
209 describe('Twitter card', async function () { 202 describe('Twitter card', async function () {
210 203
211 it('Should have valid twitter card on the watch video page', async function () { 204 it('Should have valid twitter card on the watch video page', async function () {
212 const res = await request(server.url) 205 const res = await request(servers[0].url)
213 .get('/videos/watch/' + server.video.uuid) 206 .get('/videos/watch/' + servers[0].video.uuid)
214 .set('Accept', 'text/html') 207 .set('Accept', 'text/html')
215 .expect(HttpStatusCode.OK_200) 208 .expect(HttpStatusCode.OK_200)
216 209
@@ -221,7 +214,7 @@ describe('Test a client controllers', function () {
221 }) 214 })
222 215
223 it('Should have valid twitter card on the watch playlist page', async function () { 216 it('Should have valid twitter card on the watch playlist page', async function () {
224 const res = await request(server.url) 217 const res = await request(servers[0].url)
225 .get('/videos/watch/playlist/' + playlistUUID) 218 .get('/videos/watch/playlist/' + playlistUUID)
226 .set('Accept', 'text/html') 219 .set('Accept', 'text/html')
227 .expect(HttpStatusCode.OK_200) 220 .expect(HttpStatusCode.OK_200)
@@ -233,7 +226,7 @@ describe('Test a client controllers', function () {
233 }) 226 })
234 227
235 it('Should have valid twitter card on the account page', async function () { 228 it('Should have valid twitter card on the account page', async function () {
236 const res = await request(server.url) 229 const res = await request(servers[0].url)
237 .get('/accounts/' + account.name) 230 .get('/accounts/' + account.name)
238 .set('Accept', 'text/html') 231 .set('Accept', 'text/html')
239 .expect(HttpStatusCode.OK_200) 232 .expect(HttpStatusCode.OK_200)
@@ -245,35 +238,35 @@ describe('Test a client controllers', function () {
245 }) 238 })
246 239
247 it('Should have valid twitter card on the channel page', async function () { 240 it('Should have valid twitter card on the channel page', async function () {
248 const res = await request(server.url) 241 const res = await request(servers[0].url)
249 .get('/video-channels/' + server.videoChannel.name) 242 .get('/video-channels/' + servers[0].videoChannel.name)
250 .set('Accept', 'text/html') 243 .set('Accept', 'text/html')
251 .expect(HttpStatusCode.OK_200) 244 .expect(HttpStatusCode.OK_200)
252 245
253 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') 246 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />')
254 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') 247 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
255 expect(res.text).to.contain(`<meta property="twitter:title" content="${server.videoChannel.displayName}" />`) 248 expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
256 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) 249 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
257 }) 250 })
258 251
259 it('Should have valid twitter card if Twitter is whitelisted', async function () { 252 it('Should have valid twitter card if Twitter is whitelisted', async function () {
260 const res1 = await getCustomConfig(server.url, server.accessToken) 253 const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken)
261 const config = res1.body 254 const config = res1.body
262 config.services.twitter = { 255 config.services.twitter = {
263 username: '@Kuja', 256 username: '@Kuja',
264 whitelisted: true 257 whitelisted: true
265 } 258 }
266 await updateCustomConfig(server.url, server.accessToken, config) 259 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
267 260
268 const resVideoRequest = await request(server.url) 261 const resVideoRequest = await request(servers[0].url)
269 .get('/videos/watch/' + server.video.uuid) 262 .get('/videos/watch/' + servers[0].video.uuid)
270 .set('Accept', 'text/html') 263 .set('Accept', 'text/html')
271 .expect(HttpStatusCode.OK_200) 264 .expect(HttpStatusCode.OK_200)
272 265
273 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />') 266 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />')
274 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 267 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
275 268
276 const resVideoPlaylistRequest = await request(server.url) 269 const resVideoPlaylistRequest = await request(servers[0].url)
277 .get('/videos/watch/playlist/' + playlistUUID) 270 .get('/videos/watch/playlist/' + playlistUUID)
278 .set('Accept', 'text/html') 271 .set('Accept', 'text/html')
279 .expect(HttpStatusCode.OK_200) 272 .expect(HttpStatusCode.OK_200)
@@ -281,7 +274,7 @@ describe('Test a client controllers', function () {
281 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />') 274 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />')
282 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 275 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
283 276
284 const resAccountRequest = await request(server.url) 277 const resAccountRequest = await request(servers[0].url)
285 .get('/accounts/' + account.name) 278 .get('/accounts/' + account.name)
286 .set('Accept', 'text/html') 279 .set('Accept', 'text/html')
287 .expect(HttpStatusCode.OK_200) 280 .expect(HttpStatusCode.OK_200)
@@ -289,8 +282,8 @@ describe('Test a client controllers', function () {
289 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />') 282 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />')
290 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 283 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
291 284
292 const resChannelRequest = await request(server.url) 285 const resChannelRequest = await request(servers[0].url)
293 .get('/video-channels/' + server.videoChannel.name) 286 .get('/video-channels/' + servers[0].videoChannel.name)
294 .set('Accept', 'text/html') 287 .set('Accept', 'text/html')
295 .expect(HttpStatusCode.OK_200) 288 .expect(HttpStatusCode.OK_200)
296 289
@@ -302,14 +295,14 @@ describe('Test a client controllers', function () {
302 describe('Index HTML', function () { 295 describe('Index HTML', function () {
303 296
304 it('Should have valid index html tags (title, description...)', async function () { 297 it('Should have valid index html tags (title, description...)', async function () {
305 const res = await makeHTMLRequest(server.url, '/videos/trending') 298 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
306 299
307 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' 300 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
308 checkIndexTags(res.text, 'PeerTube', description, '') 301 checkIndexTags(res.text, 'PeerTube', description, '')
309 }) 302 })
310 303
311 it('Should update the customized configuration and have the correct index html tags', async function () { 304 it('Should update the customized configuration and have the correct index html tags', async function () {
312 await updateCustomSubConfig(server.url, server.accessToken, { 305 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
313 instance: { 306 instance: {
314 name: 'PeerTube updated', 307 name: 'PeerTube updated',
315 shortDescription: 'my short description', 308 shortDescription: 'my short description',
@@ -324,24 +317,39 @@ describe('Test a client controllers', function () {
324 } 317 }
325 }) 318 })
326 319
327 const res = await makeHTMLRequest(server.url, '/videos/trending') 320 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
328 321
329 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 322 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
330 }) 323 })
331 324
332 it('Should have valid index html updated tags (title, description...)', async function () { 325 it('Should have valid index html updated tags (title, description...)', async function () {
333 const res = await makeHTMLRequest(server.url, '/videos/trending') 326 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
334 327
335 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 328 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }')
336 }) 329 })
337 330
338 it('Should use the original video URL for the canonical tag', async function () { 331 it('Should use the original video URL for the canonical tag', async function () {
339 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + videoUUID) 332 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid)
340 expect(res.text).to.contain(`<link rel="canonical" href="${videoOriginalUrl}" />`) 333 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
334 })
335
336 it('Should use the original account URL for the canonical tag', async function () {
337 const res = await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host)
338 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
339 })
340
341 it('Should use the original channel URL for the canonical tag', async function () {
342 const res = await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host)
343 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
344 })
345
346 it('Should use the original playlist URL for the canonical tag', async function () {
347 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID)
348 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`)
341 }) 349 })
342 }) 350 })
343 351
344 after(async function () { 352 after(async function () {
345 await cleanupTests([ server ]) 353 await cleanupTests(servers)
346 }) 354 })
347}) 355})
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index 4ad3eb14a..e88482e49 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -42,6 +42,7 @@ interface ServerInfo {
42 id: number 42 id: number
43 uuid: string 43 uuid: string
44 name?: string 44 name?: string
45 url?: string
45 account?: { 46 account?: {
46 name: string 47 name: string
47 } 48 }