]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/account/account.ts
Put activity pub sends inside transactions
[github/Chocobozzz/PeerTube.git] / server / models / account / account.ts
index d2293a9392c48e0ffbeeebbb54a16b30a841a41b..61a88524c2d39662557d9ba524450f01b0566981 100644 (file)
@@ -1,43 +1,26 @@
 import * as Sequelize from 'sequelize'
-
 import {
-  isUserUsernameValid,
-  isAccountPublicKeyValid,
-  isAccountUrlValid,
-  isAccountPrivateKeyValid,
+  activityPubContextify,
   isAccountFollowersCountValid,
   isAccountFollowingCountValid,
-  isAccountInboxValid,
-  isAccountOutboxValid,
-  isAccountSharedInboxValid,
-  isAccountFollowersValid,
-  isAccountFollowingValid,
-  activityPubContextify
+  isAccountPrivateKeyValid,
+  isAccountPublicKeyValid,
+  isUserUsernameValid
 } from '../../helpers'
-
-import { addMethodsToModel, getSort } from '../utils'
-import {
-  AccountInstance,
-  AccountAttributes,
-
-  AccountMethods
-} from './account-interface'
-import { sendDeleteAccount } from '../../lib/activitypub/send-request'
-import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
+import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
+import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants'
+import { sendDeleteAccount } from '../../lib/activitypub/send/send-delete'
+import { addMethodsToModel } from '../utils'
+import { AccountAttributes, AccountInstance, AccountMethods } from './account-interface'
 
 let Account: Sequelize.Model<AccountInstance, AccountAttributes>
-let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
 let load: AccountMethods.Load
 let loadApplication: AccountMethods.LoadApplication
 let loadByUUID: AccountMethods.LoadByUUID
 let loadByUrl: AccountMethods.LoadByUrl
 let loadLocalByName: AccountMethods.LoadLocalByName
 let loadByNameAndHost: AccountMethods.LoadByNameAndHost
-let listOwned: AccountMethods.ListOwned
-let listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi
-let listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi
-let listFollowingForApi: AccountMethods.ListFollowingForApi
-let listFollowersForApi: AccountMethods.ListFollowersForApi
+let listByFollowersUrls: AccountMethods.ListByFollowersUrls
 let isOwned: AccountMethods.IsOwned
 let toActivityPubObject: AccountMethods.ToActivityPubObject
 let toFormattedJSON: AccountMethods.ToFormattedJSON
@@ -72,14 +55,14 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           urlValid: value => {
-            const res = isAccountUrlValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('URL is not valid.')
           }
         }
       },
       publicKey: {
         type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PUBLIC_KEY.max),
-        allowNull: false,
+        allowNull: true,
         validate: {
           publicKeyValid: value => {
             const res = isAccountPublicKeyValid(value)
@@ -122,7 +105,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           inboxUrlValid: value => {
-            const res = isAccountInboxValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('Inbox URL is not valid.')
           }
         }
@@ -132,7 +115,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           outboxUrlValid: value => {
-            const res = isAccountOutboxValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('Outbox URL is not valid.')
           }
         }
@@ -142,7 +125,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           sharedInboxUrlValid: value => {
-            const res = isAccountSharedInboxValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('Shared inbox URL is not valid.')
           }
         }
@@ -152,7 +135,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           followersUrlValid: value => {
-            const res = isAccountFollowersValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('Followers URL is not valid.')
           }
         }
@@ -162,7 +145,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
         allowNull: false,
         validate: {
           followingUrlValid: value => {
-            const res = isAccountFollowingValid(value)
+            const res = isActivityPubUrlValid(value)
             if (res === false) throw new Error('Following URL is not valid.')
           }
         }
@@ -174,7 +157,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
           fields: [ 'name' ]
         },
         {
-          fields: [ 'podId' ]
+          fields: [ 'serverId' ]
         },
         {
           fields: [ 'userId' ],
@@ -185,7 +168,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
           unique: true
         },
         {
-          fields: [ 'name', 'podId' ],
+          fields: [ 'name', 'serverId', 'applicationId' ],
           unique: true
         }
       ],
@@ -195,18 +178,13 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
 
   const classMethods = [
     associate,
-    loadAccountByPodAndUUID,
     loadApplication,
     load,
     loadByUUID,
     loadByUrl,
     loadLocalByName,
     loadByNameAndHost,
-    listOwned,
-    listAcceptedFollowerUrlsForApi,
-    listAcceptedFollowingUrlsForApi,
-    listFollowingForApi,
-    listFollowersForApi
+    listByFollowersUrls
   ]
   const instanceMethods = [
     isOwned,
@@ -225,9 +203,9 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
 // ---------------------------------------------------------------------------
 
 function associate (models) {
-  Account.belongsTo(models.Pod, {
+  Account.belongsTo(models.Server, {
     foreignKey: {
-      name: 'podId',
+      name: 'serverId',
       allowNull: true
     },
     onDelete: 'cascade'
@@ -263,7 +241,6 @@ function associate (models) {
       name: 'accountId',
       allowNull: false
     },
-    as: 'following',
     onDelete: 'cascade'
   })
 
@@ -286,17 +263,28 @@ function afterDestroy (account: AccountInstance) {
 }
 
 toFormattedJSON = function (this: AccountInstance) {
+  let host = CONFIG.WEBSERVER.HOST
+  let score: number
+
+  if (this.Server) {
+    host = this.Server.host
+    score = this.Server.score as number
+  }
+
   const json = {
     id: this.id,
-    host: this.Pod.host,
-    name: this.name
+    host,
+    score,
+    name: this.name,
+    createdAt: this.createdAt,
+    updatedAt: this.updatedAt
   }
 
   return json
 }
 
 toActivityPubObject = function (this: AccountInstance) {
-  const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
+  const type = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person'
 
   const json = {
     type,
@@ -323,10 +311,10 @@ toActivityPubObject = function (this: AccountInstance) {
 }
 
 isOwned = function (this: AccountInstance) {
-  return this.podId === null
+  return this.serverId === null
 }
 
-getFollowerSharedInboxUrls = function (this: AccountInstance) {
+getFollowerSharedInboxUrls = function (this: AccountInstance, t: Sequelize.Transaction) {
   const query: Sequelize.FindOptions<AccountAttributes> = {
     attributes: [ 'sharedInboxUrl' ],
     include: [
@@ -338,7 +326,8 @@ getFollowerSharedInboxUrls = function (this: AccountInstance) {
           targetAccountId: this.id
         }
       }
-    ]
+    ],
+    transaction: t
   }
 
   return Account.findAll(query)
@@ -346,7 +335,7 @@ getFollowerSharedInboxUrls = function (this: AccountInstance) {
 }
 
 getFollowingUrl = function (this: AccountInstance) {
-  return this.url + '/followers'
+  return this.url + '/following'
 }
 
 getFollowersUrl = function (this: AccountInstance) {
@@ -359,86 +348,6 @@ getPublicKeyUrl = function (this: AccountInstance) {
 
 // ------------------------------ STATICS ------------------------------
 
-listOwned = function () {
-  const query: Sequelize.FindOptions<AccountAttributes> = {
-    where: {
-      podId: null
-    }
-  }
-
-  return Account.findAll(query)
-}
-
-listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
-  return createListAcceptedFollowForApiQuery('followers', id, start, count)
-}
-
-listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
-  return createListAcceptedFollowForApiQuery('following', id, start, count)
-}
-
-listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
-  const query = {
-    distinct: true,
-    offset: start,
-    limit: count,
-    order: [ getSort(sort) ],
-    include: [
-      {
-        model: Account['sequelize'].models.AccountFollow,
-        required: true,
-        as: 'following',
-        include: [
-          {
-            model: Account['sequelize'].models.Account,
-            as: 'accountFollowing',
-            required: true,
-            include: [ Account['sequelize'].models.Pod ]
-          }
-        ]
-      }
-    ]
-  }
-
-  return Account.findAndCountAll(query).then(({ rows, count }) => {
-    return {
-      data: rows,
-      total: count
-    }
-  })
-}
-
-listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
-  const query = {
-    distinct: true,
-    offset: start,
-    limit: count,
-    order: [ getSort(sort) ],
-    include: [
-      {
-        model: Account['sequelize'].models.AccountFollow,
-        required: true,
-        as: 'followers',
-        include: [
-          {
-            model: Account['sequelize'].models.Account,
-            as: 'accountFollowers',
-            required: true,
-            include: [ Account['sequelize'].models.Pod ]
-          }
-        ]
-      }
-    ]
-  }
-
-  return Account.findAndCountAll(query).then(({ rows, count }) => {
-    return {
-      data: rows,
-      total: count
-    }
-  })
-}
-
 loadApplication = function () {
   return Account.findOne({
     include: [
@@ -493,7 +402,7 @@ loadByNameAndHost = function (name: string, host: string) {
     },
     include: [
       {
-        model: Account['sequelize'].models.Pod,
+        model: Account['sequelize'].models.Server,
         required: true,
         where: {
           host
@@ -516,56 +425,15 @@ loadByUrl = function (url: string, transaction?: Sequelize.Transaction) {
   return Account.findOne(query)
 }
 
-loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Sequelize.Transaction) {
+listByFollowersUrls = function (followersUrls: string[], transaction?: Sequelize.Transaction) {
   const query: Sequelize.FindOptions<AccountAttributes> = {
     where: {
-      podId,
-      uuid
+      followersUrl: {
+        [Sequelize.Op.in]: followersUrls
+      }
     },
     transaction
   }
 
-  return Account.find(query)
-}
-
-// ------------------------------ UTILS ------------------------------
-
-async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
-  let firstJoin: string
-  let secondJoin: string
-
-  if (type === 'followers') {
-    firstJoin = 'targetAccountId'
-    secondJoin = 'accountId'
-  } else {
-    firstJoin = 'accountId'
-    secondJoin = 'targetAccountId'
-  }
-
-  const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
-  const tasks: Promise<any>[] = []
-
-  for (const selection of selections) {
-    let query = 'SELECT ' + selection + ' FROM "Account" ' +
-      'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
-      'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
-      'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
-      'LIMIT ' + start
-
-    if (count !== undefined) query += ', ' + count
-
-    const options = {
-      bind: { id },
-      type: Sequelize.QueryTypes.SELECT
-    }
-    tasks.push(Account['sequelize'].query(query, options))
-  }
-
-  const [ followers, [ { total } ]] = await Promise.all(tasks)
-  const urls: string[] = followers.map(f => f.url)
-
-  return {
-    data: urls,
-    total: parseInt(total, 10)
-  }
+  return Account.findAll(query)
 }