]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/actor/actor.ts
Force live stream termination
[github/Chocobozzz/PeerTube.git] / server / models / actor / actor.ts
index 943b7364f1b07d479cd55f5f95fbac3e35dd446a..80a646c77f59e669119c61a8337a50d1534353a4 100644 (file)
@@ -1,5 +1,4 @@
-import { values } from 'lodash'
-import { literal, Op, QueryTypes, Transaction } from 'sequelize'
+import { col, fn, literal, Op, QueryTypes, Transaction, where } from 'sequelize'
 import {
   AllowNull,
   BelongsTo,
@@ -18,8 +17,8 @@ import {
 } from 'sequelize-typescript'
 import { activityPubContextify } from '@server/lib/activitypub/context'
 import { getBiggestActorImage } from '@server/lib/actor-image'
-import { ModelCache } from '@server/models/model-cache'
-import { getLowercaseExtension } from '@shared/core-utils'
+import { ModelCache } from '@server/models/shared/model-cache'
+import { forceNumber, getLowercaseExtension } from '@shared/core-utils'
 import { ActivityIconObject, ActivityPubActorType, ActorImageType } from '@shared/models'
 import { AttributesOnly } from '@shared/typescript-utils'
 import {
@@ -56,7 +55,7 @@ import {
 import { AccountModel } from '../account/account'
 import { getServerActor } from '../application/application'
 import { ServerModel } from '../server/server'
-import { isOutdated, throwIfNotValid } from '../utils'
+import { buildSQLAttributes, isOutdated, throwIfNotValid } from '../shared'
 import { VideoModel } from '../video/video'
 import { VideoChannelModel } from '../video/video-channel'
 import { ActorFollowModel } from './actor-follow'
@@ -66,7 +65,7 @@ enum ScopeNames {
   FULL = 'FULL'
 }
 
-export const unusedActorAttributesForAPI = [
+export const unusedActorAttributesForAPI: (keyof AttributesOnly<ActorModel>)[] = [
   'publicKey',
   'privateKey',
   'inboxUrl',
@@ -131,7 +130,8 @@ export const unusedActorAttributesForAPI = [
       unique: true
     },
     {
-      fields: [ 'preferredUsername', 'serverId' ],
+      fields: [ fn('lower', col('preferredUsername')), 'serverId' ],
+      name: 'actor_preferred_username_lower_server_id',
       unique: true,
       where: {
         serverId: {
@@ -140,7 +140,8 @@ export const unusedActorAttributesForAPI = [
       }
     },
     {
-      fields: [ 'preferredUsername' ],
+      fields: [ fn('lower', col('preferredUsername')) ],
+      name: 'actor_preferred_username_lower',
       unique: true,
       where: {
         serverId: null
@@ -163,7 +164,7 @@ export const unusedActorAttributesForAPI = [
 export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
 
   @AllowNull(false)
-  @Column(DataType.ENUM(...values(ACTIVITY_PUB_ACTOR_TYPES)))
+  @Column(DataType.ENUM(...Object.values(ACTIVITY_PUB_ACTOR_TYPES)))
   type: ActivityPubActorType
 
   @AllowNull(false)
@@ -307,6 +308,33 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
   })
   VideoChannel: VideoChannelModel
 
+  // ---------------------------------------------------------------------------
+
+  static getSQLAttributes (tableName: string, aliasPrefix = '') {
+    return buildSQLAttributes({
+      model: this,
+      tableName,
+      aliasPrefix
+    })
+  }
+
+  static getSQLAPIAttributes (tableName: string, aliasPrefix = '') {
+    return buildSQLAttributes({
+      model: this,
+      tableName,
+      aliasPrefix,
+      excludeAttributes: unusedActorAttributesForAPI
+    })
+  }
+
+  // ---------------------------------------------------------------------------
+
+  static wherePreferredUsername (preferredUsername: string, colName = 'preferredUsername') {
+    return where(fn('lower', col(colName)), preferredUsername.toLowerCase())
+  }
+
+  // ---------------------------------------------------------------------------
+
   static async load (id: number): Promise<MActor> {
     const actorServer = await getServerActor()
     if (id === actorServer.id) return actorServer
@@ -352,8 +380,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
     const fun = () => {
       const query = {
         where: {
-          preferredUsername,
-          serverId: null
+          [Op.and]: [
+            this.wherePreferredUsername(preferredUsername, '"ActorModel"."preferredUsername"'),
+            {
+              serverId: null
+            }
+          ]
         },
         transaction
       }
@@ -375,8 +407,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
       const query = {
         attributes: [ 'url' ],
         where: {
-          preferredUsername,
-          serverId: null
+          [Op.and]: [
+            this.wherePreferredUsername(preferredUsername),
+            {
+              serverId: null
+            }
+          ]
         },
         transaction
       }
@@ -385,7 +421,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
     }
 
     return ModelCache.Instance.doCache({
-      cacheType: 'local-actor-name',
+      cacheType: 'local-actor-url',
       key: preferredUsername,
       // The server actor never change, so we can easily cache it
       whitelist: () => preferredUsername === SERVER_ACTOR_NAME,
@@ -395,9 +431,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
 
   static loadByNameAndHost (preferredUsername: string, host: string): Promise<MActorFull> {
     const query = {
-      where: {
-        preferredUsername
-      },
+      where: this.wherePreferredUsername(preferredUsername, '"ActorModel"."preferredUsername"'),
       include: [
         {
           model: ServerModel,
@@ -447,7 +481,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
   }
 
   static rebuildFollowsCount (ofId: number, type: 'followers' | 'following', transaction?: Transaction) {
-    const sanitizedOfId = parseInt(ofId + '', 10)
+    const sanitizedOfId = forceNumber(ofId)
     const where = { id: sanitizedOfId }
 
     let columnToUpdate: string
@@ -462,7 +496,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
     }
 
     return ActorModel.update({
-      [columnToUpdate]: literal(`(SELECT COUNT(*) FROM "actorFollow" WHERE "${columnOfCount}" = ${sanitizedOfId})`)
+      [columnToUpdate]: literal(`(SELECT COUNT(*) FROM "actorFollow" WHERE "${columnOfCount}" = ${sanitizedOfId} AND "state" = 'accepted')`)
     }, { where, transaction })
   }