aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/activitypub/actor.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/activitypub/actor.ts')
-rw-r--r--server/models/activitypub/actor.ts165
1 files changed, 142 insertions, 23 deletions
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index 4cae6a6ec..ecaa43dcf 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -1,38 +1,83 @@
1import { values } from 'lodash'
1import { join } from 'path' 2import { join } from 'path'
2import * as Sequelize from 'sequelize' 3import * as Sequelize from 'sequelize'
3import { 4import {
4 AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, HasMany, Is, IsUUID, Model, Table, 5 AllowNull,
6 BelongsTo,
7 Column,
8 CreatedAt,
9 DataType,
10 Default,
11 ForeignKey,
12 HasMany,
13 HasOne,
14 Is,
15 IsUUID,
16 Model,
17 Scopes,
18 Table,
5 UpdatedAt 19 UpdatedAt
6} from 'sequelize-typescript' 20} from 'sequelize-typescript'
21import { ActivityPubActorType } from '../../../shared/models/activitypub'
7import { Avatar } from '../../../shared/models/avatars/avatar.model' 22import { Avatar } from '../../../shared/models/avatars/avatar.model'
8import { activityPubContextify } from '../../helpers' 23import { activityPubContextify } from '../../helpers'
9import { 24import {
10 isActivityPubUrlValid, 25 isActivityPubUrlValid,
11 isActorFollowersCountValid, 26 isActorFollowersCountValid,
12 isActorFollowingCountValid, isActorPreferredUsernameValid, 27 isActorFollowingCountValid,
28 isActorNameValid,
13 isActorPrivateKeyValid, 29 isActorPrivateKeyValid,
14 isActorPublicKeyValid 30 isActorPublicKeyValid
15} from '../../helpers/custom-validators/activitypub' 31} from '../../helpers/custom-validators/activitypub'
16import { isUserUsernameValid } from '../../helpers/custom-validators/users' 32import { ACTIVITY_PUB_ACTOR_TYPES, AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
17import { AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' 33import { AccountModel } from '../account/account'
18import { AccountFollowModel } from '../account/account-follow'
19import { AvatarModel } from '../avatar/avatar' 34import { AvatarModel } from '../avatar/avatar'
20import { ServerModel } from '../server/server' 35import { ServerModel } from '../server/server'
21import { throwIfNotValid } from '../utils' 36import { throwIfNotValid } from '../utils'
37import { VideoChannelModel } from '../video/video-channel'
38import { ActorFollowModel } from './actor-follow'
22 39
40enum ScopeNames {
41 FULL = 'FULL'
42}
43
44@Scopes({
45 [ScopeNames.FULL]: {
46 include: [
47 {
48 model: () => AccountModel,
49 required: false
50 },
51 {
52 model: () => VideoChannelModel,
53 required: false
54 }
55 ]
56 }
57})
23@Table({ 58@Table({
24 tableName: 'actor' 59 tableName: 'actor',
60 indexes: [
61 {
62 fields: [ 'name', 'serverId' ],
63 unique: true
64 }
65 ]
25}) 66})
26export class ActorModel extends Model<ActorModel> { 67export class ActorModel extends Model<ActorModel> {
27 68
28 @AllowNull(false) 69 @AllowNull(false)
70 @Column(DataType.ENUM(values(ACTIVITY_PUB_ACTOR_TYPES)))
71 type: ActivityPubActorType
72
73 @AllowNull(false)
29 @Default(DataType.UUIDV4) 74 @Default(DataType.UUIDV4)
30 @IsUUID(4) 75 @IsUUID(4)
31 @Column(DataType.UUID) 76 @Column(DataType.UUID)
32 uuid: string 77 uuid: string
33 78
34 @AllowNull(false) 79 @AllowNull(false)
35 @Is('ActorName', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor name')) 80 @Is('ActorName', value => throwIfNotValid(value, isActorNameValid, 'actor name'))
36 @Column 81 @Column
37 name: string 82 name: string
38 83
@@ -104,24 +149,24 @@ export class ActorModel extends Model<ActorModel> {
104 }) 149 })
105 Avatar: AvatarModel 150 Avatar: AvatarModel
106 151
107 @HasMany(() => AccountFollowModel, { 152 @HasMany(() => ActorFollowModel, {
108 foreignKey: { 153 foreignKey: {
109 name: 'accountId', 154 name: 'actorId',
110 allowNull: false 155 allowNull: false
111 }, 156 },
112 onDelete: 'cascade' 157 onDelete: 'cascade'
113 }) 158 })
114 AccountFollowing: AccountFollowModel[] 159 AccountFollowing: ActorFollowModel[]
115 160
116 @HasMany(() => AccountFollowModel, { 161 @HasMany(() => ActorFollowModel, {
117 foreignKey: { 162 foreignKey: {
118 name: 'targetAccountId', 163 name: 'targetActorId',
119 allowNull: false 164 allowNull: false
120 }, 165 },
121 as: 'followers', 166 as: 'followers',
122 onDelete: 'cascade' 167 onDelete: 'cascade'
123 }) 168 })
124 AccountFollowers: AccountFollowModel[] 169 AccountFollowers: ActorFollowModel[]
125 170
126 @ForeignKey(() => ServerModel) 171 @ForeignKey(() => ServerModel)
127 @Column 172 @Column
@@ -135,6 +180,36 @@ export class ActorModel extends Model<ActorModel> {
135 }) 180 })
136 Server: ServerModel 181 Server: ServerModel
137 182
183 @HasOne(() => AccountModel, {
184 foreignKey: {
185 allowNull: true
186 },
187 onDelete: 'cascade'
188 })
189 Account: AccountModel
190
191 @HasOne(() => VideoChannelModel, {
192 foreignKey: {
193 allowNull: true
194 },
195 onDelete: 'cascade'
196 })
197 VideoChannel: VideoChannelModel
198
199 static load (id: number) {
200 return ActorModel.scope(ScopeNames.FULL).findById(id)
201 }
202
203 static loadByUUID (uuid: string) {
204 const query = {
205 where: {
206 uuid
207 }
208 }
209
210 return ActorModel.scope(ScopeNames.FULL).findOne(query)
211 }
212
138 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) { 213 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
139 const query = { 214 const query = {
140 where: { 215 where: {
@@ -145,7 +220,48 @@ export class ActorModel extends Model<ActorModel> {
145 transaction 220 transaction
146 } 221 }
147 222
148 return ActorModel.findAll(query) 223 return ActorModel.scope(ScopeNames.FULL).findAll(query)
224 }
225
226 static loadLocalByName (name: string) {
227 const query = {
228 where: {
229 name,
230 serverId: null
231 }
232 }
233
234 return ActorModel.scope(ScopeNames.FULL).findOne(query)
235 }
236
237 static loadByNameAndHost (name: string, host: string) {
238 const query = {
239 where: {
240 name
241 },
242 include: [
243 {
244 model: ServerModel,
245 required: true,
246 where: {
247 host
248 }
249 }
250 ]
251 }
252
253 return ActorModel.scope(ScopeNames.FULL).findOne(query)
254 }
255
256 static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
257 const query = {
258 where: {
259 url
260 },
261 transaction
262 }
263
264 return ActorModel.scope(ScopeNames.FULL).findOne(query)
149 } 265 }
150 266
151 toFormattedJSON () { 267 toFormattedJSON () {
@@ -167,6 +283,7 @@ export class ActorModel extends Model<ActorModel> {
167 283
168 return { 284 return {
169 id: this.id, 285 id: this.id,
286 uuid: this.uuid,
170 host, 287 host,
171 score, 288 score,
172 followingCount: this.followingCount, 289 followingCount: this.followingCount,
@@ -175,28 +292,30 @@ export class ActorModel extends Model<ActorModel> {
175 } 292 }
176 } 293 }
177 294
178 toActivityPubObject (name: string, uuid: string, type: 'Account' | 'VideoChannel') { 295 toActivityPubObject (preferredUsername: string, type: 'Account' | 'Application' | 'VideoChannel') {
179 let activityPubType 296 let activityPubType
180 if (type === 'Account') { 297 if (type === 'Account') {
181 activityPubType = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person' 298 activityPubType = 'Person' as 'Person'
299 } else if (type === 'Application') {
300 activityPubType = 'Application' as 'Application'
182 } else { // VideoChannel 301 } else { // VideoChannel
183 activityPubType = 'Group' 302 activityPubType = 'Group' as 'Group'
184 } 303 }
185 304
186 const json = { 305 const json = {
187 type, 306 type: activityPubType,
188 id: this.url, 307 id: this.url,
189 following: this.getFollowingUrl(), 308 following: this.getFollowingUrl(),
190 followers: this.getFollowersUrl(), 309 followers: this.getFollowersUrl(),
191 inbox: this.inboxUrl, 310 inbox: this.inboxUrl,
192 outbox: this.outboxUrl, 311 outbox: this.outboxUrl,
193 preferredUsername: name, 312 preferredUsername,
194 url: this.url, 313 url: this.url,
195 name, 314 name: this.name,
196 endpoints: { 315 endpoints: {
197 sharedInbox: this.sharedInboxUrl 316 sharedInbox: this.sharedInboxUrl
198 }, 317 },
199 uuid, 318 uuid: this.uuid,
200 publicKey: { 319 publicKey: {
201 id: this.getPublicKeyUrl(), 320 id: this.getPublicKeyUrl(),
202 owner: this.url, 321 owner: this.url,
@@ -212,11 +331,11 @@ export class ActorModel extends Model<ActorModel> {
212 attributes: [ 'sharedInboxUrl' ], 331 attributes: [ 'sharedInboxUrl' ],
213 include: [ 332 include: [
214 { 333 {
215 model: AccountFollowModel, 334 model: ActorFollowModel,
216 required: true, 335 required: true,
217 as: 'followers', 336 as: 'followers',
218 where: { 337 where: {
219 targetAccountId: this.id 338 targetActorId: this.id
220 } 339 }
221 } 340 }
222 ], 341 ],