mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 19:42:24 +02:00
server/server -> server/core
This commit is contained in:
parent
114327d4ce
commit
5a3d0650c9
838 changed files with 111 additions and 111 deletions
|
@ -0,0 +1,73 @@
|
|||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { AccountModel } from '@server/models/account/account.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import {
|
||||
MAbuseFull,
|
||||
MAbuseMessage,
|
||||
MAccountDefault,
|
||||
MUserWithNotificationSetting,
|
||||
UserNotificationModelForApi
|
||||
} from '@server/types/models/index.js'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
type NewAbuseMessagePayload = {
|
||||
abuse: MAbuseFull
|
||||
message: MAbuseMessage
|
||||
}
|
||||
|
||||
export abstract class AbstractNewAbuseMessage extends AbstractNotification <NewAbuseMessagePayload> {
|
||||
protected messageAccount: MAccountDefault
|
||||
|
||||
async loadMessageAccount () {
|
||||
this.messageAccount = await AccountModel.load(this.message.accountId)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.abuseNewMessage
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.ABUSE_NEW_MESSAGE,
|
||||
userId: user.id,
|
||||
abuseId: this.abuse.id
|
||||
})
|
||||
notification.Abuse = this.abuse
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
protected createEmailFor (to: string, target: 'moderator' | 'reporter') {
|
||||
const text = 'New message on report #' + this.abuse.id
|
||||
const abuseUrl = target === 'moderator'
|
||||
? WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.abuse.id
|
||||
: WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id
|
||||
|
||||
const action = {
|
||||
text: 'View report #' + this.abuse.id,
|
||||
url: abuseUrl
|
||||
}
|
||||
|
||||
return {
|
||||
template: 'abuse-new-message',
|
||||
to,
|
||||
subject: text,
|
||||
locals: {
|
||||
abuseId: this.abuse.id,
|
||||
abuseUrl: action.url,
|
||||
messageAccountName: this.messageAccount.getDisplayName(),
|
||||
messageText: this.message.message,
|
||||
action
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected get abuse () {
|
||||
return this.payload.abuse
|
||||
}
|
||||
|
||||
protected get message () {
|
||||
return this.payload.message
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { getAbuseTargetUrl } from '@server/lib/activitypub/url.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { AbuseState, UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class AbuseStateChangeForReporter extends AbstractNotification <MAbuseFull> {
|
||||
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
const reporter = this.abuse.ReporterAccount
|
||||
if (reporter.isOwned() !== true) return
|
||||
|
||||
this.user = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying reporter of abuse % of state change.', getAbuseTargetUrl(this.abuse))
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.abuseStateChange
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.ABUSE_STATE_CHANGE,
|
||||
userId: user.id,
|
||||
abuseId: this.abuse.id
|
||||
})
|
||||
notification.Abuse = this.abuse
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const text = this.abuse.state === AbuseState.ACCEPTED
|
||||
? 'Report #' + this.abuse.id + ' has been accepted'
|
||||
: 'Report #' + this.abuse.id + ' has been rejected'
|
||||
|
||||
const abuseUrl = WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id
|
||||
|
||||
const action = {
|
||||
text: 'View report #' + this.abuse.id,
|
||||
url: abuseUrl
|
||||
}
|
||||
|
||||
return {
|
||||
template: 'abuse-state-change',
|
||||
to,
|
||||
subject: text,
|
||||
locals: {
|
||||
action,
|
||||
abuseId: this.abuse.id,
|
||||
abuseUrl,
|
||||
isAccepted: this.abuse.state === AbuseState.ACCEPTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get abuse () {
|
||||
return this.payload
|
||||
}
|
||||
}
|
4
server/core/lib/notifier/shared/abuse/index.ts
Normal file
4
server/core/lib/notifier/shared/abuse/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './abuse-state-change-for-reporter.js'
|
||||
export * from './new-abuse-for-moderators.js'
|
||||
export * from './new-abuse-message-for-reporter.js'
|
||||
export * from './new-abuse-message-for-moderators.js'
|
|
@ -0,0 +1,119 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { getAbuseTargetUrl } from '@server/lib/activitypub/url.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserAbuse, UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export type NewAbusePayload = { abuse: UserAbuse, abuseInstance: MAbuseFull, reporter: string }
|
||||
|
||||
export class NewAbuseForModerators extends AbstractNotification <NewAbusePayload> {
|
||||
private moderators: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s user/moderators of new abuse %s.', this.moderators.length, getAbuseTargetUrl(this.payload.abuseInstance))
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.abuseAsModerator
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.moderators
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS,
|
||||
userId: user.id,
|
||||
abuseId: this.payload.abuseInstance.id
|
||||
})
|
||||
notification.Abuse = this.payload.abuseInstance
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const abuseInstance = this.payload.abuseInstance
|
||||
|
||||
if (abuseInstance.VideoAbuse) return this.createVideoAbuseEmail(to)
|
||||
if (abuseInstance.VideoCommentAbuse) return this.createCommentAbuseEmail(to)
|
||||
|
||||
return this.createAccountAbuseEmail(to)
|
||||
}
|
||||
|
||||
private createVideoAbuseEmail (to: string) {
|
||||
const video = this.payload.abuseInstance.VideoAbuse.Video
|
||||
const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
template: 'video-abuse-new',
|
||||
to,
|
||||
subject: `New video abuse report from ${this.payload.reporter}`,
|
||||
locals: {
|
||||
videoUrl,
|
||||
isLocal: video.remote === false,
|
||||
videoCreatedAt: new Date(video.createdAt).toLocaleString(),
|
||||
videoPublishedAt: new Date(video.publishedAt).toLocaleString(),
|
||||
videoName: video.name,
|
||||
reason: this.payload.abuse.reason,
|
||||
videoChannel: this.payload.abuse.video.channel,
|
||||
reporter: this.payload.reporter,
|
||||
action: this.buildEmailAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createCommentAbuseEmail (to: string) {
|
||||
const comment = this.payload.abuseInstance.VideoCommentAbuse.VideoComment
|
||||
const commentUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath() + ';threadId=' + comment.getThreadId()
|
||||
|
||||
return {
|
||||
template: 'video-comment-abuse-new',
|
||||
to,
|
||||
subject: `New comment abuse report from ${this.payload.reporter}`,
|
||||
locals: {
|
||||
commentUrl,
|
||||
videoName: comment.Video.name,
|
||||
isLocal: comment.isOwned(),
|
||||
commentCreatedAt: new Date(comment.createdAt).toLocaleString(),
|
||||
reason: this.payload.abuse.reason,
|
||||
flaggedAccount: this.payload.abuseInstance.FlaggedAccount.getDisplayName(),
|
||||
reporter: this.payload.reporter,
|
||||
action: this.buildEmailAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createAccountAbuseEmail (to: string) {
|
||||
const account = this.payload.abuseInstance.FlaggedAccount
|
||||
const accountUrl = account.getClientUrl()
|
||||
|
||||
return {
|
||||
template: 'account-abuse-new',
|
||||
to,
|
||||
subject: `New account abuse report from ${this.payload.reporter}`,
|
||||
locals: {
|
||||
accountUrl,
|
||||
accountDisplayName: account.getDisplayName(),
|
||||
isLocal: account.isOwned(),
|
||||
reason: this.payload.abuse.reason,
|
||||
reporter: this.payload.reporter,
|
||||
action: this.buildEmailAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private buildEmailAction () {
|
||||
return {
|
||||
text: 'View report #' + this.payload.abuseInstance.id,
|
||||
url: WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.payload.abuseInstance.id
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { getAbuseTargetUrl } from '@server/lib/activitypub/url.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { MUserDefault } from '@server/types/models/index.js'
|
||||
import { UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNewAbuseMessage } from './abstract-new-abuse-message.js'
|
||||
|
||||
export class NewAbuseMessageForModerators extends AbstractNewAbuseMessage {
|
||||
private moderators: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
|
||||
|
||||
// Don't notify my own message
|
||||
this.moderators = this.moderators.filter(m => m.Account.id !== this.message.accountId)
|
||||
if (this.moderators.length === 0) return
|
||||
|
||||
await this.loadMessageAccount()
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying moderators of new abuse message on %s.', getAbuseTargetUrl(this.abuse))
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.moderators
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
return this.createEmailFor(to, 'moderator')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { getAbuseTargetUrl } from '@server/lib/activitypub/url.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { MUserDefault } from '@server/types/models/index.js'
|
||||
import { AbstractNewAbuseMessage } from './abstract-new-abuse-message.js'
|
||||
|
||||
export class NewAbuseMessageForReporter extends AbstractNewAbuseMessage {
|
||||
private reporter: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
// Only notify our users
|
||||
if (this.abuse.ReporterAccount.isOwned() !== true) return
|
||||
|
||||
await this.loadMessageAccount()
|
||||
|
||||
const reporter = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId)
|
||||
// Don't notify my own message
|
||||
if (reporter.Account.id === this.message.accountId) return
|
||||
|
||||
this.reporter = reporter
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying reporter of new abuse message on %s.', getAbuseTargetUrl(this.abuse))
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.reporter) return []
|
||||
|
||||
return [ this.reporter ]
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
return this.createEmailFor(to, 'reporter')
|
||||
}
|
||||
}
|
3
server/core/lib/notifier/shared/blacklist/index.ts
Normal file
3
server/core/lib/notifier/shared/blacklist/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './new-auto-blacklist-for-moderators.js'
|
||||
export * from './new-blacklist-for-owner.js'
|
||||
export * from './unblacklist-for-owner.js'
|
|
@ -0,0 +1,65 @@
|
|||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { VideoChannelModel } from '@server/models/video/video-channel.js'
|
||||
import {
|
||||
MUserDefault,
|
||||
MUserWithNotificationSetting,
|
||||
MVideoBlacklistLightVideo,
|
||||
UserNotificationModelForApi
|
||||
} from '@server/types/models/index.js'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class NewAutoBlacklistForModerators extends AbstractNotification <MVideoBlacklistLightVideo> {
|
||||
private moderators: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_BLACKLIST)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s moderators of video auto-blacklist %s.', this.moderators.length, this.payload.Video.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.videoAutoBlacklistAsModerator
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.moderators
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS,
|
||||
userId: user.id,
|
||||
videoBlacklistId: this.payload.id
|
||||
})
|
||||
notification.VideoBlacklist = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
async createEmail (to: string) {
|
||||
const videoAutoBlacklistUrl = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list'
|
||||
const videoUrl = WEBSERVER.URL + this.payload.Video.getWatchStaticPath()
|
||||
const channel = await VideoChannelModel.loadAndPopulateAccount(this.payload.Video.channelId)
|
||||
|
||||
return {
|
||||
template: 'video-auto-blacklist-new',
|
||||
to,
|
||||
subject: 'A new video is pending moderation',
|
||||
locals: {
|
||||
channel: channel.toFormattedSummaryJSON(),
|
||||
videoUrl,
|
||||
videoName: this.payload.Video.name,
|
||||
action: {
|
||||
text: 'Review autoblacklist',
|
||||
url: videoAutoBlacklistUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { logger } from '@server/helpers/logger.js'
|
||||
import { CONFIG } from '@server/initializers/config.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import {
|
||||
MUserDefault,
|
||||
MUserWithNotificationSetting,
|
||||
MVideoBlacklistVideo,
|
||||
UserNotificationModelForApi
|
||||
} from '@server/types/models/index.js'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class NewBlacklistForOwner extends AbstractNotification <MVideoBlacklistVideo> {
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoId(this.payload.videoId)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s that its video %s has been blacklisted.', this.user.username, this.payload.Video.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.blacklistOnMyVideo
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.BLACKLIST_ON_MY_VIDEO,
|
||||
userId: user.id,
|
||||
videoBlacklistId: this.payload.id
|
||||
})
|
||||
notification.VideoBlacklist = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const videoName = this.payload.Video.name
|
||||
const videoUrl = WEBSERVER.URL + this.payload.Video.getWatchStaticPath()
|
||||
|
||||
const reasonString = this.payload.reason ? ` for the following reason: ${this.payload.reason}` : ''
|
||||
const blockedString = `Your video ${videoName} (${videoUrl} on ${CONFIG.INSTANCE.NAME} has been blacklisted${reasonString}.`
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Video ${videoName} blacklisted`,
|
||||
text: blockedString,
|
||||
locals: {
|
||||
title: 'Your video was blacklisted'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { CONFIG } from '@server/initializers/config.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class UnblacklistForOwner extends AbstractNotification <MVideoFullLight> {
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoId(this.payload.id)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s that its video %s has been unblacklisted.', this.user.username, this.payload.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.blacklistOnMyVideo
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO,
|
||||
userId: user.id,
|
||||
videoId: this.payload.id
|
||||
})
|
||||
notification.Video = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const video = this.payload
|
||||
const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Video ${video.name} unblacklisted`,
|
||||
text: `Your video "${video.name}" (${videoUrl}) on ${CONFIG.INSTANCE.NAME} has been unblacklisted.`,
|
||||
locals: {
|
||||
title: 'Your video was unblacklisted'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
server/core/lib/notifier/shared/comment/comment-mention.ts
Normal file
111
server/core/lib/notifier/shared/comment/comment-mention.ts
Normal file
|
@ -0,0 +1,111 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { toSafeHtml } from '@server/helpers/markdown.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { AccountBlocklistModel } from '@server/models/account/account-blocklist.js'
|
||||
import { getServerActor } from '@server/models/application/application.js'
|
||||
import { ServerBlocklistModel } from '@server/models/server/server-blocklist.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import {
|
||||
MCommentOwnerVideo,
|
||||
MUserDefault,
|
||||
MUserNotifSettingAccount,
|
||||
MUserWithNotificationSetting,
|
||||
UserNotificationModelForApi
|
||||
} from '@server/types/models/index.js'
|
||||
import { UserNotificationSettingValue, UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/index.js'
|
||||
|
||||
export class CommentMention extends AbstractNotification <MCommentOwnerVideo, MUserNotifSettingAccount> {
|
||||
private users: MUserDefault[]
|
||||
|
||||
private serverAccountId: number
|
||||
|
||||
private accountMutedHash: { [ id: number ]: boolean }
|
||||
private instanceMutedHash: { [ id: number ]: boolean }
|
||||
|
||||
async prepare () {
|
||||
const extractedUsernames = this.payload.extractMentions()
|
||||
logger.debug(
|
||||
'Extracted %d username from comment %s.', extractedUsernames.length, this.payload.url,
|
||||
{ usernames: extractedUsernames, text: this.payload.text }
|
||||
)
|
||||
|
||||
this.users = await UserModel.listByUsernames(extractedUsernames)
|
||||
|
||||
if (this.payload.Video.isOwned()) {
|
||||
const userException = await UserModel.loadByVideoId(this.payload.videoId)
|
||||
this.users = this.users.filter(u => u.id !== userException.id)
|
||||
}
|
||||
|
||||
// Don't notify if I mentioned myself
|
||||
this.users = this.users.filter(u => u.Account.id !== this.payload.accountId)
|
||||
|
||||
if (this.users.length === 0) return
|
||||
|
||||
this.serverAccountId = (await getServerActor()).Account.id
|
||||
|
||||
const sourceAccounts = this.users.map(u => u.Account.id).concat([ this.serverAccountId ])
|
||||
|
||||
this.accountMutedHash = await AccountBlocklistModel.isAccountMutedByAccounts(sourceAccounts, this.payload.accountId)
|
||||
this.instanceMutedHash = await ServerBlocklistModel.isServerMutedByAccounts(sourceAccounts, this.payload.Account.Actor.serverId)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %d users of new comment %s.', this.users.length, this.payload.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserNotifSettingAccount) {
|
||||
const accountId = user.Account.id
|
||||
if (
|
||||
this.accountMutedHash[accountId] === true || this.instanceMutedHash[accountId] === true ||
|
||||
this.accountMutedHash[this.serverAccountId] === true || this.instanceMutedHash[this.serverAccountId] === true
|
||||
) {
|
||||
return UserNotificationSettingValue.NONE
|
||||
}
|
||||
|
||||
return user.NotificationSetting.commentMention
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.users
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.COMMENT_MENTION,
|
||||
userId: user.id,
|
||||
commentId: this.payload.id
|
||||
})
|
||||
notification.VideoComment = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const comment = this.payload
|
||||
|
||||
const accountName = comment.Account.getDisplayName()
|
||||
const video = comment.Video
|
||||
const videoUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath()
|
||||
const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath()
|
||||
const commentHtml = toSafeHtml(comment.text)
|
||||
|
||||
return {
|
||||
template: 'video-comment-mention',
|
||||
to,
|
||||
subject: 'Mention on video ' + video.name,
|
||||
locals: {
|
||||
comment,
|
||||
commentHtml,
|
||||
video,
|
||||
videoUrl,
|
||||
accountName,
|
||||
action: {
|
||||
text: 'View comment',
|
||||
url: commentUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
server/core/lib/notifier/shared/comment/index.ts
Normal file
2
server/core/lib/notifier/shared/comment/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './comment-mention.js'
|
||||
export * from './new-comment-for-video-owner.js'
|
|
@ -0,0 +1,76 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { toSafeHtml } from '@server/helpers/markdown.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { isBlockedByServerOrAccount } from '@server/lib/blocklist.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MCommentOwnerVideo, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class NewCommentForVideoOwner extends AbstractNotification <MCommentOwnerVideo> {
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoId(this.payload.videoId)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying owner of a video %s of new comment %s.', this.user.username, this.payload.url)
|
||||
}
|
||||
|
||||
isDisabled () {
|
||||
if (this.payload.Video.isOwned() === false) return true
|
||||
|
||||
// Not our user or user comments its own video
|
||||
if (!this.user || this.payload.Account.userId === this.user.id) return true
|
||||
|
||||
return isBlockedByServerOrAccount(this.payload.Account, this.user.Account)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newCommentOnMyVideo
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_COMMENT_ON_MY_VIDEO,
|
||||
userId: user.id,
|
||||
commentId: this.payload.id
|
||||
})
|
||||
notification.VideoComment = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const video = this.payload.Video
|
||||
const videoUrl = WEBSERVER.URL + this.payload.Video.getWatchStaticPath()
|
||||
const commentUrl = WEBSERVER.URL + this.payload.getCommentStaticPath()
|
||||
const commentHtml = toSafeHtml(this.payload.text)
|
||||
|
||||
return {
|
||||
template: 'video-comment-new',
|
||||
to,
|
||||
subject: 'New comment on your video ' + video.name,
|
||||
locals: {
|
||||
accountName: this.payload.Account.getDisplayName(),
|
||||
accountUrl: this.payload.Account.Actor.url,
|
||||
comment: this.payload,
|
||||
commentHtml,
|
||||
video,
|
||||
videoUrl,
|
||||
action: {
|
||||
text: 'View comment',
|
||||
url: commentUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { EmailPayload, UserNotificationSettingValueType } from '@peertube/peertube-models'
|
||||
import { MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
|
||||
export abstract class AbstractNotification <T, U = MUserWithNotificationSetting> {
|
||||
|
||||
constructor (protected readonly payload: T) {
|
||||
|
||||
}
|
||||
|
||||
abstract prepare (): Promise<void>
|
||||
abstract log (): void
|
||||
|
||||
abstract getSetting (user: U): UserNotificationSettingValueType
|
||||
abstract getTargetUsers (): U[]
|
||||
|
||||
abstract createNotification (user: U): UserNotificationModelForApi
|
||||
abstract createEmail (to: string): EmailPayload | Promise<EmailPayload>
|
||||
|
||||
isDisabled (): boolean | Promise<boolean> {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
1
server/core/lib/notifier/shared/common/index.ts
Normal file
1
server/core/lib/notifier/shared/common/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './abstract-notification.js'
|
|
@ -0,0 +1,51 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class AutoFollowForInstance extends AbstractNotification <MActorFollowFull> {
|
||||
private admins: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %d administrators of auto instance following: %s.', this.admins.length, this.actorFollow.ActorFollowing.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.autoInstanceFollowing
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.admins
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.AUTO_INSTANCE_FOLLOWING,
|
||||
userId: user.id,
|
||||
actorFollowId: this.actorFollow.id
|
||||
})
|
||||
notification.ActorFollow = this.actorFollow
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const instanceUrl = this.actorFollow.ActorFollowing.url
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: 'Auto instance following',
|
||||
text: `Your instance automatically followed a new instance: <a href="${instanceUrl}">${instanceUrl}</a>.`
|
||||
}
|
||||
}
|
||||
|
||||
private get actorFollow () {
|
||||
return this.payload
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { isBlockedByServerOrAccount } from '@server/lib/blocklist.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class FollowForInstance extends AbstractNotification <MActorFollowFull> {
|
||||
private admins: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW)
|
||||
}
|
||||
|
||||
isDisabled () {
|
||||
const follower = Object.assign(this.actorFollow.ActorFollower.Account, { Actor: this.actorFollow.ActorFollower })
|
||||
|
||||
return isBlockedByServerOrAccount(follower)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %d administrators of new instance follower: %s.', this.admins.length, this.actorFollow.ActorFollower.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newInstanceFollower
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.admins
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_INSTANCE_FOLLOWER,
|
||||
userId: user.id,
|
||||
actorFollowId: this.actorFollow.id
|
||||
})
|
||||
notification.ActorFollow = this.actorFollow
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const awaitingApproval = this.actorFollow.state === 'pending'
|
||||
? ' awaiting manual approval.'
|
||||
: ''
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: 'New instance follower',
|
||||
text: `Your instance has a new follower: ${this.actorFollow.ActorFollower.url}${awaitingApproval}.`,
|
||||
locals: {
|
||||
title: 'New instance follower',
|
||||
action: {
|
||||
text: 'Review followers',
|
||||
url: WEBSERVER.URL + '/admin/follows/followers-list'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get actorFollow () {
|
||||
return this.payload
|
||||
}
|
||||
}
|
82
server/core/lib/notifier/shared/follow/follow-for-user.ts
Normal file
82
server/core/lib/notifier/shared/follow/follow-for-user.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { isBlockedByServerOrAccount } from '@server/lib/blocklist.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class FollowForUser extends AbstractNotification <MActorFollowFull> {
|
||||
private followType: 'account' | 'channel'
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
// Account follows one of our account?
|
||||
this.followType = 'channel'
|
||||
this.user = await UserModel.loadByChannelActorId(this.actorFollow.ActorFollowing.id)
|
||||
|
||||
// Account follows one of our channel?
|
||||
if (!this.user) {
|
||||
this.user = await UserModel.loadByAccountActorId(this.actorFollow.ActorFollowing.id)
|
||||
this.followType = 'account'
|
||||
}
|
||||
}
|
||||
|
||||
async isDisabled () {
|
||||
if (this.payload.ActorFollowing.isOwned() === false) return true
|
||||
|
||||
const followerAccount = this.actorFollow.ActorFollower.Account
|
||||
const followerAccountWithActor = Object.assign(followerAccount, { Actor: this.actorFollow.ActorFollower })
|
||||
|
||||
return isBlockedByServerOrAccount(followerAccountWithActor, this.user.Account)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s of new follower: %s.', this.user.username, this.actorFollow.ActorFollower.Account.getDisplayName())
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newFollow
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_FOLLOW,
|
||||
userId: user.id,
|
||||
actorFollowId: this.actorFollow.id
|
||||
})
|
||||
notification.ActorFollow = this.actorFollow
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const following = this.actorFollow.ActorFollowing
|
||||
const follower = this.actorFollow.ActorFollower
|
||||
|
||||
const followingName = (following.VideoChannel || following.Account).getDisplayName()
|
||||
|
||||
return {
|
||||
template: 'follower-on-channel',
|
||||
to,
|
||||
subject: `New follower on your channel ${followingName}`,
|
||||
locals: {
|
||||
followerName: follower.Account.getDisplayName(),
|
||||
followerUrl: follower.url,
|
||||
followingName,
|
||||
followingUrl: following.url,
|
||||
followType: this.followType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get actorFollow () {
|
||||
return this.payload
|
||||
}
|
||||
}
|
3
server/core/lib/notifier/shared/follow/index.ts
Normal file
3
server/core/lib/notifier/shared/follow/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './auto-follow-for-instance.js'
|
||||
export * from './follow-for-instance.js'
|
||||
export * from './follow-for-user.js'
|
7
server/core/lib/notifier/shared/index.ts
Normal file
7
server/core/lib/notifier/shared/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export * from './abuse/index.js'
|
||||
export * from './blacklist/index.js'
|
||||
export * from './comment/index.js'
|
||||
export * from './common/index.js'
|
||||
export * from './follow/index.js'
|
||||
export * from './instance/index.js'
|
||||
export * from './video-publication/index.js'
|
|
@ -0,0 +1,49 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { CONFIG } from '@server/initializers/config.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class DirectRegistrationForModerators extends AbstractNotification <MUserDefault> {
|
||||
private moderators: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.moderators = await UserModel.listWithRight(UserRight.MANAGE_USERS)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s moderators of new user registration of %s.', this.moderators.length, this.payload.username)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newUserRegistration
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.moderators
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_USER_REGISTRATION,
|
||||
userId: user.id,
|
||||
accountId: this.payload.Account.id
|
||||
})
|
||||
notification.Account = this.payload.Account
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
return {
|
||||
template: 'user-registered',
|
||||
to,
|
||||
subject: `A new user registered on ${CONFIG.INSTANCE.NAME}: ${this.payload.username}`,
|
||||
locals: {
|
||||
user: this.payload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
server/core/lib/notifier/shared/instance/index.ts
Normal file
4
server/core/lib/notifier/shared/instance/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from './new-peertube-version-for-admins.js'
|
||||
export * from './new-plugin-version-for-admins.js'
|
||||
export * from './direct-registration-for-moderators.js'
|
||||
export * from './registration-request-for-moderators.js'
|
|
@ -0,0 +1,54 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MApplication, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export type NewPeerTubeVersionForAdminsPayload = {
|
||||
application: MApplication
|
||||
latestVersion: string
|
||||
}
|
||||
|
||||
export class NewPeerTubeVersionForAdmins extends AbstractNotification <NewPeerTubeVersionForAdminsPayload> {
|
||||
private admins: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
// Use the debug right to know who is an administrator
|
||||
this.admins = await UserModel.listWithRight(UserRight.MANAGE_DEBUG)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s admins of new PeerTube version %s.', this.admins.length, this.payload.latestVersion)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newPeerTubeVersion
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.admins
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_PEERTUBE_VERSION,
|
||||
userId: user.id,
|
||||
applicationId: this.payload.application.id
|
||||
})
|
||||
notification.Application = this.payload.application
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
return {
|
||||
to,
|
||||
template: 'peertube-version-new',
|
||||
subject: `A new PeerTube version is available: ${this.payload.latestVersion}`,
|
||||
locals: {
|
||||
latestVersion: this.payload.latestVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MPlugin, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class NewPluginVersionForAdmins extends AbstractNotification <MPlugin> {
|
||||
private admins: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
// Use the debug right to know who is an administrator
|
||||
this.admins = await UserModel.listWithRight(UserRight.MANAGE_DEBUG)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s admins of new PeerTube version %s.', this.admins.length, this.payload.latestVersion)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newPluginVersion
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.admins
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_PLUGIN_VERSION,
|
||||
userId: user.id,
|
||||
pluginId: this.plugin.id
|
||||
})
|
||||
notification.Plugin = this.plugin
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const pluginUrl = WEBSERVER.URL + '/admin/plugins/list-installed?pluginType=' + this.plugin.type
|
||||
|
||||
return {
|
||||
to,
|
||||
template: 'plugin-version-new',
|
||||
subject: `A new plugin/theme version is available: ${this.plugin.name}@${this.plugin.latestVersion}`,
|
||||
locals: {
|
||||
pluginName: this.plugin.name,
|
||||
latestVersion: this.plugin.latestVersion,
|
||||
pluginUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get plugin () {
|
||||
return this.payload
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MRegistration, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, UserRight } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class RegistrationRequestForModerators extends AbstractNotification <MRegistration> {
|
||||
private moderators: MUserDefault[]
|
||||
|
||||
async prepare () {
|
||||
this.moderators = await UserModel.listWithRight(UserRight.MANAGE_REGISTRATIONS)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %s moderators of new user registration request of %s.', this.moderators.length, this.payload.username)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newUserRegistration
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.moderators
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_USER_REGISTRATION_REQUEST,
|
||||
userId: user.id,
|
||||
userRegistrationId: this.payload.id
|
||||
})
|
||||
notification.UserRegistration = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
return {
|
||||
template: 'user-registration-request',
|
||||
to,
|
||||
subject: `A new user wants to register: ${this.payload.username}`,
|
||||
locals: {
|
||||
registration: this.payload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export abstract class AbstractOwnedVideoPublication extends AbstractNotification <MVideoFullLight> {
|
||||
protected user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoId(this.payload.id)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s of the publication of its video %s.', this.user.username, this.payload.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.myVideoPublished
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.MY_VIDEO_PUBLISHED,
|
||||
userId: user.id,
|
||||
videoId: this.payload.id
|
||||
})
|
||||
notification.Video = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Your video ${this.payload.name} has been published`,
|
||||
text: `Your video "${this.payload.name}" has been published.`,
|
||||
locals: {
|
||||
title: 'Your video is live',
|
||||
action: {
|
||||
text: 'View video',
|
||||
url: videoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserDefault, MUserWithNotificationSetting, MVideoImportVideo, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export type ImportFinishedForOwnerPayload = {
|
||||
videoImport: MVideoImportVideo
|
||||
success: boolean
|
||||
}
|
||||
|
||||
export class ImportFinishedForOwner extends AbstractNotification <ImportFinishedForOwnerPayload> {
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoImportId(this.videoImport.id)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s its video import %s is finished.', this.user.username, this.videoImport.getTargetIdentifier())
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.myVideoImportFinished
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: this.payload.success
|
||||
? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS
|
||||
: UserNotificationType.MY_VIDEO_IMPORT_ERROR,
|
||||
|
||||
userId: user.id,
|
||||
videoImportId: this.videoImport.id
|
||||
})
|
||||
notification.VideoImport = this.videoImport
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
if (this.payload.success) return this.createSuccessEmail(to)
|
||||
|
||||
return this.createFailEmail(to)
|
||||
}
|
||||
|
||||
private createSuccessEmail (to: string) {
|
||||
const videoUrl = WEBSERVER.URL + this.videoImport.Video.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Your video import ${this.videoImport.getTargetIdentifier()} is complete`,
|
||||
text: `Your video "${this.videoImport.getTargetIdentifier()}" just finished importing.`,
|
||||
locals: {
|
||||
title: 'Import complete',
|
||||
action: {
|
||||
text: 'View video',
|
||||
url: videoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createFailEmail (to: string) {
|
||||
const importUrl = WEBSERVER.URL + '/my-library/video-imports'
|
||||
|
||||
const text =
|
||||
`Your video import "${this.videoImport.getTargetIdentifier()}" encountered an error.` +
|
||||
'\n\n' +
|
||||
`See your videos import dashboard for more information: <a href="${importUrl}">${importUrl}</a>.`
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Your video import "${this.videoImport.getTargetIdentifier()}" encountered an error`,
|
||||
text,
|
||||
locals: {
|
||||
title: 'Import failed',
|
||||
action: {
|
||||
text: 'Review imports',
|
||||
url: importUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get videoImport () {
|
||||
return this.payload.videoImport
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export * from './new-video-for-subscribers.js'
|
||||
export * from './import-finished-for-owner.js'
|
||||
export * from './owned-publication-after-auto-unblacklist.js'
|
||||
export * from './owned-publication-after-schedule-update.js'
|
||||
export * from './owned-publication-after-transcoding.js'
|
||||
export * from './studio-edition-finished-for-owner.js'
|
|
@ -0,0 +1,61 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserWithNotificationSetting, MVideoAccountLight, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType, VideoPrivacy, VideoState } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class NewVideoForSubscribers extends AbstractNotification <MVideoAccountLight> {
|
||||
private users: MUserWithNotificationSetting[]
|
||||
|
||||
async prepare () {
|
||||
// List all followers that are users
|
||||
this.users = await UserModel.listUserSubscribersOf(this.payload.VideoChannel.actorId)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying %d users of new video %s.', this.users.length, this.payload.url)
|
||||
}
|
||||
|
||||
isDisabled () {
|
||||
return this.payload.privacy !== VideoPrivacy.PUBLIC || this.payload.state !== VideoState.PUBLISHED || this.payload.isBlacklisted()
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.newVideoFromSubscription
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
return this.users
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION,
|
||||
userId: user.id,
|
||||
videoId: this.payload.id
|
||||
})
|
||||
notification.Video = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const channelName = this.payload.VideoChannel.getDisplayName()
|
||||
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: channelName + ' just published a new video',
|
||||
text: `Your subscription ${channelName} just published a new video: "${this.payload.name}".`,
|
||||
locals: {
|
||||
title: 'New content ',
|
||||
action: {
|
||||
text: 'View video',
|
||||
url: videoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
import { VideoState } from '@peertube/peertube-models'
|
||||
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
|
||||
|
||||
export class OwnedPublicationAfterAutoUnblacklist extends AbstractOwnedVideoPublication {
|
||||
|
||||
isDisabled () {
|
||||
// Don't notify if video is still waiting for transcoding or scheduled update
|
||||
return !!this.payload.ScheduleVideoUpdate || (this.payload.waitTranscoding && this.payload.state !== VideoState.PUBLISHED)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { VideoState } from '@peertube/peertube-models'
|
||||
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
|
||||
|
||||
export class OwnedPublicationAfterScheduleUpdate extends AbstractOwnedVideoPublication {
|
||||
|
||||
isDisabled () {
|
||||
// Don't notify if video is still blacklisted or waiting for transcoding
|
||||
return !!this.payload.VideoBlacklist || (this.payload.waitTranscoding && this.payload.state !== VideoState.PUBLISHED)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
|
||||
|
||||
export class OwnedPublicationAfterTranscoding extends AbstractOwnedVideoPublication {
|
||||
|
||||
isDisabled () {
|
||||
// Don't notify if didn't wait for transcoding or video is still blacklisted/waiting for scheduled update
|
||||
return !this.payload.waitTranscoding || !!this.payload.VideoBlacklist || !!this.payload.ScheduleVideoUpdate
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import { logger } from '@server/helpers/logger.js'
|
||||
import { WEBSERVER } from '@server/initializers/constants.js'
|
||||
import { UserModel } from '@server/models/user/user.js'
|
||||
import { UserNotificationModel } from '@server/models/user/user-notification.js'
|
||||
import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotificationModelForApi } from '@server/types/models/index.js'
|
||||
import { UserNotificationType } from '@peertube/peertube-models'
|
||||
import { AbstractNotification } from '../common/abstract-notification.js'
|
||||
|
||||
export class StudioEditionFinishedForOwner extends AbstractNotification <MVideoFullLight> {
|
||||
private user: MUserDefault
|
||||
|
||||
async prepare () {
|
||||
this.user = await UserModel.loadByVideoId(this.payload.id)
|
||||
}
|
||||
|
||||
log () {
|
||||
logger.info('Notifying user %s its video studio edition %s is finished.', this.user.username, this.payload.url)
|
||||
}
|
||||
|
||||
getSetting (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.myVideoStudioEditionFinished
|
||||
}
|
||||
|
||||
getTargetUsers () {
|
||||
if (!this.user) return []
|
||||
|
||||
return [ this.user ]
|
||||
}
|
||||
|
||||
createNotification (user: MUserWithNotificationSetting) {
|
||||
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED,
|
||||
userId: user.id,
|
||||
videoId: this.payload.id
|
||||
})
|
||||
notification.Video = this.payload
|
||||
|
||||
return notification
|
||||
}
|
||||
|
||||
createEmail (to: string) {
|
||||
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
|
||||
|
||||
return {
|
||||
to,
|
||||
subject: `Edition of your video ${this.payload.name} has finished`,
|
||||
text: `Edition of your video ${this.payload.name} has finished.`,
|
||||
locals: {
|
||||
title: 'Video edition has finished',
|
||||
action: {
|
||||
text: 'View video',
|
||||
url: videoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue