aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2017-12-14 11:18:49 +0100
committerChocobozzz <me@florianbigard.com>2017-12-19 10:51:09 +0100
commitfadf619ad61a016c1c7fc53de5a8f398a4f77519 (patch)
treebd449b9fe2353d812f4cf57f6dd03c2221b25607 /server/models
parent7efe153b0bc23e596d5019b9fb3e3e32b6cfeccd (diff)
downloadPeerTube-fadf619ad61a016c1c7fc53de5a8f398a4f77519.tar.gz
PeerTube-fadf619ad61a016c1c7fc53de5a8f398a4f77519.tar.zst
PeerTube-fadf619ad61a016c1c7fc53de5a8f398a4f77519.zip
Save
Diffstat (limited to 'server/models')
-rw-r--r--server/models/account/account.ts234
-rw-r--r--server/models/activitypub/actor.ts245
-rw-r--r--server/models/video/video-channel.ts60
3 files changed, 303 insertions, 236 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}
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
new file mode 100644
index 000000000..4cae6a6ec
--- /dev/null
+++ b/server/models/activitypub/actor.ts
@@ -0,0 +1,245 @@
1import { join } from 'path'
2import * as Sequelize from 'sequelize'
3import {
4 AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, HasMany, Is, IsUUID, Model, Table,
5 UpdatedAt
6} from 'sequelize-typescript'
7import { Avatar } from '../../../shared/models/avatars/avatar.model'
8import { activityPubContextify } from '../../helpers'
9import {
10 isActivityPubUrlValid,
11 isActorFollowersCountValid,
12 isActorFollowingCountValid, isActorPreferredUsernameValid,
13 isActorPrivateKeyValid,
14 isActorPublicKeyValid
15} from '../../helpers/custom-validators/activitypub'
16import { isUserUsernameValid } from '../../helpers/custom-validators/users'
17import { AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
18import { AccountFollowModel } from '../account/account-follow'
19import { AvatarModel } from '../avatar/avatar'
20import { ServerModel } from '../server/server'
21import { throwIfNotValid } from '../utils'
22
23@Table({
24 tableName: 'actor'
25})
26export class ActorModel extends Model<ActorModel> {
27
28 @AllowNull(false)
29 @Default(DataType.UUIDV4)
30 @IsUUID(4)
31 @Column(DataType.UUID)
32 uuid: string
33
34 @AllowNull(false)
35 @Is('ActorName', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor name'))
36 @Column
37 name: string
38
39 @AllowNull(false)
40 @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
41 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
42 url: string
43
44 @AllowNull(true)
45 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key'))
46 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max))
47 publicKey: string
48
49 @AllowNull(true)
50 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key'))
51 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max))
52 privateKey: string
53
54 @AllowNull(false)
55 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowersCountValid, 'followers count'))
56 @Column
57 followersCount: number
58
59 @AllowNull(false)
60 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowingCountValid, 'following count'))
61 @Column
62 followingCount: number
63
64 @AllowNull(false)
65 @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url'))
66 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
67 inboxUrl: string
68
69 @AllowNull(false)
70 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
71 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
72 outboxUrl: string
73
74 @AllowNull(false)
75 @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url'))
76 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
77 sharedInboxUrl: string
78
79 @AllowNull(false)
80 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
81 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
82 followersUrl: string
83
84 @AllowNull(false)
85 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
86 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
87 followingUrl: string
88
89 @CreatedAt
90 createdAt: Date
91
92 @UpdatedAt
93 updatedAt: Date
94
95 @ForeignKey(() => AvatarModel)
96 @Column
97 avatarId: number
98
99 @BelongsTo(() => AvatarModel, {
100 foreignKey: {
101 allowNull: true
102 },
103 onDelete: 'cascade'
104 })
105 Avatar: AvatarModel
106
107 @HasMany(() => AccountFollowModel, {
108 foreignKey: {
109 name: 'accountId',
110 allowNull: false
111 },
112 onDelete: 'cascade'
113 })
114 AccountFollowing: AccountFollowModel[]
115
116 @HasMany(() => AccountFollowModel, {
117 foreignKey: {
118 name: 'targetAccountId',
119 allowNull: false
120 },
121 as: 'followers',
122 onDelete: 'cascade'
123 })
124 AccountFollowers: AccountFollowModel[]
125
126 @ForeignKey(() => ServerModel)
127 @Column
128 serverId: number
129
130 @BelongsTo(() => ServerModel, {
131 foreignKey: {
132 allowNull: true
133 },
134 onDelete: 'cascade'
135 })
136 Server: ServerModel
137
138 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
139 const query = {
140 where: {
141 followersUrl: {
142 [ Sequelize.Op.in ]: followersUrls
143 }
144 },
145 transaction
146 }
147
148 return ActorModel.findAll(query)
149 }
150
151 toFormattedJSON () {
152 let avatar: Avatar = null
153 if (this.Avatar) {
154 avatar = {
155 path: join(AVATARS_DIR.ACCOUNT, this.Avatar.filename),
156 createdAt: this.Avatar.createdAt,
157 updatedAt: this.Avatar.updatedAt
158 }
159 }
160
161 let host = CONFIG.WEBSERVER.HOST
162 let score: number
163 if (this.Server) {
164 host = this.Server.host
165 score = this.Server.score
166 }
167
168 return {
169 id: this.id,
170 host,
171 score,
172 followingCount: this.followingCount,
173 followersCount: this.followersCount,
174 avatar
175 }
176 }
177
178 toActivityPubObject (name: string, uuid: string, type: 'Account' | 'VideoChannel') {
179 let activityPubType
180 if (type === 'Account') {
181 activityPubType = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person'
182 } else { // VideoChannel
183 activityPubType = 'Group'
184 }
185
186 const json = {
187 type,
188 id: this.url,
189 following: this.getFollowingUrl(),
190 followers: this.getFollowersUrl(),
191 inbox: this.inboxUrl,
192 outbox: this.outboxUrl,
193 preferredUsername: name,
194 url: this.url,
195 name,
196 endpoints: {
197 sharedInbox: this.sharedInboxUrl
198 },
199 uuid,
200 publicKey: {
201 id: this.getPublicKeyUrl(),
202 owner: this.url,
203 publicKeyPem: this.publicKey
204 }
205 }
206
207 return activityPubContextify(json)
208 }
209
210 getFollowerSharedInboxUrls (t: Sequelize.Transaction) {
211 const query = {
212 attributes: [ 'sharedInboxUrl' ],
213 include: [
214 {
215 model: AccountFollowModel,
216 required: true,
217 as: 'followers',
218 where: {
219 targetAccountId: this.id
220 }
221 }
222 ],
223 transaction: t
224 }
225
226 return ActorModel.findAll(query)
227 .then(accounts => accounts.map(a => a.sharedInboxUrl))
228 }
229
230 getFollowingUrl () {
231 return this.url + '/following'
232 }
233
234 getFollowersUrl () {
235 return this.url + '/followers'
236 }
237
238 getPublicKeyUrl () {
239 return this.url + '#main-key'
240 }
241
242 isOwned () {
243 return this.serverId === null
244 }
245}
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index 068c8029d..fe44d3d53 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -11,18 +11,16 @@ import {
11 HasMany, 11 HasMany,
12 Is, 12 Is,
13 IsUUID, 13 IsUUID,
14 Model, Scopes, 14 Model,
15 Scopes,
15 Table, 16 Table,
16 UpdatedAt 17 UpdatedAt
17} from 'sequelize-typescript' 18} from 'sequelize-typescript'
18import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions' 19import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions'
19import { activityPubCollection } from '../../helpers'
20import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub'
21import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' 20import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
22import { CONSTRAINTS_FIELDS } from '../../initializers'
23import { getAnnounceActivityPubUrl } from '../../lib/activitypub'
24import { sendDeleteVideoChannel } from '../../lib/activitypub/send' 21import { sendDeleteVideoChannel } from '../../lib/activitypub/send'
25import { AccountModel } from '../account/account' 22import { AccountModel } from '../account/account'
23import { ActorModel } from '../activitypub/actor'
26import { ServerModel } from '../server/server' 24import { ServerModel } from '../server/server'
27import { getSort, throwIfNotValid } from '../utils' 25import { getSort, throwIfNotValid } from '../utils'
28import { VideoModel } from './video' 26import { VideoModel } from './video'
@@ -78,17 +76,24 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
78 @Column 76 @Column
79 remote: boolean 77 remote: boolean
80 78
81 @AllowNull(false)
82 @Is('VideoChannelUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
83 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.URL.max))
84 url: string
85
86 @CreatedAt 79 @CreatedAt
87 createdAt: Date 80 createdAt: Date
88 81
89 @UpdatedAt 82 @UpdatedAt
90 updatedAt: Date 83 updatedAt: Date
91 84
85 @ForeignKey(() => ActorModel)
86 @Column
87 actorId: number
88
89 @BelongsTo(() => ActorModel, {
90 foreignKey: {
91 allowNull: false
92 },
93 onDelete: 'cascade'
94 })
95 Actor: ActorModel
96
92 @ForeignKey(() => AccountModel) 97 @ForeignKey(() => AccountModel)
93 @Column 98 @Column
94 accountId: number 99 accountId: number
@@ -174,9 +179,15 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
174 179
175 static loadByUrl (url: string, t?: Sequelize.Transaction) { 180 static loadByUrl (url: string, t?: Sequelize.Transaction) {
176 const query: IFindOptions<VideoChannelModel> = { 181 const query: IFindOptions<VideoChannelModel> = {
177 where: { 182 include: [
178 url 183 {
179 } 184 model: ActorModel,
185 required: true,
186 where: {
187 url
188 }
189 }
190 ]
180 } 191 }
181 192
182 if (t !== undefined) query.transaction = t 193 if (t !== undefined) query.transaction = t
@@ -264,27 +275,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
264 } 275 }
265 276
266 toActivityPubObject () { 277 toActivityPubObject () {
267 let sharesObject 278 return this.Actor.toActivityPubObject(this.name, this.uuid, 'VideoChannel')
268 if (Array.isArray(this.VideoChannelShares)) {
269 const shares: string[] = []
270
271 for (const videoChannelShare of this.VideoChannelShares) {
272 const shareUrl = getAnnounceActivityPubUrl(this.url, videoChannelShare.Account)
273 shares.push(shareUrl)
274 }
275
276 sharesObject = activityPubCollection(shares)
277 }
278
279 return {
280 type: 'VideoChannel' as 'VideoChannel',
281 id: this.url,
282 uuid: this.uuid,
283 content: this.description,
284 name: this.name,
285 published: this.createdAt.toISOString(),
286 updated: this.updatedAt.toISOString(),
287 shares: sharesObject
288 }
289 } 279 }
290} 280}