notifier.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. import { getServerActor } from '@server/models/application/application'
  2. import { ServerBlocklistModel } from '@server/models/server/server-blocklist'
  3. import {
  4. MUser,
  5. MUserAccount,
  6. MUserDefault,
  7. MUserNotifSettingAccount,
  8. MUserWithNotificationSetting,
  9. UserNotificationModelForApi
  10. } from '@server/types/models/user'
  11. import { MVideoImportVideo } from '@server/types/models/video/video-import'
  12. import { UserNotificationSettingValue, UserNotificationType, UserRight } from '../../shared/models/users'
  13. import { VideoAbuse, VideoPrivacy, VideoState } from '../../shared/models/videos'
  14. import { logger } from '../helpers/logger'
  15. import { CONFIG } from '../initializers/config'
  16. import { AccountBlocklistModel } from '../models/account/account-blocklist'
  17. import { UserModel } from '../models/account/user'
  18. import { UserNotificationModel } from '../models/account/user-notification'
  19. import { MAccountServer, MActorFollowFull } from '../types/models'
  20. import {
  21. MCommentOwnerVideo,
  22. MVideoAbuseVideo,
  23. MVideoAccountLight,
  24. MVideoBlacklistLightVideo,
  25. MVideoBlacklistVideo,
  26. MVideoFullLight
  27. } from '../types/models/video'
  28. import { isBlockedByServerOrAccount } from './blocklist'
  29. import { Emailer } from './emailer'
  30. import { PeerTubeSocket } from './peertube-socket'
  31. class Notifier {
  32. private static instance: Notifier
  33. private constructor () {
  34. }
  35. notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void {
  36. // Only notify on public and published videos which are not blacklisted
  37. if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return
  38. this.notifySubscribersOfNewVideo(video)
  39. .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err }))
  40. }
  41. notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void {
  42. // don't notify if didn't wait for transcoding or video is still blacklisted/waiting for scheduled update
  43. if (!video.waitTranscoding || video.VideoBlacklist || video.ScheduleVideoUpdate) return
  44. this.notifyOwnedVideoHasBeenPublished(video)
  45. .catch(err => logger.error('Cannot notify owner that its video %s has been published after transcoding.', video.url, { err }))
  46. }
  47. notifyOnVideoPublishedAfterScheduledUpdate (video: MVideoFullLight): void {
  48. // don't notify if video is still blacklisted or waiting for transcoding
  49. if (video.VideoBlacklist || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return
  50. this.notifyOwnedVideoHasBeenPublished(video)
  51. .catch(err => logger.error('Cannot notify owner that its video %s has been published after scheduled update.', video.url, { err }))
  52. }
  53. notifyOnVideoPublishedAfterRemovedFromAutoBlacklist (video: MVideoFullLight): void {
  54. // don't notify if video is still waiting for transcoding or scheduled update
  55. if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return
  56. this.notifyOwnedVideoHasBeenPublished(video)
  57. .catch(err => {
  58. logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })
  59. })
  60. }
  61. notifyOnNewComment (comment: MCommentOwnerVideo): void {
  62. this.notifyVideoOwnerOfNewComment(comment)
  63. .catch(err => logger.error('Cannot notify video owner of new comment %s.', comment.url, { err }))
  64. this.notifyOfCommentMention(comment)
  65. .catch(err => logger.error('Cannot notify mentions of comment %s.', comment.url, { err }))
  66. }
  67. notifyOnNewVideoAbuse (parameters: { videoAbuse: VideoAbuse, videoAbuseInstance: MVideoAbuseVideo, reporter: string }): void {
  68. this.notifyModeratorsOfNewVideoAbuse(parameters)
  69. .catch(err => logger.error('Cannot notify of new video abuse of video %s.', parameters.videoAbuseInstance.Video.url, { err }))
  70. }
  71. notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void {
  72. this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist)
  73. .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err }))
  74. }
  75. notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void {
  76. this.notifyVideoOwnerOfBlacklist(videoBlacklist)
  77. .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err }))
  78. }
  79. notifyOnVideoUnblacklist (video: MVideoFullLight): void {
  80. this.notifyVideoOwnerOfUnblacklist(video)
  81. .catch(err => logger.error('Cannot notify video owner of unblacklist of %s.', video.url, { err }))
  82. }
  83. notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void {
  84. this.notifyOwnerVideoImportIsFinished(videoImport, success)
  85. .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err }))
  86. }
  87. notifyOnNewUserRegistration (user: MUserDefault): void {
  88. this.notifyModeratorsOfNewUserRegistration(user)
  89. .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err }))
  90. }
  91. notifyOfNewUserFollow (actorFollow: MActorFollowFull): void {
  92. this.notifyUserOfNewActorFollow(actorFollow)
  93. .catch(err => {
  94. logger.error(
  95. 'Cannot notify owner of channel %s of a new follow by %s.',
  96. actorFollow.ActorFollowing.VideoChannel.getDisplayName(),
  97. actorFollow.ActorFollower.Account.getDisplayName(),
  98. { err }
  99. )
  100. })
  101. }
  102. notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void {
  103. this.notifyAdminsOfNewInstanceFollow(actorFollow)
  104. .catch(err => {
  105. logger.error('Cannot notify administrators of new follower %s.', actorFollow.ActorFollower.url, { err })
  106. })
  107. }
  108. notifyOfAutoInstanceFollowing (actorFollow: MActorFollowFull): void {
  109. this.notifyAdminsOfAutoInstanceFollowing(actorFollow)
  110. .catch(err => {
  111. logger.error('Cannot notify administrators of auto instance following %s.', actorFollow.ActorFollowing.url, { err })
  112. })
  113. }
  114. private async notifySubscribersOfNewVideo (video: MVideoAccountLight) {
  115. // List all followers that are users
  116. const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId)
  117. logger.info('Notifying %d users of new video %s.', users.length, video.url)
  118. function settingGetter (user: MUserWithNotificationSetting) {
  119. return user.NotificationSetting.newVideoFromSubscription
  120. }
  121. async function notificationCreator (user: MUserWithNotificationSetting) {
  122. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  123. type: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION,
  124. userId: user.id,
  125. videoId: video.id
  126. })
  127. notification.Video = video
  128. return notification
  129. }
  130. function emailSender (emails: string[]) {
  131. return Emailer.Instance.addNewVideoFromSubscriberNotification(emails, video)
  132. }
  133. return this.notify({ users, settingGetter, notificationCreator, emailSender })
  134. }
  135. private async notifyVideoOwnerOfNewComment (comment: MCommentOwnerVideo) {
  136. if (comment.Video.isOwned() === false) return
  137. const user = await UserModel.loadByVideoId(comment.videoId)
  138. // Not our user or user comments its own video
  139. if (!user || comment.Account.userId === user.id) return
  140. if (await this.isBlockedByServerOrUser(comment.Account, user)) return
  141. logger.info('Notifying user %s of new comment %s.', user.username, comment.url)
  142. function settingGetter (user: MUserWithNotificationSetting) {
  143. return user.NotificationSetting.newCommentOnMyVideo
  144. }
  145. async function notificationCreator (user: MUserWithNotificationSetting) {
  146. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  147. type: UserNotificationType.NEW_COMMENT_ON_MY_VIDEO,
  148. userId: user.id,
  149. commentId: comment.id
  150. })
  151. notification.Comment = comment
  152. return notification
  153. }
  154. function emailSender (emails: string[]) {
  155. return Emailer.Instance.addNewCommentOnMyVideoNotification(emails, comment)
  156. }
  157. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  158. }
  159. private async notifyOfCommentMention (comment: MCommentOwnerVideo) {
  160. const extractedUsernames = comment.extractMentions()
  161. logger.debug(
  162. 'Extracted %d username from comment %s.', extractedUsernames.length, comment.url,
  163. { usernames: extractedUsernames, text: comment.text }
  164. )
  165. let users = await UserModel.listByUsernames(extractedUsernames)
  166. if (comment.Video.isOwned()) {
  167. const userException = await UserModel.loadByVideoId(comment.videoId)
  168. users = users.filter(u => u.id !== userException.id)
  169. }
  170. // Don't notify if I mentioned myself
  171. users = users.filter(u => u.Account.id !== comment.accountId)
  172. if (users.length === 0) return
  173. const serverAccountId = (await getServerActor()).Account.id
  174. const sourceAccounts = users.map(u => u.Account.id).concat([ serverAccountId ])
  175. const accountMutedHash = await AccountBlocklistModel.isAccountMutedByMulti(sourceAccounts, comment.accountId)
  176. const instanceMutedHash = await ServerBlocklistModel.isServerMutedByMulti(sourceAccounts, comment.Account.Actor.serverId)
  177. logger.info('Notifying %d users of new comment %s.', users.length, comment.url)
  178. function settingGetter (user: MUserNotifSettingAccount) {
  179. const accountId = user.Account.id
  180. if (
  181. accountMutedHash[accountId] === true || instanceMutedHash[accountId] === true ||
  182. accountMutedHash[serverAccountId] === true || instanceMutedHash[serverAccountId] === true
  183. ) {
  184. return UserNotificationSettingValue.NONE
  185. }
  186. return user.NotificationSetting.commentMention
  187. }
  188. async function notificationCreator (user: MUserNotifSettingAccount) {
  189. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  190. type: UserNotificationType.COMMENT_MENTION,
  191. userId: user.id,
  192. commentId: comment.id
  193. })
  194. notification.Comment = comment
  195. return notification
  196. }
  197. function emailSender (emails: string[]) {
  198. return Emailer.Instance.addNewCommentMentionNotification(emails, comment)
  199. }
  200. return this.notify({ users, settingGetter, notificationCreator, emailSender })
  201. }
  202. private async notifyUserOfNewActorFollow (actorFollow: MActorFollowFull) {
  203. if (actorFollow.ActorFollowing.isOwned() === false) return
  204. // Account follows one of our account?
  205. let followType: 'account' | 'channel' = 'channel'
  206. let user = await UserModel.loadByChannelActorId(actorFollow.ActorFollowing.id)
  207. // Account follows one of our channel?
  208. if (!user) {
  209. user = await UserModel.loadByAccountActorId(actorFollow.ActorFollowing.id)
  210. followType = 'account'
  211. }
  212. if (!user) return
  213. const followerAccount = actorFollow.ActorFollower.Account
  214. const followerAccountWithActor = Object.assign(followerAccount, { Actor: actorFollow.ActorFollower })
  215. if (await this.isBlockedByServerOrUser(followerAccountWithActor, user)) return
  216. logger.info('Notifying user %s of new follower: %s.', user.username, followerAccount.getDisplayName())
  217. function settingGetter (user: MUserWithNotificationSetting) {
  218. return user.NotificationSetting.newFollow
  219. }
  220. async function notificationCreator (user: MUserWithNotificationSetting) {
  221. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  222. type: UserNotificationType.NEW_FOLLOW,
  223. userId: user.id,
  224. actorFollowId: actorFollow.id
  225. })
  226. notification.ActorFollow = actorFollow
  227. return notification
  228. }
  229. function emailSender (emails: string[]) {
  230. return Emailer.Instance.addNewFollowNotification(emails, actorFollow, followType)
  231. }
  232. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  233. }
  234. private async notifyAdminsOfNewInstanceFollow (actorFollow: MActorFollowFull) {
  235. const admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW)
  236. const follower = Object.assign(actorFollow.ActorFollower.Account, { Actor: actorFollow.ActorFollower })
  237. if (await this.isBlockedByServerOrUser(follower)) return
  238. logger.info('Notifying %d administrators of new instance follower: %s.', admins.length, actorFollow.ActorFollower.url)
  239. function settingGetter (user: MUserWithNotificationSetting) {
  240. return user.NotificationSetting.newInstanceFollower
  241. }
  242. async function notificationCreator (user: MUserWithNotificationSetting) {
  243. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  244. type: UserNotificationType.NEW_INSTANCE_FOLLOWER,
  245. userId: user.id,
  246. actorFollowId: actorFollow.id
  247. })
  248. notification.ActorFollow = actorFollow
  249. return notification
  250. }
  251. function emailSender (emails: string[]) {
  252. return Emailer.Instance.addNewInstanceFollowerNotification(emails, actorFollow)
  253. }
  254. return this.notify({ users: admins, settingGetter, notificationCreator, emailSender })
  255. }
  256. private async notifyAdminsOfAutoInstanceFollowing (actorFollow: MActorFollowFull) {
  257. const admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW)
  258. logger.info('Notifying %d administrators of auto instance following: %s.', admins.length, actorFollow.ActorFollowing.url)
  259. function settingGetter (user: MUserWithNotificationSetting) {
  260. return user.NotificationSetting.autoInstanceFollowing
  261. }
  262. async function notificationCreator (user: MUserWithNotificationSetting) {
  263. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  264. type: UserNotificationType.AUTO_INSTANCE_FOLLOWING,
  265. userId: user.id,
  266. actorFollowId: actorFollow.id
  267. })
  268. notification.ActorFollow = actorFollow
  269. return notification
  270. }
  271. function emailSender (emails: string[]) {
  272. return Emailer.Instance.addAutoInstanceFollowingNotification(emails, actorFollow)
  273. }
  274. return this.notify({ users: admins, settingGetter, notificationCreator, emailSender })
  275. }
  276. private async notifyModeratorsOfNewVideoAbuse (parameters: {
  277. videoAbuse: VideoAbuse
  278. videoAbuseInstance: MVideoAbuseVideo
  279. reporter: string
  280. }) {
  281. const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES)
  282. if (moderators.length === 0) return
  283. logger.info('Notifying %s user/moderators of new video abuse %s.', moderators.length, parameters.videoAbuseInstance.Video.url)
  284. function settingGetter (user: MUserWithNotificationSetting) {
  285. return user.NotificationSetting.videoAbuseAsModerator
  286. }
  287. async function notificationCreator (user: MUserWithNotificationSetting) {
  288. const notification: UserNotificationModelForApi = await UserNotificationModel.create<UserNotificationModelForApi>({
  289. type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS,
  290. userId: user.id,
  291. videoAbuseId: parameters.videoAbuse.id
  292. })
  293. notification.VideoAbuse = parameters.videoAbuseInstance
  294. return notification
  295. }
  296. function emailSender (emails: string[]) {
  297. return Emailer.Instance.addVideoAbuseModeratorsNotification(emails, parameters)
  298. }
  299. return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender })
  300. }
  301. private async notifyModeratorsOfVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo) {
  302. const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_BLACKLIST)
  303. if (moderators.length === 0) return
  304. logger.info('Notifying %s moderators of video auto-blacklist %s.', moderators.length, videoBlacklist.Video.url)
  305. function settingGetter (user: MUserWithNotificationSetting) {
  306. return user.NotificationSetting.videoAutoBlacklistAsModerator
  307. }
  308. async function notificationCreator (user: MUserWithNotificationSetting) {
  309. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  310. type: UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS,
  311. userId: user.id,
  312. videoBlacklistId: videoBlacklist.id
  313. })
  314. notification.VideoBlacklist = videoBlacklist
  315. return notification
  316. }
  317. function emailSender (emails: string[]) {
  318. return Emailer.Instance.addVideoAutoBlacklistModeratorsNotification(emails, videoBlacklist)
  319. }
  320. return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender })
  321. }
  322. private async notifyVideoOwnerOfBlacklist (videoBlacklist: MVideoBlacklistVideo) {
  323. const user = await UserModel.loadByVideoId(videoBlacklist.videoId)
  324. if (!user) return
  325. logger.info('Notifying user %s that its video %s has been blacklisted.', user.username, videoBlacklist.Video.url)
  326. function settingGetter (user: MUserWithNotificationSetting) {
  327. return user.NotificationSetting.blacklistOnMyVideo
  328. }
  329. async function notificationCreator (user: MUserWithNotificationSetting) {
  330. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  331. type: UserNotificationType.BLACKLIST_ON_MY_VIDEO,
  332. userId: user.id,
  333. videoBlacklistId: videoBlacklist.id
  334. })
  335. notification.VideoBlacklist = videoBlacklist
  336. return notification
  337. }
  338. function emailSender (emails: string[]) {
  339. return Emailer.Instance.addVideoBlacklistNotification(emails, videoBlacklist)
  340. }
  341. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  342. }
  343. private async notifyVideoOwnerOfUnblacklist (video: MVideoFullLight) {
  344. const user = await UserModel.loadByVideoId(video.id)
  345. if (!user) return
  346. logger.info('Notifying user %s that its video %s has been unblacklisted.', user.username, video.url)
  347. function settingGetter (user: MUserWithNotificationSetting) {
  348. return user.NotificationSetting.blacklistOnMyVideo
  349. }
  350. async function notificationCreator (user: MUserWithNotificationSetting) {
  351. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  352. type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO,
  353. userId: user.id,
  354. videoId: video.id
  355. })
  356. notification.Video = video
  357. return notification
  358. }
  359. function emailSender (emails: string[]) {
  360. return Emailer.Instance.addVideoUnblacklistNotification(emails, video)
  361. }
  362. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  363. }
  364. private async notifyOwnedVideoHasBeenPublished (video: MVideoFullLight) {
  365. const user = await UserModel.loadByVideoId(video.id)
  366. if (!user) return
  367. logger.info('Notifying user %s of the publication of its video %s.', user.username, video.url)
  368. function settingGetter (user: MUserWithNotificationSetting) {
  369. return user.NotificationSetting.myVideoPublished
  370. }
  371. async function notificationCreator (user: MUserWithNotificationSetting) {
  372. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  373. type: UserNotificationType.MY_VIDEO_PUBLISHED,
  374. userId: user.id,
  375. videoId: video.id
  376. })
  377. notification.Video = video
  378. return notification
  379. }
  380. function emailSender (emails: string[]) {
  381. return Emailer.Instance.myVideoPublishedNotification(emails, video)
  382. }
  383. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  384. }
  385. private async notifyOwnerVideoImportIsFinished (videoImport: MVideoImportVideo, success: boolean) {
  386. const user = await UserModel.loadByVideoImportId(videoImport.id)
  387. if (!user) return
  388. logger.info('Notifying user %s its video import %s is finished.', user.username, videoImport.getTargetIdentifier())
  389. function settingGetter (user: MUserWithNotificationSetting) {
  390. return user.NotificationSetting.myVideoImportFinished
  391. }
  392. async function notificationCreator (user: MUserWithNotificationSetting) {
  393. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  394. type: success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR,
  395. userId: user.id,
  396. videoImportId: videoImport.id
  397. })
  398. notification.VideoImport = videoImport
  399. return notification
  400. }
  401. function emailSender (emails: string[]) {
  402. return success
  403. ? Emailer.Instance.myVideoImportSuccessNotification(emails, videoImport)
  404. : Emailer.Instance.myVideoImportErrorNotification(emails, videoImport)
  405. }
  406. return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender })
  407. }
  408. private async notifyModeratorsOfNewUserRegistration (registeredUser: MUserDefault) {
  409. const moderators = await UserModel.listWithRight(UserRight.MANAGE_USERS)
  410. if (moderators.length === 0) return
  411. logger.info(
  412. 'Notifying %s moderators of new user registration of %s.',
  413. moderators.length, registeredUser.username
  414. )
  415. function settingGetter (user: MUserWithNotificationSetting) {
  416. return user.NotificationSetting.newUserRegistration
  417. }
  418. async function notificationCreator (user: MUserWithNotificationSetting) {
  419. const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
  420. type: UserNotificationType.NEW_USER_REGISTRATION,
  421. userId: user.id,
  422. accountId: registeredUser.Account.id
  423. })
  424. notification.Account = registeredUser.Account
  425. return notification
  426. }
  427. function emailSender (emails: string[]) {
  428. return Emailer.Instance.addNewUserRegistrationNotification(emails, registeredUser)
  429. }
  430. return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender })
  431. }
  432. private async notify<T extends MUserWithNotificationSetting> (options: {
  433. users: T[]
  434. notificationCreator: (user: T) => Promise<UserNotificationModelForApi>
  435. emailSender: (emails: string[]) => void
  436. settingGetter: (user: T) => UserNotificationSettingValue
  437. }) {
  438. const emails: string[] = []
  439. for (const user of options.users) {
  440. if (this.isWebNotificationEnabled(options.settingGetter(user))) {
  441. const notification = await options.notificationCreator(user)
  442. PeerTubeSocket.Instance.sendNotification(user.id, notification)
  443. }
  444. if (this.isEmailEnabled(user, options.settingGetter(user))) {
  445. emails.push(user.email)
  446. }
  447. }
  448. if (emails.length !== 0) {
  449. options.emailSender(emails)
  450. }
  451. }
  452. private isEmailEnabled (user: MUser, value: UserNotificationSettingValue) {
  453. if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION === true && user.emailVerified === false) return false
  454. return value & UserNotificationSettingValue.EMAIL
  455. }
  456. private isWebNotificationEnabled (value: UserNotificationSettingValue) {
  457. return value & UserNotificationSettingValue.WEB
  458. }
  459. private isBlockedByServerOrUser (targetAccount: MAccountServer, user?: MUserAccount) {
  460. return isBlockedByServerOrAccount(targetAccount, user?.Account)
  461. }
  462. static get Instance () {
  463. return this.instance || (this.instance = new this())
  464. }
  465. }
  466. // ---------------------------------------------------------------------------
  467. export {
  468. Notifier
  469. }