diff options
author | Chocobozzz <me@florianbigard.com> | 2021-04-06 11:35:56 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2021-04-08 10:07:53 +0200 |
commit | f479685678406a5df864d89615b33d29085ebfc6 (patch) | |
tree | 8de15e90cd8d97d8810715df8585c61f48d5282a /server/models | |
parent | 968aaed2066873fc1c39f95168284122d9d15e21 (diff) | |
download | PeerTube-f479685678406a5df864d89615b33d29085ebfc6.tar.gz PeerTube-f479685678406a5df864d89615b33d29085ebfc6.tar.zst PeerTube-f479685678406a5df864d89615b33d29085ebfc6.zip |
Agnostic actor image storage
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/account/account.ts | 5 | ||||
-rw-r--r-- | server/models/account/actor-image.ts (renamed from server/models/avatar/avatar.ts) | 41 | ||||
-rw-r--r-- | server/models/account/user-notification.ts | 8 | ||||
-rw-r--r-- | server/models/activitypub/actor.ts | 35 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 5 | ||||
-rw-r--r-- | server/models/video/video-query-builder.ts | 5 | ||||
-rw-r--r-- | server/models/video/video.ts | 10 |
7 files changed, 70 insertions, 39 deletions
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index c72f9c63d..312451abe 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -33,7 +33,7 @@ import { | |||
33 | import { ActorModel } from '../activitypub/actor' | 33 | import { ActorModel } from '../activitypub/actor' |
34 | import { ActorFollowModel } from '../activitypub/actor-follow' | 34 | import { ActorFollowModel } from '../activitypub/actor-follow' |
35 | import { ApplicationModel } from '../application/application' | 35 | import { ApplicationModel } from '../application/application' |
36 | import { AvatarModel } from '../avatar/avatar' | 36 | import { ActorImageModel } from './actor-image' |
37 | import { ServerModel } from '../server/server' | 37 | import { ServerModel } from '../server/server' |
38 | import { ServerBlocklistModel } from '../server/server-blocklist' | 38 | import { ServerBlocklistModel } from '../server/server-blocklist' |
39 | import { getSort, throwIfNotValid } from '../utils' | 39 | import { getSort, throwIfNotValid } from '../utils' |
@@ -82,7 +82,8 @@ export type SummaryOptions = { | |||
82 | serverInclude, | 82 | serverInclude, |
83 | 83 | ||
84 | { | 84 | { |
85 | model: AvatarModel.unscoped(), | 85 | model: ActorImageModel.unscoped(), |
86 | as: 'Avatar', | ||
86 | required: false | 87 | required: false |
87 | } | 88 | } |
88 | ] | 89 | ] |
diff --git a/server/models/avatar/avatar.ts b/server/models/account/actor-image.ts index 0d246a144..c532bd08d 100644 --- a/server/models/avatar/avatar.ts +++ b/server/models/account/actor-image.ts | |||
@@ -1,16 +1,17 @@ | |||
1 | import { remove } from 'fs-extra' | ||
1 | import { join } from 'path' | 2 | import { join } from 'path' |
2 | import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 3 | import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { Avatar } from '../../../shared/models/avatars/avatar.model' | 4 | import { MActorImageFormattable } from '@server/types/models' |
4 | import { LAZY_STATIC_PATHS } from '../../initializers/constants' | 5 | import { ActorImageType } from '@shared/models' |
6 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' | ||
7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | ||
5 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
6 | import { remove } from 'fs-extra' | ||
7 | import { CONFIG } from '../../initializers/config' | 9 | import { CONFIG } from '../../initializers/config' |
10 | import { LAZY_STATIC_PATHS } from '../../initializers/constants' | ||
8 | import { throwIfNotValid } from '../utils' | 11 | import { throwIfNotValid } from '../utils' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | ||
10 | import { MAvatarFormattable } from '@server/types/models' | ||
11 | 12 | ||
12 | @Table({ | 13 | @Table({ |
13 | tableName: 'avatar', | 14 | tableName: 'actorImage', |
14 | indexes: [ | 15 | indexes: [ |
15 | { | 16 | { |
16 | fields: [ 'filename' ], | 17 | fields: [ 'filename' ], |
@@ -18,14 +19,14 @@ import { MAvatarFormattable } from '@server/types/models' | |||
18 | } | 19 | } |
19 | ] | 20 | ] |
20 | }) | 21 | }) |
21 | export class AvatarModel extends Model { | 22 | export class ActorImageModel extends Model { |
22 | 23 | ||
23 | @AllowNull(false) | 24 | @AllowNull(false) |
24 | @Column | 25 | @Column |
25 | filename: string | 26 | filename: string |
26 | 27 | ||
27 | @AllowNull(true) | 28 | @AllowNull(true) |
28 | @Is('AvatarFileUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'fileUrl', true)) | 29 | @Is('ActorImageFileUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'fileUrl', true)) |
29 | @Column | 30 | @Column |
30 | fileUrl: string | 31 | fileUrl: string |
31 | 32 | ||
@@ -33,6 +34,10 @@ export class AvatarModel extends Model { | |||
33 | @Column | 34 | @Column |
34 | onDisk: boolean | 35 | onDisk: boolean |
35 | 36 | ||
37 | @AllowNull(false) | ||
38 | @Column | ||
39 | type: ActorImageType | ||
40 | |||
36 | @CreatedAt | 41 | @CreatedAt |
37 | createdAt: Date | 42 | createdAt: Date |
38 | 43 | ||
@@ -40,12 +45,12 @@ export class AvatarModel extends Model { | |||
40 | updatedAt: Date | 45 | updatedAt: Date |
41 | 46 | ||
42 | @AfterDestroy | 47 | @AfterDestroy |
43 | static removeFilesAndSendDelete (instance: AvatarModel) { | 48 | static removeFilesAndSendDelete (instance: ActorImageModel) { |
44 | logger.info('Removing avatar file %s.', instance.filename) | 49 | logger.info('Removing actor image file %s.', instance.filename) |
45 | 50 | ||
46 | // Don't block the transaction | 51 | // Don't block the transaction |
47 | instance.removeAvatar() | 52 | instance.removeImage() |
48 | .catch(err => logger.error('Cannot remove avatar file %s.', instance.filename, err)) | 53 | .catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, err)) |
49 | } | 54 | } |
50 | 55 | ||
51 | static loadByName (filename: string) { | 56 | static loadByName (filename: string) { |
@@ -55,10 +60,10 @@ export class AvatarModel extends Model { | |||
55 | } | 60 | } |
56 | } | 61 | } |
57 | 62 | ||
58 | return AvatarModel.findOne(query) | 63 | return ActorImageModel.findOne(query) |
59 | } | 64 | } |
60 | 65 | ||
61 | toFormattedJSON (this: MAvatarFormattable): Avatar { | 66 | toFormattedJSON (this: MActorImageFormattable): ActorImage { |
62 | return { | 67 | return { |
63 | path: this.getStaticPath(), | 68 | path: this.getStaticPath(), |
64 | createdAt: this.createdAt, | 69 | createdAt: this.createdAt, |
@@ -71,11 +76,11 @@ export class AvatarModel extends Model { | |||
71 | } | 76 | } |
72 | 77 | ||
73 | getPath () { | 78 | getPath () { |
74 | return join(CONFIG.STORAGE.AVATARS_DIR, this.filename) | 79 | return join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename) |
75 | } | 80 | } |
76 | 81 | ||
77 | removeAvatar () { | 82 | removeImage () { |
78 | const avatarPath = join(CONFIG.STORAGE.AVATARS_DIR, this.filename) | 83 | const imagePath = join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename) |
79 | return remove(avatarPath) | 84 | return remove(imagePath) |
80 | } | 85 | } |
81 | } | 86 | } |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index 25c523203..805095002 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -10,7 +10,6 @@ import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' | |||
10 | import { ActorModel } from '../activitypub/actor' | 10 | import { ActorModel } from '../activitypub/actor' |
11 | import { ActorFollowModel } from '../activitypub/actor-follow' | 11 | import { ActorFollowModel } from '../activitypub/actor-follow' |
12 | import { ApplicationModel } from '../application/application' | 12 | import { ApplicationModel } from '../application/application' |
13 | import { AvatarModel } from '../avatar/avatar' | ||
14 | import { PluginModel } from '../server/plugin' | 13 | import { PluginModel } from '../server/plugin' |
15 | import { ServerModel } from '../server/server' | 14 | import { ServerModel } from '../server/server' |
16 | import { getSort, throwIfNotValid } from '../utils' | 15 | import { getSort, throwIfNotValid } from '../utils' |
@@ -20,6 +19,7 @@ import { VideoChannelModel } from '../video/video-channel' | |||
20 | import { VideoCommentModel } from '../video/video-comment' | 19 | import { VideoCommentModel } from '../video/video-comment' |
21 | import { VideoImportModel } from '../video/video-import' | 20 | import { VideoImportModel } from '../video/video-import' |
22 | import { AccountModel } from './account' | 21 | import { AccountModel } from './account' |
22 | import { ActorImageModel } from './actor-image' | ||
23 | import { UserModel } from './user' | 23 | import { UserModel } from './user' |
24 | 24 | ||
25 | enum ScopeNames { | 25 | enum ScopeNames { |
@@ -34,7 +34,8 @@ function buildActorWithAvatarInclude () { | |||
34 | include: [ | 34 | include: [ |
35 | { | 35 | { |
36 | attributes: [ 'filename' ], | 36 | attributes: [ 'filename' ], |
37 | model: AvatarModel.unscoped(), | 37 | as: 'Avatar', |
38 | model: ActorImageModel.unscoped(), | ||
38 | required: false | 39 | required: false |
39 | }, | 40 | }, |
40 | { | 41 | { |
@@ -172,7 +173,8 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
172 | }, | 173 | }, |
173 | { | 174 | { |
174 | attributes: [ 'filename' ], | 175 | attributes: [ 'filename' ], |
175 | model: AvatarModel.unscoped(), | 176 | as: 'Avatar', |
177 | model: ActorImageModel.unscoped(), | ||
176 | required: false | 178 | required: false |
177 | }, | 179 | }, |
178 | { | 180 | { |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 3b98e8841..09d96b24d 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -19,7 +19,7 @@ import { | |||
19 | } from 'sequelize-typescript' | 19 | } from 'sequelize-typescript' |
20 | import { ModelCache } from '@server/models/model-cache' | 20 | import { ModelCache } from '@server/models/model-cache' |
21 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' | 21 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' |
22 | import { Avatar } from '../../../shared/models/avatars/avatar.model' | 22 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' |
23 | import { activityPubContextify } from '../../helpers/activitypub' | 23 | import { activityPubContextify } from '../../helpers/activitypub' |
24 | import { | 24 | import { |
25 | isActorFollowersCountValid, | 25 | isActorFollowersCountValid, |
@@ -43,7 +43,7 @@ import { | |||
43 | MActorWithInboxes | 43 | MActorWithInboxes |
44 | } from '../../types/models' | 44 | } from '../../types/models' |
45 | import { AccountModel } from '../account/account' | 45 | import { AccountModel } from '../account/account' |
46 | import { AvatarModel } from '../avatar/avatar' | 46 | import { ActorImageModel } from '../account/actor-image' |
47 | import { ServerModel } from '../server/server' | 47 | import { ServerModel } from '../server/server' |
48 | import { isOutdated, throwIfNotValid } from '../utils' | 48 | import { isOutdated, throwIfNotValid } from '../utils' |
49 | import { VideoModel } from '../video/video' | 49 | import { VideoModel } from '../video/video' |
@@ -73,7 +73,8 @@ export const unusedActorAttributesForAPI = [ | |||
73 | required: false | 73 | required: false |
74 | }, | 74 | }, |
75 | { | 75 | { |
76 | model: AvatarModel, | 76 | model: ActorImageModel, |
77 | as: 'Avatar', | ||
77 | required: false | 78 | required: false |
78 | } | 79 | } |
79 | ] | 80 | ] |
@@ -100,7 +101,8 @@ export const unusedActorAttributesForAPI = [ | |||
100 | required: false | 101 | required: false |
101 | }, | 102 | }, |
102 | { | 103 | { |
103 | model: AvatarModel, | 104 | model: ActorImageModel, |
105 | as: 'Avatar', | ||
104 | required: false | 106 | required: false |
105 | } | 107 | } |
106 | ] | 108 | ] |
@@ -213,18 +215,35 @@ export class ActorModel extends Model { | |||
213 | @UpdatedAt | 215 | @UpdatedAt |
214 | updatedAt: Date | 216 | updatedAt: Date |
215 | 217 | ||
216 | @ForeignKey(() => AvatarModel) | 218 | @ForeignKey(() => ActorImageModel) |
217 | @Column | 219 | @Column |
218 | avatarId: number | 220 | avatarId: number |
219 | 221 | ||
220 | @BelongsTo(() => AvatarModel, { | 222 | @ForeignKey(() => ActorImageModel) |
223 | @Column | ||
224 | bannerId: number | ||
225 | |||
226 | @BelongsTo(() => ActorImageModel, { | ||
227 | foreignKey: { | ||
228 | name: 'avatarId', | ||
229 | allowNull: true | ||
230 | }, | ||
231 | as: 'Avatar', | ||
232 | onDelete: 'set null', | ||
233 | hooks: true | ||
234 | }) | ||
235 | Avatar: ActorImageModel | ||
236 | |||
237 | @BelongsTo(() => ActorImageModel, { | ||
221 | foreignKey: { | 238 | foreignKey: { |
239 | name: 'bannerId', | ||
222 | allowNull: true | 240 | allowNull: true |
223 | }, | 241 | }, |
242 | as: 'Banner', | ||
224 | onDelete: 'set null', | 243 | onDelete: 'set null', |
225 | hooks: true | 244 | hooks: true |
226 | }) | 245 | }) |
227 | Avatar: AvatarModel | 246 | Banner: ActorImageModel |
228 | 247 | ||
229 | @HasMany(() => ActorFollowModel, { | 248 | @HasMany(() => ActorFollowModel, { |
230 | foreignKey: { | 249 | foreignKey: { |
@@ -496,7 +515,7 @@ export class ActorModel extends Model { | |||
496 | } | 515 | } |
497 | 516 | ||
498 | toFormattedSummaryJSON (this: MActorSummaryFormattable) { | 517 | toFormattedSummaryJSON (this: MActorSummaryFormattable) { |
499 | let avatar: Avatar = null | 518 | let avatar: ActorImage = null |
500 | if (this.Avatar) { | 519 | if (this.Avatar) { |
501 | avatar = this.Avatar.toFormattedJSON() | 520 | avatar = this.Avatar.toFormattedJSON() |
502 | } | 521 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 178878c55..815fb16c0 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -36,9 +36,9 @@ import { | |||
36 | MChannelSummaryFormattable | 36 | MChannelSummaryFormattable |
37 | } from '../../types/models/video' | 37 | } from '../../types/models/video' |
38 | import { AccountModel, ScopeNames as AccountModelScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account' | 38 | import { AccountModel, ScopeNames as AccountModelScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account' |
39 | import { ActorImageModel } from '../account/actor-image' | ||
39 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' | 40 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' |
40 | import { ActorFollowModel } from '../activitypub/actor-follow' | 41 | import { ActorFollowModel } from '../activitypub/actor-follow' |
41 | import { AvatarModel } from '../avatar/avatar' | ||
42 | import { ServerModel } from '../server/server' | 42 | import { ServerModel } from '../server/server' |
43 | import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' | 43 | import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' |
44 | import { VideoModel } from './video' | 44 | import { VideoModel } from './video' |
@@ -130,7 +130,8 @@ export type SummaryOptions = { | |||
130 | required: false | 130 | required: false |
131 | }, | 131 | }, |
132 | { | 132 | { |
133 | model: AvatarModel.unscoped(), | 133 | model: ActorImageModel.unscoped(), |
134 | as: 'Avatar', | ||
134 | required: false | 135 | required: false |
135 | } | 136 | } |
136 | ] | 137 | ] |
diff --git a/server/models/video/video-query-builder.ts b/server/models/video/video-query-builder.ts index 96df0a7f8..4d95ddee2 100644 --- a/server/models/video/video-query-builder.ts +++ b/server/models/video/video-query-builder.ts | |||
@@ -490,12 +490,13 @@ function wrapForAPIResults (baseQuery: string, replacements: any, options: Build | |||
490 | 'INNER JOIN "actor" AS "VideoChannel->Account->Actor" ON "VideoChannel->Account"."actorId" = "VideoChannel->Account->Actor"."id"', | 490 | 'INNER JOIN "actor" AS "VideoChannel->Account->Actor" ON "VideoChannel->Account"."actorId" = "VideoChannel->Account->Actor"."id"', |
491 | 491 | ||
492 | 'LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server"."id"', | 492 | 'LEFT OUTER JOIN "server" AS "VideoChannel->Actor->Server" ON "VideoChannel->Actor"."serverId" = "VideoChannel->Actor->Server"."id"', |
493 | 'LEFT OUTER JOIN "avatar" AS "VideoChannel->Actor->Avatar" ON "VideoChannel->Actor"."avatarId" = "VideoChannel->Actor->Avatar"."id"', | 493 | 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatar" ' + |
494 | 'ON "VideoChannel->Actor"."avatarId" = "VideoChannel->Actor->Avatar"."id"', | ||
494 | 495 | ||
495 | 'LEFT OUTER JOIN "server" AS "VideoChannel->Account->Actor->Server" ' + | 496 | 'LEFT OUTER JOIN "server" AS "VideoChannel->Account->Actor->Server" ' + |
496 | 'ON "VideoChannel->Account->Actor"."serverId" = "VideoChannel->Account->Actor->Server"."id"', | 497 | 'ON "VideoChannel->Account->Actor"."serverId" = "VideoChannel->Account->Actor->Server"."id"', |
497 | 498 | ||
498 | 'LEFT OUTER JOIN "avatar" AS "VideoChannel->Account->Actor->Avatar" ' + | 499 | 'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Account->Actor->Avatar" ' + |
499 | 'ON "VideoChannel->Account->Actor"."avatarId" = "VideoChannel->Account->Actor->Avatar"."id"', | 500 | 'ON "VideoChannel->Account->Actor"."avatarId" = "VideoChannel->Account->Actor->Avatar"."id"', |
500 | 501 | ||
501 | 'LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"' | 502 | 'LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"' |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 9d89efa5b..086269921 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -100,10 +100,10 @@ import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../types/models | |||
100 | import { VideoAbuseModel } from '../abuse/video-abuse' | 100 | import { VideoAbuseModel } from '../abuse/video-abuse' |
101 | import { AccountModel } from '../account/account' | 101 | import { AccountModel } from '../account/account' |
102 | import { AccountVideoRateModel } from '../account/account-video-rate' | 102 | import { AccountVideoRateModel } from '../account/account-video-rate' |
103 | import { ActorImageModel } from '../account/actor-image' | ||
103 | import { UserModel } from '../account/user' | 104 | import { UserModel } from '../account/user' |
104 | import { UserVideoHistoryModel } from '../account/user-video-history' | 105 | import { UserVideoHistoryModel } from '../account/user-video-history' |
105 | import { ActorModel } from '../activitypub/actor' | 106 | import { ActorModel } from '../activitypub/actor' |
106 | import { AvatarModel } from '../avatar/avatar' | ||
107 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 107 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
108 | import { ServerModel } from '../server/server' | 108 | import { ServerModel } from '../server/server' |
109 | import { TrackerModel } from '../server/tracker' | 109 | import { TrackerModel } from '../server/tracker' |
@@ -286,7 +286,8 @@ export type AvailableForListIDsOptions = { | |||
286 | required: false | 286 | required: false |
287 | }, | 287 | }, |
288 | { | 288 | { |
289 | model: AvatarModel.unscoped(), | 289 | model: ActorImageModel.unscoped(), |
290 | as: 'Avatar', | ||
290 | required: false | 291 | required: false |
291 | } | 292 | } |
292 | ] | 293 | ] |
@@ -308,7 +309,8 @@ export type AvailableForListIDsOptions = { | |||
308 | required: false | 309 | required: false |
309 | }, | 310 | }, |
310 | { | 311 | { |
311 | model: AvatarModel.unscoped(), | 312 | model: ActorImageModel.unscoped(), |
313 | as: 'Avatar', | ||
312 | required: false | 314 | required: false |
313 | } | 315 | } |
314 | ] | 316 | ] |
@@ -1703,7 +1705,7 @@ export class VideoModel extends Model { | |||
1703 | 1705 | ||
1704 | function buildActor (rowActor: any) { | 1706 | function buildActor (rowActor: any) { |
1705 | const avatarModel = rowActor.Avatar.id !== null | 1707 | const avatarModel = rowActor.Avatar.id !== null |
1706 | ? new AvatarModel(pick(rowActor.Avatar, avatarKeys), buildOpts) | 1708 | ? new ActorImageModel(pick(rowActor.Avatar, avatarKeys), buildOpts) |
1707 | : null | 1709 | : null |
1708 | 1710 | ||
1709 | const serverModel = rowActor.Server.id !== null | 1711 | const serverModel = rowActor.Server.id !== null |