Avoid too many requests and fetching outbox
[oweals/peertube.git] / server / models / account / account.ts
1 import * as Sequelize from 'sequelize'
2 import {
3   AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Model, Table,
4   UpdatedAt
5 } from 'sequelize-typescript'
6 import { Account } from '../../../shared/models/actors'
7 import { logger } from '../../helpers/logger'
8 import { sendDeleteActor } from '../../lib/activitypub/send'
9 import { ActorModel } from '../activitypub/actor'
10 import { ApplicationModel } from '../application/application'
11 import { AvatarModel } from '../avatar/avatar'
12 import { ServerModel } from '../server/server'
13 import { getSort } from '../utils'
14 import { VideoChannelModel } from '../video/video-channel'
15 import { VideoCommentModel } from '../video/video-comment'
16 import { UserModel } from './user'
17
18 @DefaultScope({
19   include: [
20     {
21       model: () => ActorModel,
22       required: true,
23       include: [
24         {
25           model: () => ServerModel,
26           required: false
27         },
28         {
29           model: () => AvatarModel,
30           required: false
31         }
32       ]
33     }
34   ]
35 })
36 @Table({
37   tableName: 'account'
38 })
39 export class AccountModel extends Model<AccountModel> {
40
41   @AllowNull(false)
42   @Column
43   name: string
44
45   @CreatedAt
46   createdAt: Date
47
48   @UpdatedAt
49   updatedAt: Date
50
51   @ForeignKey(() => ActorModel)
52   @Column
53   actorId: number
54
55   @BelongsTo(() => ActorModel, {
56     foreignKey: {
57       allowNull: false
58     },
59     onDelete: 'cascade'
60   })
61   Actor: ActorModel
62
63   @ForeignKey(() => UserModel)
64   @Column
65   userId: number
66
67   @BelongsTo(() => UserModel, {
68     foreignKey: {
69       allowNull: true
70     },
71     onDelete: 'cascade'
72   })
73   User: UserModel
74
75   @ForeignKey(() => ApplicationModel)
76   @Column
77   applicationId: number
78
79   @BelongsTo(() => ApplicationModel, {
80     foreignKey: {
81       allowNull: true
82     },
83     onDelete: 'cascade'
84   })
85   Application: ApplicationModel
86
87   @HasMany(() => VideoChannelModel, {
88     foreignKey: {
89       allowNull: false
90     },
91     onDelete: 'cascade',
92     hooks: true
93   })
94   VideoChannels: VideoChannelModel[]
95
96   @HasMany(() => VideoCommentModel, {
97     foreignKey: {
98       allowNull: false
99     },
100     onDelete: 'cascade',
101     hooks: true
102   })
103   VideoComments: VideoCommentModel[]
104
105   @BeforeDestroy
106   static async sendDeleteIfOwned (instance: AccountModel, options) {
107     if (!instance.Actor) {
108       instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
109     }
110
111     if (instance.isOwned()) {
112       logger.debug('Sending delete of actor of account %s.', instance.Actor.url)
113       return sendDeleteActor(instance.Actor, options.transaction)
114     }
115
116     return undefined
117   }
118
119   static load (id: number) {
120     return AccountModel.findById(id)
121   }
122
123   static loadByUUID (uuid: string) {
124     const query = {
125       include: [
126         {
127           model: ActorModel,
128           required: true,
129           where: {
130             uuid
131           }
132         }
133       ]
134     }
135
136     return AccountModel.findOne(query)
137   }
138
139   static loadLocalByName (name: string) {
140     const query = {
141       where: {
142         name,
143         [ Sequelize.Op.or ]: [
144           {
145             userId: {
146               [ Sequelize.Op.ne ]: null
147             }
148           },
149           {
150             applicationId: {
151               [ Sequelize.Op.ne ]: null
152             }
153           }
154         ]
155       }
156     }
157
158     return AccountModel.findOne(query)
159   }
160
161   static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
162     const query = {
163       include: [
164         {
165           model: ActorModel,
166           required: true,
167           where: {
168             url
169           }
170         }
171       ],
172       transaction
173     }
174
175     return AccountModel.findOne(query)
176   }
177
178   static listForApi (start: number, count: number, sort: string) {
179     const query = {
180       offset: start,
181       limit: count,
182       order: [ getSort(sort) ]
183     }
184
185     return AccountModel.findAndCountAll(query)
186       .then(({ rows, count }) => {
187         return {
188           data: rows,
189           total: count
190         }
191       })
192   }
193
194   toFormattedJSON (): Account {
195     const actor = this.Actor.toFormattedJSON()
196     const account = {
197       id: this.id,
198       displayName: this.name,
199       createdAt: this.createdAt,
200       updatedAt: this.updatedAt
201     }
202
203     return Object.assign(actor, account)
204   }
205
206   toActivityPubObject () {
207     return this.Actor.toActivityPubObject(this.name, 'Account')
208   }
209
210   isOwned () {
211     return this.Actor.isOwned()
212   }
213 }