aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-04-06 11:35:56 +0200
committerChocobozzz <chocobozzz@cpy.re>2021-04-08 10:07:53 +0200
commitf479685678406a5df864d89615b33d29085ebfc6 (patch)
tree8de15e90cd8d97d8810715df8585c61f48d5282a /server/models
parent968aaed2066873fc1c39f95168284122d9d15e21 (diff)
downloadPeerTube-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.ts5
-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.ts8
-rw-r--r--server/models/activitypub/actor.ts35
-rw-r--r--server/models/video/video-channel.ts5
-rw-r--r--server/models/video/video-query-builder.ts5
-rw-r--r--server/models/video/video.ts10
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 {
33import { ActorModel } from '../activitypub/actor' 33import { ActorModel } from '../activitypub/actor'
34import { ActorFollowModel } from '../activitypub/actor-follow' 34import { ActorFollowModel } from '../activitypub/actor-follow'
35import { ApplicationModel } from '../application/application' 35import { ApplicationModel } from '../application/application'
36import { AvatarModel } from '../avatar/avatar' 36import { ActorImageModel } from './actor-image'
37import { ServerModel } from '../server/server' 37import { ServerModel } from '../server/server'
38import { ServerBlocklistModel } from '../server/server-blocklist' 38import { ServerBlocklistModel } from '../server/server-blocklist'
39import { getSort, throwIfNotValid } from '../utils' 39import { 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 @@
1import { remove } from 'fs-extra'
1import { join } from 'path' 2import { join } from 'path'
2import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' 3import { AfterDestroy, AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
3import { Avatar } from '../../../shared/models/avatars/avatar.model' 4import { MActorImageFormattable } from '@server/types/models'
4import { LAZY_STATIC_PATHS } from '../../initializers/constants' 5import { ActorImageType } from '@shared/models'
6import { ActorImage } from '../../../shared/models/actors/actor-image.model'
7import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
5import { logger } from '../../helpers/logger' 8import { logger } from '../../helpers/logger'
6import { remove } from 'fs-extra'
7import { CONFIG } from '../../initializers/config' 9import { CONFIG } from '../../initializers/config'
10import { LAZY_STATIC_PATHS } from '../../initializers/constants'
8import { throwIfNotValid } from '../utils' 11import { throwIfNotValid } from '../utils'
9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
10import { 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})
21export class AvatarModel extends Model { 22export 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'
10import { ActorModel } from '../activitypub/actor' 10import { ActorModel } from '../activitypub/actor'
11import { ActorFollowModel } from '../activitypub/actor-follow' 11import { ActorFollowModel } from '../activitypub/actor-follow'
12import { ApplicationModel } from '../application/application' 12import { ApplicationModel } from '../application/application'
13import { AvatarModel } from '../avatar/avatar'
14import { PluginModel } from '../server/plugin' 13import { PluginModel } from '../server/plugin'
15import { ServerModel } from '../server/server' 14import { ServerModel } from '../server/server'
16import { getSort, throwIfNotValid } from '../utils' 15import { getSort, throwIfNotValid } from '../utils'
@@ -20,6 +19,7 @@ import { VideoChannelModel } from '../video/video-channel'
20import { VideoCommentModel } from '../video/video-comment' 19import { VideoCommentModel } from '../video/video-comment'
21import { VideoImportModel } from '../video/video-import' 20import { VideoImportModel } from '../video/video-import'
22import { AccountModel } from './account' 21import { AccountModel } from './account'
22import { ActorImageModel } from './actor-image'
23import { UserModel } from './user' 23import { UserModel } from './user'
24 24
25enum ScopeNames { 25enum 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'
20import { ModelCache } from '@server/models/model-cache' 20import { ModelCache } from '@server/models/model-cache'
21import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' 21import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub'
22import { Avatar } from '../../../shared/models/avatars/avatar.model' 22import { ActorImage } from '../../../shared/models/actors/actor-image.model'
23import { activityPubContextify } from '../../helpers/activitypub' 23import { activityPubContextify } from '../../helpers/activitypub'
24import { 24import {
25 isActorFollowersCountValid, 25 isActorFollowersCountValid,
@@ -43,7 +43,7 @@ import {
43 MActorWithInboxes 43 MActorWithInboxes
44} from '../../types/models' 44} from '../../types/models'
45import { AccountModel } from '../account/account' 45import { AccountModel } from '../account/account'
46import { AvatarModel } from '../avatar/avatar' 46import { ActorImageModel } from '../account/actor-image'
47import { ServerModel } from '../server/server' 47import { ServerModel } from '../server/server'
48import { isOutdated, throwIfNotValid } from '../utils' 48import { isOutdated, throwIfNotValid } from '../utils'
49import { VideoModel } from '../video/video' 49import { 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'
38import { AccountModel, ScopeNames as AccountModelScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account' 38import { AccountModel, ScopeNames as AccountModelScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account'
39import { ActorImageModel } from '../account/actor-image'
39import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' 40import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor'
40import { ActorFollowModel } from '../activitypub/actor-follow' 41import { ActorFollowModel } from '../activitypub/actor-follow'
41import { AvatarModel } from '../avatar/avatar'
42import { ServerModel } from '../server/server' 42import { ServerModel } from '../server/server'
43import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' 43import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils'
44import { VideoModel } from './video' 44import { 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
100import { VideoAbuseModel } from '../abuse/video-abuse' 100import { VideoAbuseModel } from '../abuse/video-abuse'
101import { AccountModel } from '../account/account' 101import { AccountModel } from '../account/account'
102import { AccountVideoRateModel } from '../account/account-video-rate' 102import { AccountVideoRateModel } from '../account/account-video-rate'
103import { ActorImageModel } from '../account/actor-image'
103import { UserModel } from '../account/user' 104import { UserModel } from '../account/user'
104import { UserVideoHistoryModel } from '../account/user-video-history' 105import { UserVideoHistoryModel } from '../account/user-video-history'
105import { ActorModel } from '../activitypub/actor' 106import { ActorModel } from '../activitypub/actor'
106import { AvatarModel } from '../avatar/avatar'
107import { VideoRedundancyModel } from '../redundancy/video-redundancy' 107import { VideoRedundancyModel } from '../redundancy/video-redundancy'
108import { ServerModel } from '../server/server' 108import { ServerModel } from '../server/server'
109import { TrackerModel } from '../server/tracker' 109import { 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