aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/account/account.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/account/account.ts')
-rw-r--r--server/models/account/account.ts234
1 files changed, 33 insertions, 201 deletions
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index d6758fa10..b26395fd4 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -1,4 +1,3 @@
1import { join } from 'path'
2import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
3import { 2import {
4 AfterDestroy, 3 AfterDestroy,
@@ -16,24 +15,13 @@ import {
16 Table, 15 Table,
17 UpdatedAt 16 UpdatedAt
18} from 'sequelize-typescript' 17} from 'sequelize-typescript'
19import { Avatar } from '../../../shared/models/avatars/avatar.model'
20import { activityPubContextify } from '../../helpers'
21import {
22 isAccountFollowersCountValid,
23 isAccountFollowingCountValid,
24 isAccountPrivateKeyValid,
25 isAccountPublicKeyValid,
26 isActivityPubUrlValid
27} from '../../helpers/custom-validators/activitypub'
28import { isUserUsernameValid } from '../../helpers/custom-validators/users' 18import { isUserUsernameValid } from '../../helpers/custom-validators/users'
29import { AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
30import { sendDeleteAccount } from '../../lib/activitypub/send' 19import { sendDeleteAccount } from '../../lib/activitypub/send'
20import { ActorModel } from '../activitypub/actor'
31import { ApplicationModel } from '../application/application' 21import { ApplicationModel } from '../application/application'
32import { AvatarModel } from '../avatar/avatar'
33import { ServerModel } from '../server/server' 22import { ServerModel } from '../server/server'
34import { throwIfNotValid } from '../utils' 23import { throwIfNotValid } from '../utils'
35import { VideoChannelModel } from '../video/video-channel' 24import { VideoChannelModel } from '../video/video-channel'
36import { AccountFollowModel } from './account-follow'
37import { UserModel } from './user' 25import { UserModel } from './user'
38 26
39@Table({ 27@Table({
@@ -59,68 +47,7 @@ import { UserModel } from './user'
59 } 47 }
60 ] 48 ]
61}) 49})
62export class AccountModel extends Model<Account> { 50export class AccountModel extends Model<AccountModel> {
63
64 @AllowNull(false)
65 @Default(DataType.UUIDV4)
66 @IsUUID(4)
67 @Column(DataType.UUID)
68 uuid: string
69
70 @AllowNull(false)
71 @Is('AccountName', value => throwIfNotValid(value, isUserUsernameValid, 'account name'))
72 @Column
73 name: string
74
75 @AllowNull(false)
76 @Is('AccountUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
77 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
78 url: string
79
80 @AllowNull(true)
81 @Is('AccountPublicKey', value => throwIfNotValid(value, isAccountPublicKeyValid, 'public key'))
82 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PUBLIC_KEY.max))
83 publicKey: string
84
85 @AllowNull(true)
86 @Is('AccountPublicKey', value => throwIfNotValid(value, isAccountPrivateKeyValid, 'private key'))
87 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PRIVATE_KEY.max))
88 privateKey: string
89
90 @AllowNull(false)
91 @Is('AccountFollowersCount', value => throwIfNotValid(value, isAccountFollowersCountValid, 'followers count'))
92 @Column
93 followersCount: number
94
95 @AllowNull(false)
96 @Is('AccountFollowersCount', value => throwIfNotValid(value, isAccountFollowingCountValid, 'following count'))
97 @Column
98 followingCount: number
99
100 @AllowNull(false)
101 @Is('AccountInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url'))
102 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
103 inboxUrl: string
104
105 @AllowNull(false)
106 @Is('AccountOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
107 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
108 outboxUrl: string
109
110 @AllowNull(false)
111 @Is('AccountSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url'))
112 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
113 sharedInboxUrl: string
114
115 @AllowNull(false)
116 @Is('AccountFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
117 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
118 followersUrl: string
119
120 @AllowNull(false)
121 @Is('AccountFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
122 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max))
123 followingUrl: string
124 51
125 @CreatedAt 52 @CreatedAt
126 createdAt: Date 53 createdAt: Date
@@ -128,29 +55,17 @@ export class AccountModel extends Model<Account> {
128 @UpdatedAt 55 @UpdatedAt
129 updatedAt: Date 56 updatedAt: Date
130 57
131 @ForeignKey(() => AvatarModel) 58 @ForeignKey(() => ActorModel)
132 @Column
133 avatarId: number
134
135 @BelongsTo(() => AvatarModel, {
136 foreignKey: {
137 allowNull: true
138 },
139 onDelete: 'cascade'
140 })
141 Avatar: AvatarModel
142
143 @ForeignKey(() => ServerModel)
144 @Column 59 @Column
145 serverId: number 60 actorId: number
146 61
147 @BelongsTo(() => ServerModel, { 62 @BelongsTo(() => ActorModel, {
148 foreignKey: { 63 foreignKey: {
149 allowNull: true 64 allowNull: false
150 }, 65 },
151 onDelete: 'cascade' 66 onDelete: 'cascade'
152 }) 67 })
153 Server: ServerModel 68 Actor: ActorModel
154 69
155 @ForeignKey(() => UserModel) 70 @ForeignKey(() => UserModel)
156 @Column 71 @Column
@@ -185,25 +100,6 @@ export class AccountModel extends Model<Account> {
185 }) 100 })
186 VideoChannels: VideoChannelModel[] 101 VideoChannels: VideoChannelModel[]
187 102
188 @HasMany(() => AccountFollowModel, {
189 foreignKey: {
190 name: 'accountId',
191 allowNull: false
192 },
193 onDelete: 'cascade'
194 })
195 AccountFollowing: AccountFollowModel[]
196
197 @HasMany(() => AccountFollowModel, {
198 foreignKey: {
199 name: 'targetAccountId',
200 allowNull: false
201 },
202 as: 'followers',
203 onDelete: 'cascade'
204 })
205 AccountFollowers: AccountFollowModel[]
206
207 @AfterDestroy 103 @AfterDestroy
208 static sendDeleteIfOwned (instance: AccountModel) { 104 static sendDeleteIfOwned (instance: AccountModel) {
209 if (instance.isOwned()) { 105 if (instance.isOwned()) {
@@ -281,9 +177,15 @@ export class AccountModel extends Model<Account> {
281 177
282 static loadByUrl (url: string, transaction?: Sequelize.Transaction) { 178 static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
283 const query = { 179 const query = {
284 where: { 180 include: [
285 url 181 {
286 }, 182 model: ActorModel,
183 required: true,
184 where: {
185 url
186 }
187 }
188 ],
287 transaction 189 transaction
288 } 190 }
289 191
@@ -292,11 +194,17 @@ export class AccountModel extends Model<Account> {
292 194
293 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) { 195 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
294 const query = { 196 const query = {
295 where: { 197 include: [
296 followersUrl: { 198 {
297 [ Sequelize.Op.in ]: followersUrls 199 model: ActorModel,
200 required: true,
201 where: {
202 followersUrl: {
203 [ Sequelize.Op.in ]: followersUrls
204 }
205 }
298 } 206 }
299 }, 207 ],
300 transaction 208 transaction
301 } 209 }
302 210
@@ -304,97 +212,21 @@ export class AccountModel extends Model<Account> {
304 } 212 }
305 213
306 toFormattedJSON () { 214 toFormattedJSON () {
307 let host = CONFIG.WEBSERVER.HOST 215 const actor = this.Actor.toFormattedJSON()
308 let score: number 216 const account = {
309 let avatar: Avatar = null
310
311 if (this.Avatar) {
312 avatar = {
313 path: join(AVATARS_DIR.ACCOUNT, this.Avatar.filename),
314 createdAt: this.Avatar.createdAt,
315 updatedAt: this.Avatar.updatedAt
316 }
317 }
318
319 if (this.Server) {
320 host = this.Server.host
321 score = this.Server.score
322 }
323
324 return {
325 id: this.id, 217 id: this.id,
326 uuid: this.uuid,
327 host,
328 score,
329 name: this.name,
330 followingCount: this.followingCount,
331 followersCount: this.followersCount,
332 createdAt: this.createdAt, 218 createdAt: this.createdAt,
333 updatedAt: this.updatedAt, 219 updatedAt: this.updatedAt
334 avatar
335 } 220 }
221
222 return Object.assign(actor, account)
336 } 223 }
337 224
338 toActivityPubObject () { 225 toActivityPubObject () {
339 const type = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person' 226 return this.Actor.toActivityPubObject(this.name, this.uuid, 'Account')
340
341 const json = {
342 type,
343 id: this.url,
344 following: this.getFollowingUrl(),
345 followers: this.getFollowersUrl(),
346 inbox: this.inboxUrl,
347 outbox: this.outboxUrl,
348 preferredUsername: this.name,
349 url: this.url,
350 name: this.name,
351 endpoints: {
352 sharedInbox: this.sharedInboxUrl
353 },
354 uuid: this.uuid,
355 publicKey: {
356 id: this.getPublicKeyUrl(),
357 owner: this.url,
358 publicKeyPem: this.publicKey
359 }
360 }
361
362 return activityPubContextify(json)
363 } 227 }
364 228
365 isOwned () { 229 isOwned () {
366 return this.serverId === null 230 return this.Actor.isOwned()
367 }
368
369 getFollowerSharedInboxUrls (t: Sequelize.Transaction) {
370 const query = {
371 attributes: [ 'sharedInboxUrl' ],
372 include: [
373 {
374 model: AccountFollowModel,
375 required: true,
376 as: 'followers',
377 where: {
378 targetAccountId: this.id
379 }
380 }
381 ],
382 transaction: t
383 }
384
385 return AccountModel.findAll(query)
386 .then(accounts => accounts.map(a => a.sharedInboxUrl))
387 }
388
389 getFollowingUrl () {
390 return this.url + '/following'
391 }
392
393 getFollowersUrl () {
394 return this.url + '/followers'
395 }
396
397 getPublicKeyUrl () {
398 return this.url + '#main-key'
399 } 231 }
400} 232}