From d26836cd95e981d636006652927773c7943e77ce Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Fri, 30 Jul 2021 16:51:27 +0200
Subject: Refactor notifier

---
 .../shared/follow/auto-follow-for-instance.ts      | 51 ++++++++++++++
 .../notifier/shared/follow/follow-for-instance.ts  | 68 ++++++++++++++++++
 .../lib/notifier/shared/follow/follow-for-user.ts  | 82 ++++++++++++++++++++++
 server/lib/notifier/shared/follow/index.ts         |  3 +
 4 files changed, 204 insertions(+)
 create mode 100644 server/lib/notifier/shared/follow/auto-follow-for-instance.ts
 create mode 100644 server/lib/notifier/shared/follow/follow-for-instance.ts
 create mode 100644 server/lib/notifier/shared/follow/follow-for-user.ts
 create mode 100644 server/lib/notifier/shared/follow/index.ts

(limited to 'server/lib/notifier/shared/follow')

diff --git a/server/lib/notifier/shared/follow/auto-follow-for-instance.ts b/server/lib/notifier/shared/follow/auto-follow-for-instance.ts
new file mode 100644
index 000000000..16cc62984
--- /dev/null
+++ b/server/lib/notifier/shared/follow/auto-follow-for-instance.ts
@@ -0,0 +1,51 @@
+import { logger } from '@server/helpers/logger'
+import { UserModel } from '@server/models/user/user'
+import { UserNotificationModel } from '@server/models/user/user-notification'
+import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
+import { UserNotificationType, UserRight } from '@shared/models'
+import { AbstractNotification } from '../common/abstract-notification'
+
+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
+  }
+
+  async createNotification (user: MUserWithNotificationSetting) {
+    const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
+      type: UserNotificationType.AUTO_INSTANCE_FOLLOWING,
+      userId: user.id,
+      actorFollowId: this.actorFollow.id
+    })
+    notification.ActorFollow = this.actorFollow
+
+    return notification
+  }
+
+  async 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
+  }
+}
diff --git a/server/lib/notifier/shared/follow/follow-for-instance.ts b/server/lib/notifier/shared/follow/follow-for-instance.ts
new file mode 100644
index 000000000..9ab269cf1
--- /dev/null
+++ b/server/lib/notifier/shared/follow/follow-for-instance.ts
@@ -0,0 +1,68 @@
+import { logger } from '@server/helpers/logger'
+import { WEBSERVER } from '@server/initializers/constants'
+import { isBlockedByServerOrAccount } from '@server/lib/blocklist'
+import { UserModel } from '@server/models/user/user'
+import { UserNotificationModel } from '@server/models/user/user-notification'
+import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
+import { UserNotificationType, UserRight } from '@shared/models'
+import { AbstractNotification } from '../common/abstract-notification'
+
+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
+  }
+
+  async createNotification (user: MUserWithNotificationSetting) {
+    const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
+      type: UserNotificationType.NEW_INSTANCE_FOLLOWER,
+      userId: user.id,
+      actorFollowId: this.actorFollow.id
+    })
+    notification.ActorFollow = this.actorFollow
+
+    return notification
+  }
+
+  async 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
+  }
+}
diff --git a/server/lib/notifier/shared/follow/follow-for-user.ts b/server/lib/notifier/shared/follow/follow-for-user.ts
new file mode 100644
index 000000000..2d0f675a8
--- /dev/null
+++ b/server/lib/notifier/shared/follow/follow-for-user.ts
@@ -0,0 +1,82 @@
+import { logger } from '@server/helpers/logger'
+import { isBlockedByServerOrAccount } from '@server/lib/blocklist'
+import { UserModel } from '@server/models/user/user'
+import { UserNotificationModel } from '@server/models/user/user-notification'
+import { MActorFollowFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
+import { UserNotificationType } from '@shared/models'
+import { AbstractNotification } from '../common/abstract-notification'
+
+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 ]
+  }
+
+  async createNotification (user: MUserWithNotificationSetting) {
+    const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
+      type: UserNotificationType.NEW_FOLLOW,
+      userId: user.id,
+      actorFollowId: this.actorFollow.id
+    })
+    notification.ActorFollow = this.actorFollow
+
+    return notification
+  }
+
+  async 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
+  }
+}
diff --git a/server/lib/notifier/shared/follow/index.ts b/server/lib/notifier/shared/follow/index.ts
new file mode 100644
index 000000000..27f5289d9
--- /dev/null
+++ b/server/lib/notifier/shared/follow/index.ts
@@ -0,0 +1,3 @@
+export * from './auto-follow-for-instance'
+export * from './follow-for-instance'
+export * from './follow-for-user'
-- 
cgit v1.2.3