diff options
Diffstat (limited to 'server')
19 files changed, 656 insertions, 204 deletions
diff --git a/server/controllers/api/users/my-notifications.ts b/server/controllers/api/users/my-notifications.ts index cef1d237c..4b81777a4 100644 --- a/server/controllers/api/users/my-notifications.ts +++ b/server/controllers/api/users/my-notifications.ts | |||
@@ -14,10 +14,11 @@ import { getFormattedObjects } from '../../../helpers/utils' | |||
14 | import { UserNotificationModel } from '../../../models/account/user-notification' | 14 | import { UserNotificationModel } from '../../../models/account/user-notification' |
15 | import { meRouter } from './me' | 15 | import { meRouter } from './me' |
16 | import { | 16 | import { |
17 | listUserNotificationsValidator, | ||
17 | markAsReadUserNotificationsValidator, | 18 | markAsReadUserNotificationsValidator, |
18 | updateNotificationSettingsValidator | 19 | updateNotificationSettingsValidator |
19 | } from '../../../middlewares/validators/user-notifications' | 20 | } from '../../../middlewares/validators/user-notifications' |
20 | import { UserNotificationSetting } from '../../../../shared/models/users' | 21 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../../shared/models/users' |
21 | import { UserNotificationSettingModel } from '../../../models/account/user-notification-setting' | 22 | import { UserNotificationSettingModel } from '../../../models/account/user-notification-setting' |
22 | 23 | ||
23 | const myNotificationsRouter = express.Router() | 24 | const myNotificationsRouter = express.Router() |
@@ -34,6 +35,7 @@ myNotificationsRouter.get('/me/notifications', | |||
34 | userNotificationsSortValidator, | 35 | userNotificationsSortValidator, |
35 | setDefaultSort, | 36 | setDefaultSort, |
36 | setDefaultPagination, | 37 | setDefaultPagination, |
38 | listUserNotificationsValidator, | ||
37 | asyncMiddleware(listUserNotifications) | 39 | asyncMiddleware(listUserNotifications) |
38 | ) | 40 | ) |
39 | 41 | ||
@@ -61,7 +63,11 @@ async function updateNotificationSettings (req: express.Request, res: express.Re | |||
61 | 63 | ||
62 | await UserNotificationSettingModel.update({ | 64 | await UserNotificationSettingModel.update({ |
63 | newVideoFromSubscription: body.newVideoFromSubscription, | 65 | newVideoFromSubscription: body.newVideoFromSubscription, |
64 | newCommentOnMyVideo: body.newCommentOnMyVideo | 66 | newCommentOnMyVideo: body.newCommentOnMyVideo, |
67 | videoAbuseAsModerator: body.videoAbuseAsModerator, | ||
68 | blacklistOnMyVideo: body.blacklistOnMyVideo, | ||
69 | myVideoPublished: body.myVideoPublished, | ||
70 | myVideoImportFinished: body.myVideoImportFinished | ||
65 | }, query) | 71 | }, query) |
66 | 72 | ||
67 | return res.status(204).end() | 73 | return res.status(204).end() |
@@ -70,7 +76,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re | |||
70 | async function listUserNotifications (req: express.Request, res: express.Response) { | 76 | async function listUserNotifications (req: express.Request, res: express.Response) { |
71 | const user: UserModel = res.locals.oauth.token.User | 77 | const user: UserModel = res.locals.oauth.token.User |
72 | 78 | ||
73 | const resultList = await UserNotificationModel.listForApi(user.id, req.query.start, req.query.count, req.query.sort) | 79 | const resultList = await UserNotificationModel.listForApi(user.id, req.query.start, req.query.count, req.query.sort, req.query.unread) |
74 | 80 | ||
75 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 81 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
76 | } | 82 | } |
diff --git a/server/initializers/migrations/0315-user-notifications.ts b/server/initializers/migrations/0315-user-notifications.ts index 2bd9c657d..8c54c5d6c 100644 --- a/server/initializers/migrations/0315-user-notifications.ts +++ b/server/initializers/migrations/0315-user-notifications.ts | |||
@@ -13,6 +13,8 @@ CREATE TABLE IF NOT EXISTS "userNotificationSetting" ("id" SERIAL, | |||
13 | "newCommentOnMyVideo" INTEGER NOT NULL DEFAULT NULL, | 13 | "newCommentOnMyVideo" INTEGER NOT NULL DEFAULT NULL, |
14 | "videoAbuseAsModerator" INTEGER NOT NULL DEFAULT NULL, | 14 | "videoAbuseAsModerator" INTEGER NOT NULL DEFAULT NULL, |
15 | "blacklistOnMyVideo" INTEGER NOT NULL DEFAULT NULL, | 15 | "blacklistOnMyVideo" INTEGER NOT NULL DEFAULT NULL, |
16 | "myVideoPublished" INTEGER NOT NULL DEFAULT NULL, | ||
17 | "myVideoImportFinished" INTEGER NOT NULL DEFAULT NULL, | ||
16 | "userId" INTEGER REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE, | 18 | "userId" INTEGER REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE, |
17 | "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, | 19 | "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, |
18 | "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, | 20 | "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, |
@@ -24,8 +26,8 @@ PRIMARY KEY ("id")) | |||
24 | { | 26 | { |
25 | const query = 'INSERT INTO "userNotificationSetting" ' + | 27 | const query = 'INSERT INTO "userNotificationSetting" ' + |
26 | '("newVideoFromSubscription", "newCommentOnMyVideo", "videoAbuseAsModerator", "blacklistOnMyVideo", ' + | 28 | '("newVideoFromSubscription", "newCommentOnMyVideo", "videoAbuseAsModerator", "blacklistOnMyVideo", ' + |
27 | '"userId", "createdAt", "updatedAt") ' + | 29 | '"myVideoPublished", "myVideoImportFinished", "userId", "createdAt", "updatedAt") ' + |
28 | '(SELECT 2, 2, 4, 4, id, NOW(), NOW() FROM "user")' | 30 | '(SELECT 2, 2, 4, 4, 2, 2, id, NOW(), NOW() FROM "user")' |
29 | 31 | ||
30 | await utils.sequelize.query(query) | 32 | await utils.sequelize.query(query) |
31 | } | 33 | } |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index d766e655b..6dc8f2adf 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -10,6 +10,7 @@ import { readFileSync } from 'fs-extra' | |||
10 | import { VideoCommentModel } from '../models/video/video-comment' | 10 | import { VideoCommentModel } from '../models/video/video-comment' |
11 | import { VideoAbuseModel } from '../models/video/video-abuse' | 11 | import { VideoAbuseModel } from '../models/video/video-abuse' |
12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' | 12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' |
13 | import { VideoImportModel } from '../models/video/video-import' | ||
13 | 14 | ||
14 | class Emailer { | 15 | class Emailer { |
15 | 16 | ||
@@ -102,6 +103,66 @@ class Emailer { | |||
102 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 103 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
103 | } | 104 | } |
104 | 105 | ||
106 | myVideoPublishedNotification (to: string[], video: VideoModel) { | ||
107 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() | ||
108 | |||
109 | const text = `Hi dear user,\n\n` + | ||
110 | `Your video ${video.name} has been published.` + | ||
111 | `\n\n` + | ||
112 | `You can view it on ${videoUrl} ` + | ||
113 | `\n\n` + | ||
114 | `Cheers,\n` + | ||
115 | `PeerTube.` | ||
116 | |||
117 | const emailPayload: EmailPayload = { | ||
118 | to, | ||
119 | subject: `Your video ${video.name} is published`, | ||
120 | text | ||
121 | } | ||
122 | |||
123 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
124 | } | ||
125 | |||
126 | myVideoImportSuccessNotification (to: string[], videoImport: VideoImportModel) { | ||
127 | const videoUrl = CONFIG.WEBSERVER.URL + videoImport.Video.getWatchStaticPath() | ||
128 | |||
129 | const text = `Hi dear user,\n\n` + | ||
130 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + | ||
131 | `\n\n` + | ||
132 | `You can view the imported video on ${videoUrl} ` + | ||
133 | `\n\n` + | ||
134 | `Cheers,\n` + | ||
135 | `PeerTube.` | ||
136 | |||
137 | const emailPayload: EmailPayload = { | ||
138 | to, | ||
139 | subject: `Your video import ${videoImport.getTargetIdentifier()} is finished`, | ||
140 | text | ||
141 | } | ||
142 | |||
143 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
144 | } | ||
145 | |||
146 | myVideoImportErrorNotification (to: string[], videoImport: VideoImportModel) { | ||
147 | const importUrl = CONFIG.WEBSERVER.URL + '/my-account/video-imports' | ||
148 | |||
149 | const text = `Hi dear user,\n\n` + | ||
150 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + | ||
151 | `\n\n` + | ||
152 | `See your videos import dashboard for more information: ${importUrl}` + | ||
153 | `\n\n` + | ||
154 | `Cheers,\n` + | ||
155 | `PeerTube.` | ||
156 | |||
157 | const emailPayload: EmailPayload = { | ||
158 | to, | ||
159 | subject: `Your video import ${videoImport.getTargetIdentifier()} encountered an error`, | ||
160 | text | ||
161 | } | ||
162 | |||
163 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
164 | } | ||
165 | |||
105 | addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { | 166 | addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { |
106 | const accountName = comment.Account.getDisplayName() | 167 | const accountName = comment.Account.getDisplayName() |
107 | const video = comment.Video | 168 | const video = comment.Video |
diff --git a/server/lib/job-queue/handlers/video-file.ts b/server/lib/job-queue/handlers/video-file.ts index 480d324dc..593e43cc5 100644 --- a/server/lib/job-queue/handlers/video-file.ts +++ b/server/lib/job-queue/handlers/video-file.ts | |||
@@ -68,17 +68,17 @@ async function processVideoFile (job: Bull.Job) { | |||
68 | async function onVideoFileTranscoderOrImportSuccess (video: VideoModel) { | 68 | async function onVideoFileTranscoderOrImportSuccess (video: VideoModel) { |
69 | if (video === undefined) return undefined | 69 | if (video === undefined) return undefined |
70 | 70 | ||
71 | const { videoDatabase, isNewVideo } = await sequelizeTypescript.transaction(async t => { | 71 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { |
72 | // Maybe the video changed in database, refresh it | 72 | // Maybe the video changed in database, refresh it |
73 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) | 73 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) |
74 | // Video does not exist anymore | 74 | // Video does not exist anymore |
75 | if (!videoDatabase) return undefined | 75 | if (!videoDatabase) return undefined |
76 | 76 | ||
77 | let isNewVideo = false | 77 | let videoPublished = false |
78 | 78 | ||
79 | // We transcoded the video file in another format, now we can publish it | 79 | // We transcoded the video file in another format, now we can publish it |
80 | if (videoDatabase.state !== VideoState.PUBLISHED) { | 80 | if (videoDatabase.state !== VideoState.PUBLISHED) { |
81 | isNewVideo = true | 81 | videoPublished = true |
82 | 82 | ||
83 | videoDatabase.state = VideoState.PUBLISHED | 83 | videoDatabase.state = VideoState.PUBLISHED |
84 | videoDatabase.publishedAt = new Date() | 84 | videoDatabase.publishedAt = new Date() |
@@ -86,12 +86,15 @@ async function onVideoFileTranscoderOrImportSuccess (video: VideoModel) { | |||
86 | } | 86 | } |
87 | 87 | ||
88 | // If the video was not published, we consider it is a new one for other instances | 88 | // If the video was not published, we consider it is a new one for other instances |
89 | await federateVideoIfNeeded(videoDatabase, isNewVideo, t) | 89 | await federateVideoIfNeeded(videoDatabase, videoPublished, t) |
90 | 90 | ||
91 | return { videoDatabase, isNewVideo } | 91 | return { videoDatabase, videoPublished } |
92 | }) | 92 | }) |
93 | 93 | ||
94 | if (isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) | 94 | if (videoPublished) { |
95 | Notifier.Instance.notifyOnNewVideo(videoDatabase) | ||
96 | Notifier.Instance.notifyOnPendingVideoPublished(videoDatabase) | ||
97 | } | ||
95 | } | 98 | } |
96 | 99 | ||
97 | async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: boolean) { | 100 | async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: boolean) { |
@@ -100,7 +103,7 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: bo | |||
100 | // Outside the transaction (IO on disk) | 103 | // Outside the transaction (IO on disk) |
101 | const { videoFileResolution } = await videoArg.getOriginalFileResolution() | 104 | const { videoFileResolution } = await videoArg.getOriginalFileResolution() |
102 | 105 | ||
103 | const videoDatabase = await sequelizeTypescript.transaction(async t => { | 106 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { |
104 | // Maybe the video changed in database, refresh it | 107 | // Maybe the video changed in database, refresh it |
105 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) | 108 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) |
106 | // Video does not exist anymore | 109 | // Video does not exist anymore |
@@ -113,6 +116,8 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: bo | |||
113 | { resolutions: resolutionsEnabled } | 116 | { resolutions: resolutionsEnabled } |
114 | ) | 117 | ) |
115 | 118 | ||
119 | let videoPublished = false | ||
120 | |||
116 | if (resolutionsEnabled.length !== 0) { | 121 | if (resolutionsEnabled.length !== 0) { |
117 | const tasks: Bluebird<Bull.Job<any>>[] = [] | 122 | const tasks: Bluebird<Bull.Job<any>>[] = [] |
118 | 123 | ||
@@ -130,6 +135,8 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: bo | |||
130 | 135 | ||
131 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) | 136 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) |
132 | } else { | 137 | } else { |
138 | videoPublished = true | ||
139 | |||
133 | // No transcoding to do, it's now published | 140 | // No transcoding to do, it's now published |
134 | videoDatabase.state = VideoState.PUBLISHED | 141 | videoDatabase.state = VideoState.PUBLISHED |
135 | videoDatabase = await videoDatabase.save({ transaction: t }) | 142 | videoDatabase = await videoDatabase.save({ transaction: t }) |
@@ -139,10 +146,11 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, isNewVideo: bo | |||
139 | 146 | ||
140 | await federateVideoIfNeeded(videoDatabase, isNewVideo, t) | 147 | await federateVideoIfNeeded(videoDatabase, isNewVideo, t) |
141 | 148 | ||
142 | return videoDatabase | 149 | return { videoDatabase, videoPublished } |
143 | }) | 150 | }) |
144 | 151 | ||
145 | if (isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) | 152 | if (isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) |
153 | if (videoPublished) Notifier.Instance.notifyOnPendingVideoPublished(videoDatabase) | ||
146 | } | 154 | } |
147 | 155 | ||
148 | // --------------------------------------------------------------------------- | 156 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 29cd1198c..12004dcd7 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -197,6 +197,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide | |||
197 | }) | 197 | }) |
198 | 198 | ||
199 | Notifier.Instance.notifyOnNewVideo(videoImportUpdated.Video) | 199 | Notifier.Instance.notifyOnNewVideo(videoImportUpdated.Video) |
200 | Notifier.Instance.notifyOnFinishedVideoImport(videoImportUpdated, true) | ||
200 | 201 | ||
201 | // Create transcoding jobs? | 202 | // Create transcoding jobs? |
202 | if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { | 203 | if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { |
@@ -220,6 +221,8 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide | |||
220 | videoImport.state = VideoImportState.FAILED | 221 | videoImport.state = VideoImportState.FAILED |
221 | await videoImport.save() | 222 | await videoImport.save() |
222 | 223 | ||
224 | Notifier.Instance.notifyOnFinishedVideoImport(videoImport, false) | ||
225 | |||
223 | throw err | 226 | throw err |
224 | } | 227 | } |
225 | } | 228 | } |
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index a21b50b2d..11b0937e9 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -11,6 +11,8 @@ import { VideoPrivacy, VideoState } from '../../shared/models/videos' | |||
11 | import { VideoAbuseModel } from '../models/video/video-abuse' | 11 | import { VideoAbuseModel } from '../models/video/video-abuse' |
12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' | 12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' |
13 | import * as Bluebird from 'bluebird' | 13 | import * as Bluebird from 'bluebird' |
14 | import { VideoImportModel } from '../models/video/video-import' | ||
15 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | ||
14 | 16 | ||
15 | class Notifier { | 17 | class Notifier { |
16 | 18 | ||
@@ -26,6 +28,14 @@ class Notifier { | |||
26 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) | 28 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) |
27 | } | 29 | } |
28 | 30 | ||
31 | notifyOnPendingVideoPublished (video: VideoModel): void { | ||
32 | // Only notify on public videos that has been published while the user waited transcoding/scheduled update | ||
33 | if (video.waitTranscoding === false && !video.ScheduleVideoUpdate) return | ||
34 | |||
35 | this.notifyOwnedVideoHasBeenPublished(video) | ||
36 | .catch(err => logger.error('Cannot notify owner that its video %s has been published.', video.url, { err })) | ||
37 | } | ||
38 | |||
29 | notifyOnNewComment (comment: VideoCommentModel): void { | 39 | notifyOnNewComment (comment: VideoCommentModel): void { |
30 | this.notifyVideoOwnerOfNewComment(comment) | 40 | this.notifyVideoOwnerOfNewComment(comment) |
31 | .catch(err => logger.error('Cannot notify of new comment %s.', comment.url, { err })) | 41 | .catch(err => logger.error('Cannot notify of new comment %s.', comment.url, { err })) |
@@ -46,6 +56,11 @@ class Notifier { | |||
46 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', video.url, { err })) | 56 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', video.url, { err })) |
47 | } | 57 | } |
48 | 58 | ||
59 | notifyOnFinishedVideoImport (videoImport: VideoImportModel, success: boolean): void { | ||
60 | this.notifyOwnerVideoImportIsFinished(videoImport, success) | ||
61 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) | ||
62 | } | ||
63 | |||
49 | private async notifySubscribersOfNewVideo (video: VideoModel) { | 64 | private async notifySubscribersOfNewVideo (video: VideoModel) { |
50 | // List all followers that are users | 65 | // List all followers that are users |
51 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) | 66 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) |
@@ -80,6 +95,9 @@ class Notifier { | |||
80 | // Not our user or user comments its own video | 95 | // Not our user or user comments its own video |
81 | if (!user || comment.Account.userId === user.id) return | 96 | if (!user || comment.Account.userId === user.id) return |
82 | 97 | ||
98 | const accountMuted = await AccountBlocklistModel.isAccountMutedBy(user.Account.id, comment.accountId) | ||
99 | if (accountMuted) return | ||
100 | |||
83 | logger.info('Notifying user %s of new comment %s.', user.username, comment.url) | 101 | logger.info('Notifying user %s of new comment %s.', user.username, comment.url) |
84 | 102 | ||
85 | function settingGetter (user: UserModel) { | 103 | function settingGetter (user: UserModel) { |
@@ -188,6 +206,64 @@ class Notifier { | |||
188 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | 206 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) |
189 | } | 207 | } |
190 | 208 | ||
209 | private async notifyOwnedVideoHasBeenPublished (video: VideoModel) { | ||
210 | const user = await UserModel.loadByVideoId(video.id) | ||
211 | if (!user) return | ||
212 | |||
213 | logger.info('Notifying user %s of the publication of its video %s.', user.username, video.url) | ||
214 | |||
215 | function settingGetter (user: UserModel) { | ||
216 | return user.NotificationSetting.myVideoPublished | ||
217 | } | ||
218 | |||
219 | async function notificationCreator (user: UserModel) { | ||
220 | const notification = await UserNotificationModel.create({ | ||
221 | type: UserNotificationType.MY_VIDEO_PUBLISHED, | ||
222 | userId: user.id, | ||
223 | videoId: video.id | ||
224 | }) | ||
225 | notification.Video = video | ||
226 | |||
227 | return notification | ||
228 | } | ||
229 | |||
230 | function emailSender (emails: string[]) { | ||
231 | return Emailer.Instance.myVideoPublishedNotification(emails, video) | ||
232 | } | ||
233 | |||
234 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
235 | } | ||
236 | |||
237 | private async notifyOwnerVideoImportIsFinished (videoImport: VideoImportModel, success: boolean) { | ||
238 | const user = await UserModel.loadByVideoImportId(videoImport.id) | ||
239 | if (!user) return | ||
240 | |||
241 | logger.info('Notifying user %s its video import %s is finished.', user.username, videoImport.getTargetIdentifier()) | ||
242 | |||
243 | function settingGetter (user: UserModel) { | ||
244 | return user.NotificationSetting.myVideoImportFinished | ||
245 | } | ||
246 | |||
247 | async function notificationCreator (user: UserModel) { | ||
248 | const notification = await UserNotificationModel.create({ | ||
249 | type: success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR, | ||
250 | userId: user.id, | ||
251 | videoImportId: videoImport.id | ||
252 | }) | ||
253 | notification.VideoImport = videoImport | ||
254 | |||
255 | return notification | ||
256 | } | ||
257 | |||
258 | function emailSender (emails: string[]) { | ||
259 | return success | ||
260 | ? Emailer.Instance.myVideoImportSuccessNotification(emails, videoImport) | ||
261 | : Emailer.Instance.myVideoImportErrorNotification(emails, videoImport) | ||
262 | } | ||
263 | |||
264 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
265 | } | ||
266 | |||
191 | private async notify (options: { | 267 | private async notify (options: { |
192 | users: UserModel[], | 268 | users: UserModel[], |
193 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, | 269 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, |
diff --git a/server/lib/schedulers/update-videos-scheduler.ts b/server/lib/schedulers/update-videos-scheduler.ts index b7fb029f1..2618a5857 100644 --- a/server/lib/schedulers/update-videos-scheduler.ts +++ b/server/lib/schedulers/update-videos-scheduler.ts | |||
@@ -6,6 +6,7 @@ import { federateVideoIfNeeded } from '../activitypub' | |||
6 | import { SCHEDULER_INTERVALS_MS, sequelizeTypescript } from '../../initializers' | 6 | import { SCHEDULER_INTERVALS_MS, sequelizeTypescript } from '../../initializers' |
7 | import { VideoPrivacy } from '../../../shared/models/videos' | 7 | import { VideoPrivacy } from '../../../shared/models/videos' |
8 | import { Notifier } from '../notifier' | 8 | import { Notifier } from '../notifier' |
9 | import { VideoModel } from '../../models/video/video' | ||
9 | 10 | ||
10 | export class UpdateVideosScheduler extends AbstractScheduler { | 11 | export class UpdateVideosScheduler extends AbstractScheduler { |
11 | 12 | ||
@@ -24,8 +25,9 @@ export class UpdateVideosScheduler extends AbstractScheduler { | |||
24 | private async updateVideos () { | 25 | private async updateVideos () { |
25 | if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined | 26 | if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined |
26 | 27 | ||
27 | return sequelizeTypescript.transaction(async t => { | 28 | const publishedVideos = await sequelizeTypescript.transaction(async t => { |
28 | const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate(t) | 29 | const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate(t) |
30 | const publishedVideos: VideoModel[] = [] | ||
29 | 31 | ||
30 | for (const schedule of schedules) { | 32 | for (const schedule of schedules) { |
31 | const video = schedule.Video | 33 | const video = schedule.Video |
@@ -42,13 +44,21 @@ export class UpdateVideosScheduler extends AbstractScheduler { | |||
42 | await federateVideoIfNeeded(video, isNewVideo, t) | 44 | await federateVideoIfNeeded(video, isNewVideo, t) |
43 | 45 | ||
44 | if (oldPrivacy === VideoPrivacy.UNLISTED || oldPrivacy === VideoPrivacy.PRIVATE) { | 46 | if (oldPrivacy === VideoPrivacy.UNLISTED || oldPrivacy === VideoPrivacy.PRIVATE) { |
45 | Notifier.Instance.notifyOnNewVideo(video) | 47 | video.ScheduleVideoUpdate = schedule |
48 | publishedVideos.push(video) | ||
46 | } | 49 | } |
47 | } | 50 | } |
48 | 51 | ||
49 | await schedule.destroy({ transaction: t }) | 52 | await schedule.destroy({ transaction: t }) |
50 | } | 53 | } |
54 | |||
55 | return publishedVideos | ||
51 | }) | 56 | }) |
57 | |||
58 | for (const v of publishedVideos) { | ||
59 | Notifier.Instance.notifyOnNewVideo(v) | ||
60 | Notifier.Instance.notifyOnPendingVideoPublished(v) | ||
61 | } | ||
52 | } | 62 | } |
53 | 63 | ||
54 | static get Instance () { | 64 | static get Instance () { |
diff --git a/server/lib/user.ts b/server/lib/user.ts index 72127819c..481571828 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -100,6 +100,8 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Tr | |||
100 | userId: user.id, | 100 | userId: user.id, |
101 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION, | 101 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION, |
102 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION, | 102 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION, |
103 | myVideoImportFinished: UserNotificationSettingValue.WEB_NOTIFICATION, | ||
104 | myVideoPublished: UserNotificationSettingValue.WEB_NOTIFICATION, | ||
103 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | 105 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, |
104 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | 106 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL |
105 | }, { transaction: t }) | 107 | }, { transaction: t }) |
diff --git a/server/middlewares/validators/user-notifications.ts b/server/middlewares/validators/user-notifications.ts index 8202f307e..1c31f0a73 100644 --- a/server/middlewares/validators/user-notifications.ts +++ b/server/middlewares/validators/user-notifications.ts | |||
@@ -1,11 +1,26 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import 'express-validator' | 2 | import 'express-validator' |
3 | import { body } from 'express-validator/check' | 3 | import { body, query } from 'express-validator/check' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' | 6 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' |
7 | import { isIntArray } from '../../helpers/custom-validators/misc' | 7 | import { isIntArray } from '../../helpers/custom-validators/misc' |
8 | 8 | ||
9 | const listUserNotificationsValidator = [ | ||
10 | query('unread') | ||
11 | .optional() | ||
12 | .toBoolean() | ||
13 | .isBoolean().withMessage('Should have a valid unread boolean'), | ||
14 | |||
15 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
16 | logger.debug('Checking listUserNotificationsValidator parameters', { parameters: req.query }) | ||
17 | |||
18 | if (areValidationErrors(req, res)) return | ||
19 | |||
20 | return next() | ||
21 | } | ||
22 | ] | ||
23 | |||
9 | const updateNotificationSettingsValidator = [ | 24 | const updateNotificationSettingsValidator = [ |
10 | body('newVideoFromSubscription') | 25 | body('newVideoFromSubscription') |
11 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'), | 26 | .custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'), |
@@ -41,6 +56,7 @@ const markAsReadUserNotificationsValidator = [ | |||
41 | // --------------------------------------------------------------------------- | 56 | // --------------------------------------------------------------------------- |
42 | 57 | ||
43 | export { | 58 | export { |
59 | listUserNotificationsValidator, | ||
44 | updateNotificationSettingsValidator, | 60 | updateNotificationSettingsValidator, |
45 | markAsReadUserNotificationsValidator | 61 | markAsReadUserNotificationsValidator |
46 | } | 62 | } |
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index fa2819235..54ac290c4 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts | |||
@@ -72,6 +72,21 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> { | |||
72 | }) | 72 | }) |
73 | BlockedAccount: AccountModel | 73 | BlockedAccount: AccountModel |
74 | 74 | ||
75 | static isAccountMutedBy (accountId: number, targetAccountId: number) { | ||
76 | const query = { | ||
77 | attributes: [ 'id' ], | ||
78 | where: { | ||
79 | accountId, | ||
80 | targetAccountId | ||
81 | }, | ||
82 | raw: true | ||
83 | } | ||
84 | |||
85 | return AccountBlocklistModel.unscoped() | ||
86 | .findOne(query) | ||
87 | .then(a => !!a) | ||
88 | } | ||
89 | |||
75 | static loadByAccountAndTarget (accountId: number, targetAccountId: number) { | 90 | static loadByAccountAndTarget (accountId: number, targetAccountId: number) { |
76 | const query = { | 91 | const query = { |
77 | where: { | 92 | where: { |
diff --git a/server/models/account/user-notification-setting.ts b/server/models/account/user-notification-setting.ts index bc24b1e33..6470defa7 100644 --- a/server/models/account/user-notification-setting.ts +++ b/server/models/account/user-notification-setting.ts | |||
@@ -65,6 +65,24 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM | |||
65 | @Column | 65 | @Column |
66 | blacklistOnMyVideo: UserNotificationSettingValue | 66 | blacklistOnMyVideo: UserNotificationSettingValue |
67 | 67 | ||
68 | @AllowNull(false) | ||
69 | @Default(null) | ||
70 | @Is( | ||
71 | 'UserNotificationSettingMyVideoPublished', | ||
72 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoPublished') | ||
73 | ) | ||
74 | @Column | ||
75 | myVideoPublished: UserNotificationSettingValue | ||
76 | |||
77 | @AllowNull(false) | ||
78 | @Default(null) | ||
79 | @Is( | ||
80 | 'UserNotificationSettingMyVideoImportFinished', | ||
81 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoImportFinished') | ||
82 | ) | ||
83 | @Column | ||
84 | myVideoImportFinished: UserNotificationSettingValue | ||
85 | |||
68 | @ForeignKey(() => UserModel) | 86 | @ForeignKey(() => UserModel) |
69 | @Column | 87 | @Column |
70 | userId: number | 88 | userId: number |
@@ -94,7 +112,9 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM | |||
94 | newCommentOnMyVideo: this.newCommentOnMyVideo, | 112 | newCommentOnMyVideo: this.newCommentOnMyVideo, |
95 | newVideoFromSubscription: this.newVideoFromSubscription, | 113 | newVideoFromSubscription: this.newVideoFromSubscription, |
96 | videoAbuseAsModerator: this.videoAbuseAsModerator, | 114 | videoAbuseAsModerator: this.videoAbuseAsModerator, |
97 | blacklistOnMyVideo: this.blacklistOnMyVideo | 115 | blacklistOnMyVideo: this.blacklistOnMyVideo, |
116 | myVideoPublished: this.myVideoPublished, | ||
117 | myVideoImportFinished: this.myVideoImportFinished | ||
98 | } | 118 | } |
99 | } | 119 | } |
100 | } | 120 | } |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index e22f0d57f..251244374 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -1,4 +1,17 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { |
2 | AllowNull, | ||
3 | BelongsTo, | ||
4 | Column, | ||
5 | CreatedAt, | ||
6 | Default, | ||
7 | ForeignKey, | ||
8 | IFindOptions, | ||
9 | Is, | ||
10 | Model, | ||
11 | Scopes, | ||
12 | Table, | ||
13 | UpdatedAt | ||
14 | } from 'sequelize-typescript' | ||
2 | import { UserNotification, UserNotificationType } from '../../../shared' | 15 | import { UserNotification, UserNotificationType } from '../../../shared' |
3 | import { getSort, throwIfNotValid } from '../utils' | 16 | import { getSort, throwIfNotValid } from '../utils' |
4 | import { isBooleanValid } from '../../helpers/custom-validators/misc' | 17 | import { isBooleanValid } from '../../helpers/custom-validators/misc' |
@@ -11,66 +24,68 @@ import { VideoChannelModel } from '../video/video-channel' | |||
11 | import { AccountModel } from './account' | 24 | import { AccountModel } from './account' |
12 | import { VideoAbuseModel } from '../video/video-abuse' | 25 | import { VideoAbuseModel } from '../video/video-abuse' |
13 | import { VideoBlacklistModel } from '../video/video-blacklist' | 26 | import { VideoBlacklistModel } from '../video/video-blacklist' |
27 | import { VideoImportModel } from '../video/video-import' | ||
14 | 28 | ||
15 | enum ScopeNames { | 29 | enum ScopeNames { |
16 | WITH_ALL = 'WITH_ALL' | 30 | WITH_ALL = 'WITH_ALL' |
17 | } | 31 | } |
18 | 32 | ||
33 | function buildVideoInclude (required: boolean) { | ||
34 | return { | ||
35 | attributes: [ 'id', 'uuid', 'name' ], | ||
36 | model: () => VideoModel.unscoped(), | ||
37 | required | ||
38 | } | ||
39 | } | ||
40 | |||
41 | function buildChannelInclude () { | ||
42 | return { | ||
43 | required: true, | ||
44 | attributes: [ 'id', 'name' ], | ||
45 | model: () => VideoChannelModel.unscoped() | ||
46 | } | ||
47 | } | ||
48 | |||
49 | function buildAccountInclude () { | ||
50 | return { | ||
51 | required: true, | ||
52 | attributes: [ 'id', 'name' ], | ||
53 | model: () => AccountModel.unscoped() | ||
54 | } | ||
55 | } | ||
56 | |||
19 | @Scopes({ | 57 | @Scopes({ |
20 | [ScopeNames.WITH_ALL]: { | 58 | [ScopeNames.WITH_ALL]: { |
21 | include: [ | 59 | include: [ |
60 | Object.assign(buildVideoInclude(false), { | ||
61 | include: [ buildChannelInclude() ] | ||
62 | }), | ||
22 | { | 63 | { |
23 | attributes: [ 'id', 'uuid', 'name' ], | 64 | attributes: [ 'id', 'originCommentId' ], |
24 | model: () => VideoModel.unscoped(), | ||
25 | required: false, | ||
26 | include: [ | ||
27 | { | ||
28 | required: true, | ||
29 | attributes: [ 'id', 'name' ], | ||
30 | model: () => VideoChannelModel.unscoped() | ||
31 | } | ||
32 | ] | ||
33 | }, | ||
34 | { | ||
35 | attributes: [ 'id' ], | ||
36 | model: () => VideoCommentModel.unscoped(), | 65 | model: () => VideoCommentModel.unscoped(), |
37 | required: false, | 66 | required: false, |
38 | include: [ | 67 | include: [ |
39 | { | 68 | buildAccountInclude(), |
40 | required: true, | 69 | buildVideoInclude(true) |
41 | attributes: [ 'id', 'name' ], | ||
42 | model: () => AccountModel.unscoped() | ||
43 | }, | ||
44 | { | ||
45 | required: true, | ||
46 | attributes: [ 'id', 'uuid', 'name' ], | ||
47 | model: () => VideoModel.unscoped() | ||
48 | } | ||
49 | ] | 70 | ] |
50 | }, | 71 | }, |
51 | { | 72 | { |
52 | attributes: [ 'id' ], | 73 | attributes: [ 'id' ], |
53 | model: () => VideoAbuseModel.unscoped(), | 74 | model: () => VideoAbuseModel.unscoped(), |
54 | required: false, | 75 | required: false, |
55 | include: [ | 76 | include: [ buildVideoInclude(true) ] |
56 | { | ||
57 | required: true, | ||
58 | attributes: [ 'id', 'uuid', 'name' ], | ||
59 | model: () => VideoModel.unscoped() | ||
60 | } | ||
61 | ] | ||
62 | }, | 77 | }, |
63 | { | 78 | { |
64 | attributes: [ 'id' ], | 79 | attributes: [ 'id' ], |
65 | model: () => VideoBlacklistModel.unscoped(), | 80 | model: () => VideoBlacklistModel.unscoped(), |
66 | required: false, | 81 | required: false, |
67 | include: [ | 82 | include: [ buildVideoInclude(true) ] |
68 | { | 83 | }, |
69 | required: true, | 84 | { |
70 | attributes: [ 'id', 'uuid', 'name' ], | 85 | attributes: [ 'id', 'magnetUri', 'targetUrl', 'torrentName' ], |
71 | model: () => VideoModel.unscoped() | 86 | model: () => VideoImportModel.unscoped(), |
72 | } | 87 | required: false, |
73 | ] | 88 | include: [ buildVideoInclude(false) ] |
74 | } | 89 | } |
75 | ] | 90 | ] |
76 | } | 91 | } |
@@ -166,8 +181,20 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
166 | }) | 181 | }) |
167 | VideoBlacklist: VideoBlacklistModel | 182 | VideoBlacklist: VideoBlacklistModel |
168 | 183 | ||
169 | static listForApi (userId: number, start: number, count: number, sort: string) { | 184 | @ForeignKey(() => VideoImportModel) |
170 | const query = { | 185 | @Column |
186 | videoImportId: number | ||
187 | |||
188 | @BelongsTo(() => VideoImportModel, { | ||
189 | foreignKey: { | ||
190 | allowNull: true | ||
191 | }, | ||
192 | onDelete: 'cascade' | ||
193 | }) | ||
194 | VideoImport: VideoImportModel | ||
195 | |||
196 | static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { | ||
197 | const query: IFindOptions<UserNotificationModel> = { | ||
171 | offset: start, | 198 | offset: start, |
172 | limit: count, | 199 | limit: count, |
173 | order: getSort(sort), | 200 | order: getSort(sort), |
@@ -176,6 +203,8 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
176 | } | 203 | } |
177 | } | 204 | } |
178 | 205 | ||
206 | if (unread !== undefined) query.where['read'] = !unread | ||
207 | |||
179 | return UserNotificationModel.scope(ScopeNames.WITH_ALL) | 208 | return UserNotificationModel.scope(ScopeNames.WITH_ALL) |
180 | .findAndCountAll(query) | 209 | .findAndCountAll(query) |
181 | .then(({ rows, count }) => { | 210 | .then(({ rows, count }) => { |
@@ -200,45 +229,39 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
200 | } | 229 | } |
201 | 230 | ||
202 | toFormattedJSON (): UserNotification { | 231 | toFormattedJSON (): UserNotification { |
203 | const video = this.Video ? { | 232 | const video = this.Video ? Object.assign(this.formatVideo(this.Video), { |
204 | id: this.Video.id, | ||
205 | uuid: this.Video.uuid, | ||
206 | name: this.Video.name, | ||
207 | channel: { | 233 | channel: { |
208 | id: this.Video.VideoChannel.id, | 234 | id: this.Video.VideoChannel.id, |
209 | displayName: this.Video.VideoChannel.getDisplayName() | 235 | displayName: this.Video.VideoChannel.getDisplayName() |
210 | } | 236 | } |
237 | }) : undefined | ||
238 | |||
239 | const videoImport = this.VideoImport ? { | ||
240 | id: this.VideoImport.id, | ||
241 | video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined, | ||
242 | torrentName: this.VideoImport.torrentName, | ||
243 | magnetUri: this.VideoImport.magnetUri, | ||
244 | targetUrl: this.VideoImport.targetUrl | ||
211 | } : undefined | 245 | } : undefined |
212 | 246 | ||
213 | const comment = this.Comment ? { | 247 | const comment = this.Comment ? { |
214 | id: this.Comment.id, | 248 | id: this.Comment.id, |
249 | threadId: this.Comment.getThreadId(), | ||
215 | account: { | 250 | account: { |
216 | id: this.Comment.Account.id, | 251 | id: this.Comment.Account.id, |
217 | displayName: this.Comment.Account.getDisplayName() | 252 | displayName: this.Comment.Account.getDisplayName() |
218 | }, | 253 | }, |
219 | video: { | 254 | video: this.formatVideo(this.Comment.Video) |
220 | id: this.Comment.Video.id, | ||
221 | uuid: this.Comment.Video.uuid, | ||
222 | name: this.Comment.Video.name | ||
223 | } | ||
224 | } : undefined | 255 | } : undefined |
225 | 256 | ||
226 | const videoAbuse = this.VideoAbuse ? { | 257 | const videoAbuse = this.VideoAbuse ? { |
227 | id: this.VideoAbuse.id, | 258 | id: this.VideoAbuse.id, |
228 | video: { | 259 | video: this.formatVideo(this.VideoAbuse.Video) |
229 | id: this.VideoAbuse.Video.id, | ||
230 | uuid: this.VideoAbuse.Video.uuid, | ||
231 | name: this.VideoAbuse.Video.name | ||
232 | } | ||
233 | } : undefined | 260 | } : undefined |
234 | 261 | ||
235 | const videoBlacklist = this.VideoBlacklist ? { | 262 | const videoBlacklist = this.VideoBlacklist ? { |
236 | id: this.VideoBlacklist.id, | 263 | id: this.VideoBlacklist.id, |
237 | video: { | 264 | video: this.formatVideo(this.VideoBlacklist.Video) |
238 | id: this.VideoBlacklist.Video.id, | ||
239 | uuid: this.VideoBlacklist.Video.uuid, | ||
240 | name: this.VideoBlacklist.Video.name | ||
241 | } | ||
242 | } : undefined | 265 | } : undefined |
243 | 266 | ||
244 | return { | 267 | return { |
@@ -246,6 +269,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
246 | type: this.type, | 269 | type: this.type, |
247 | read: this.read, | 270 | read: this.read, |
248 | video, | 271 | video, |
272 | videoImport, | ||
249 | comment, | 273 | comment, |
250 | videoAbuse, | 274 | videoAbuse, |
251 | videoBlacklist, | 275 | videoBlacklist, |
@@ -253,4 +277,12 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
253 | updatedAt: this.updatedAt.toISOString() | 277 | updatedAt: this.updatedAt.toISOString() |
254 | } | 278 | } |
255 | } | 279 | } |
280 | |||
281 | private formatVideo (video: VideoModel) { | ||
282 | return { | ||
283 | id: video.id, | ||
284 | uuid: video.uuid, | ||
285 | name: video.name | ||
286 | } | ||
287 | } | ||
256 | } | 288 | } |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 55ec14d05..33f56f641 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -48,6 +48,7 @@ import { UserNotificationSettingModel } from './user-notification-setting' | |||
48 | import { VideoModel } from '../video/video' | 48 | import { VideoModel } from '../video/video' |
49 | import { ActorModel } from '../activitypub/actor' | 49 | import { ActorModel } from '../activitypub/actor' |
50 | import { ActorFollowModel } from '../activitypub/actor-follow' | 50 | import { ActorFollowModel } from '../activitypub/actor-follow' |
51 | import { VideoImportModel } from '../video/video-import' | ||
51 | 52 | ||
52 | enum ScopeNames { | 53 | enum ScopeNames { |
53 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' | 54 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' |
@@ -186,6 +187,12 @@ export class UserModel extends Model<UserModel> { | |||
186 | }) | 187 | }) |
187 | NotificationSetting: UserNotificationSettingModel | 188 | NotificationSetting: UserNotificationSettingModel |
188 | 189 | ||
190 | @HasMany(() => VideoImportModel, { | ||
191 | foreignKey: 'userId', | ||
192 | onDelete: 'cascade' | ||
193 | }) | ||
194 | VideoImports: VideoImportModel[] | ||
195 | |||
189 | @HasMany(() => OAuthTokenModel, { | 196 | @HasMany(() => OAuthTokenModel, { |
190 | foreignKey: 'userId', | 197 | foreignKey: 'userId', |
191 | onDelete: 'cascade' | 198 | onDelete: 'cascade' |
@@ -400,6 +407,23 @@ export class UserModel extends Model<UserModel> { | |||
400 | return UserModel.findOne(query) | 407 | return UserModel.findOne(query) |
401 | } | 408 | } |
402 | 409 | ||
410 | static loadByVideoImportId (videoImportId: number) { | ||
411 | const query = { | ||
412 | include: [ | ||
413 | { | ||
414 | required: true, | ||
415 | attributes: [ 'id' ], | ||
416 | model: VideoImportModel.unscoped(), | ||
417 | where: { | ||
418 | id: videoImportId | ||
419 | } | ||
420 | } | ||
421 | ] | ||
422 | } | ||
423 | |||
424 | return UserModel.findOne(query) | ||
425 | } | ||
426 | |||
403 | static getOriginalVideoFileTotalFromUser (user: UserModel) { | 427 | static getOriginalVideoFileTotalFromUser (user: UserModel) { |
404 | // Don't use sequelize because we need to use a sub query | 428 | // Don't use sequelize because we need to use a sub query |
405 | const query = UserModel.generateUserQuotaBaseSQL() | 429 | const query = UserModel.generateUserQuotaBaseSQL() |
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 3fd2d5a99..0fd868cd6 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | import { values } from 'lodash' | ||
2 | import { | 1 | import { |
3 | AllowNull, | 2 | AllowNull, |
4 | BelongsTo, | 3 | BelongsTo, |
@@ -20,7 +19,6 @@ import { | |||
20 | isVideoFileSizeValid, | 19 | isVideoFileSizeValid, |
21 | isVideoFPSResolutionValid | 20 | isVideoFPSResolutionValid |
22 | } from '../../helpers/custom-validators/videos' | 21 | } from '../../helpers/custom-validators/videos' |
23 | import { CONSTRAINTS_FIELDS } from '../../initializers' | ||
24 | import { throwIfNotValid } from '../utils' | 22 | import { throwIfNotValid } from '../utils' |
25 | import { VideoModel } from './video' | 23 | import { VideoModel } from './video' |
26 | import * as Sequelize from 'sequelize' | 24 | import * as Sequelize from 'sequelize' |
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index 8d442b3f8..c723e57c0 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -144,6 +144,10 @@ export class VideoImportModel extends Model<VideoImportModel> { | |||
144 | }) | 144 | }) |
145 | } | 145 | } |
146 | 146 | ||
147 | getTargetIdentifier () { | ||
148 | return this.targetUrl || this.magnetUri || this.torrentName | ||
149 | } | ||
150 | |||
147 | toFormattedJSON (): VideoImport { | 151 | toFormattedJSON (): VideoImport { |
148 | const videoFormatOptions = { | 152 | const videoFormatOptions = { |
149 | completeDescription: true, | 153 | completeDescription: true, |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index fc200e5d1..80a6c7832 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -94,6 +94,7 @@ import { | |||
94 | import * as validator from 'validator' | 94 | import * as validator from 'validator' |
95 | import { UserVideoHistoryModel } from '../account/user-video-history' | 95 | import { UserVideoHistoryModel } from '../account/user-video-history' |
96 | import { UserModel } from '../account/user' | 96 | import { UserModel } from '../account/user' |
97 | import { VideoImportModel } from './video-import' | ||
97 | 98 | ||
98 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 99 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
99 | const indexes: Sequelize.DefineIndexesOptions[] = [ | 100 | const indexes: Sequelize.DefineIndexesOptions[] = [ |
@@ -785,6 +786,15 @@ export class VideoModel extends Model<VideoModel> { | |||
785 | }) | 786 | }) |
786 | VideoBlacklist: VideoBlacklistModel | 787 | VideoBlacklist: VideoBlacklistModel |
787 | 788 | ||
789 | @HasOne(() => VideoImportModel, { | ||
790 | foreignKey: { | ||
791 | name: 'videoId', | ||
792 | allowNull: true | ||
793 | }, | ||
794 | onDelete: 'set null' | ||
795 | }) | ||
796 | VideoImport: VideoImportModel | ||
797 | |||
788 | @HasMany(() => VideoCaptionModel, { | 798 | @HasMany(() => VideoCaptionModel, { |
789 | foreignKey: { | 799 | foreignKey: { |
790 | name: 'videoId', | 800 | name: 'videoId', |
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts index 3ae36ddb3..4f21f7b95 100644 --- a/server/tests/api/check-params/user-notifications.ts +++ b/server/tests/api/check-params/user-notifications.ts | |||
@@ -52,6 +52,18 @@ describe('Test user notifications API validators', function () { | |||
52 | await checkBadSortPagination(server.url, path, server.accessToken) | 52 | await checkBadSortPagination(server.url, path, server.accessToken) |
53 | }) | 53 | }) |
54 | 54 | ||
55 | it('Should fail with an incorrect unread parameter', async function () { | ||
56 | await makeGetRequest({ | ||
57 | url: server.url, | ||
58 | path, | ||
59 | query: { | ||
60 | unread: 'toto' | ||
61 | }, | ||
62 | token: server.accessToken, | ||
63 | statusCodeExpected: 200 | ||
64 | }) | ||
65 | }) | ||
66 | |||
55 | it('Should fail with a non authenticated user', async function () { | 67 | it('Should fail with a non authenticated user', async function () { |
56 | await makeGetRequest({ | 68 | await makeGetRequest({ |
57 | url: server.url, | 69 | url: server.url, |
@@ -125,7 +137,9 @@ describe('Test user notifications API validators', function () { | |||
125 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION, | 137 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION, |
126 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION, | 138 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION, |
127 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION, | 139 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION, |
128 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION | 140 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION, |
141 | myVideoImportFinished: UserNotificationSettingValue.WEB_NOTIFICATION, | ||
142 | myVideoPublished: UserNotificationSettingValue.WEB_NOTIFICATION | ||
129 | } | 143 | } |
130 | 144 | ||
131 | it('Should fail with missing fields', async function () { | 145 | it('Should fail with missing fields', async function () { |
diff --git a/server/tests/api/users/user-notifications.ts b/server/tests/api/users/user-notifications.ts index 09c0479fd..e4966dbf5 100644 --- a/server/tests/api/users/user-notifications.ts +++ b/server/tests/api/users/user-notifications.ts | |||
@@ -29,33 +29,46 @@ import { | |||
29 | getLastNotification, | 29 | getLastNotification, |
30 | getUserNotifications, | 30 | getUserNotifications, |
31 | markAsReadNotifications, | 31 | markAsReadNotifications, |
32 | updateMyNotificationSettings | 32 | updateMyNotificationSettings, |
33 | checkVideoIsPublished, checkMyVideoImportIsFinished | ||
33 | } from '../../../../shared/utils/users/user-notifications' | 34 | } from '../../../../shared/utils/users/user-notifications' |
34 | import { User, UserNotification, UserNotificationSettingValue } from '../../../../shared/models/users' | 35 | import { |
36 | User, | ||
37 | UserNotification, | ||
38 | UserNotificationSetting, | ||
39 | UserNotificationSettingValue, | ||
40 | UserNotificationType | ||
41 | } from '../../../../shared/models/users' | ||
35 | import { MockSmtpServer } from '../../../../shared/utils/miscs/email' | 42 | import { MockSmtpServer } from '../../../../shared/utils/miscs/email' |
36 | import { addUserSubscription } from '../../../../shared/utils/users/user-subscriptions' | 43 | import { addUserSubscription } from '../../../../shared/utils/users/user-subscriptions' |
37 | import { VideoPrivacy } from '../../../../shared/models/videos' | 44 | import { VideoPrivacy } from '../../../../shared/models/videos' |
38 | import { getYoutubeVideoUrl, importVideo } from '../../../../shared/utils/videos/video-imports' | 45 | import { getYoutubeVideoUrl, importVideo, getBadVideoUrl } from '../../../../shared/utils/videos/video-imports' |
39 | import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/utils/videos/video-comments' | 46 | import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/utils/videos/video-comments' |
47 | import * as uuidv4 from 'uuid/v4' | ||
48 | import { addAccountToAccountBlocklist, removeAccountFromAccountBlocklist } from '../../../../shared/utils/users/blocklist' | ||
40 | 49 | ||
41 | const expect = chai.expect | 50 | const expect = chai.expect |
42 | 51 | ||
43 | async function uploadVideoByRemoteAccount (servers: ServerInfo[], videoNameId: number, additionalParams: any = {}) { | 52 | async function uploadVideoByRemoteAccount (servers: ServerInfo[], additionalParams: any = {}) { |
44 | const data = Object.assign({ name: 'remote video ' + videoNameId }, additionalParams) | 53 | const name = 'remote video ' + uuidv4() |
54 | |||
55 | const data = Object.assign({ name }, additionalParams) | ||
45 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data) | 56 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data) |
46 | 57 | ||
47 | await waitJobs(servers) | 58 | await waitJobs(servers) |
48 | 59 | ||
49 | return res.body.video.uuid | 60 | return { uuid: res.body.video.uuid, name } |
50 | } | 61 | } |
51 | 62 | ||
52 | async function uploadVideoByLocalAccount (servers: ServerInfo[], videoNameId: number, additionalParams: any = {}) { | 63 | async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParams: any = {}) { |
53 | const data = Object.assign({ name: 'local video ' + videoNameId }, additionalParams) | 64 | const name = 'local video ' + uuidv4() |
65 | |||
66 | const data = Object.assign({ name }, additionalParams) | ||
54 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data) | 67 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data) |
55 | 68 | ||
56 | await waitJobs(servers) | 69 | await waitJobs(servers) |
57 | 70 | ||
58 | return res.body.video.uuid | 71 | return { uuid: res.body.video.uuid, name } |
59 | } | 72 | } |
60 | 73 | ||
61 | describe('Test users notifications', function () { | 74 | describe('Test users notifications', function () { |
@@ -63,7 +76,18 @@ describe('Test users notifications', function () { | |||
63 | let userAccessToken: string | 76 | let userAccessToken: string |
64 | let userNotifications: UserNotification[] = [] | 77 | let userNotifications: UserNotification[] = [] |
65 | let adminNotifications: UserNotification[] = [] | 78 | let adminNotifications: UserNotification[] = [] |
79 | let adminNotificationsServer2: UserNotification[] = [] | ||
66 | const emails: object[] = [] | 80 | const emails: object[] = [] |
81 | let channelId: number | ||
82 | |||
83 | const allNotificationSettings: UserNotificationSetting = { | ||
84 | myVideoPublished: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
85 | myVideoImportFinished: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
86 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
87 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
88 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
89 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | ||
90 | } | ||
67 | 91 | ||
68 | before(async function () { | 92 | before(async function () { |
69 | this.timeout(120000) | 93 | this.timeout(120000) |
@@ -94,12 +118,9 @@ describe('Test users notifications', function () { | |||
94 | await createUser(servers[0].url, servers[0].accessToken, user.username, user.password, 10 * 1000 * 1000) | 118 | await createUser(servers[0].url, servers[0].accessToken, user.username, user.password, 10 * 1000 * 1000) |
95 | userAccessToken = await userLogin(servers[0], user) | 119 | userAccessToken = await userLogin(servers[0], user) |
96 | 120 | ||
97 | await updateMyNotificationSettings(servers[0].url, userAccessToken, { | 121 | await updateMyNotificationSettings(servers[0].url, userAccessToken, allNotificationSettings) |
98 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | 122 | await updateMyNotificationSettings(servers[0].url, servers[0].accessToken, allNotificationSettings) |
99 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | 123 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) |
100 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
101 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | ||
102 | }) | ||
103 | 124 | ||
104 | { | 125 | { |
105 | const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken) | 126 | const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken) |
@@ -109,6 +130,15 @@ describe('Test users notifications', function () { | |||
109 | const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken) | 130 | const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken) |
110 | socket.on('new-notification', n => adminNotifications.push(n)) | 131 | socket.on('new-notification', n => adminNotifications.push(n)) |
111 | } | 132 | } |
133 | { | ||
134 | const socket = getUserNotificationSocket(servers[ 1 ].url, servers[1].accessToken) | ||
135 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) | ||
136 | } | ||
137 | |||
138 | { | ||
139 | const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) | ||
140 | channelId = resChannel.body.videoChannels[0].id | ||
141 | } | ||
112 | }) | 142 | }) |
113 | 143 | ||
114 | describe('New video from my subscription notification', function () { | 144 | describe('New video from my subscription notification', function () { |
@@ -124,7 +154,7 @@ describe('Test users notifications', function () { | |||
124 | }) | 154 | }) |
125 | 155 | ||
126 | it('Should not send notifications if the user does not follow the video publisher', async function () { | 156 | it('Should not send notifications if the user does not follow the video publisher', async function () { |
127 | await uploadVideoByLocalAccount(servers, 1) | 157 | await uploadVideoByLocalAccount(servers) |
128 | 158 | ||
129 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | 159 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) |
130 | expect(notification).to.be.undefined | 160 | expect(notification).to.be.undefined |
@@ -136,11 +166,8 @@ describe('Test users notifications', function () { | |||
136 | it('Should send a new video notification if the user follows the local video publisher', async function () { | 166 | it('Should send a new video notification if the user follows the local video publisher', async function () { |
137 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9001') | 167 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9001') |
138 | 168 | ||
139 | const videoNameId = 10 | 169 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
140 | const videoName = 'local video ' + videoNameId | 170 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
141 | |||
142 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId) | ||
143 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | ||
144 | }) | 171 | }) |
145 | 172 | ||
146 | it('Should send a new video notification from a remote account', async function () { | 173 | it('Should send a new video notification from a remote account', async function () { |
@@ -148,21 +175,13 @@ describe('Test users notifications', function () { | |||
148 | 175 | ||
149 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9002') | 176 | await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9002') |
150 | 177 | ||
151 | const videoNameId = 20 | 178 | const { name, uuid } = await uploadVideoByRemoteAccount(servers) |
152 | const videoName = 'remote video ' + videoNameId | 179 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
153 | |||
154 | const uuid = await uploadVideoByRemoteAccount(servers, videoNameId) | ||
155 | await waitJobs(servers) | ||
156 | |||
157 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | ||
158 | }) | 180 | }) |
159 | 181 | ||
160 | it('Should send a new video notification on a scheduled publication', async function () { | 182 | it('Should send a new video notification on a scheduled publication', async function () { |
161 | this.timeout(20000) | 183 | this.timeout(20000) |
162 | 184 | ||
163 | const videoNameId = 30 | ||
164 | const videoName = 'local video ' + videoNameId | ||
165 | |||
166 | // In 2 seconds | 185 | // In 2 seconds |
167 | let updateAt = new Date(new Date().getTime() + 2000) | 186 | let updateAt = new Date(new Date().getTime() + 2000) |
168 | 187 | ||
@@ -173,18 +192,15 @@ describe('Test users notifications', function () { | |||
173 | privacy: VideoPrivacy.PUBLIC | 192 | privacy: VideoPrivacy.PUBLIC |
174 | } | 193 | } |
175 | } | 194 | } |
176 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId, data) | 195 | const { name, uuid } = await uploadVideoByLocalAccount(servers, data) |
177 | 196 | ||
178 | await wait(6000) | 197 | await wait(6000) |
179 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 198 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
180 | }) | 199 | }) |
181 | 200 | ||
182 | it('Should send a new video notification on a remote scheduled publication', async function () { | 201 | it('Should send a new video notification on a remote scheduled publication', async function () { |
183 | this.timeout(20000) | 202 | this.timeout(20000) |
184 | 203 | ||
185 | const videoNameId = 40 | ||
186 | const videoName = 'remote video ' + videoNameId | ||
187 | |||
188 | // In 2 seconds | 204 | // In 2 seconds |
189 | let updateAt = new Date(new Date().getTime() + 2000) | 205 | let updateAt = new Date(new Date().getTime() + 2000) |
190 | 206 | ||
@@ -195,19 +211,16 @@ describe('Test users notifications', function () { | |||
195 | privacy: VideoPrivacy.PUBLIC | 211 | privacy: VideoPrivacy.PUBLIC |
196 | } | 212 | } |
197 | } | 213 | } |
198 | const uuid = await uploadVideoByRemoteAccount(servers, videoNameId, data) | 214 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, data) |
199 | await waitJobs(servers) | 215 | await waitJobs(servers) |
200 | 216 | ||
201 | await wait(6000) | 217 | await wait(6000) |
202 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 218 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
203 | }) | 219 | }) |
204 | 220 | ||
205 | it('Should not send a notification before the video is published', async function () { | 221 | it('Should not send a notification before the video is published', async function () { |
206 | this.timeout(20000) | 222 | this.timeout(20000) |
207 | 223 | ||
208 | const videoNameId = 50 | ||
209 | const videoName = 'local video ' + videoNameId | ||
210 | |||
211 | let updateAt = new Date(new Date().getTime() + 100000) | 224 | let updateAt = new Date(new Date().getTime() + 100000) |
212 | 225 | ||
213 | const data = { | 226 | const data = { |
@@ -217,86 +230,70 @@ describe('Test users notifications', function () { | |||
217 | privacy: VideoPrivacy.PUBLIC | 230 | privacy: VideoPrivacy.PUBLIC |
218 | } | 231 | } |
219 | } | 232 | } |
220 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId, data) | 233 | const { name, uuid } = await uploadVideoByLocalAccount(servers, data) |
221 | 234 | ||
222 | await wait(6000) | 235 | await wait(6000) |
223 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'absence') | 236 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence') |
224 | }) | 237 | }) |
225 | 238 | ||
226 | it('Should send a new video notification when a video becomes public', async function () { | 239 | it('Should send a new video notification when a video becomes public', async function () { |
227 | this.timeout(10000) | 240 | this.timeout(10000) |
228 | 241 | ||
229 | const videoNameId = 60 | ||
230 | const videoName = 'local video ' + videoNameId | ||
231 | |||
232 | const data = { privacy: VideoPrivacy.PRIVATE } | 242 | const data = { privacy: VideoPrivacy.PRIVATE } |
233 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId, data) | 243 | const { name, uuid } = await uploadVideoByLocalAccount(servers, data) |
234 | 244 | ||
235 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'absence') | 245 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence') |
236 | 246 | ||
237 | await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC }) | 247 | await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC }) |
238 | 248 | ||
239 | await wait(500) | 249 | await wait(500) |
240 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 250 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
241 | }) | 251 | }) |
242 | 252 | ||
243 | it('Should send a new video notification when a remote video becomes public', async function () { | 253 | it('Should send a new video notification when a remote video becomes public', async function () { |
244 | this.timeout(20000) | 254 | this.timeout(20000) |
245 | 255 | ||
246 | const videoNameId = 70 | ||
247 | const videoName = 'remote video ' + videoNameId | ||
248 | |||
249 | const data = { privacy: VideoPrivacy.PRIVATE } | 256 | const data = { privacy: VideoPrivacy.PRIVATE } |
250 | const uuid = await uploadVideoByRemoteAccount(servers, videoNameId, data) | 257 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, data) |
251 | await waitJobs(servers) | ||
252 | 258 | ||
253 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'absence') | 259 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence') |
254 | 260 | ||
255 | await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC }) | 261 | await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC }) |
256 | 262 | ||
257 | await waitJobs(servers) | 263 | await waitJobs(servers) |
258 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 264 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
259 | }) | 265 | }) |
260 | 266 | ||
261 | it('Should not send a new video notification when a video becomes unlisted', async function () { | 267 | it('Should not send a new video notification when a video becomes unlisted', async function () { |
262 | this.timeout(20000) | 268 | this.timeout(20000) |
263 | 269 | ||
264 | const videoNameId = 80 | ||
265 | const videoName = 'local video ' + videoNameId | ||
266 | |||
267 | const data = { privacy: VideoPrivacy.PRIVATE } | 270 | const data = { privacy: VideoPrivacy.PRIVATE } |
268 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId, data) | 271 | const { name, uuid } = await uploadVideoByLocalAccount(servers, data) |
269 | 272 | ||
270 | await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED }) | 273 | await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED }) |
271 | 274 | ||
272 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'absence') | 275 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence') |
273 | }) | 276 | }) |
274 | 277 | ||
275 | it('Should not send a new video notification when a remote video becomes unlisted', async function () { | 278 | it('Should not send a new video notification when a remote video becomes unlisted', async function () { |
276 | this.timeout(20000) | 279 | this.timeout(20000) |
277 | 280 | ||
278 | const videoNameId = 90 | ||
279 | const videoName = 'remote video ' + videoNameId | ||
280 | |||
281 | const data = { privacy: VideoPrivacy.PRIVATE } | 281 | const data = { privacy: VideoPrivacy.PRIVATE } |
282 | const uuid = await uploadVideoByRemoteAccount(servers, videoNameId, data) | 282 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, data) |
283 | await waitJobs(servers) | ||
284 | 283 | ||
285 | await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED }) | 284 | await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED }) |
286 | 285 | ||
287 | await waitJobs(servers) | 286 | await waitJobs(servers) |
288 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'absence') | 287 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence') |
289 | }) | 288 | }) |
290 | 289 | ||
291 | it('Should send a new video notification after a video import', async function () { | 290 | it('Should send a new video notification after a video import', async function () { |
292 | this.timeout(30000) | 291 | this.timeout(30000) |
293 | 292 | ||
294 | const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 293 | const name = 'video import ' + uuidv4() |
295 | const channelId = resChannel.body.videoChannels[0].id | ||
296 | const videoName = 'local video 100' | ||
297 | 294 | ||
298 | const attributes = { | 295 | const attributes = { |
299 | name: videoName, | 296 | name, |
300 | channelId, | 297 | channelId, |
301 | privacy: VideoPrivacy.PUBLIC, | 298 | privacy: VideoPrivacy.PUBLIC, |
302 | targetUrl: getYoutubeVideoUrl() | 299 | targetUrl: getYoutubeVideoUrl() |
@@ -306,7 +303,7 @@ describe('Test users notifications', function () { | |||
306 | 303 | ||
307 | await waitJobs(servers) | 304 | await waitJobs(servers) |
308 | 305 | ||
309 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 306 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
310 | }) | 307 | }) |
311 | }) | 308 | }) |
312 | 309 | ||
@@ -348,6 +345,23 @@ describe('Test users notifications', function () { | |||
348 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') | 345 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') |
349 | }) | 346 | }) |
350 | 347 | ||
348 | it('Should not send a new comment notification if the account is muted', async function () { | ||
349 | this.timeout(10000) | ||
350 | |||
351 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | ||
352 | |||
353 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) | ||
354 | const uuid = resVideo.body.video.uuid | ||
355 | |||
356 | const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, uuid, 'comment') | ||
357 | const commentId = resComment.body.comment.id | ||
358 | |||
359 | await wait(500) | ||
360 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') | ||
361 | |||
362 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | ||
363 | }) | ||
364 | |||
351 | it('Should send a new comment notification after a local comment on my video', async function () { | 365 | it('Should send a new comment notification after a local comment on my video', async function () { |
352 | this.timeout(10000) | 366 | this.timeout(10000) |
353 | 367 | ||
@@ -425,23 +439,21 @@ describe('Test users notifications', function () { | |||
425 | it('Should send a notification to moderators on local video abuse', async function () { | 439 | it('Should send a notification to moderators on local video abuse', async function () { |
426 | this.timeout(10000) | 440 | this.timeout(10000) |
427 | 441 | ||
428 | const videoName = 'local video 110' | 442 | const name = 'video for abuse ' + uuidv4() |
429 | 443 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | |
430 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName }) | ||
431 | const uuid = resVideo.body.video.uuid | 444 | const uuid = resVideo.body.video.uuid |
432 | 445 | ||
433 | await reportVideoAbuse(servers[0].url, servers[0].accessToken, uuid, 'super reason') | 446 | await reportVideoAbuse(servers[0].url, servers[0].accessToken, uuid, 'super reason') |
434 | 447 | ||
435 | await waitJobs(servers) | 448 | await waitJobs(servers) |
436 | await checkNewVideoAbuseForModerators(baseParams, uuid, videoName, 'presence') | 449 | await checkNewVideoAbuseForModerators(baseParams, uuid, name, 'presence') |
437 | }) | 450 | }) |
438 | 451 | ||
439 | it('Should send a notification to moderators on remote video abuse', async function () { | 452 | it('Should send a notification to moderators on remote video abuse', async function () { |
440 | this.timeout(10000) | 453 | this.timeout(10000) |
441 | 454 | ||
442 | const videoName = 'remote video 120' | 455 | const name = 'video for abuse ' + uuidv4() |
443 | 456 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | |
444 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName }) | ||
445 | const uuid = resVideo.body.video.uuid | 457 | const uuid = resVideo.body.video.uuid |
446 | 458 | ||
447 | await waitJobs(servers) | 459 | await waitJobs(servers) |
@@ -449,7 +461,7 @@ describe('Test users notifications', function () { | |||
449 | await reportVideoAbuse(servers[1].url, servers[1].accessToken, uuid, 'super reason') | 461 | await reportVideoAbuse(servers[1].url, servers[1].accessToken, uuid, 'super reason') |
450 | 462 | ||
451 | await waitJobs(servers) | 463 | await waitJobs(servers) |
452 | await checkNewVideoAbuseForModerators(baseParams, uuid, videoName, 'presence') | 464 | await checkNewVideoAbuseForModerators(baseParams, uuid, name, 'presence') |
453 | }) | 465 | }) |
454 | }) | 466 | }) |
455 | 467 | ||
@@ -468,23 +480,21 @@ describe('Test users notifications', function () { | |||
468 | it('Should send a notification to video owner on blacklist', async function () { | 480 | it('Should send a notification to video owner on blacklist', async function () { |
469 | this.timeout(10000) | 481 | this.timeout(10000) |
470 | 482 | ||
471 | const videoName = 'local video 130' | 483 | const name = 'video for abuse ' + uuidv4() |
472 | 484 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | |
473 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName }) | ||
474 | const uuid = resVideo.body.video.uuid | 485 | const uuid = resVideo.body.video.uuid |
475 | 486 | ||
476 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, uuid) | 487 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, uuid) |
477 | 488 | ||
478 | await waitJobs(servers) | 489 | await waitJobs(servers) |
479 | await checkNewBlacklistOnMyVideo(baseParams, uuid, videoName, 'blacklist') | 490 | await checkNewBlacklistOnMyVideo(baseParams, uuid, name, 'blacklist') |
480 | }) | 491 | }) |
481 | 492 | ||
482 | it('Should send a notification to video owner on unblacklist', async function () { | 493 | it('Should send a notification to video owner on unblacklist', async function () { |
483 | this.timeout(10000) | 494 | this.timeout(10000) |
484 | 495 | ||
485 | const videoName = 'local video 130' | 496 | const name = 'video for abuse ' + uuidv4() |
486 | 497 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | |
487 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName }) | ||
488 | const uuid = resVideo.body.video.uuid | 498 | const uuid = resVideo.body.video.uuid |
489 | 499 | ||
490 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, uuid) | 500 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, uuid) |
@@ -494,38 +504,187 @@ describe('Test users notifications', function () { | |||
494 | await waitJobs(servers) | 504 | await waitJobs(servers) |
495 | 505 | ||
496 | await wait(500) | 506 | await wait(500) |
497 | await checkNewBlacklistOnMyVideo(baseParams, uuid, videoName, 'unblacklist') | 507 | await checkNewBlacklistOnMyVideo(baseParams, uuid, name, 'unblacklist') |
508 | }) | ||
509 | }) | ||
510 | |||
511 | describe('My video is published', function () { | ||
512 | let baseParams: CheckerBaseParams | ||
513 | |||
514 | before(() => { | ||
515 | baseParams = { | ||
516 | server: servers[1], | ||
517 | emails, | ||
518 | socketNotifications: adminNotificationsServer2, | ||
519 | token: servers[1].accessToken | ||
520 | } | ||
521 | }) | ||
522 | |||
523 | it('Should not send a notification if transcoding is not enabled', async function () { | ||
524 | const { name, uuid } = await uploadVideoByLocalAccount(servers) | ||
525 | await waitJobs(servers) | ||
526 | |||
527 | await checkVideoIsPublished(baseParams, name, uuid, 'absence') | ||
528 | }) | ||
529 | |||
530 | it('Should not send a notification if the wait transcoding is false', async function () { | ||
531 | this.timeout(50000) | ||
532 | |||
533 | await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) | ||
534 | await waitJobs(servers) | ||
535 | |||
536 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | ||
537 | if (notification) { | ||
538 | expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) | ||
539 | } | ||
540 | }) | ||
541 | |||
542 | it('Should send a notification even if the video is not transcoded in other resolutions', async function () { | ||
543 | this.timeout(50000) | ||
544 | |||
545 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, { waitTranscoding: true, fixture: 'video_short_240p.mp4' }) | ||
546 | await waitJobs(servers) | ||
547 | |||
548 | await checkVideoIsPublished(baseParams, name, uuid, 'presence') | ||
549 | }) | ||
550 | |||
551 | it('Should send a notification with a transcoded video', async function () { | ||
552 | this.timeout(50000) | ||
553 | |||
554 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, { waitTranscoding: true }) | ||
555 | await waitJobs(servers) | ||
556 | |||
557 | await checkVideoIsPublished(baseParams, name, uuid, 'presence') | ||
558 | }) | ||
559 | |||
560 | it('Should send a notification when an imported video is transcoded', async function () { | ||
561 | this.timeout(50000) | ||
562 | |||
563 | const name = 'video import ' + uuidv4() | ||
564 | |||
565 | const attributes = { | ||
566 | name, | ||
567 | channelId, | ||
568 | privacy: VideoPrivacy.PUBLIC, | ||
569 | targetUrl: getYoutubeVideoUrl(), | ||
570 | waitTranscoding: true | ||
571 | } | ||
572 | const res = await importVideo(servers[1].url, servers[1].accessToken, attributes) | ||
573 | const uuid = res.body.video.uuid | ||
574 | |||
575 | await waitJobs(servers) | ||
576 | await checkVideoIsPublished(baseParams, name, uuid, 'presence') | ||
577 | }) | ||
578 | |||
579 | it('Should send a notification when the scheduled update has been proceeded', async function () { | ||
580 | this.timeout(70000) | ||
581 | |||
582 | // In 2 seconds | ||
583 | let updateAt = new Date(new Date().getTime() + 2000) | ||
584 | |||
585 | const data = { | ||
586 | privacy: VideoPrivacy.PRIVATE, | ||
587 | scheduleUpdate: { | ||
588 | updateAt: updateAt.toISOString(), | ||
589 | privacy: VideoPrivacy.PUBLIC | ||
590 | } | ||
591 | } | ||
592 | const { name, uuid } = await uploadVideoByRemoteAccount(servers, data) | ||
593 | |||
594 | await wait(6000) | ||
595 | await checkVideoIsPublished(baseParams, name, uuid, 'presence') | ||
596 | }) | ||
597 | }) | ||
598 | |||
599 | describe('My video is imported', function () { | ||
600 | let baseParams: CheckerBaseParams | ||
601 | |||
602 | before(() => { | ||
603 | baseParams = { | ||
604 | server: servers[0], | ||
605 | emails, | ||
606 | socketNotifications: adminNotifications, | ||
607 | token: servers[0].accessToken | ||
608 | } | ||
609 | }) | ||
610 | |||
611 | it('Should send a notification when the video import failed', async function () { | ||
612 | this.timeout(70000) | ||
613 | |||
614 | const name = 'video import ' + uuidv4() | ||
615 | |||
616 | const attributes = { | ||
617 | name, | ||
618 | channelId, | ||
619 | privacy: VideoPrivacy.PRIVATE, | ||
620 | targetUrl: getBadVideoUrl() | ||
621 | } | ||
622 | const res = await importVideo(servers[0].url, servers[0].accessToken, attributes) | ||
623 | const uuid = res.body.video.uuid | ||
624 | |||
625 | await waitJobs(servers) | ||
626 | await checkMyVideoImportIsFinished(baseParams, name, uuid, getBadVideoUrl(), false, 'presence') | ||
627 | }) | ||
628 | |||
629 | it('Should send a notification when the video import succeeded', async function () { | ||
630 | this.timeout(70000) | ||
631 | |||
632 | const name = 'video import ' + uuidv4() | ||
633 | |||
634 | const attributes = { | ||
635 | name, | ||
636 | channelId, | ||
637 | privacy: VideoPrivacy.PRIVATE, | ||
638 | targetUrl: getYoutubeVideoUrl() | ||
639 | } | ||
640 | const res = await importVideo(servers[0].url, servers[0].accessToken, attributes) | ||
641 | const uuid = res.body.video.uuid | ||
642 | |||
643 | await waitJobs(servers) | ||
644 | await checkMyVideoImportIsFinished(baseParams, name, uuid, getYoutubeVideoUrl(), true, 'presence') | ||
498 | }) | 645 | }) |
499 | }) | 646 | }) |
500 | 647 | ||
501 | describe('Mark as read', function () { | 648 | describe('Mark as read', function () { |
502 | it('Should mark as read some notifications', async function () { | 649 | it('Should mark as read some notifications', async function () { |
503 | const res = await getUserNotifications(servers[0].url, userAccessToken, 2, 3) | 650 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 2, 3) |
504 | const ids = res.body.data.map(n => n.id) | 651 | const ids = res.body.data.map(n => n.id) |
505 | 652 | ||
506 | await markAsReadNotifications(servers[0].url, userAccessToken, ids) | 653 | await markAsReadNotifications(servers[ 0 ].url, userAccessToken, ids) |
507 | }) | 654 | }) |
508 | 655 | ||
509 | it('Should have the notifications marked as read', async function () { | 656 | it('Should have the notifications marked as read', async function () { |
510 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10) | 657 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10) |
658 | |||
659 | const notifications = res.body.data as UserNotification[] | ||
660 | expect(notifications[ 0 ].read).to.be.false | ||
661 | expect(notifications[ 1 ].read).to.be.false | ||
662 | expect(notifications[ 2 ].read).to.be.true | ||
663 | expect(notifications[ 3 ].read).to.be.true | ||
664 | expect(notifications[ 4 ].read).to.be.true | ||
665 | expect(notifications[ 5 ].read).to.be.false | ||
666 | }) | ||
667 | |||
668 | it('Should only list read notifications', async function () { | ||
669 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, false) | ||
511 | 670 | ||
512 | const notifications = res.body.data as UserNotification[] | 671 | const notifications = res.body.data as UserNotification[] |
513 | expect(notifications[0].read).to.be.false | 672 | for (const notification of notifications) { |
514 | expect(notifications[1].read).to.be.false | 673 | expect(notification.read).to.be.true |
515 | expect(notifications[2].read).to.be.true | 674 | } |
516 | expect(notifications[3].read).to.be.true | 675 | }) |
517 | expect(notifications[4].read).to.be.true | 676 | |
518 | expect(notifications[5].read).to.be.false | 677 | it('Should only list unread notifications', async function () { |
678 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) | ||
679 | |||
680 | const notifications = res.body.data as UserNotification[] | ||
681 | for (const notification of notifications) { | ||
682 | expect(notification.read).to.be.false | ||
683 | } | ||
519 | }) | 684 | }) |
520 | }) | 685 | }) |
521 | 686 | ||
522 | describe('Notification settings', function () { | 687 | describe('Notification settings', function () { |
523 | const baseUpdateNotificationParams = { | ||
524 | newCommentOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
525 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
526 | videoAbuseAsModerator: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL, | ||
527 | blacklistOnMyVideo: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | ||
528 | } | ||
529 | let baseParams: CheckerBaseParams | 688 | let baseParams: CheckerBaseParams |
530 | 689 | ||
531 | before(() => { | 690 | before(() => { |
@@ -538,7 +697,7 @@ describe('Test users notifications', function () { | |||
538 | }) | 697 | }) |
539 | 698 | ||
540 | it('Should not have notifications', async function () { | 699 | it('Should not have notifications', async function () { |
541 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(baseUpdateNotificationParams, { | 700 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(allNotificationSettings, { |
542 | newVideoFromSubscription: UserNotificationSettingValue.NONE | 701 | newVideoFromSubscription: UserNotificationSettingValue.NONE |
543 | })) | 702 | })) |
544 | 703 | ||
@@ -548,16 +707,14 @@ describe('Test users notifications', function () { | |||
548 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.NONE) | 707 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.NONE) |
549 | } | 708 | } |
550 | 709 | ||
551 | const videoNameId = 42 | 710 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
552 | const videoName = 'local video ' + videoNameId | ||
553 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId) | ||
554 | 711 | ||
555 | const check = { web: true, mail: true } | 712 | const check = { web: true, mail: true } |
556 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), videoName, uuid, 'absence') | 713 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), name, uuid, 'absence') |
557 | }) | 714 | }) |
558 | 715 | ||
559 | it('Should only have web notifications', async function () { | 716 | it('Should only have web notifications', async function () { |
560 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(baseUpdateNotificationParams, { | 717 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(allNotificationSettings, { |
561 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION | 718 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION |
562 | })) | 719 | })) |
563 | 720 | ||
@@ -567,23 +724,21 @@ describe('Test users notifications', function () { | |||
567 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.WEB_NOTIFICATION) | 724 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.WEB_NOTIFICATION) |
568 | } | 725 | } |
569 | 726 | ||
570 | const videoNameId = 52 | 727 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
571 | const videoName = 'local video ' + videoNameId | ||
572 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId) | ||
573 | 728 | ||
574 | { | 729 | { |
575 | const check = { mail: true, web: false } | 730 | const check = { mail: true, web: false } |
576 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), videoName, uuid, 'absence') | 731 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), name, uuid, 'absence') |
577 | } | 732 | } |
578 | 733 | ||
579 | { | 734 | { |
580 | const check = { mail: false, web: true } | 735 | const check = { mail: false, web: true } |
581 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), videoName, uuid, 'presence') | 736 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), name, uuid, 'presence') |
582 | } | 737 | } |
583 | }) | 738 | }) |
584 | 739 | ||
585 | it('Should only have mail notifications', async function () { | 740 | it('Should only have mail notifications', async function () { |
586 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(baseUpdateNotificationParams, { | 741 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(allNotificationSettings, { |
587 | newVideoFromSubscription: UserNotificationSettingValue.EMAIL | 742 | newVideoFromSubscription: UserNotificationSettingValue.EMAIL |
588 | })) | 743 | })) |
589 | 744 | ||
@@ -593,23 +748,21 @@ describe('Test users notifications', function () { | |||
593 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.EMAIL) | 748 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.EMAIL) |
594 | } | 749 | } |
595 | 750 | ||
596 | const videoNameId = 62 | 751 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
597 | const videoName = 'local video ' + videoNameId | ||
598 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId) | ||
599 | 752 | ||
600 | { | 753 | { |
601 | const check = { mail: false, web: true } | 754 | const check = { mail: false, web: true } |
602 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), videoName, uuid, 'absence') | 755 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), name, uuid, 'absence') |
603 | } | 756 | } |
604 | 757 | ||
605 | { | 758 | { |
606 | const check = { mail: true, web: false } | 759 | const check = { mail: true, web: false } |
607 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), videoName, uuid, 'presence') | 760 | await checkNewVideoFromSubscription(immutableAssign(baseParams, { check }), name, uuid, 'presence') |
608 | } | 761 | } |
609 | }) | 762 | }) |
610 | 763 | ||
611 | it('Should have email and web notifications', async function () { | 764 | it('Should have email and web notifications', async function () { |
612 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(baseUpdateNotificationParams, { | 765 | await updateMyNotificationSettings(servers[0].url, userAccessToken, immutableAssign(allNotificationSettings, { |
613 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | 766 | newVideoFromSubscription: UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL |
614 | })) | 767 | })) |
615 | 768 | ||
@@ -619,11 +772,9 @@ describe('Test users notifications', function () { | |||
619 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL) | 772 | expect(info.notificationSettings.newVideoFromSubscription).to.equal(UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL) |
620 | } | 773 | } |
621 | 774 | ||
622 | const videoNameId = 72 | 775 | const { name, uuid } = await uploadVideoByLocalAccount(servers) |
623 | const videoName = 'local video ' + videoNameId | ||
624 | const uuid = await uploadVideoByLocalAccount(servers, videoNameId) | ||
625 | 776 | ||
626 | await checkNewVideoFromSubscription(baseParams, videoName, uuid, 'presence') | 777 | await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence') |
627 | }) | 778 | }) |
628 | }) | 779 | }) |
629 | 780 | ||
diff --git a/server/tests/fixtures/video_short_240p.mp4 b/server/tests/fixtures/video_short_240p.mp4 new file mode 100644 index 000000000..db074940b --- /dev/null +++ b/server/tests/fixtures/video_short_240p.mp4 | |||
Binary files differ | |||