diff options
-rw-r--r-- | server/controllers/api/users.ts | 24 | ||||
-rw-r--r-- | server/helpers/database-utils.ts | 12 | ||||
-rw-r--r-- | server/helpers/webfinger.ts | 5 | ||||
-rw-r--r-- | server/initializers/constants.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/actor.ts | 80 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 45 | ||||
-rw-r--r-- | server/models/activitypub/actor.ts | 13 |
7 files changed, 122 insertions, 61 deletions
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index ef2b63f51..d8ecbdbe2 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts | |||
@@ -8,6 +8,7 @@ import { retryTransactionWrapper } from '../../helpers/database-utils' | |||
8 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
9 | import { createReqFiles, getFormattedObjects } from '../../helpers/utils' | 9 | import { createReqFiles, getFormattedObjects } from '../../helpers/utils' |
10 | import { AVATAR_MIMETYPE_EXT, AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../../initializers' | 10 | import { AVATAR_MIMETYPE_EXT, AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../../initializers' |
11 | import { updateActorAvatarInstance } from '../../lib/activitypub' | ||
11 | import { sendUpdateUser } from '../../lib/activitypub/send' | 12 | import { sendUpdateUser } from '../../lib/activitypub/send' |
12 | import { createUserAccountAndChannel } from '../../lib/user' | 13 | import { createUserAccountAndChannel } from '../../lib/user' |
13 | import { | 14 | import { |
@@ -18,7 +19,6 @@ import { | |||
18 | import { usersUpdateMyAvatarValidator, videosSortValidator } from '../../middlewares/validators' | 19 | import { usersUpdateMyAvatarValidator, videosSortValidator } from '../../middlewares/validators' |
19 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | 20 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
20 | import { UserModel } from '../../models/account/user' | 21 | import { UserModel } from '../../models/account/user' |
21 | import { AvatarModel } from '../../models/avatar/avatar' | ||
22 | import { VideoModel } from '../../models/video/video' | 22 | import { VideoModel } from '../../models/video/video' |
23 | 23 | ||
24 | const reqAvatarFile = createReqFiles('avatarfile', CONFIG.STORAGE.AVATARS_DIR, AVATAR_MIMETYPE_EXT) | 24 | const reqAvatarFile = createReqFiles('avatarfile', CONFIG.STORAGE.AVATARS_DIR, AVATAR_MIMETYPE_EXT) |
@@ -248,26 +248,12 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next | |||
248 | 248 | ||
249 | await unlinkPromise(source) | 249 | await unlinkPromise(source) |
250 | 250 | ||
251 | const { avatar } = await sequelizeTypescript.transaction(async t => { | 251 | const avatar = await sequelizeTypescript.transaction(async t => { |
252 | const avatar = await AvatarModel.create({ | 252 | await updateActorAvatarInstance(actor, avatarName, t) |
253 | filename: avatarName | ||
254 | }, { transaction: t }) | ||
255 | 253 | ||
256 | if (actor.Avatar) { | 254 | await sendUpdateUser(user, t) |
257 | try { | ||
258 | await actor.Avatar.destroy({ transaction: t }) | ||
259 | } catch (err) { | ||
260 | logger.error('Cannot remove old avatar of user %s.', user.username, err) | ||
261 | } | ||
262 | } | ||
263 | 255 | ||
264 | actor.set('avatarId', avatar.id) | 256 | return avatar |
265 | actor.Avatar = avatar | ||
266 | await actor.save({ transaction: t }) | ||
267 | |||
268 | await sendUpdateUser(user, undefined) | ||
269 | |||
270 | return { actor, avatar } | ||
271 | }) | 257 | }) |
272 | 258 | ||
273 | return res | 259 | return res |
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index fb8ad22b0..78ca768b9 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as retry from 'async/retry' | 1 | import * as retry from 'async/retry' |
2 | import * as Bluebird from 'bluebird' | 2 | import * as Bluebird from 'bluebird' |
3 | import { Model } from 'sequelize-typescript' | ||
3 | import { logger } from './logger' | 4 | import { logger } from './logger' |
4 | 5 | ||
5 | type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] } | 6 | type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] } |
@@ -34,9 +35,18 @@ function transactionRetryer <T> (func: (err: any, data: T) => any) { | |||
34 | }) | 35 | }) |
35 | } | 36 | } |
36 | 37 | ||
38 | function updateInstanceWithAnother <T> (instanceToUpdate: Model<T>, baseInstance: Model<T>) { | ||
39 | const obj = baseInstance.toJSON() | ||
40 | |||
41 | for (const key of Object.keys(obj)) { | ||
42 | instanceToUpdate.set(key, obj[key]) | ||
43 | } | ||
44 | } | ||
45 | |||
37 | // --------------------------------------------------------------------------- | 46 | // --------------------------------------------------------------------------- |
38 | 47 | ||
39 | export { | 48 | export { |
40 | retryTransactionWrapper, | 49 | retryTransactionWrapper, |
41 | transactionRetryer | 50 | transactionRetryer, |
51 | updateInstanceWithAnother | ||
42 | } | 52 | } |
diff --git a/server/helpers/webfinger.ts b/server/helpers/webfinger.ts index de8d52c9b..688bf2bab 100644 --- a/server/helpers/webfinger.ts +++ b/server/helpers/webfinger.ts | |||
@@ -15,6 +15,10 @@ async function loadActorUrlOrGetFromWebfinger (name: string, host: string) { | |||
15 | const actor = await ActorModel.loadByNameAndHost(name, host) | 15 | const actor = await ActorModel.loadByNameAndHost(name, host) |
16 | if (actor) return actor.url | 16 | if (actor) return actor.url |
17 | 17 | ||
18 | return getUrlFromWebfinger(name, host) | ||
19 | } | ||
20 | |||
21 | async function getUrlFromWebfinger (name: string, host: string) { | ||
18 | const webfingerData: WebFingerData = await webfingerLookup(name + '@' + host) | 22 | const webfingerData: WebFingerData = await webfingerLookup(name + '@' + host) |
19 | return getLinkOrThrow(webfingerData) | 23 | return getLinkOrThrow(webfingerData) |
20 | } | 24 | } |
@@ -22,6 +26,7 @@ async function loadActorUrlOrGetFromWebfinger (name: string, host: string) { | |||
22 | // --------------------------------------------------------------------------- | 26 | // --------------------------------------------------------------------------- |
23 | 27 | ||
24 | export { | 28 | export { |
29 | getUrlFromWebfinger, | ||
25 | loadActorUrlOrGetFromWebfinger | 30 | loadActorUrlOrGetFromWebfinger |
26 | } | 31 | } |
27 | 32 | ||
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index d2bcea443..1f18b4401 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -278,7 +278,8 @@ const ACTIVITY_PUB = { | |||
278 | VIDEO: [ 'video/mp4', 'video/webm', 'video/ogg' ], // TODO: Merge with VIDEO_MIMETYPE_EXT | 278 | VIDEO: [ 'video/mp4', 'video/webm', 'video/ogg' ], // TODO: Merge with VIDEO_MIMETYPE_EXT |
279 | TORRENT: [ 'application/x-bittorrent' ], | 279 | TORRENT: [ 'application/x-bittorrent' ], |
280 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] | 280 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] |
281 | } | 281 | }, |
282 | ACTOR_REFRESH_INTERVAL: 3600 * 24 // 1 day | ||
282 | } | 283 | } |
283 | 284 | ||
284 | const ACTIVITY_PUB_ACTOR_TYPES: { [ id: string ]: ActivityPubActorType } = { | 285 | const ACTIVITY_PUB_ACTOR_TYPES: { [ id: string ]: ActivityPubActorType } = { |
@@ -350,6 +351,7 @@ if (isTestInstance() === true) { | |||
350 | REMOTE_SCHEME.WS = 'ws' | 351 | REMOTE_SCHEME.WS = 'ws' |
351 | STATIC_MAX_AGE = '0' | 352 | STATIC_MAX_AGE = '0' |
352 | ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 | 353 | ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 |
354 | ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL = 60 // 1 minute | ||
353 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB | 355 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB |
354 | } | 356 | } |
355 | 357 | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index b6ba2cc22..0882ab843 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -7,10 +7,11 @@ import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/a | |||
7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
10 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
11 | import { logger } from '../../helpers/logger' | 11 | import { logger } from '../../helpers/logger' |
12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
14 | import { getUrlFromWebfinger } from '../../helpers/webfinger' | ||
14 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' | 15 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' |
15 | import { AccountModel } from '../../models/account/account' | 16 | import { AccountModel } from '../../models/account/account' |
16 | import { ActorModel } from '../../models/activitypub/actor' | 17 | import { ActorModel } from '../../models/activitypub/actor' |
@@ -63,7 +64,7 @@ async function getOrCreateActorAndServerAndModel (actorUrl: string, recurseIfNee | |||
63 | actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) | 64 | actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) |
64 | } | 65 | } |
65 | 66 | ||
66 | return actor | 67 | return refreshActorIfNeeded(actor) |
67 | } | 68 | } |
68 | 69 | ||
69 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { | 70 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { |
@@ -84,6 +85,45 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU | |||
84 | }) | 85 | }) |
85 | } | 86 | } |
86 | 87 | ||
88 | async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) { | ||
89 | const followersCount = await fetchActorTotalItems(attributes.followers) | ||
90 | const followingCount = await fetchActorTotalItems(attributes.following) | ||
91 | |||
92 | actorInstance.set('type', attributes.type) | ||
93 | actorInstance.set('uuid', attributes.uuid) | ||
94 | actorInstance.set('preferredUsername', attributes.preferredUsername) | ||
95 | actorInstance.set('url', attributes.id) | ||
96 | actorInstance.set('publicKey', attributes.publicKey.publicKeyPem) | ||
97 | actorInstance.set('followersCount', followersCount) | ||
98 | actorInstance.set('followingCount', followingCount) | ||
99 | actorInstance.set('inboxUrl', attributes.inbox) | ||
100 | actorInstance.set('outboxUrl', attributes.outbox) | ||
101 | actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox) | ||
102 | actorInstance.set('followersUrl', attributes.followers) | ||
103 | actorInstance.set('followingUrl', attributes.following) | ||
104 | } | ||
105 | |||
106 | async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { | ||
107 | if (avatarName !== undefined) { | ||
108 | if (actorInstance.avatarId) { | ||
109 | try { | ||
110 | await actorInstance.Avatar.destroy({ transaction: t }) | ||
111 | } catch (err) { | ||
112 | logger.error('Cannot remove old avatar of actor %s.', actorInstance.url, err) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | const avatar = await AvatarModel.create({ | ||
117 | filename: avatarName | ||
118 | }, { transaction: t }) | ||
119 | |||
120 | actorInstance.set('avatarId', avatar.id) | ||
121 | actorInstance.Avatar = avatar | ||
122 | } | ||
123 | |||
124 | return actorInstance | ||
125 | } | ||
126 | |||
87 | async function fetchActorTotalItems (url: string) { | 127 | async function fetchActorTotalItems (url: string) { |
88 | const options = { | 128 | const options = { |
89 | uri: url, | 129 | uri: url, |
@@ -129,7 +169,9 @@ export { | |||
129 | buildActorInstance, | 169 | buildActorInstance, |
130 | setAsyncActorKeys, | 170 | setAsyncActorKeys, |
131 | fetchActorTotalItems, | 171 | fetchActorTotalItems, |
132 | fetchAvatarIfExists | 172 | fetchAvatarIfExists, |
173 | updateActorInstance, | ||
174 | updateActorAvatarInstance | ||
133 | } | 175 | } |
134 | 176 | ||
135 | // --------------------------------------------------------------------------- | 177 | // --------------------------------------------------------------------------- |
@@ -263,3 +305,35 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu | |||
263 | 305 | ||
264 | return videoChannel.save({ transaction: t }) | 306 | return videoChannel.save({ transaction: t }) |
265 | } | 307 | } |
308 | |||
309 | async function refreshActorIfNeeded (actor: ActorModel) { | ||
310 | if (!actor.isOutdated()) return actor | ||
311 | |||
312 | const actorUrl = await getUrlFromWebfinger(actor.preferredUsername, actor.getHost()) | ||
313 | const result = await fetchRemoteActor(actorUrl) | ||
314 | if (result === undefined) throw new Error('Cannot fetch remote actor in refresh actor.') | ||
315 | |||
316 | return sequelizeTypescript.transaction(async t => { | ||
317 | updateInstanceWithAnother(actor, result.actor) | ||
318 | |||
319 | if (result.avatarName !== undefined) { | ||
320 | await updateActorAvatarInstance(actor, result.avatarName, t) | ||
321 | } | ||
322 | |||
323 | await actor.save({ transaction: t }) | ||
324 | |||
325 | if (actor.Account) { | ||
326 | await actor.save({ transaction: t }) | ||
327 | |||
328 | actor.Account.set('name', result.name) | ||
329 | await actor.Account.save({ transaction: t }) | ||
330 | } else if (actor.VideoChannel) { | ||
331 | await actor.save({ transaction: t }) | ||
332 | |||
333 | actor.VideoChannel.set('name', result.name) | ||
334 | await actor.VideoChannel.save({ transaction: t }) | ||
335 | } | ||
336 | |||
337 | return actor | ||
338 | }) | ||
339 | } | ||
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 05ea7d272..2c094f7ca 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -8,11 +8,10 @@ import { resetSequelizeInstance } from '../../../helpers/utils' | |||
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import { AccountModel } from '../../../models/account/account' | 9 | import { AccountModel } from '../../../models/account/account' |
10 | import { ActorModel } from '../../../models/activitypub/actor' | 10 | import { ActorModel } from '../../../models/activitypub/actor' |
11 | import { AvatarModel } from '../../../models/avatar/avatar' | ||
12 | import { TagModel } from '../../../models/video/tag' | 11 | import { TagModel } from '../../../models/video/tag' |
13 | import { VideoModel } from '../../../models/video/video' | 12 | import { VideoModel } from '../../../models/video/video' |
14 | import { VideoFileModel } from '../../../models/video/video-file' | 13 | import { VideoFileModel } from '../../../models/video/video-file' |
15 | import { fetchActorTotalItems, fetchAvatarIfExists, getOrCreateActorAndServerAndModel } from '../actor' | 14 | import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor' |
16 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' | 15 | import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' |
17 | 16 | ||
18 | async function processUpdateActivity (activity: ActivityUpdate) { | 17 | async function processUpdateActivity (activity: ActivityUpdate) { |
@@ -124,7 +123,6 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) | |||
124 | const accountAttributesToUpdate = activity.object as ActivityPubActor | 123 | const accountAttributesToUpdate = activity.object as ActivityPubActor |
125 | 124 | ||
126 | logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid) | 125 | logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid) |
127 | let actorInstance: ActorModel | ||
128 | let accountInstance: AccountModel | 126 | let accountInstance: AccountModel |
129 | let actorFieldsSave: object | 127 | let actorFieldsSave: object |
130 | let accountFieldsSave: object | 128 | let accountFieldsSave: object |
@@ -134,39 +132,14 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) | |||
134 | 132 | ||
135 | try { | 133 | try { |
136 | await sequelizeTypescript.transaction(async t => { | 134 | await sequelizeTypescript.transaction(async t => { |
137 | actorInstance = await ActorModel.loadByUrl(accountAttributesToUpdate.id, t) | 135 | actorFieldsSave = actor.toJSON() |
138 | if (!actorInstance) throw new Error('Actor ' + accountAttributesToUpdate.id + ' not found.') | 136 | accountInstance = actor.Account |
139 | 137 | accountFieldsSave = actor.Account.toJSON() | |
140 | actorFieldsSave = actorInstance.toJSON() | ||
141 | accountInstance = actorInstance.Account | ||
142 | accountFieldsSave = actorInstance.Account.toJSON() | ||
143 | |||
144 | const followersCount = await fetchActorTotalItems(accountAttributesToUpdate.followers) | ||
145 | const followingCount = await fetchActorTotalItems(accountAttributesToUpdate.following) | ||
146 | |||
147 | actorInstance.set('type', accountAttributesToUpdate.type) | ||
148 | actorInstance.set('uuid', accountAttributesToUpdate.uuid) | ||
149 | actorInstance.set('preferredUsername', accountAttributesToUpdate.preferredUsername) | ||
150 | actorInstance.set('url', accountAttributesToUpdate.id) | ||
151 | actorInstance.set('publicKey', accountAttributesToUpdate.publicKey.publicKeyPem) | ||
152 | actorInstance.set('followersCount', followersCount) | ||
153 | actorInstance.set('followingCount', followingCount) | ||
154 | actorInstance.set('inboxUrl', accountAttributesToUpdate.inbox) | ||
155 | actorInstance.set('outboxUrl', accountAttributesToUpdate.outbox) | ||
156 | actorInstance.set('sharedInboxUrl', accountAttributesToUpdate.endpoints.sharedInbox) | ||
157 | actorInstance.set('followersUrl', accountAttributesToUpdate.followers) | ||
158 | actorInstance.set('followingUrl', accountAttributesToUpdate.following) | ||
159 | 138 | ||
160 | if (avatarName !== undefined) { | 139 | await updateActorInstance(actor, accountAttributesToUpdate) |
161 | if (actorInstance.avatarId) { | ||
162 | await actorInstance.Avatar.destroy({ transaction: t }) | ||
163 | } | ||
164 | |||
165 | const avatar = await AvatarModel.create({ | ||
166 | filename: avatarName | ||
167 | }, { transaction: t }) | ||
168 | 140 | ||
169 | actor.set('avatarId', avatar.id) | 141 | if (avatarName !== undefined) { |
142 | await updateActorAvatarInstance(actor, avatarName, t) | ||
170 | } | 143 | } |
171 | 144 | ||
172 | await actor.save({ transaction: t }) | 145 | await actor.save({ transaction: t }) |
@@ -177,8 +150,8 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) | |||
177 | 150 | ||
178 | logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid) | 151 | logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid) |
179 | } catch (err) { | 152 | } catch (err) { |
180 | if (actorInstance !== undefined && actorFieldsSave !== undefined) { | 153 | if (actor !== undefined && actorFieldsSave !== undefined) { |
181 | resetSequelizeInstance(actorInstance, actorFieldsSave) | 154 | resetSequelizeInstance(actor, actorFieldsSave) |
182 | } | 155 | } |
183 | 156 | ||
184 | if (accountInstance !== undefined && accountFieldsSave !== undefined) { | 157 | if (accountInstance !== undefined && accountFieldsSave !== undefined) { |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index ed7fcfe27..707f140af 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -13,7 +13,7 @@ import { | |||
13 | isActorPublicKeyValid | 13 | isActorPublicKeyValid |
14 | } from '../../helpers/custom-validators/activitypub/actor' | 14 | } from '../../helpers/custom-validators/activitypub/actor' |
15 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 15 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
16 | import { ACTIVITY_PUB_ACTOR_TYPES, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' | 16 | import { ACTIVITY_PUB, ACTIVITY_PUB_ACTOR_TYPES, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers' |
17 | import { AccountModel } from '../account/account' | 17 | import { AccountModel } from '../account/account' |
18 | import { AvatarModel } from '../avatar/avatar' | 18 | import { AvatarModel } from '../avatar/avatar' |
19 | import { ServerModel } from '../server/server' | 19 | import { ServerModel } from '../server/server' |
@@ -375,4 +375,15 @@ export class ActorModel extends Model<ActorModel> { | |||
375 | 375 | ||
376 | return CONFIG.WEBSERVER.URL + this.Avatar.getWebserverPath() | 376 | return CONFIG.WEBSERVER.URL + this.Avatar.getWebserverPath() |
377 | } | 377 | } |
378 | |||
379 | isOutdated () { | ||
380 | if (this.isOwned()) return false | ||
381 | |||
382 | const now = Date.now() | ||
383 | const createdAtTime = this.createdAt.getTime() | ||
384 | const updatedAtTime = this.updatedAt.getTime() | ||
385 | |||
386 | return (now - createdAtTime) > ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL && | ||
387 | (now - updatedAtTime) > ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL | ||
388 | } | ||
378 | } | 389 | } |