diff options
author | Chocobozzz <me@florianbigard.com> | 2017-12-22 12:10:40 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2017-12-22 12:12:33 +0100 |
commit | d3ea89759104e6c14b00443526f2c2a0a13aeb97 (patch) | |
tree | e30dc7025f284c163a450cb08f7060875e368e6c | |
parent | bf1f650817dadfd5eeee9e5e0b6b6938c136e25d (diff) | |
download | PeerTube-d3ea89759104e6c14b00443526f2c2a0a13aeb97.tar.gz PeerTube-d3ea89759104e6c14b00443526f2c2a0a13aeb97.tar.zst PeerTube-d3ea89759104e6c14b00443526f2c2a0a13aeb97.zip |
Begin unit tests
-rw-r--r-- | server/controllers/api/videos/comment.ts | 8 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 4 | ||||
-rw-r--r-- | server/lib/video-comment.ts | 24 | ||||
-rw-r--r-- | server/middlewares/validators/video-comments.ts | 21 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 30 | ||||
-rw-r--r-- | server/tests/api/index-slow.ts | 1 | ||||
-rw-r--r-- | server/tests/api/video-comments.ts | 135 | ||||
-rw-r--r-- | server/tests/utils/video-comments.ts | 64 | ||||
-rw-r--r-- | shared/models/videos/video-comment.model.ts | 7 |
9 files changed, 252 insertions, 42 deletions
diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index 81c9e7d16..ac64f0154 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts | |||
@@ -78,9 +78,9 @@ function addVideoCommentThread (req: express.Request, res: express.Response) { | |||
78 | return sequelizeTypescript.transaction(async t => { | 78 | return sequelizeTypescript.transaction(async t => { |
79 | return createVideoComment({ | 79 | return createVideoComment({ |
80 | text: videoCommentInfo.text, | 80 | text: videoCommentInfo.text, |
81 | inReplyToComment: null, | 81 | inReplyToCommentId: null, |
82 | video: res.locals.video, | 82 | video: res.locals.video, |
83 | actorId: res.locals.oauth.token.User.Account.Actor.id | 83 | accountId: res.locals.oauth.token.User.Account.id |
84 | }, t) | 84 | }, t) |
85 | }) | 85 | }) |
86 | } | 86 | } |
@@ -106,9 +106,9 @@ function addVideoCommentReply (req: express.Request, res: express.Response, next | |||
106 | return sequelizeTypescript.transaction(async t => { | 106 | return sequelizeTypescript.transaction(async t => { |
107 | return createVideoComment({ | 107 | return createVideoComment({ |
108 | text: videoCommentInfo.text, | 108 | text: videoCommentInfo.text, |
109 | inReplyToComment: res.locals.videoComment.id, | 109 | inReplyToCommentId: res.locals.videoComment.id, |
110 | video: res.locals.video, | 110 | video: res.locals.video, |
111 | actorId: res.locals.oauth.token.User.Account.Actor.id | 111 | accountId: res.locals.oauth.token.User.Account.id |
112 | }, t) | 112 | }, t) |
113 | }) | 113 | }) |
114 | } | 114 | } |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 102e54b19..6c2ee97eb 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -267,7 +267,7 @@ function createVideoComment (byActor: ActorModel, activity: ActivityCreate) { | |||
267 | originCommentId: null, | 267 | originCommentId: null, |
268 | inReplyToComment: null, | 268 | inReplyToComment: null, |
269 | videoId: video.id, | 269 | videoId: video.id, |
270 | actorId: byActor.id | 270 | accountId: byAccount.id |
271 | }, { transaction: t }) | 271 | }, { transaction: t }) |
272 | } | 272 | } |
273 | 273 | ||
@@ -281,7 +281,7 @@ function createVideoComment (byActor: ActorModel, activity: ActivityCreate) { | |||
281 | originCommentId, | 281 | originCommentId, |
282 | inReplyToCommentId: inReplyToComment.id, | 282 | inReplyToCommentId: inReplyToComment.id, |
283 | videoId: inReplyToComment.videoId, | 283 | videoId: inReplyToComment.videoId, |
284 | actorId: byActor.id | 284 | accountId: byAccount.id |
285 | }, { transaction: t }) | 285 | }, { transaction: t }) |
286 | }) | 286 | }) |
287 | } | 287 | } |
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index edb72d4e2..e3fe26e35 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts | |||
@@ -1,19 +1,20 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { ResultList } from '../../shared/models' | 2 | import { ResultList } from '../../shared/models' |
3 | import { VideoCommentThread } from '../../shared/models/videos/video-comment.model' | 3 | import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model' |
4 | import { VideoModel } from '../models/video/video' | 4 | import { VideoModel } from '../models/video/video' |
5 | import { VideoCommentModel } from '../models/video/video-comment' | 5 | import { VideoCommentModel } from '../models/video/video-comment' |
6 | import { getVideoCommentActivityPubUrl } from './activitypub' | 6 | import { getVideoCommentActivityPubUrl } from './activitypub' |
7 | 7 | ||
8 | async function createVideoComment (obj: { | 8 | async function createVideoComment (obj: { |
9 | text: string, | 9 | text: string, |
10 | inReplyToComment: number, | 10 | inReplyToCommentId: number, |
11 | video: VideoModel | 11 | video: VideoModel |
12 | actorId: number | 12 | accountId: number |
13 | }, t: Sequelize.Transaction) { | 13 | }, t: Sequelize.Transaction) { |
14 | let originCommentId: number = null | 14 | let originCommentId: number = null |
15 | if (obj.inReplyToComment) { | 15 | |
16 | const repliedComment = await VideoCommentModel.loadById(obj.inReplyToComment) | 16 | if (obj.inReplyToCommentId) { |
17 | const repliedComment = await VideoCommentModel.loadById(obj.inReplyToCommentId) | ||
17 | if (!repliedComment) throw new Error('Unknown replied comment.') | 18 | if (!repliedComment) throw new Error('Unknown replied comment.') |
18 | 19 | ||
19 | originCommentId = repliedComment.originCommentId || repliedComment.id | 20 | originCommentId = repliedComment.originCommentId || repliedComment.id |
@@ -22,22 +23,23 @@ async function createVideoComment (obj: { | |||
22 | const comment = await VideoCommentModel.create({ | 23 | const comment = await VideoCommentModel.create({ |
23 | text: obj.text, | 24 | text: obj.text, |
24 | originCommentId, | 25 | originCommentId, |
25 | inReplyToComment: obj.inReplyToComment, | 26 | inReplyToCommentId: obj.inReplyToCommentId, |
26 | videoId: obj.video.id, | 27 | videoId: obj.video.id, |
27 | actorId: obj.actorId | 28 | accountId: obj.accountId, |
28 | }, { transaction: t }) | 29 | url: 'fake url' |
30 | }, { transaction: t, validate: false }) | ||
29 | 31 | ||
30 | comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment)) | 32 | comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment)) |
31 | 33 | ||
32 | return comment.save({ transaction: t }) | 34 | return comment.save({ transaction: t }) |
33 | } | 35 | } |
34 | 36 | ||
35 | function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>): VideoCommentThread { | 37 | function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>): VideoCommentThreadTree { |
36 | // Comments are sorted by id ASC | 38 | // Comments are sorted by id ASC |
37 | const comments = resultList.data | 39 | const comments = resultList.data |
38 | 40 | ||
39 | const comment = comments.shift() | 41 | const comment = comments.shift() |
40 | const thread: VideoCommentThread = { | 42 | const thread: VideoCommentThreadTree = { |
41 | comment: comment.toFormattedJSON(), | 43 | comment: comment.toFormattedJSON(), |
42 | children: [] | 44 | children: [] |
43 | } | 45 | } |
@@ -48,7 +50,7 @@ function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>): | |||
48 | while (comments.length !== 0) { | 50 | while (comments.length !== 0) { |
49 | const childComment = comments.shift() | 51 | const childComment = comments.shift() |
50 | 52 | ||
51 | const childCommentThread: VideoCommentThread = { | 53 | const childCommentThread: VideoCommentThreadTree = { |
52 | comment: childComment.toFormattedJSON(), | 54 | comment: childComment.toFormattedJSON(), |
53 | children: [] | 55 | children: [] |
54 | } | 56 | } |
diff --git a/server/middlewares/validators/video-comments.ts b/server/middlewares/validators/video-comments.ts index 5e1be00f2..1d19fac58 100644 --- a/server/middlewares/validators/video-comments.ts +++ b/server/middlewares/validators/video-comments.ts | |||
@@ -4,6 +4,7 @@ import { logger } from '../../helpers' | |||
4 | import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc' |
5 | import { isValidVideoCommentText } from '../../helpers/custom-validators/video-comments' | 5 | import { isValidVideoCommentText } from '../../helpers/custom-validators/video-comments' |
6 | import { isVideoExist } from '../../helpers/custom-validators/videos' | 6 | import { isVideoExist } from '../../helpers/custom-validators/videos' |
7 | import { VideoModel } from '../../models/video/video' | ||
7 | import { VideoCommentModel } from '../../models/video/video-comment' | 8 | import { VideoCommentModel } from '../../models/video/video-comment' |
8 | import { areValidationErrors } from './utils' | 9 | import { areValidationErrors } from './utils' |
9 | 10 | ||
@@ -11,7 +12,7 @@ const listVideoCommentThreadsValidator = [ | |||
11 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), | 12 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), |
12 | 13 | ||
13 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 14 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
14 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | 15 | logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params }) |
15 | 16 | ||
16 | if (areValidationErrors(req, res)) return | 17 | if (areValidationErrors(req, res)) return |
17 | if (!await isVideoExist(req.params.videoId, res)) return | 18 | if (!await isVideoExist(req.params.videoId, res)) return |
@@ -25,11 +26,11 @@ const listVideoThreadCommentsValidator = [ | |||
25 | param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'), | 26 | param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'), |
26 | 27 | ||
27 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 28 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
28 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | 29 | logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params }) |
29 | 30 | ||
30 | if (areValidationErrors(req, res)) return | 31 | if (areValidationErrors(req, res)) return |
31 | if (!await isVideoExist(req.params.videoId, res)) return | 32 | if (!await isVideoExist(req.params.videoId, res)) return |
32 | if (!await isVideoCommentThreadExist(req.params.threadId, req.params.videoId, res)) return | 33 | if (!await isVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return |
33 | 34 | ||
34 | return next() | 35 | return next() |
35 | } | 36 | } |
@@ -40,7 +41,7 @@ const addVideoCommentThreadValidator = [ | |||
40 | body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), | 41 | body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), |
41 | 42 | ||
42 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 43 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
43 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | 44 | logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params }) |
44 | 45 | ||
45 | if (areValidationErrors(req, res)) return | 46 | if (areValidationErrors(req, res)) return |
46 | if (!await isVideoExist(req.params.videoId, res)) return | 47 | if (!await isVideoExist(req.params.videoId, res)) return |
@@ -55,11 +56,11 @@ const addVideoCommentReplyValidator = [ | |||
55 | body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), | 56 | body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), |
56 | 57 | ||
57 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 58 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
58 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | 59 | logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params }) |
59 | 60 | ||
60 | if (areValidationErrors(req, res)) return | 61 | if (areValidationErrors(req, res)) return |
61 | if (!await isVideoExist(req.params.videoId, res)) return | 62 | if (!await isVideoExist(req.params.videoId, res)) return |
62 | if (!await isVideoCommentExist(req.params.commentId, req.params.videoId, res)) return | 63 | if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return |
63 | 64 | ||
64 | return next() | 65 | return next() |
65 | } | 66 | } |
@@ -76,7 +77,7 @@ export { | |||
76 | 77 | ||
77 | // --------------------------------------------------------------------------- | 78 | // --------------------------------------------------------------------------- |
78 | 79 | ||
79 | async function isVideoCommentThreadExist (id: number, videoId: number, res: express.Response) { | 80 | async function isVideoCommentThreadExist (id: number, video: VideoModel, res: express.Response) { |
80 | const videoComment = await VideoCommentModel.loadById(id) | 81 | const videoComment = await VideoCommentModel.loadById(id) |
81 | 82 | ||
82 | if (!videoComment) { | 83 | if (!videoComment) { |
@@ -87,7 +88,7 @@ async function isVideoCommentThreadExist (id: number, videoId: number, res: expr | |||
87 | return false | 88 | return false |
88 | } | 89 | } |
89 | 90 | ||
90 | if (videoComment.videoId !== videoId) { | 91 | if (videoComment.videoId !== video.id) { |
91 | res.status(400) | 92 | res.status(400) |
92 | .json({ error: 'Video comment is associated to this video.' }) | 93 | .json({ error: 'Video comment is associated to this video.' }) |
93 | .end() | 94 | .end() |
@@ -107,7 +108,7 @@ async function isVideoCommentThreadExist (id: number, videoId: number, res: expr | |||
107 | return true | 108 | return true |
108 | } | 109 | } |
109 | 110 | ||
110 | async function isVideoCommentExist (id: number, videoId: number, res: express.Response) { | 111 | async function isVideoCommentExist (id: number, video: VideoModel, res: express.Response) { |
111 | const videoComment = await VideoCommentModel.loadById(id) | 112 | const videoComment = await VideoCommentModel.loadById(id) |
112 | 113 | ||
113 | if (!videoComment) { | 114 | if (!videoComment) { |
@@ -118,7 +119,7 @@ async function isVideoCommentExist (id: number, videoId: number, res: express.Re | |||
118 | return false | 119 | return false |
119 | } | 120 | } |
120 | 121 | ||
121 | if (videoComment.videoId !== videoId) { | 122 | if (videoComment.videoId !== video.id) { |
122 | res.status(400) | 123 | res.status(400) |
123 | .json({ error: 'Video comment is associated to this video.' }) | 124 | .json({ error: 'Video comment is associated to this video.' }) |
124 | .end() | 125 | .end() |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index d66f933ee..8e84bfc06 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -6,18 +6,18 @@ import { | |||
6 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' | 6 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' |
7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub' | 7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub' |
8 | import { CONSTRAINTS_FIELDS } from '../../initializers' | 8 | import { CONSTRAINTS_FIELDS } from '../../initializers' |
9 | import { ActorModel } from '../activitypub/actor' | 9 | import { AccountModel } from '../account/account' |
10 | import { getSort, throwIfNotValid } from '../utils' | 10 | import { getSort, throwIfNotValid } from '../utils' |
11 | import { VideoModel } from './video' | 11 | import { VideoModel } from './video' |
12 | 12 | ||
13 | enum ScopeNames { | 13 | enum ScopeNames { |
14 | WITH_ACTOR = 'WITH_ACTOR' | 14 | WITH_ACCOUNT = 'WITH_ACCOUNT' |
15 | } | 15 | } |
16 | 16 | ||
17 | @Scopes({ | 17 | @Scopes({ |
18 | [ScopeNames.WITH_ACTOR]: { | 18 | [ScopeNames.WITH_ACCOUNT]: { |
19 | include: [ | 19 | include: [ |
20 | () => ActorModel | 20 | () => AccountModel |
21 | ] | 21 | ] |
22 | } | 22 | } |
23 | }) | 23 | }) |
@@ -84,17 +84,17 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
84 | }) | 84 | }) |
85 | Video: VideoModel | 85 | Video: VideoModel |
86 | 86 | ||
87 | @ForeignKey(() => ActorModel) | 87 | @ForeignKey(() => AccountModel) |
88 | @Column | 88 | @Column |
89 | actorId: number | 89 | accountId: number |
90 | 90 | ||
91 | @BelongsTo(() => ActorModel, { | 91 | @BelongsTo(() => AccountModel, { |
92 | foreignKey: { | 92 | foreignKey: { |
93 | allowNull: false | 93 | allowNull: false |
94 | }, | 94 | }, |
95 | onDelete: 'CASCADE' | 95 | onDelete: 'CASCADE' |
96 | }) | 96 | }) |
97 | Actor: ActorModel | 97 | Account: AccountModel |
98 | 98 | ||
99 | @AfterDestroy | 99 | @AfterDestroy |
100 | static sendDeleteIfOwned (instance: VideoCommentModel) { | 100 | static sendDeleteIfOwned (instance: VideoCommentModel) { |
@@ -132,12 +132,13 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
132 | limit: count, | 132 | limit: count, |
133 | order: [ getSort(sort) ], | 133 | order: [ getSort(sort) ], |
134 | where: { | 134 | where: { |
135 | videoId | 135 | videoId, |
136 | inReplyToCommentId: null | ||
136 | } | 137 | } |
137 | } | 138 | } |
138 | 139 | ||
139 | return VideoCommentModel | 140 | return VideoCommentModel |
140 | .scope([ ScopeNames.WITH_ACTOR ]) | 141 | .scope([ ScopeNames.WITH_ACCOUNT ]) |
141 | .findAndCountAll(query) | 142 | .findAndCountAll(query) |
142 | .then(({ rows, count }) => { | 143 | .then(({ rows, count }) => { |
143 | return { total: count, data: rows } | 144 | return { total: count, data: rows } |
@@ -146,7 +147,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
146 | 147 | ||
147 | static listThreadCommentsForApi (videoId: number, threadId: number) { | 148 | static listThreadCommentsForApi (videoId: number, threadId: number) { |
148 | const query = { | 149 | const query = { |
149 | order: [ 'id', 'ASC' ], | 150 | order: [ [ 'id', 'ASC' ] ], |
150 | where: { | 151 | where: { |
151 | videoId, | 152 | videoId, |
152 | [ Sequelize.Op.or ]: [ | 153 | [ Sequelize.Op.or ]: [ |
@@ -157,7 +158,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
157 | } | 158 | } |
158 | 159 | ||
159 | return VideoCommentModel | 160 | return VideoCommentModel |
160 | .scope([ ScopeNames.WITH_ACTOR ]) | 161 | .scope([ ScopeNames.WITH_ACCOUNT ]) |
161 | .findAndCountAll(query) | 162 | .findAndCountAll(query) |
162 | .then(({ rows, count }) => { | 163 | .then(({ rows, count }) => { |
163 | return { total: count, data: rows } | 164 | return { total: count, data: rows } |
@@ -173,7 +174,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
173 | inReplyToCommentId: this.inReplyToCommentId, | 174 | inReplyToCommentId: this.inReplyToCommentId, |
174 | videoId: this.videoId, | 175 | videoId: this.videoId, |
175 | createdAt: this.createdAt, | 176 | createdAt: this.createdAt, |
176 | updatedAt: this.updatedAt | 177 | updatedAt: this.updatedAt, |
178 | account: { | ||
179 | name: this.Account.name | ||
180 | } | ||
177 | } as VideoComment | 181 | } as VideoComment |
178 | } | 182 | } |
179 | } | 183 | } |
diff --git a/server/tests/api/index-slow.ts b/server/tests/api/index-slow.ts index 4cd5b09a2..b525d6f01 100644 --- a/server/tests/api/index-slow.ts +++ b/server/tests/api/index-slow.ts | |||
@@ -4,3 +4,4 @@ import './video-transcoder' | |||
4 | import './multiple-servers' | 4 | import './multiple-servers' |
5 | import './follows' | 5 | import './follows' |
6 | import './jobs' | 6 | import './jobs' |
7 | import './video-comments' | ||
diff --git a/server/tests/api/video-comments.ts b/server/tests/api/video-comments.ts new file mode 100644 index 000000000..fbc1a0a20 --- /dev/null +++ b/server/tests/api/video-comments.ts | |||
@@ -0,0 +1,135 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | ||
5 | import { VideoComment, VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | ||
6 | import { dateIsValid, flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../utils' | ||
7 | import { addVideoCommentReply, addVideoCommentThread, getVideoCommentThreads, getVideoThreadComments } from '../utils/video-comments' | ||
8 | |||
9 | const expect = chai.expect | ||
10 | |||
11 | describe('Test a video comments', function () { | ||
12 | let server: ServerInfo | ||
13 | let videoId | ||
14 | let videoUUID | ||
15 | let threadId | ||
16 | |||
17 | before(async function () { | ||
18 | this.timeout(10000) | ||
19 | |||
20 | await flushTests() | ||
21 | |||
22 | server = await runServer(1) | ||
23 | |||
24 | await setAccessTokensToServers([ server ]) | ||
25 | |||
26 | const res = await uploadVideo(server.url, server.accessToken, {}) | ||
27 | videoUUID = res.body.video.uuid | ||
28 | videoId = res.body.video.id | ||
29 | }) | ||
30 | |||
31 | it('Should not have threads on this video', async function () { | ||
32 | const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5) | ||
33 | |||
34 | expect(res.body.total).to.equal(0) | ||
35 | expect(res.body.data).to.be.an('array') | ||
36 | expect(res.body.data).to.have.lengthOf(0) | ||
37 | }) | ||
38 | |||
39 | it('Should create a thread in this video', async function () { | ||
40 | const text = 'my super first comment' | ||
41 | |||
42 | await addVideoCommentThread(server.url, server.accessToken, videoUUID, text) | ||
43 | }) | ||
44 | |||
45 | it('Should list threads of this video', async function () { | ||
46 | const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5) | ||
47 | |||
48 | expect(res.body.total).to.equal(1) | ||
49 | expect(res.body.data).to.be.an('array') | ||
50 | expect(res.body.data).to.have.lengthOf(1) | ||
51 | |||
52 | const comment: VideoComment = res.body.data[0] | ||
53 | expect(comment.inReplyToCommentId).to.be.null | ||
54 | expect(comment.text).equal('my super first comment') | ||
55 | expect(comment.videoId).to.equal(videoId) | ||
56 | expect(comment.id).to.equal(comment.threadId) | ||
57 | expect(comment.account.name).to.equal('root') | ||
58 | expect(dateIsValid(comment.createdAt as string)).to.be.true | ||
59 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | ||
60 | |||
61 | threadId = comment.threadId | ||
62 | }) | ||
63 | |||
64 | it('Should get all the thread created', async function () { | ||
65 | const res = await getVideoThreadComments(server.url, videoUUID, threadId) | ||
66 | |||
67 | const rootComment = res.body.comment | ||
68 | expect(rootComment.inReplyToCommentId).to.be.null | ||
69 | expect(rootComment.text).equal('my super first comment') | ||
70 | expect(rootComment.videoId).to.equal(videoId) | ||
71 | expect(dateIsValid(rootComment.createdAt as string)).to.be.true | ||
72 | expect(dateIsValid(rootComment.updatedAt as string)).to.be.true | ||
73 | }) | ||
74 | |||
75 | it('Should create multiple replies in this thread', async function () { | ||
76 | const text1 = 'my super answer to thread 1' | ||
77 | const childCommentRes = await addVideoCommentReply(server.url, server.accessToken, videoId, threadId, text1) | ||
78 | const childCommentId = childCommentRes.body.comment.id | ||
79 | |||
80 | const text2 = 'my super answer to answer of thread 1' | ||
81 | await addVideoCommentReply(server.url, server.accessToken, videoId, childCommentId, text2) | ||
82 | |||
83 | const text3 = 'my second answer to thread 1' | ||
84 | await addVideoCommentReply(server.url, server.accessToken, videoId, threadId, text3) | ||
85 | }) | ||
86 | |||
87 | it('Should get correctly the replies', async function () { | ||
88 | const res = await getVideoThreadComments(server.url, videoUUID, threadId) | ||
89 | |||
90 | const tree: VideoCommentThreadTree = res.body | ||
91 | expect(tree.comment.text).equal('my super first comment') | ||
92 | expect(tree.children).to.have.lengthOf(2) | ||
93 | |||
94 | const firstChild = tree.children[0] | ||
95 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') | ||
96 | expect(firstChild.children).to.have.lengthOf(1) | ||
97 | |||
98 | const childOfFirstChild = firstChild.children[0] | ||
99 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') | ||
100 | expect(childOfFirstChild.children).to.have.lengthOf(0) | ||
101 | |||
102 | const secondChild = tree.children[1] | ||
103 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') | ||
104 | expect(secondChild.children).to.have.lengthOf(0) | ||
105 | }) | ||
106 | |||
107 | it('Should create other threads', async function () { | ||
108 | const text1 = 'super thread 2' | ||
109 | await addVideoCommentThread(server.url, server.accessToken, videoUUID, text1) | ||
110 | |||
111 | const text2 = 'super thread 3' | ||
112 | await addVideoCommentThread(server.url, server.accessToken, videoUUID, text2) | ||
113 | }) | ||
114 | |||
115 | it('Should list the threads', async function () { | ||
116 | const res = await getVideoCommentThreads(server.url, videoUUID, 0, 5, 'createdAt') | ||
117 | |||
118 | expect(res.body.total).to.equal(3) | ||
119 | expect(res.body.data).to.be.an('array') | ||
120 | expect(res.body.data).to.have.lengthOf(3) | ||
121 | |||
122 | expect(res.body.data[0].text).to.equal('my super first comment') | ||
123 | expect(res.body.data[1].text).to.equal('super thread 2') | ||
124 | expect(res.body.data[2].text).to.equal('super thread 3') | ||
125 | }) | ||
126 | |||
127 | after(async function () { | ||
128 | killallServers([ server ]) | ||
129 | |||
130 | // Keep the logs if the test failed | ||
131 | if (this['ok']) { | ||
132 | await flushTests() | ||
133 | } | ||
134 | }) | ||
135 | }) | ||
diff --git a/server/tests/utils/video-comments.ts b/server/tests/utils/video-comments.ts new file mode 100644 index 000000000..be062f815 --- /dev/null +++ b/server/tests/utils/video-comments.ts | |||
@@ -0,0 +1,64 @@ | |||
1 | import * as request from 'supertest' | ||
2 | |||
3 | function getVideoCommentThreads (url: string, videoId: number, start: number, count: number, sort?: string) { | ||
4 | const path = '/api/v1/videos/' + videoId + '/comment-threads' | ||
5 | |||
6 | const req = request(url) | ||
7 | .get(path) | ||
8 | .query({ start: start }) | ||
9 | .query({ count: count }) | ||
10 | |||
11 | if (sort) req.query({ sort }) | ||
12 | |||
13 | return req.set('Accept', 'application/json') | ||
14 | .expect(200) | ||
15 | .expect('Content-Type', /json/) | ||
16 | } | ||
17 | |||
18 | function getVideoThreadComments (url: string, videoId: number, threadId: number) { | ||
19 | const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId | ||
20 | |||
21 | return request(url) | ||
22 | .get(path) | ||
23 | .set('Accept', 'application/json') | ||
24 | .expect(200) | ||
25 | .expect('Content-Type', /json/) | ||
26 | } | ||
27 | |||
28 | function addVideoCommentThread (url: string, token: string, videoId: number, text: string, expectedStatus = 200) { | ||
29 | const path = '/api/v1/videos/' + videoId + '/comment-threads' | ||
30 | |||
31 | return request(url) | ||
32 | .post(path) | ||
33 | .send({ text }) | ||
34 | .set('Accept', 'application/json') | ||
35 | .set('Authorization', 'Bearer ' + token) | ||
36 | .expect(expectedStatus) | ||
37 | } | ||
38 | |||
39 | function addVideoCommentReply ( | ||
40 | url: string, | ||
41 | token: string, | ||
42 | videoId: number, | ||
43 | inReplyToCommentId: number, | ||
44 | text: string, | ||
45 | expectedStatus = 200 | ||
46 | ) { | ||
47 | const path = '/api/v1/videos/' + videoId + '/comments/' + inReplyToCommentId | ||
48 | |||
49 | return request(url) | ||
50 | .post(path) | ||
51 | .send({ text }) | ||
52 | .set('Accept', 'application/json') | ||
53 | .set('Authorization', 'Bearer ' + token) | ||
54 | .expect(expectedStatus) | ||
55 | } | ||
56 | |||
57 | // --------------------------------------------------------------------------- | ||
58 | |||
59 | export { | ||
60 | getVideoCommentThreads, | ||
61 | getVideoThreadComments, | ||
62 | addVideoCommentThread, | ||
63 | addVideoCommentReply | ||
64 | } | ||
diff --git a/shared/models/videos/video-comment.model.ts b/shared/models/videos/video-comment.model.ts index bdeb30d28..69884782f 100644 --- a/shared/models/videos/video-comment.model.ts +++ b/shared/models/videos/video-comment.model.ts | |||
@@ -7,11 +7,14 @@ export interface VideoComment { | |||
7 | videoId: number | 7 | videoId: number |
8 | createdAt: Date | string | 8 | createdAt: Date | string |
9 | updatedAt: Date | string | 9 | updatedAt: Date | string |
10 | account: { | ||
11 | name: string | ||
12 | } | ||
10 | } | 13 | } |
11 | 14 | ||
12 | export interface VideoCommentThread { | 15 | export interface VideoCommentThreadTree { |
13 | comment: VideoComment | 16 | comment: VideoComment |
14 | children: VideoCommentThread[] | 17 | children: VideoCommentThreadTree[] |
15 | } | 18 | } |
16 | 19 | ||
17 | export interface VideoCommentCreate { | 20 | export interface VideoCommentCreate { |