aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/actor/actor.ts
diff options
context:
space:
mode:
authorkontrollanten <6680299+kontrollanten@users.noreply.github.com>2022-02-28 08:34:43 +0100
committerGitHub <noreply@github.com>2022-02-28 08:34:43 +0100
commitd0800f7661f13fabe7bb6f4aa0ea50764f106405 (patch)
treed43e6b0b6f4a5a32e03487e6464edbcaf288be2a /server/models/actor/actor.ts
parent5cad2ca9db9b9d138f8a33058d10b94a9fd50c69 (diff)
downloadPeerTube-d0800f7661f13fabe7bb6f4aa0ea50764f106405.tar.gz
PeerTube-d0800f7661f13fabe7bb6f4aa0ea50764f106405.tar.zst
PeerTube-d0800f7661f13fabe7bb6f4aa0ea50764f106405.zip
Implement avatar miniatures (#4639)
* client: remove unused file * refactor(client/my-actor-avatar): size from input Read size from component input instead of scss, to make it possible to use smaller avatar images when implemented. * implement avatar miniatures close #4560 * fix(test): max file size * fix(search-index): normalize res acc to avatarMini * refactor avatars to an array * client/search: resize channel avatar to 120 * refactor(client/videos): remove unused function * client(actor-avatar): set default size * fix tests and avatars full result When findOne is used only an array containting one avatar is returned. * update migration version and version notations * server/search: harmonize normalizing * Cleanup avatar miniature PR Co-authored-by: Chocobozzz <me@florianbigard.com>
Diffstat (limited to 'server/models/actor/actor.ts')
-rw-r--r--server/models/actor/actor.ts129
1 files changed, 57 insertions, 72 deletions
diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts
index c12dcf634..08cb2fd24 100644
--- a/server/models/actor/actor.ts
+++ b/server/models/actor/actor.ts
@@ -16,11 +16,11 @@ import {
16 Table, 16 Table,
17 UpdatedAt 17 UpdatedAt
18} from 'sequelize-typescript' 18} from 'sequelize-typescript'
19import { getBiggestActorImage } from '@server/lib/actor-image'
19import { ModelCache } from '@server/models/model-cache' 20import { ModelCache } from '@server/models/model-cache'
20import { getLowercaseExtension } from '@shared/core-utils' 21import { getLowercaseExtension } from '@shared/core-utils'
22import { ActivityIconObject, ActivityPubActorType, ActorImageType } from '@shared/models'
21import { AttributesOnly } from '@shared/typescript-utils' 23import { AttributesOnly } from '@shared/typescript-utils'
22import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub'
23import { ActorImage } from '../../../shared/models/actors/actor-image.model'
24import { activityPubContextify } from '../../helpers/activitypub' 24import { activityPubContextify } from '../../helpers/activitypub'
25import { 25import {
26 isActorFollowersCountValid, 26 isActorFollowersCountValid,
@@ -81,7 +81,7 @@ export const unusedActorAttributesForAPI = [
81 }, 81 },
82 { 82 {
83 model: ActorImageModel, 83 model: ActorImageModel,
84 as: 'Avatar', 84 as: 'Avatars',
85 required: false 85 required: false
86 } 86 }
87 ] 87 ]
@@ -109,12 +109,12 @@ export const unusedActorAttributesForAPI = [
109 }, 109 },
110 { 110 {
111 model: ActorImageModel, 111 model: ActorImageModel,
112 as: 'Avatar', 112 as: 'Avatars',
113 required: false 113 required: false
114 }, 114 },
115 { 115 {
116 model: ActorImageModel, 116 model: ActorImageModel,
117 as: 'Banner', 117 as: 'Banners',
118 required: false 118 required: false
119 } 119 }
120 ] 120 ]
@@ -153,9 +153,6 @@ export const unusedActorAttributesForAPI = [
153 fields: [ 'serverId' ] 153 fields: [ 'serverId' ]
154 }, 154 },
155 { 155 {
156 fields: [ 'avatarId' ]
157 },
158 {
159 fields: [ 'followersUrl' ] 156 fields: [ 'followersUrl' ]
160 } 157 }
161 ] 158 ]
@@ -231,35 +228,31 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
231 @UpdatedAt 228 @UpdatedAt
232 updatedAt: Date 229 updatedAt: Date
233 230
234 @ForeignKey(() => ActorImageModel) 231 @HasMany(() => ActorImageModel, {
235 @Column 232 as: 'Avatars',
236 avatarId: number 233 onDelete: 'cascade',
237 234 hooks: true,
238 @ForeignKey(() => ActorImageModel)
239 @Column
240 bannerId: number
241
242 @BelongsTo(() => ActorImageModel, {
243 foreignKey: { 235 foreignKey: {
244 name: 'avatarId', 236 allowNull: false
245 allowNull: true
246 }, 237 },
247 as: 'Avatar', 238 scope: {
248 onDelete: 'set null', 239 type: ActorImageType.AVATAR
249 hooks: true 240 }
250 }) 241 })
251 Avatar: ActorImageModel 242 Avatars: ActorImageModel[]
252 243
253 @BelongsTo(() => ActorImageModel, { 244 @HasMany(() => ActorImageModel, {
245 as: 'Banners',
246 onDelete: 'cascade',
247 hooks: true,
254 foreignKey: { 248 foreignKey: {
255 name: 'bannerId', 249 allowNull: false
256 allowNull: true
257 }, 250 },
258 as: 'Banner', 251 scope: {
259 onDelete: 'set null', 252 type: ActorImageType.BANNER
260 hooks: true 253 }
261 }) 254 })
262 Banner: ActorImageModel 255 Banners: ActorImageModel[]
263 256
264 @HasMany(() => ActorFollowModel, { 257 @HasMany(() => ActorFollowModel, {
265 foreignKey: { 258 foreignKey: {
@@ -386,8 +379,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
386 transaction 379 transaction
387 } 380 }
388 381
389 return ActorModel.scope(ScopeNames.FULL) 382 return ActorModel.scope(ScopeNames.FULL).findOne(query)
390 .findOne(query)
391 } 383 }
392 384
393 return ModelCache.Instance.doCache({ 385 return ModelCache.Instance.doCache({
@@ -410,8 +402,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
410 transaction 402 transaction
411 } 403 }
412 404
413 return ActorModel.unscoped() 405 return ActorModel.unscoped().findOne(query)
414 .findOne(query)
415 } 406 }
416 407
417 return ModelCache.Instance.doCache({ 408 return ModelCache.Instance.doCache({
@@ -532,55 +523,50 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
532 } 523 }
533 524
534 toFormattedSummaryJSON (this: MActorSummaryFormattable) { 525 toFormattedSummaryJSON (this: MActorSummaryFormattable) {
535 let avatar: ActorImage = null
536 if (this.Avatar) {
537 avatar = this.Avatar.toFormattedJSON()
538 }
539
540 return { 526 return {
541 url: this.url, 527 url: this.url,
542 name: this.preferredUsername, 528 name: this.preferredUsername,
543 host: this.getHost(), 529 host: this.getHost(),
544 avatar 530 avatars: (this.Avatars || []).map(a => a.toFormattedJSON()),
531
532 // TODO: remove, deprecated in 4.2
533 avatar: this.hasImage(ActorImageType.AVATAR)
534 ? this.Avatars[0].toFormattedJSON()
535 : undefined
545 } 536 }
546 } 537 }
547 538
548 toFormattedJSON (this: MActorFormattable) { 539 toFormattedJSON (this: MActorFormattable) {
549 const base = this.toFormattedSummaryJSON() 540 return {
550 541 ...this.toFormattedSummaryJSON(),
551 let banner: ActorImage = null
552 if (this.Banner) {
553 banner = this.Banner.toFormattedJSON()
554 }
555 542
556 return Object.assign(base, {
557 id: this.id, 543 id: this.id,
558 hostRedundancyAllowed: this.getRedundancyAllowed(), 544 hostRedundancyAllowed: this.getRedundancyAllowed(),
559 followingCount: this.followingCount, 545 followingCount: this.followingCount,
560 followersCount: this.followersCount, 546 followersCount: this.followersCount,
561 banner, 547 createdAt: this.getCreatedAt(),
562 createdAt: this.getCreatedAt() 548
563 }) 549 banners: (this.Banners || []).map(b => b.toFormattedJSON()),
550
551 // TODO: remove, deprecated in 4.2
552 banner: this.hasImage(ActorImageType.BANNER)
553 ? this.Banners[0].toFormattedJSON()
554 : undefined
555 }
564 } 556 }
565 557
566 toActivityPubObject (this: MActorAPChannel | MActorAPAccount, name: string) { 558 toActivityPubObject (this: MActorAPChannel | MActorAPAccount, name: string) {
567 let icon: ActivityIconObject 559 let icon: ActivityIconObject
560 let icons: ActivityIconObject[]
568 let image: ActivityIconObject 561 let image: ActivityIconObject
569 562
570 if (this.avatarId) { 563 if (this.hasImage(ActorImageType.AVATAR)) {
571 const extension = getLowercaseExtension(this.Avatar.filename) 564 icon = getBiggestActorImage(this.Avatars).toActivityPubObject()
572 565 icons = this.Avatars.map(a => a.toActivityPubObject())
573 icon = {
574 type: 'Image',
575 mediaType: MIMETYPES.IMAGE.EXT_MIMETYPE[extension],
576 height: this.Avatar.height,
577 width: this.Avatar.width,
578 url: this.getAvatarUrl()
579 }
580 } 566 }
581 567
582 if (this.bannerId) { 568 if (this.hasImage(ActorImageType.BANNER)) {
583 const banner = (this as MActorAPChannel).Banner 569 const banner = getBiggestActorImage((this as MActorAPChannel).Banners)
584 const extension = getLowercaseExtension(banner.filename) 570 const extension = getLowercaseExtension(banner.filename)
585 571
586 image = { 572 image = {
@@ -588,7 +574,7 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
588 mediaType: MIMETYPES.IMAGE.EXT_MIMETYPE[extension], 574 mediaType: MIMETYPES.IMAGE.EXT_MIMETYPE[extension],
589 height: banner.height, 575 height: banner.height,
590 width: banner.width, 576 width: banner.width,
591 url: this.getBannerUrl() 577 url: ActorImageModel.getImageUrl(banner)
592 } 578 }
593 } 579 }
594 580
@@ -612,7 +598,10 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
612 publicKeyPem: this.publicKey 598 publicKeyPem: this.publicKey
613 }, 599 },
614 published: this.getCreatedAt().toISOString(), 600 published: this.getCreatedAt().toISOString(),
601
615 icon, 602 icon,
603 icons,
604
616 image 605 image
617 } 606 }
618 607
@@ -677,16 +666,12 @@ export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> {
677 return this.Server ? this.Server.redundancyAllowed : false 666 return this.Server ? this.Server.redundancyAllowed : false
678 } 667 }
679 668
680 getAvatarUrl () { 669 hasImage (type: ActorImageType) {
681 if (!this.avatarId) return undefined 670 const images = type === ActorImageType.AVATAR
682 671 ? this.Avatars
683 return WEBSERVER.URL + this.Avatar.getStaticPath() 672 : this.Banners
684 }
685
686 getBannerUrl () {
687 if (!this.bannerId) return undefined
688 673
689 return WEBSERVER.URL + this.Banner.getStaticPath() 674 return Array.isArray(images) && images.length !== 0
690 } 675 }
691 676
692 isOutdated () { 677 isOutdated () {