Limit associations fetch when loading token
[oweals/peertube.git] / server / models / account / account.ts
1 import * as Sequelize from 'sequelize'
2 import {
3   AllowNull,
4   BeforeDestroy,
5   BelongsTo,
6   Column,
7   CreatedAt,
8   Default,
9   DefaultScope,
10   ForeignKey,
11   HasMany,
12   Is,
13   Model,
14   Table,
15   UpdatedAt
16 } from 'sequelize-typescript'
17 import { Account } from '../../../shared/models/actors'
18 import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts'
19 import { sendDeleteActor } from '../../lib/activitypub/send'
20 import { ActorModel } from '../activitypub/actor'
21 import { ApplicationModel } from '../application/application'
22 import { AvatarModel } from '../avatar/avatar'
23 import { ServerModel } from '../server/server'
24 import { getSort, throwIfNotValid } from '../utils'
25 import { VideoChannelModel } from '../video/video-channel'
26 import { VideoCommentModel } from '../video/video-comment'
27 import { UserModel } from './user'
28
29 @DefaultScope({
30   include: [
31     {
32       model: () => ActorModel, // Default scope includes avatar and server
33       required: true
34     }
35   ]
36 })
37 @Table({
38   tableName: 'account',
39   indexes: [
40     {
41       fields: [ 'actorId' ],
42       unique: true
43     },
44     {
45       fields: [ 'applicationId' ]
46     },
47     {
48       fields: [ 'userId' ]
49     }
50   ]
51 })
52 export class AccountModel extends Model<AccountModel> {
53
54   @AllowNull(false)
55   @Column
56   name: string
57
58   @AllowNull(true)
59   @Default(null)
60   @Is('AccountDescription', value => throwIfNotValid(value, isAccountDescriptionValid, 'description'))
61   @Column
62   description: string
63
64   @CreatedAt
65   createdAt: Date
66
67   @UpdatedAt
68   updatedAt: Date
69
70   @ForeignKey(() => ActorModel)
71   @Column
72   actorId: number
73
74   @BelongsTo(() => ActorModel, {
75     foreignKey: {
76       allowNull: false
77     },
78     onDelete: 'cascade'
79   })
80   Actor: ActorModel
81
82   @ForeignKey(() => UserModel)
83   @Column
84   userId: number
85
86   @BelongsTo(() => UserModel, {
87     foreignKey: {
88       allowNull: true
89     },
90     onDelete: 'cascade'
91   })
92   User: UserModel
93
94   @ForeignKey(() => ApplicationModel)
95   @Column
96   applicationId: number
97
98   @BelongsTo(() => ApplicationModel, {
99     foreignKey: {
100       allowNull: true
101     },
102     onDelete: 'cascade'
103   })
104   Application: ApplicationModel
105
106   @HasMany(() => VideoChannelModel, {
107     foreignKey: {
108       allowNull: false
109     },
110     onDelete: 'cascade',
111     hooks: true
112   })
113   VideoChannels: VideoChannelModel[]
114
115   @HasMany(() => VideoCommentModel, {
116     foreignKey: {
117       allowNull: false
118     },
119     onDelete: 'cascade',
120     hooks: true
121   })
122   VideoComments: VideoCommentModel[]
123
124   @BeforeDestroy
125   static async sendDeleteIfOwned (instance: AccountModel, options) {
126     if (!instance.Actor) {
127       instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
128     }
129
130     if (instance.isOwned()) {
131       return sendDeleteActor(instance.Actor, options.transaction)
132     }
133
134     return undefined
135   }
136
137   static load (id: number, transaction?: Sequelize.Transaction) {
138     return AccountModel.findById(id, { transaction })
139   }
140
141   static loadByUUID (uuid: string) {
142     const query = {
143       include: [
144         {
145           model: ActorModel,
146           required: true,
147           where: {
148             uuid
149           }
150         }
151       ]
152     }
153
154     return AccountModel.findOne(query)
155   }
156
157   static loadLocalByName (name: string) {
158     const query = {
159       where: {
160         [ Sequelize.Op.or ]: [
161           {
162             userId: {
163               [ Sequelize.Op.ne ]: null
164             }
165           },
166           {
167             applicationId: {
168               [ Sequelize.Op.ne ]: null
169             }
170           }
171         ]
172       },
173       include: [
174         {
175           model: ActorModel,
176           required: true,
177           where: {
178             preferredUsername: name
179           }
180         }
181       ]
182     }
183
184     return AccountModel.findOne(query)
185   }
186
187   static loadByNameAndHost (name: string, host: string) {
188     const query = {
189       include: [
190         {
191           model: ActorModel,
192           required: true,
193           where: {
194             preferredUsername: name
195           },
196           include: [
197             {
198               model: ServerModel,
199               required: true,
200               where: {
201                 host
202               }
203             }
204           ]
205         }
206       ]
207     }
208
209     return AccountModel.findOne(query)
210   }
211
212   static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
213     const query = {
214       include: [
215         {
216           model: ActorModel,
217           required: true,
218           where: {
219             url
220           }
221         }
222       ],
223       transaction
224     }
225
226     return AccountModel.findOne(query)
227   }
228
229   static listForApi (start: number, count: number, sort: string) {
230     const query = {
231       offset: start,
232       limit: count,
233       order: getSort(sort)
234     }
235
236     return AccountModel.findAndCountAll(query)
237       .then(({ rows, count }) => {
238         return {
239           data: rows,
240           total: count
241         }
242       })
243   }
244
245   toFormattedJSON (): Account {
246     const actor = this.Actor.toFormattedJSON()
247     const account = {
248       id: this.id,
249       displayName: this.getDisplayName(),
250       description: this.description,
251       createdAt: this.createdAt,
252       updatedAt: this.updatedAt
253     }
254
255     return Object.assign(actor, account)
256   }
257
258   toActivityPubObject () {
259     const obj = this.Actor.toActivityPubObject(this.name, 'Account')
260
261     return Object.assign(obj, {
262       summary: this.description
263     })
264   }
265
266   isOwned () {
267     return this.Actor.isOwned()
268   }
269
270   getDisplayName () {
271     return this.name
272   }
273 }