]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/actor/actor-image.ts
Force live stream termination
[github/Chocobozzz/PeerTube.git] / server / models / actor / actor-image.ts
CommitLineData
f4796856 1import { remove } from 'fs-extra'
c5911fd3 2import { join } from 'path'
d0800f76 3import {
4 AfterDestroy,
5 AllowNull,
6 BelongsTo,
7 Column,
8 CreatedAt,
9 Default,
10 ForeignKey,
11 Is,
12 Model,
13 Table,
14 UpdatedAt
15} from 'sequelize-typescript'
16import { MActorImage, MActorImageFormattable } from '@server/types/models'
17import { getLowercaseExtension } from '@shared/core-utils'
18import { ActivityIconObject, ActorImageType } from '@shared/models'
6b5f72be 19import { AttributesOnly } from '@shared/typescript-utils'
f4796856
C
20import { ActorImage } from '../../../shared/models/actors/actor-image.model'
21import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
8e0fd45e 22import { logger } from '../../helpers/logger'
6dd9de95 23import { CONFIG } from '../../initializers/config'
d0800f76 24import { LAZY_STATIC_PATHS, MIMETYPES, WEBSERVER } from '../../initializers/constants'
8c4bbd94 25import { buildSQLAttributes, throwIfNotValid } from '../shared'
d0800f76 26import { ActorModel } from './actor'
2295ce6c 27
3fd3ab2d 28@Table({
f4796856 29 tableName: 'actorImage',
557b13ae
C
30 indexes: [
31 {
32 fields: [ 'filename' ],
33 unique: true
d0800f76 34 },
35 {
36 fields: [ 'actorId', 'type', 'width' ],
37 unique: true
557b13ae
C
38 }
39 ]
3fd3ab2d 40})
16c016e8 41export class ActorImageModel extends Model<Partial<AttributesOnly<ActorImageModel>>> {
2295ce6c 42
3fd3ab2d
C
43 @AllowNull(false)
44 @Column
45 filename: string
2295ce6c 46
84531547
C
47 @AllowNull(true)
48 @Default(null)
49 @Column
50 height: number
51
52 @AllowNull(true)
53 @Default(null)
54 @Column
55 width: number
56
557b13ae 57 @AllowNull(true)
f4796856 58 @Is('ActorImageFileUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'fileUrl', true))
557b13ae
C
59 @Column
60 fileUrl: string
61
62 @AllowNull(false)
63 @Column
64 onDisk: boolean
65
f4796856
C
66 @AllowNull(false)
67 @Column
68 type: ActorImageType
69
3fd3ab2d
C
70 @CreatedAt
71 createdAt: Date
2295ce6c 72
3fd3ab2d
C
73 @UpdatedAt
74 updatedAt: Date
c5911fd3 75
d0800f76 76 @ForeignKey(() => ActorModel)
77 @Column
78 actorId: number
79
80 @BelongsTo(() => ActorModel, {
81 foreignKey: {
82 allowNull: false
83 },
84 onDelete: 'CASCADE'
85 })
86 Actor: ActorModel
87
c5911fd3 88 @AfterDestroy
f4796856
C
89 static removeFilesAndSendDelete (instance: ActorImageModel) {
90 logger.info('Removing actor image file %s.', instance.filename)
ecf3f060
C
91
92 // Don't block the transaction
f4796856 93 instance.removeImage()
1cc97746 94 .catch(err => logger.error('Cannot remove actor image file %s.', instance.filename, { err }))
c5911fd3
C
95 }
96
eb66ee88
C
97 // ---------------------------------------------------------------------------
98
99 static getSQLAttributes (tableName: string, aliasPrefix = '') {
100 return buildSQLAttributes({
101 model: this,
102 tableName,
103 aliasPrefix
104 })
105 }
106
107 // ---------------------------------------------------------------------------
108
557b13ae
C
109 static loadByName (filename: string) {
110 const query = {
111 where: {
112 filename
113 }
114 }
115
f4796856 116 return ActorImageModel.findOne(query)
557b13ae
C
117 }
118
d0800f76 119 static getImageUrl (image: MActorImage) {
120 if (!image) return undefined
121
122 return WEBSERVER.URL + image.getStaticPath()
123 }
124
f4796856 125 toFormattedJSON (this: MActorImageFormattable): ActorImage {
c5911fd3 126 return {
d0800f76 127 width: this.width,
557b13ae 128 path: this.getStaticPath(),
c5911fd3
C
129 createdAt: this.createdAt,
130 updatedAt: this.updatedAt
131 }
132 }
133
d0800f76 134 toActivityPubObject (): ActivityIconObject {
135 const extension = getLowercaseExtension(this.filename)
136
137 return {
138 type: 'Image',
139 mediaType: MIMETYPES.IMAGE.EXT_MIMETYPE[extension],
140 height: this.height,
141 width: this.width,
142 url: ActorImageModel.getImageUrl(this)
cdeddff1 143 }
d0800f76 144 }
cdeddff1 145
d0800f76 146 getStaticPath () {
147 switch (this.type) {
148 case ActorImageType.AVATAR:
149 return join(LAZY_STATIC_PATHS.AVATARS, this.filename)
150
151 case ActorImageType.BANNER:
152 return join(LAZY_STATIC_PATHS.BANNERS, this.filename)
a220b84b
C
153
154 default:
155 throw new Error('Unknown actor image type: ' + this.type)
d0800f76 156 }
557b13ae
C
157 }
158
159 getPath () {
f4796856 160 return join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename)
c5911fd3
C
161 }
162
f4796856
C
163 removeImage () {
164 const imagePath = join(CONFIG.STORAGE.ACTOR_IMAGES, this.filename)
165 return remove(imagePath)
c5911fd3 166 }
79db409a
C
167
168 isOwned () {
169 return !this.fileUrl
170 }
2295ce6c 171}