1 import { join } from 'path'
2 import * as Sequelize from 'sequelize'
4 AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, HasMany, Is, IsUUID, Model, Table,
6 } from 'sequelize-typescript'
7 import { Avatar } from '../../../shared/models/avatars/avatar.model'
8 import { activityPubContextify } from '../../helpers'
10 isActivityPubUrlValid,
11 isActorFollowersCountValid,
12 isActorFollowingCountValid, isActorPreferredUsernameValid,
13 isActorPrivateKeyValid,
15 } from '../../helpers/custom-validators/activitypub'
16 import { isUserUsernameValid } from '../../helpers/custom-validators/users'
17 import { AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
18 import { AccountFollowModel } from '../account/account-follow'
19 import { AvatarModel } from '../avatar/avatar'
20 import { ServerModel } from '../server/server'
21 import { throwIfNotValid } from '../utils'
26 export class ActorModel extends Model<ActorModel> {
29 @Default(DataType.UUIDV4)
31 @Column(DataType.UUID)
35 @Is('ActorName', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor name'))
40 @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
41 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
45 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key'))
46 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max))
50 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key'))
51 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max))
55 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowersCountValid, 'followers count'))
57 followersCount: number
60 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowingCountValid, 'following count'))
62 followingCount: number
65 @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url'))
66 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
70 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
71 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
75 @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url'))
76 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
77 sharedInboxUrl: string
80 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
81 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
85 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
86 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
95 @ForeignKey(() => AvatarModel)
99 @BelongsTo(() => AvatarModel, {
107 @HasMany(() => AccountFollowModel, {
114 AccountFollowing: AccountFollowModel[]
116 @HasMany(() => AccountFollowModel, {
118 name: 'targetAccountId',
124 AccountFollowers: AccountFollowModel[]
126 @ForeignKey(() => ServerModel)
130 @BelongsTo(() => ServerModel, {
138 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
142 [ Sequelize.Op.in ]: followersUrls
148 return ActorModel.findAll(query)
152 let avatar: Avatar = null
155 path: join(AVATARS_DIR.ACCOUNT, this.Avatar.filename),
156 createdAt: this.Avatar.createdAt,
157 updatedAt: this.Avatar.updatedAt
161 let host = CONFIG.WEBSERVER.HOST
164 host = this.Server.host
165 score = this.Server.score
172 followingCount: this.followingCount,
173 followersCount: this.followersCount,
178 toActivityPubObject (name: string, uuid: string, type: 'Account' | 'VideoChannel') {
180 if (type === 'Account') {
181 activityPubType = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person'
182 } else { // VideoChannel
183 activityPubType = 'Group'
189 following: this.getFollowingUrl(),
190 followers: this.getFollowersUrl(),
191 inbox: this.inboxUrl,
192 outbox: this.outboxUrl,
193 preferredUsername: name,
197 sharedInbox: this.sharedInboxUrl
201 id: this.getPublicKeyUrl(),
203 publicKeyPem: this.publicKey
207 return activityPubContextify(json)
210 getFollowerSharedInboxUrls (t: Sequelize.Transaction) {
212 attributes: [ 'sharedInboxUrl' ],
215 model: AccountFollowModel,
219 targetAccountId: this.id
226 return ActorModel.findAll(query)
227 .then(accounts => accounts.map(a => a.sharedInboxUrl))
231 return this.url + '/following'
235 return this.url + '/followers'
239 return this.url + '#main-key'
243 return this.serverId === null