aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xscripts/update-host.ts141
-rw-r--r--server.ts11
-rw-r--r--server/initializers/checker.ts25
-rw-r--r--server/tests/cli/update-host.ts65
-rw-r--r--support/doc/tools.md9
-rw-r--r--support/doc/translation.md5
6 files changed, 222 insertions, 34 deletions
diff --git a/scripts/update-host.ts b/scripts/update-host.ts
index ed8b999a9..1dc19664d 100755
--- a/scripts/update-host.ts
+++ b/scripts/update-host.ts
@@ -1,35 +1,126 @@
1import { getServerActor } from '../server/helpers/utils' 1import { CONFIG, initDatabaseModels } from '../server/initializers'
2import { initDatabaseModels } from '../server/initializers'
3import { ActorFollowModel } from '../server/models/activitypub/actor-follow' 2import { ActorFollowModel } from '../server/models/activitypub/actor-follow'
4import { VideoModel } from '../server/models/video/video' 3import { VideoModel } from '../server/models/video/video'
4import { ActorModel } from '../server/models/activitypub/actor'
5import {
6 getAccountActivityPubUrl,
7 getAnnounceActivityPubUrl,
8 getVideoActivityPubUrl, getVideoChannelActivityPubUrl,
9 getVideoCommentActivityPubUrl
10} from '../server/lib/activitypub'
11import { VideoShareModel } from '../server/models/video/video-share'
12import { VideoCommentModel } from '../server/models/video/video-comment'
13import { getServerActor } from '../server/helpers/utils'
14import { AccountModel } from '../server/models/account/account'
15import { VideoChannelModel } from '../server/models/video/video-channel'
5 16
6initDatabaseModels(true) 17run()
7 .then(() => { 18 .then(() => process.exit(0))
8 return getServerActor() 19 .catch(err => {
9 }) 20 console.error(err)
10 .then(serverAccount => { 21 process.exit(-1)
11 return ActorFollowModel.listAcceptedFollowingUrlsForApi([ serverAccount.id ], undefined)
12 })
13 .then(res => {
14 return res.total > 0
15 }) 22 })
16 .then(hasFollowing => { 23
24async function run () {
25 await initDatabaseModels(true)
26
27 const serverAccount = await getServerActor()
28
29 {
30 const res = await ActorFollowModel.listAcceptedFollowingUrlsForApi([ serverAccount.id ], undefined)
31 const hasFollowing = res.total > 0
32
17 if (hasFollowing === true) { 33 if (hasFollowing === true) {
18 console.log('Cannot update host because you follow other servers!') 34 throw new Error('Cannot update host because you follow other servers!')
19 process.exit(-1)
20 } 35 }
36 }
21 37
22 console.log('Updating torrent files.') 38 console.log('Updating actors.')
23 return VideoModel.list() 39
24 }) 40 const actors: ActorModel[] = await ActorModel.unscoped().findAll({
25 .then(async videos => { 41 include: [
26 for (const video of videos) { 42 {
27 for (const file of video.VideoFiles) { 43 model: VideoChannelModel.unscoped(),
28 await video.createTorrentAndSetInfoHash(file) 44 required: false
29 console.log('Updated video ' + video.uuid) 45 },
46 {
47 model: AccountModel.unscoped(),
48 required: false
30 } 49 }
31 } 50 ]
51 })
52 for (const actor of actors) {
53 if (actor.isOwned() === false) continue
54
55 console.log('Updating actor ' + actor.url)
56
57 const newUrl = actor.Account
58 ? getAccountActivityPubUrl(actor.preferredUsername)
59 : getVideoChannelActivityPubUrl(actor.preferredUsername)
60
61 actor.url = newUrl
62 actor.inboxUrl = newUrl + '/inbox'
63 actor.outboxUrl = newUrl + '/outbox'
64 actor.sharedInboxUrl = CONFIG.WEBSERVER.URL + '/inbox'
65 actor.followersUrl = newUrl + '/followers'
66 actor.followingUrl = newUrl + '/following'
67
68 await actor.save()
69 }
70
71 console.log('Updating video shares.')
72
73 const videoShares: VideoShareModel[] = await VideoShareModel.findAll({
74 include: [ VideoModel.unscoped(), ActorModel.unscoped() ]
32 }) 75 })
33 .then(() => { 76 for (const videoShare of videoShares) {
34 process.exit(0) 77 if (videoShare.Video.isOwned() === false) continue
78
79 console.log('Updating video share ' + videoShare.url)
80
81 videoShare.url = getAnnounceActivityPubUrl(videoShare.Video.url, videoShare.Actor)
82 await videoShare.save()
83 }
84
85 console.log('Updating video comments.')
86 const videoComments: VideoCommentModel[] = await VideoCommentModel.findAll({
87 include: [
88 {
89 model: VideoModel.unscoped()
90 },
91 {
92 model: AccountModel.unscoped(),
93 include: [
94 {
95 model: ActorModel.unscoped()
96 }
97 ]
98 }
99 ]
35 }) 100 })
101 for (const comment of videoComments) {
102 if (comment.isOwned() === false) continue
103
104 console.log('Updating comment ' + comment.url)
105
106 comment.url = getVideoCommentActivityPubUrl(comment.Video, comment)
107 await comment.save()
108 }
109
110 console.log('Updating video and torrent files.')
111
112 const videos = await VideoModel.list()
113 for (const video of videos) {
114 if (video.isOwned() === false) continue
115
116 console.log('Updated video ' + video.uuid)
117
118 video.url = getVideoActivityPubUrl(video)
119 await video.save()
120
121 for (const file of video.VideoFiles) {
122 console.log('Updating torrent file %s of video %s.', file.resolution, video.uuid)
123 await video.createTorrentAndSetInfoHash(file)
124 }
125 }
126}
diff --git a/server.ts b/server.ts
index ef89ff5f6..f756bf9d4 100644
--- a/server.ts
+++ b/server.ts
@@ -1,6 +1,4 @@
1// FIXME: https://github.com/nodejs/node/pull/16853 1// FIXME: https://github.com/nodejs/node/pull/16853
2import { ScheduleVideoUpdateModel } from './server/models/video/schedule-video-update'
3
4require('tls').DEFAULT_ECDH_CURVE = 'auto' 2require('tls').DEFAULT_ECDH_CURVE = 'auto'
5 3
6import { isTestInstance } from './server/helpers/core-utils' 4import { isTestInstance } from './server/helpers/core-utils'
@@ -26,7 +24,7 @@ process.title = 'peertube'
26const app = express() 24const app = express()
27 25
28// ----------- Core checker ----------- 26// ----------- Core checker -----------
29import { checkMissedConfig, checkFFmpeg, checkConfig } from './server/initializers/checker' 27import { checkMissedConfig, checkFFmpeg, checkConfig, checkActivityPubUrls } from './server/initializers/checker'
30 28
31// Do not use barrels because we don't want to load all modules here (we need to initialize database first) 29// Do not use barrels because we don't want to load all modules here (we need to initialize database first)
32import { logger } from './server/helpers/logger' 30import { logger } from './server/helpers/logger'
@@ -191,6 +189,13 @@ async function startApplication () {
191 189
192 await installApplication() 190 await installApplication()
193 191
192 // Check activity pub urls are valid
193 checkActivityPubUrls()
194 .catch(err => {
195 logger.error('Error in ActivityPub URLs checker.', { err })
196 process.exit(-1)
197 })
198
194 // Email initialization 199 // Email initialization
195 Emailer.Instance.init() 200 Emailer.Instance.init()
196 await Emailer.Instance.checkConnectionOrDie() 201 await Emailer.Instance.checkConnectionOrDie()
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts
index 6259c7b6c..d5402098f 100644
--- a/server/initializers/checker.ts
+++ b/server/initializers/checker.ts
@@ -3,6 +3,28 @@ import { promisify0 } from '../helpers/core-utils'
3import { UserModel } from '../models/account/user' 3import { UserModel } from '../models/account/user'
4import { ApplicationModel } from '../models/application/application' 4import { ApplicationModel } from '../models/application/application'
5import { OAuthClientModel } from '../models/oauth/oauth-client' 5import { OAuthClientModel } from '../models/oauth/oauth-client'
6import { parse } from 'url'
7import { CONFIG } from './constants'
8import { logger } from '../helpers/logger'
9import { getServerActor } from '../helpers/utils'
10
11async function checkActivityPubUrls () {
12 const actor = await getServerActor()
13
14 const parsed = parse(actor.url)
15 if (CONFIG.WEBSERVER.HOST !== parsed.host) {
16 const NODE_ENV = config.util.getEnv('NODE_ENV')
17 const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')
18
19 logger.warn(
20 'It seems PeerTube was started (and created some data) with another domain name. ' +
21 'This means you will not be able to federate! ' +
22 'Please use %s %s npm run update-host to fix this.',
23 NODE_CONFIG_DIR ? `NODE_CONFIG_DIR=${NODE_CONFIG_DIR}` : '',
24 NODE_ENV ? `NODE_ENV=${NODE_ENV}` : ''
25 )
26 }
27}
6 28
7// Some checks on configuration files 29// Some checks on configuration files
8// Return an error message, or null if everything is okay 30// Return an error message, or null if everything is okay
@@ -95,5 +117,6 @@ export {
95 checkMissedConfig, 117 checkMissedConfig,
96 clientsExist, 118 clientsExist,
97 usersExist, 119 usersExist,
98 applicationExist 120 applicationExist,
121 checkActivityPubUrls
99} 122}
diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts
index d0c6d2042..968b7bd7f 100644
--- a/server/tests/cli/update-host.ts
+++ b/server/tests/cli/update-host.ts
@@ -3,20 +3,26 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { VideoDetails } from '../../../shared/models/videos' 5import { VideoDetails } from '../../../shared/models/videos'
6import { waitJobs } from '../utils/server/jobs'
7import { addVideoCommentThread } from '../utils/videos/video-comments'
6import { 8import {
9 addVideoChannel,
10 createUser,
7 execCLI, 11 execCLI,
8 flushTests, 12 flushTests,
9 getEnvCli, 13 getEnvCli,
10 getVideo, 14 getVideo,
15 getVideoChannelsList,
11 getVideosList, 16 getVideosList,
12 killallServers, 17 killallServers,
18 makeActivityPubGetRequest,
13 parseTorrentVideo, 19 parseTorrentVideo,
14 runServer, 20 runServer,
15 ServerInfo, 21 ServerInfo,
16 setAccessTokensToServers, 22 setAccessTokensToServers,
17 uploadVideo 23 uploadVideo
18} from '../utils' 24} from '../utils'
19import { waitJobs } from '../utils/server/jobs' 25import { getAccountsList } from '../utils/users/accounts'
20 26
21const expect = chai.expect 27const expect = chai.expect
22 28
@@ -39,13 +45,28 @@ describe('Test update host scripts', function () {
39 45
40 // Upload two videos for our needs 46 // Upload two videos for our needs
41 const videoAttributes = {} 47 const videoAttributes = {}
48 const resVideo1 = await uploadVideo(server.url, server.accessToken, videoAttributes)
49 const video1UUID = resVideo1.body.video.uuid
42 await uploadVideo(server.url, server.accessToken, videoAttributes) 50 await uploadVideo(server.url, server.accessToken, videoAttributes)
43 await uploadVideo(server.url, server.accessToken, videoAttributes) 51
52 // Create a user
53 await createUser(server.url, server.accessToken, 'toto', 'coucou')
54
55 // Create channel
56 const videoChannel = {
57 displayName: 'second video channel',
58 description: 'super video channel description'
59 }
60 await addVideoChannel(server.url, server.accessToken, videoChannel)
61
62 // Create comments
63 const text = 'my super first comment'
64 await addVideoCommentThread(server.url, server.accessToken, video1UUID, text)
44 65
45 await waitJobs(server) 66 await waitJobs(server)
46 }) 67 })
47 68
48 it('Should update torrent hosts', async function () { 69 it('Should run update host', async function () {
49 this.timeout(30000) 70 this.timeout(30000)
50 71
51 killallServers([ server ]) 72 killallServers([ server ])
@@ -54,6 +75,44 @@ describe('Test update host scripts', function () {
54 75
55 const env = getEnvCli(server) 76 const env = getEnvCli(server)
56 await execCLI(`${env} npm run update-host`) 77 await execCLI(`${env} npm run update-host`)
78 })
79
80 it('Should have updated videos url', async function () {
81 const res = await getVideosList(server.url)
82 expect(res.body.total).to.equal(2)
83
84 for (const video of res.body.data) {
85 const { body } = await makeActivityPubGetRequest(server.url, '/videos/watch/' + video.uuid)
86
87 expect(body.id).to.equal('http://localhost:9002/videos/watch/' + video.uuid)
88 }
89 })
90
91 it('Should have updated video channels url', async function () {
92 const res = await getVideoChannelsList(server.url, 0, 5, '-name')
93 expect(res.body.total).to.equal(3)
94
95 for (const channel of res.body.data) {
96 const { body } = await makeActivityPubGetRequest(server.url, '/video-channels/' + channel.uuid)
97
98 expect(body.id).to.equal('http://localhost:9002/video-channels/' + channel.uuid)
99 }
100 })
101
102 it('Should have update accounts url', async function () {
103 const res = await getAccountsList(server.url)
104 expect(res.body.total).to.equal(3)
105
106 for (const account of res.body.data) {
107 const usernameWithDomain = account.name
108 const { body } = await makeActivityPubGetRequest(server.url, '/accounts/' + usernameWithDomain)
109
110 expect(body.id).to.equal('http://localhost:9002/accounts/' + usernameWithDomain)
111 }
112 })
113
114 it('Should update torrent hosts', async function () {
115 this.timeout(30000)
57 116
58 const res = await getVideosList(server.url) 117 const res = await getVideosList(server.url)
59 const videos = res.body.data 118 const videos = res.body.data
diff --git a/support/doc/tools.md b/support/doc/tools.md
index 0addc0803..cb3944595 100644
--- a/support/doc/tools.md
+++ b/support/doc/tools.md
@@ -113,4 +113,13 @@ To delete them (a confirmation will be demanded first):
113 113
114``` 114```
115$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage 115$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run prune-storage
116```
117
118### update-host.js
119
120If you started PeerTube with a domain, and then changed it you will have invalid torrent files and invalid URLs in your database.
121To fix this, you have to run:
122
123```
124$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run update-host
116``` \ No newline at end of file 125``` \ No newline at end of file
diff --git a/support/doc/translation.md b/support/doc/translation.md
index 3ad239278..52045083c 100644
--- a/support/doc/translation.md
+++ b/support/doc/translation.md
@@ -18,7 +18,8 @@ If you don't see your locale in the platform, please [create an issue](https://g
18 18
19There are 4 files: 19There are 4 files:
20 * **angular**: contains client strings 20 * **angular**: contains client strings
21 * **player**: contains player strings 21 * **player**: contains player strings.
22 * **server**: contains server strings (language, licence...) 22 Most of the strings come from VideoJS, so you can help yourself by using [video.js JSON files](https://github.com/videojs/video.js/tree/master/lang)
23 * **server**: contains server strings (privacies, licences...)
23 * **iso639**: contains iso639 (languages) strings used by PeerTube to describe the audio language of a particular video. 24 * **iso639**: contains iso639 (languages) strings used by PeerTube to describe the audio language of a particular video.
24 It's the reason why these strings should be translated too. There are many strings so do not hesitate to translate only main audio languages. 25 It's the reason why these strings should be translated too. There are many strings so do not hesitate to translate only main audio languages.