From 2cb03dc1f4e01ba491c36caff30c33fe9c5bad89 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Apr 2021 17:01:35 +0200 Subject: Add banners support --- server/lib/activitypub/actor.ts | 106 +++++++++++++++++------ server/lib/activitypub/process/process-delete.ts | 6 +- server/lib/activitypub/process/process-update.ts | 14 +-- 3 files changed, 90 insertions(+), 36 deletions(-) (limited to 'server/lib/activitypub') diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index da831dcfd..fe4796a3d 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -4,6 +4,7 @@ import { Op, Transaction } from 'sequelize' import { URL } from 'url' import { v4 as uuidv4 } from 'uuid' import { getServerActor } from '@server/models/application/application' +import { ActorImageType } from '@shared/models' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' import { ActivityPubActor, ActivityPubActorType, ActivityPubOrderedCollection } from '../../../shared/models/activitypub' import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' @@ -30,10 +31,10 @@ import { MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, - MActorDefault, MActorFull, MActorFullActor, MActorId, + MActorImages, MChannel } from '../../types/models' import { JobQueue } from '../job-queue' @@ -168,43 +169,60 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ } } -type AvatarInfo = { name: string, onDisk: boolean, fileUrl: string } -async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo, t: Transaction) { +type AvatarInfo = { name: string, onDisk: boolean, fileUrl: string, type: ActorImageType } +async function updateActorImageInstance (actor: MActorImages, info: AvatarInfo, t: Transaction) { if (!info.name) return actor - if (actor.Avatar) { + const oldImageModel = info.type === ActorImageType.AVATAR + ? actor.Avatar + : actor.Banner + + if (oldImageModel) { // Don't update the avatar if the file URL did not change - if (info.fileUrl && actor.Avatar.fileUrl === info.fileUrl) return actor + if (info.fileUrl && oldImageModel.fileUrl === info.fileUrl) return actor try { - await actor.Avatar.destroy({ transaction: t }) + await oldImageModel.destroy({ transaction: t }) } catch (err) { - logger.error('Cannot remove old avatar of actor %s.', actor.url, { err }) + logger.error('Cannot remove old actor image of actor %s.', actor.url, { err }) } } - const avatar = await ActorImageModel.create({ + const imageModel = await ActorImageModel.create({ filename: info.name, onDisk: info.onDisk, - fileUrl: info.fileUrl + fileUrl: info.fileUrl, + type: info.type }, { transaction: t }) - actor.avatarId = avatar.id - actor.Avatar = avatar + if (info.type === ActorImageType.AVATAR) { + actor.avatarId = imageModel.id + actor.Avatar = imageModel + } else { + actor.bannerId = imageModel.id + actor.Banner = imageModel + } return actor } -async function deleteActorAvatarInstance (actor: MActorDefault, t: Transaction) { +async function deleteActorImageInstance (actor: MActorImages, type: ActorImageType, t: Transaction) { try { - await actor.Avatar.destroy({ transaction: t }) + if (type === ActorImageType.AVATAR) { + await actor.Avatar.destroy({ transaction: t }) + + actor.avatarId = null + actor.Avatar = null + } else { + await actor.Banner.destroy({ transaction: t }) + + actor.bannerId = null + actor.Banner = null + } } catch (err) { - logger.error('Cannot remove old avatar of actor %s.', actor.url, { err }) + logger.error('Cannot remove old image of actor %s.', actor.url, { err }) } - actor.avatarId = null - actor.Avatar = null - return actor } @@ -219,9 +237,11 @@ async function fetchActorTotalItems (url: string) { } } -function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { +function getImageInfoIfExists (actorJSON: ActivityPubActor, type: ActorImageType) { const mimetypes = MIMETYPES.IMAGE - const icon = actorJSON.icon + const icon = type === ActorImageType.AVATAR + ? actorJSON.icon + : actorJSON.image if (!icon || icon.type !== 'Image' || !isActivityPubUrlValid(icon.url)) return undefined @@ -239,7 +259,8 @@ function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { return { name: uuidv4() + extension, - fileUrl: icon.url + fileUrl: icon.url, + type } } @@ -293,10 +314,22 @@ async function refreshActorIfNeeded ({ @@ -440,6 +486,10 @@ type FetchRemoteActorResult = { name: string fileUrl: string } + banner?: { + name: string + fileUrl: string + } attributedTo: ActivityPubAttributedTo[] } async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: number, result: FetchRemoteActorResult }> { @@ -479,7 +529,8 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe : null }) - const avatarInfo = await getAvatarInfoIfExists(actorJSON) + const avatarInfo = getImageInfoIfExists(actorJSON, ActorImageType.AVATAR) + const bannerInfo = getImageInfoIfExists(actorJSON, ActorImageType.BANNER) const name = actorJSON.name || actorJSON.preferredUsername return { @@ -488,6 +539,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe actor, name, avatar: avatarInfo, + banner: bannerInfo, summary: actorJSON.summary, support: actorJSON.support, playlists: actorJSON.playlists, diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index a86def936..070ee0f1d 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts @@ -7,7 +7,7 @@ import { VideoModel } from '../../../models/video/video' import { VideoCommentModel } from '../../../models/video/video-comment' import { VideoPlaylistModel } from '../../../models/video/video-playlist' import { APProcessorOptions } from '../../../types/activitypub-processor.model' -import { MAccountActor, MActor, MActorSignature, MChannelActor, MChannelActorAccountActor, MCommentOwnerVideo } from '../../../types/models' +import { MAccountActor, MActor, MActorSignature, MChannelActor, MCommentOwnerVideo } from '../../../types/models' import { markCommentAsDeleted } from '../../video-comment' import { forwardVideoRelatedActivity } from '../send/utils' @@ -30,9 +30,7 @@ async function processDeleteActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -119,7 +120,8 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) let accountOrChannelFieldsSave: object // Fetch icon? - const avatarInfo = await getAvatarInfoIfExists(actorAttributesToUpdate) + const avatarInfo = getImageInfoIfExists(actorAttributesToUpdate, ActorImageType.AVATAR) + const bannerInfo = getImageInfoIfExists(actorAttributesToUpdate, ActorImageType.BANNER) try { await sequelizeTypescript.transaction(async t => { @@ -132,10 +134,12 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) await updateActorInstance(actor, actorAttributesToUpdate) - if (avatarInfo !== undefined) { - const avatarOptions = Object.assign({}, avatarInfo, { onDisk: false }) + for (const imageInfo of [ avatarInfo, bannerInfo ]) { + if (!imageInfo) continue - await updateActorAvatarInstance(actor, avatarOptions, t) + const imageOptions = Object.assign({}, imageInfo, { onDisk: false }) + + await updateActorImageInstance(actor, imageOptions, t) } await actor.save({ transaction: t }) -- cgit v1.2.3