diff --git a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts index 5ad83fc47..d05232202 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts +++ b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts @@ -66,7 +66,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit { err => this.notificationsService.error('Error', err.text) ) -} + } isAddButtonDisplayed () { return this.form.value['text'] diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index fab43757a..ded854ee1 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -17,12 +17,12 @@ import { sendUndoLikeToVideoFollowers } from './send' -function fetchRemoteVideoPreview (video: VideoModel) { +function fetchRemoteVideoPreview (video: VideoModel, reject: Function) { // FIXME: use url const host = video.VideoChannel.Account.Actor.Server.host const path = join(STATIC_PATHS.PREVIEWS, video.getPreviewName()) - return request.get(REMOTE_SCHEME.HTTP + '://' + host + path) + return request.get(REMOTE_SCHEME.HTTP + '://' + host + path, err => reject(err)) } async function fetchRemoteVideoDescription (video: VideoModel) { diff --git a/server/lib/cache/videos-preview-cache.ts b/server/lib/cache/videos-preview-cache.ts index 0eb43efcc..ea959076d 100644 --- a/server/lib/cache/videos-preview-cache.ts +++ b/server/lib/cache/videos-preview-cache.ts @@ -52,21 +52,19 @@ class VideosPreviewCache { if (video.isOwned()) throw new Error('Cannot load preview of owned video.') - const res = await this.saveRemotePreviewAndReturnPath(video) - - return res + return this.saveRemotePreviewAndReturnPath(video) } private saveRemotePreviewAndReturnPath (video: VideoModel) { - const req = fetchRemoteVideoPreview(video) return new Promise((res, rej) => { + const req = fetchRemoteVideoPreview(video, rej) const path = join(CACHE.DIRECTORIES.PREVIEWS, video.getPreviewName()) const stream = createWriteStream(path) req.pipe(stream) - .on('finish', () => res(path)) - .on('error', (err) => rej(err)) + .on('error', (err) => rej(err)) + .on('finish', () => res(path)) }) } } diff --git a/server/middlewares/validators/video-channels.ts b/server/middlewares/validators/video-channels.ts index cc7d54c06..0e6eff493 100644 --- a/server/middlewares/validators/video-channels.ts +++ b/server/middlewares/validators/video-channels.ts @@ -51,7 +51,7 @@ const videoChannelsUpdateValidator = [ if (!await isVideoChannelExist(req.params.id, res)) return // We need to make additional checks - if (res.locals.videoChannel.isOwned() === false) { + if (res.locals.videoChannel.Actor.isOwned() === false) { return res.status(403) .json({ error: 'Cannot update video channel of another server' }) .end() diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index a3e8c48d4..8ceeb563a 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts @@ -212,7 +212,7 @@ export class VideoCommentModel extends Model { url: this.url, text: this.text, threadId: this.originCommentId || this.id, - inReplyToCommentId: this.inReplyToCommentId, + inReplyToCommentId: this.inReplyToCommentId || null, videoId: this.videoId, createdAt: this.createdAt, updatedAt: this.updatedAt, diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index e72b2cb6c..7103aec25 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts @@ -69,9 +69,9 @@ describe('Test videos API validator', function () { }) }) - describe('When listing author video channels', function () { - it('Should fail with bad author', async function () { - const path = '/api/v1/videos/authors/hello/channels' + describe('When listing account video channels', function () { + it('Should fail with bad account', async function () { + const path = '/api/v1/videos/accounts/hello/channels' await request(server.url) .get(path) @@ -79,8 +79,8 @@ describe('Test videos API validator', function () { .expect(400) }) - it('Should fail with a unknown author', async function () { - const path = '/api/v1/videos/authors/156/channels' + it('Should fail with a unknown account', async function () { + const path = '/api/v1/videos/accounts/156/channels' await request(server.url) .get(path) diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts index 5112274f0..e8d7ddf38 100644 --- a/server/tests/api/check-params/video-comments.ts +++ b/server/tests/api/check-params/video-comments.ts @@ -2,17 +2,13 @@ import 'mocha' import * as request from 'supertest' -import { - createUser, flushTests, getUserAccessToken, killallServers, makePostBodyRequest, runServer, ServerInfo, setAccessTokensToServers, - uploadVideo -} from '../../utils' +import { flushTests, killallServers, makePostBodyRequest, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../../utils' import { addVideoCommentThread } from '../../utils/video-comments' describe('Test video comments API validator', function () { let pathThread: string let pathComment: string let server: ServerInfo - let accessTokenUser: string let videoUUID: string let commentId: number @@ -27,16 +23,6 @@ describe('Test video comments API validator', function () { await setAccessTokensToServers([ server ]) - { - const user = { - username: 'fake', - password: 'fake_password' - } - await createUser(server.url, server.accessToken, user.username, user.password) - - accessTokenUser = await getUserAccessToken(server, user) - } - { const res = await uploadVideo(server.url, server.accessToken, {}) videoUUID = res.body.video.uuid diff --git a/server/tests/api/multiple-servers.ts b/server/tests/api/multiple-servers.ts index 6fe1fb651..06274d4cc 100644 --- a/server/tests/api/multiple-servers.ts +++ b/server/tests/api/multiple-servers.ts @@ -1,32 +1,18 @@ /* tslint:disable:no-unused-expression */ -import 'mocha' import * as chai from 'chai' +import 'mocha' import { join } from 'path' import * as request from 'supertest' +import { VideoComment, VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' import { - dateIsValid, - flushAndRunMultipleServers, - flushTests, - getVideo, - getVideosList, - killallServers, - rateVideo, - removeVideo, - ServerInfo, - setAccessTokensToServers, - testVideoImage, - updateVideo, - uploadVideo, - wait, - webtorrentAdd, - addVideoChannel, - getVideoChannelsList, - getUserAccessToken, - doubleFollow + addVideoChannel, dateIsValid, doubleFollow, flushAndRunMultipleServers, flushTests, getUserAccessToken, getVideo, + getVideoChannelsList, getVideosList, killallServers, rateVideo, removeVideo, ServerInfo, setAccessTokensToServers, testVideoImage, + updateVideo, uploadVideo, wait, webtorrentAdd } from '../utils' import { createUser } from '../utils/users' +import { addVideoCommentReply, addVideoCommentThread, getVideoCommentThreads, getVideoThreadComments } from '../utils/video-comments' import { viewVideo } from '../utils/videos' const expect = chai.expect @@ -709,6 +695,115 @@ describe('Test multiple servers', function () { }) }) + describe('Should comment these videos', function () { + it('Should add comment (threads and replies)', async function () { + this.timeout(25000) + + { + const text = 'my super first comment' + await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text) + } + + { + const text = 'my super second comment' + await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text) + } + + await wait(5000) + + { + const res = await getVideoCommentThreads(servers[1].url, videoUUID, 0, 5) + const threadId = res.body.data.find(c => c.text === 'my super first comment').id + + const text = 'my super answer to thread 1' + await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text) + } + + await wait(5000) + + { + const res1 = await getVideoCommentThreads(servers[2].url, videoUUID, 0, 5) + const threadId = res1.body.data.find(c => c.text === 'my super first comment').id + + const res2 = await getVideoThreadComments(servers[2].url, videoUUID, threadId) + const childCommentId = res2.body.children[0].comment.id + + const text3 = 'my second answer to thread 1' + await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3) + + const text2 = 'my super answer to answer of thread 1' + await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2) + } + + await wait(5000) + }) + + it('Should have these threads', async function () { + for (const server of servers) { + const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5) + + expect(res.body.total).to.equal(2) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(2) + + { + const comment: VideoComment = res.body.data.find(c => c.text === 'my super first comment') + expect(comment).to.not.be.undefined + expect(comment.inReplyToCommentId).to.be.null + expect(comment.account.name).to.equal('root') + expect(comment.account.host).to.equal('localhost:9001') + expect(comment.totalReplies).to.equal(3) + expect(dateIsValid(comment.createdAt as string)).to.be.true + expect(dateIsValid(comment.updatedAt as string)).to.be.true + } + + { + const comment: VideoComment = res.body.data.find(c => c.text === 'my super second comment') + expect(comment).to.not.be.undefined + expect(comment.inReplyToCommentId).to.be.null + expect(comment.account.name).to.equal('root') + expect(comment.account.host).to.equal('localhost:9003') + expect(comment.totalReplies).to.equal(0) + expect(dateIsValid(comment.createdAt as string)).to.be.true + expect(dateIsValid(comment.updatedAt as string)).to.be.true + } + } + }) + + it('Should have these comments', async function () { + for (const server of servers) { + const res1 = await getVideoCommentThreads(server.url, videoUUID, 0, 5) + const threadId = res1.body.data.find(c => c.text === 'my super first comment').id + + const res2 = await getVideoThreadComments(server.url, videoUUID, threadId) + + const tree: VideoCommentThreadTree = res2.body + expect(tree.comment.text).equal('my super first comment') + expect(tree.comment.account.name).equal('root') + expect(tree.comment.account.host).equal('localhost:9001') + expect(tree.children).to.have.lengthOf(2) + + const firstChild = tree.children[0] + expect(firstChild.comment.text).to.equal('my super answer to thread 1') + expect(firstChild.comment.account.name).equal('root') + expect(firstChild.comment.account.host).equal('localhost:9002') + expect(firstChild.children).to.have.lengthOf(1) + + const childOfFirstChild = firstChild.children[0] + expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') + expect(childOfFirstChild.comment.account.name).equal('root') + expect(childOfFirstChild.comment.account.host).equal('localhost:9003') + expect(childOfFirstChild.children).to.have.lengthOf(0) + + const secondChild = tree.children[1] + expect(secondChild.comment.text).to.equal('my second answer to thread 1') + expect(secondChild.comment.account.name).equal('root') + expect(secondChild.comment.account.host).equal('localhost:9003') + expect(secondChild.children).to.have.lengthOf(0) + } + }) + }) + describe('With minimum parameters', function () { it('Should upload and propagate the video', async function () { this.timeout(50000) diff --git a/server/tests/api/video-comments.ts b/server/tests/api/video-comments.ts index 2c7d1c6e2..f05ca5e81 100644 --- a/server/tests/api/video-comments.ts +++ b/server/tests/api/video-comments.ts @@ -40,7 +40,7 @@ describe('Test video comments', function () { const text = 'my super first comment' const res = await addVideoCommentThread(server.url, server.accessToken, videoUUID, text) - const comment = res.body + const comment = res.body.comment expect(comment.inReplyToCommentId).to.be.null expect(comment.text).equal('my super first comment') @@ -133,9 +133,9 @@ describe('Test video comments', function () { expect(res.body.data).to.have.lengthOf(3) expect(res.body.data[0].text).to.equal('my super first comment') - expect(res.body.data[0].totalReplies).to.equal(2) + expect(res.body.data[0].totalReplies).to.equal(3) expect(res.body.data[1].text).to.equal('super thread 2') - expect(res.body.data[1].totalReplies).to.equal(1) + expect(res.body.data[1].totalReplies).to.equal(0) expect(res.body.data[2].text).to.equal('super thread 3') expect(res.body.data[2].totalReplies).to.equal(0) }) diff --git a/server/tests/utils/video-comments.ts b/server/tests/utils/video-comments.ts index 6a6e225f3..878147049 100644 --- a/server/tests/utils/video-comments.ts +++ b/server/tests/utils/video-comments.ts @@ -1,6 +1,6 @@ import * as request from 'supertest' -function getVideoCommentThreads (url: string, videoId: number, start: number, count: number, sort?: string) { +function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string) { const path = '/api/v1/videos/' + videoId + '/comment-threads' const req = request(url) @@ -15,7 +15,7 @@ function getVideoCommentThreads (url: string, videoId: number, start: number, co .expect('Content-Type', /json/) } -function getVideoThreadComments (url: string, videoId: number, threadId: number) { +function getVideoThreadComments (url: string, videoId: number | string, threadId: number) { const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId return request(url) @@ -39,7 +39,7 @@ function addVideoCommentThread (url: string, token: string, videoId: number | st function addVideoCommentReply ( url: string, token: string, - videoId: number, + videoId: number | string, inReplyToCommentId: number, text: string, expectedStatus = 200