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 | |
parent | 968aaed2066873fc1c39f95168284122d9d15e21 (diff) | |
download | PeerTube-f479685678406a5df864d89615b33d29085ebfc6.tar.gz PeerTube-f479685678406a5df864d89615b33d29085ebfc6.tar.zst PeerTube-f479685678406a5df864d89615b33d29085ebfc6.zip |
Agnostic actor image storage
Diffstat (limited to 'server')
20 files changed, 149 insertions, 112 deletions
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 5a3e9e51a..4671ec5ac 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -11,7 +11,7 @@ import { CONFIG } from '../../../initializers/config' | |||
11 | import { MIMETYPES } from '../../../initializers/constants' | 11 | import { MIMETYPES } from '../../../initializers/constants' |
12 | import { sequelizeTypescript } from '../../../initializers/database' | 12 | import { sequelizeTypescript } from '../../../initializers/database' |
13 | import { sendUpdateActor } from '../../../lib/activitypub/send' | 13 | import { sendUpdateActor } from '../../../lib/activitypub/send' |
14 | import { deleteLocalActorAvatarFile, updateLocalActorAvatarFile } from '../../../lib/avatar' | 14 | import { deleteLocalActorAvatarFile, updateLocalActorAvatarFile } from '../../../lib/actor-image' |
15 | import { getOriginalVideoFileTotalDailyFromUser, getOriginalVideoFileTotalFromUser, sendVerifyUserEmail } from '../../../lib/user' | 15 | import { getOriginalVideoFileTotalDailyFromUser, getOriginalVideoFileTotalFromUser, sendVerifyUserEmail } from '../../../lib/user' |
16 | import { | 16 | import { |
17 | asyncMiddleware, | 17 | asyncMiddleware, |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 03617dc8d..c9d8e1120 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -13,7 +13,7 @@ import { CONFIG } from '../../initializers/config' | |||
13 | import { MIMETYPES } from '../../initializers/constants' | 13 | import { MIMETYPES } from '../../initializers/constants' |
14 | import { sequelizeTypescript } from '../../initializers/database' | 14 | import { sequelizeTypescript } from '../../initializers/database' |
15 | import { sendUpdateActor } from '../../lib/activitypub/send' | 15 | import { sendUpdateActor } from '../../lib/activitypub/send' |
16 | import { deleteLocalActorAvatarFile, updateLocalActorAvatarFile } from '../../lib/avatar' | 16 | import { deleteLocalActorAvatarFile, updateLocalActorAvatarFile } from '../../lib/actor-image' |
17 | import { JobQueue } from '../../lib/job-queue' | 17 | import { JobQueue } from '../../lib/job-queue' |
18 | import { createLocalVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel' | 18 | import { createLocalVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel' |
19 | import { | 19 | import { |
diff --git a/server/controllers/lazy-static.ts b/server/controllers/lazy-static.ts index 4e553479b..68b5c9eec 100644 --- a/server/controllers/lazy-static.ts +++ b/server/controllers/lazy-static.ts | |||
@@ -4,10 +4,10 @@ import { VideosTorrentCache } from '@server/lib/files-cache/videos-torrent-cache | |||
4 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' | 4 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' |
5 | import { logger } from '../helpers/logger' | 5 | import { logger } from '../helpers/logger' |
6 | import { LAZY_STATIC_PATHS, STATIC_MAX_AGE } from '../initializers/constants' | 6 | import { LAZY_STATIC_PATHS, STATIC_MAX_AGE } from '../initializers/constants' |
7 | import { avatarPathUnsafeCache, pushAvatarProcessInQueue } from '../lib/avatar' | 7 | import { actorImagePathUnsafeCache, pushActorImageProcessInQueue } from '../lib/actor-image' |
8 | import { VideosCaptionCache, VideosPreviewCache } from '../lib/files-cache' | 8 | import { VideosCaptionCache, VideosPreviewCache } from '../lib/files-cache' |
9 | import { asyncMiddleware } from '../middlewares' | 9 | import { asyncMiddleware } from '../middlewares' |
10 | import { AvatarModel } from '../models/avatar/avatar' | 10 | import { ActorImageModel } from '../models/account/actor-image' |
11 | 11 | ||
12 | const lazyStaticRouter = express.Router() | 12 | const lazyStaticRouter = express.Router() |
13 | 13 | ||
@@ -15,7 +15,12 @@ lazyStaticRouter.use(cors()) | |||
15 | 15 | ||
16 | lazyStaticRouter.use( | 16 | lazyStaticRouter.use( |
17 | LAZY_STATIC_PATHS.AVATARS + ':filename', | 17 | LAZY_STATIC_PATHS.AVATARS + ':filename', |
18 | asyncMiddleware(getAvatar) | 18 | asyncMiddleware(getActorImage) |
19 | ) | ||
20 | |||
21 | lazyStaticRouter.use( | ||
22 | LAZY_STATIC_PATHS.BANNERS + ':filename', | ||
23 | asyncMiddleware(getActorImage) | ||
19 | ) | 24 | ) |
20 | 25 | ||
21 | lazyStaticRouter.use( | 26 | lazyStaticRouter.use( |
@@ -43,36 +48,36 @@ export { | |||
43 | 48 | ||
44 | // --------------------------------------------------------------------------- | 49 | // --------------------------------------------------------------------------- |
45 | 50 | ||
46 | async function getAvatar (req: express.Request, res: express.Response) { | 51 | async function getActorImage (req: express.Request, res: express.Response) { |
47 | const filename = req.params.filename | 52 | const filename = req.params.filename |
48 | 53 | ||
49 | if (avatarPathUnsafeCache.has(filename)) { | 54 | if (actorImagePathUnsafeCache.has(filename)) { |
50 | return res.sendFile(avatarPathUnsafeCache.get(filename), { maxAge: STATIC_MAX_AGE.SERVER }) | 55 | return res.sendFile(actorImagePathUnsafeCache.get(filename), { maxAge: STATIC_MAX_AGE.SERVER }) |
51 | } | 56 | } |
52 | 57 | ||
53 | const avatar = await AvatarModel.loadByName(filename) | 58 | const image = await ActorImageModel.loadByName(filename) |
54 | if (!avatar) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) | 59 | if (!image) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) |
55 | 60 | ||
56 | if (avatar.onDisk === false) { | 61 | if (image.onDisk === false) { |
57 | if (!avatar.fileUrl) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) | 62 | if (!image.fileUrl) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) |
58 | 63 | ||
59 | logger.info('Lazy serve remote avatar image %s.', avatar.fileUrl) | 64 | logger.info('Lazy serve remote actor image %s.', image.fileUrl) |
60 | 65 | ||
61 | try { | 66 | try { |
62 | await pushAvatarProcessInQueue({ filename: avatar.filename, fileUrl: avatar.fileUrl }) | 67 | await pushActorImageProcessInQueue({ filename: image.filename, fileUrl: image.fileUrl }) |
63 | } catch (err) { | 68 | } catch (err) { |
64 | logger.warn('Cannot process remote avatar %s.', avatar.fileUrl, { err }) | 69 | logger.warn('Cannot process remote actor image %s.', image.fileUrl, { err }) |
65 | return res.sendStatus(HttpStatusCode.NOT_FOUND_404) | 70 | return res.sendStatus(HttpStatusCode.NOT_FOUND_404) |
66 | } | 71 | } |
67 | 72 | ||
68 | avatar.onDisk = true | 73 | image.onDisk = true |
69 | avatar.save() | 74 | image.save() |
70 | .catch(err => logger.error('Cannot save new avatar disk state.', { err })) | 75 | .catch(err => logger.error('Cannot save new actor image disk state.', { err })) |
71 | } | 76 | } |
72 | 77 | ||
73 | const path = avatar.getPath() | 78 | const path = image.getPath() |
74 | 79 | ||
75 | avatarPathUnsafeCache.set(filename, path) | 80 | actorImagePathUnsafeCache.set(filename, path) |
76 | return res.sendFile(path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }) | 81 | return res.sendFile(path, { maxAge: STATIC_MAX_AGE.LAZY_SERVER }) |
77 | } | 82 | } |
78 | 83 | ||
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 48e7f7397..93dd5ac04 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -59,7 +59,7 @@ const CONFIG = { | |||
59 | }, | 59 | }, |
60 | STORAGE: { | 60 | STORAGE: { |
61 | TMP_DIR: buildPath(config.get<string>('storage.tmp')), | 61 | TMP_DIR: buildPath(config.get<string>('storage.tmp')), |
62 | AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), | 62 | ACTOR_IMAGES: buildPath(config.get<string>('storage.avatars')), |
63 | LOG_DIR: buildPath(config.get<string>('storage.logs')), | 63 | LOG_DIR: buildPath(config.get<string>('storage.logs')), |
64 | VIDEOS_DIR: buildPath(config.get<string>('storage.videos')), | 64 | VIDEOS_DIR: buildPath(config.get<string>('storage.videos')), |
65 | STREAMING_PLAYLISTS_DIR: buildPath(config.get<string>('storage.streaming_playlists')), | 65 | STREAMING_PLAYLISTS_DIR: buildPath(config.get<string>('storage.streaming_playlists')), |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 25e9aad9c..3f934688b 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -580,6 +580,7 @@ const STATIC_DOWNLOAD_PATHS = { | |||
580 | HLS_VIDEOS: '/download/streaming-playlists/hls/videos/' | 580 | HLS_VIDEOS: '/download/streaming-playlists/hls/videos/' |
581 | } | 581 | } |
582 | const LAZY_STATIC_PATHS = { | 582 | const LAZY_STATIC_PATHS = { |
583 | BANNERS: '/lazy-static/banners/', | ||
583 | AVATARS: '/lazy-static/avatars/', | 584 | AVATARS: '/lazy-static/avatars/', |
584 | PREVIEWS: '/lazy-static/previews/', | 585 | PREVIEWS: '/lazy-static/previews/', |
585 | VIDEO_CAPTIONS: '/lazy-static/video-captions/', | 586 | VIDEO_CAPTIONS: '/lazy-static/video-captions/', |
@@ -634,7 +635,7 @@ const LRU_CACHE = { | |||
634 | USER_TOKENS: { | 635 | USER_TOKENS: { |
635 | MAX_SIZE: 1000 | 636 | MAX_SIZE: 1000 |
636 | }, | 637 | }, |
637 | AVATAR_STATIC: { | 638 | ACTOR_IMAGE_STATIC: { |
638 | MAX_SIZE: 500 | 639 | MAX_SIZE: 500 |
639 | } | 640 | } |
640 | } | 641 | } |
@@ -671,7 +672,7 @@ const MEMOIZE_LENGTH = { | |||
671 | } | 672 | } |
672 | 673 | ||
673 | const QUEUE_CONCURRENCY = { | 674 | const QUEUE_CONCURRENCY = { |
674 | AVATAR_PROCESS_IMAGE: 3 | 675 | ACTOR_PROCESS_IMAGE: 3 |
675 | } | 676 | } |
676 | 677 | ||
677 | const REDUNDANCY = { | 678 | const REDUNDANCY = { |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 8378fa982..4c9d7c610 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { TrackerModel } from '@server/models/server/tracker' | ||
2 | import { VideoTrackerModel } from '@server/models/server/video-tracker' | ||
3 | import { QueryTypes, Transaction } from 'sequelize' | 1 | import { QueryTypes, Transaction } from 'sequelize' |
4 | import { Sequelize as SequelizeTypescript } from 'sequelize-typescript' | 2 | import { Sequelize as SequelizeTypescript } from 'sequelize-typescript' |
3 | import { TrackerModel } from '@server/models/server/tracker' | ||
4 | import { VideoTrackerModel } from '@server/models/server/video-tracker' | ||
5 | import { isTestInstance } from '../helpers/core-utils' | 5 | import { isTestInstance } from '../helpers/core-utils' |
6 | import { logger } from '../helpers/logger' | 6 | import { logger } from '../helpers/logger' |
7 | import { AbuseModel } from '../models/abuse/abuse' | 7 | import { AbuseModel } from '../models/abuse/abuse' |
@@ -11,6 +11,7 @@ import { VideoCommentAbuseModel } from '../models/abuse/video-comment-abuse' | |||
11 | import { AccountModel } from '../models/account/account' | 11 | import { AccountModel } from '../models/account/account' |
12 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | 12 | import { AccountBlocklistModel } from '../models/account/account-blocklist' |
13 | import { AccountVideoRateModel } from '../models/account/account-video-rate' | 13 | import { AccountVideoRateModel } from '../models/account/account-video-rate' |
14 | import { ActorImageModel } from '../models/account/actor-image' | ||
14 | import { UserModel } from '../models/account/user' | 15 | import { UserModel } from '../models/account/user' |
15 | import { UserNotificationModel } from '../models/account/user-notification' | 16 | import { UserNotificationModel } from '../models/account/user-notification' |
16 | import { UserNotificationSettingModel } from '../models/account/user-notification-setting' | 17 | import { UserNotificationSettingModel } from '../models/account/user-notification-setting' |
@@ -18,7 +19,6 @@ import { UserVideoHistoryModel } from '../models/account/user-video-history' | |||
18 | import { ActorModel } from '../models/activitypub/actor' | 19 | import { ActorModel } from '../models/activitypub/actor' |
19 | import { ActorFollowModel } from '../models/activitypub/actor-follow' | 20 | import { ActorFollowModel } from '../models/activitypub/actor-follow' |
20 | import { ApplicationModel } from '../models/application/application' | 21 | import { ApplicationModel } from '../models/application/application' |
21 | import { AvatarModel } from '../models/avatar/avatar' | ||
22 | import { OAuthClientModel } from '../models/oauth/oauth-client' | 22 | import { OAuthClientModel } from '../models/oauth/oauth-client' |
23 | import { OAuthTokenModel } from '../models/oauth/oauth-token' | 23 | import { OAuthTokenModel } from '../models/oauth/oauth-token' |
24 | import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' | 24 | import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' |
@@ -95,7 +95,7 @@ async function initDatabaseModels (silent: boolean) { | |||
95 | ApplicationModel, | 95 | ApplicationModel, |
96 | ActorModel, | 96 | ActorModel, |
97 | ActorFollowModel, | 97 | ActorFollowModel, |
98 | AvatarModel, | 98 | ActorImageModel, |
99 | AccountModel, | 99 | AccountModel, |
100 | OAuthClientModel, | 100 | OAuthClientModel, |
101 | OAuthTokenModel, | 101 | OAuthTokenModel, |
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 3c9a7ba02..da831dcfd 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -19,8 +19,8 @@ import { getUrlFromWebfinger } from '../../helpers/webfinger' | |||
19 | import { MIMETYPES, WEBSERVER } from '../../initializers/constants' | 19 | import { MIMETYPES, WEBSERVER } from '../../initializers/constants' |
20 | import { sequelizeTypescript } from '../../initializers/database' | 20 | import { sequelizeTypescript } from '../../initializers/database' |
21 | import { AccountModel } from '../../models/account/account' | 21 | import { AccountModel } from '../../models/account/account' |
22 | import { ActorImageModel } from '../../models/account/actor-image' | ||
22 | import { ActorModel } from '../../models/activitypub/actor' | 23 | import { ActorModel } from '../../models/activitypub/actor' |
23 | import { AvatarModel } from '../../models/avatar/avatar' | ||
24 | import { ServerModel } from '../../models/server/server' | 24 | import { ServerModel } from '../../models/server/server' |
25 | import { VideoChannelModel } from '../../models/video/video-channel' | 25 | import { VideoChannelModel } from '../../models/video/video-channel' |
26 | import { | 26 | import { |
@@ -183,7 +183,7 @@ async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo | |||
183 | } | 183 | } |
184 | } | 184 | } |
185 | 185 | ||
186 | const avatar = await AvatarModel.create({ | 186 | const avatar = await ActorImageModel.create({ |
187 | filename: info.name, | 187 | filename: info.name, |
188 | onDisk: info.onDisk, | 188 | onDisk: info.onDisk, |
189 | fileUrl: info.fileUrl | 189 | fileUrl: info.fileUrl |
@@ -378,7 +378,7 @@ function saveActorAndServerAndModelIfNotExist ( | |||
378 | 378 | ||
379 | // Avatar? | 379 | // Avatar? |
380 | if (result.avatar) { | 380 | if (result.avatar) { |
381 | const avatar = await AvatarModel.create({ | 381 | const avatar = await ActorImageModel.create({ |
382 | filename: result.avatar.name, | 382 | filename: result.avatar.name, |
383 | fileUrl: result.avatar.fileUrl, | 383 | fileUrl: result.avatar.fileUrl, |
384 | onDisk: false | 384 | onDisk: false |
diff --git a/server/lib/avatar.ts b/server/lib/actor-image.ts index 86f1e7bdb..ca7f9658d 100644 --- a/server/lib/avatar.ts +++ b/server/lib/actor-image.ts | |||
@@ -1,17 +1,17 @@ | |||
1 | import 'multer' | 1 | import 'multer' |
2 | import { sendUpdateActor } from './activitypub/send' | 2 | import { queue } from 'async' |
3 | import { AVATARS_SIZE, LRU_CACHE, QUEUE_CONCURRENCY } from '../initializers/constants' | 3 | import * as LRUCache from 'lru-cache' |
4 | import { updateActorAvatarInstance, deleteActorAvatarInstance } from './activitypub/actor' | ||
5 | import { processImage } from '../helpers/image-utils' | ||
6 | import { extname, join } from 'path' | 4 | import { extname, join } from 'path' |
7 | import { retryTransactionWrapper } from '../helpers/database-utils' | ||
8 | import { v4 as uuidv4 } from 'uuid' | 5 | import { v4 as uuidv4 } from 'uuid' |
6 | import { retryTransactionWrapper } from '../helpers/database-utils' | ||
7 | import { processImage } from '../helpers/image-utils' | ||
8 | import { downloadImage } from '../helpers/requests' | ||
9 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
10 | import { AVATARS_SIZE, LRU_CACHE, QUEUE_CONCURRENCY } from '../initializers/constants' | ||
10 | import { sequelizeTypescript } from '../initializers/database' | 11 | import { sequelizeTypescript } from '../initializers/database' |
11 | import * as LRUCache from 'lru-cache' | ||
12 | import { queue } from 'async' | ||
13 | import { downloadImage } from '../helpers/requests' | ||
14 | import { MAccountDefault, MChannelDefault } from '../types/models' | 12 | import { MAccountDefault, MChannelDefault } from '../types/models' |
13 | import { deleteActorAvatarInstance, updateActorAvatarInstance } from './activitypub/actor' | ||
14 | import { sendUpdateActor } from './activitypub/send' | ||
15 | 15 | ||
16 | async function updateLocalActorAvatarFile ( | 16 | async function updateLocalActorAvatarFile ( |
17 | accountOrChannel: MAccountDefault | MChannelDefault, | 17 | accountOrChannel: MAccountDefault | MChannelDefault, |
@@ -20,7 +20,7 @@ async function updateLocalActorAvatarFile ( | |||
20 | const extension = extname(avatarPhysicalFile.filename) | 20 | const extension = extname(avatarPhysicalFile.filename) |
21 | 21 | ||
22 | const avatarName = uuidv4() + extension | 22 | const avatarName = uuidv4() + extension |
23 | const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName) | 23 | const destination = join(CONFIG.STORAGE.ACTOR_IMAGES, avatarName) |
24 | await processImage(avatarPhysicalFile.path, destination, AVATARS_SIZE) | 24 | await processImage(avatarPhysicalFile.path, destination, AVATARS_SIZE) |
25 | 25 | ||
26 | return retryTransactionWrapper(() => { | 26 | return retryTransactionWrapper(() => { |
@@ -59,12 +59,12 @@ async function deleteLocalActorAvatarFile ( | |||
59 | type DownloadImageQueueTask = { fileUrl: string, filename: string } | 59 | type DownloadImageQueueTask = { fileUrl: string, filename: string } |
60 | 60 | ||
61 | const downloadImageQueue = queue<DownloadImageQueueTask, Error>((task, cb) => { | 61 | const downloadImageQueue = queue<DownloadImageQueueTask, Error>((task, cb) => { |
62 | downloadImage(task.fileUrl, CONFIG.STORAGE.AVATARS_DIR, task.filename, AVATARS_SIZE) | 62 | downloadImage(task.fileUrl, CONFIG.STORAGE.ACTOR_IMAGES, task.filename, AVATARS_SIZE) |
63 | .then(() => cb()) | 63 | .then(() => cb()) |
64 | .catch(err => cb(err)) | 64 | .catch(err => cb(err)) |
65 | }, QUEUE_CONCURRENCY.AVATAR_PROCESS_IMAGE) | 65 | }, QUEUE_CONCURRENCY.ACTOR_PROCESS_IMAGE) |
66 | 66 | ||
67 | function pushAvatarProcessInQueue (task: DownloadImageQueueTask) { | 67 | function pushActorImageProcessInQueue (task: DownloadImageQueueTask) { |
68 | return new Promise<void>((res, rej) => { | 68 | return new Promise<void>((res, rej) => { |
69 | downloadImageQueue.push(task, err => { | 69 | downloadImageQueue.push(task, err => { |
70 | if (err) return rej(err) | 70 | if (err) return rej(err) |
@@ -75,11 +75,11 @@ function pushAvatarProcessInQueue (task: DownloadImageQueueTask) { | |||
75 | } | 75 | } |
76 | 76 | ||
77 | // Unsafe so could returns paths that does not exist anymore | 77 | // Unsafe so could returns paths that does not exist anymore |
78 | const avatarPathUnsafeCache = new LRUCache<string, string>({ max: LRU_CACHE.AVATAR_STATIC.MAX_SIZE }) | 78 | const actorImagePathUnsafeCache = new LRUCache<string, string>({ max: LRU_CACHE.ACTOR_IMAGE_STATIC.MAX_SIZE }) |
79 | 79 | ||
80 | export { | 80 | export { |
81 | avatarPathUnsafeCache, | 81 | actorImagePathUnsafeCache, |
82 | updateLocalActorAvatarFile, | 82 | updateLocalActorAvatarFile, |
83 | deleteLocalActorAvatarFile, | 83 | deleteLocalActorAvatarFile, |
84 | pushAvatarProcessInQueue | 84 | pushActorImageProcessInQueue |
85 | } | 85 | } |
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 |
diff --git a/server/types/models/account/actor-image.ts b/server/types/models/account/actor-image.ts new file mode 100644 index 000000000..e59f8b141 --- /dev/null +++ b/server/types/models/account/actor-image.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import { ActorImageModel } from '../../../models/account/actor-image' | ||
2 | import { FunctionProperties } from '@shared/core-utils' | ||
3 | |||
4 | export type MActorImage = ActorImageModel | ||
5 | |||
6 | // ############################################################################ | ||
7 | |||
8 | // Format for API or AP object | ||
9 | |||
10 | export type MActorImageFormattable = | ||
11 | FunctionProperties<MActorImage> & | ||
12 | Pick<MActorImage, 'filename' | 'createdAt' | 'updatedAt'> | ||
diff --git a/server/types/models/account/actor.ts b/server/types/models/account/actor.ts index ee0d05f4e..8af19c4da 100644 --- a/server/types/models/account/actor.ts +++ b/server/types/models/account/actor.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import { ActorModel } from '../../../models/activitypub/actor' | ||
2 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/core-utils' | 1 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/core-utils' |
3 | import { MAccount, MAccountDefault, MAccountId, MAccountIdActor } from './account' | 2 | import { ActorModel } from '../../../models/activitypub/actor' |
4 | import { MServer, MServerHost, MServerHostBlocks, MServerRedundancyAllowed } from '../server' | 3 | import { MServer, MServerHost, MServerHostBlocks, MServerRedundancyAllowed } from '../server' |
5 | import { MAvatar, MAvatarFormattable } from './avatar' | ||
6 | import { MChannel, MChannelAccountActor, MChannelAccountDefault, MChannelId, MChannelIdActor } from '../video' | 4 | import { MChannel, MChannelAccountActor, MChannelAccountDefault, MChannelId, MChannelIdActor } from '../video' |
5 | import { MAccount, MAccountDefault, MAccountId, MAccountIdActor } from './account' | ||
6 | import { MActorImage, MActorImageFormattable } from './actor-image' | ||
7 | 7 | ||
8 | type Use<K extends keyof ActorModel, M> = PickWith<ActorModel, K, M> | 8 | type Use<K extends keyof ActorModel, M> = PickWith<ActorModel, K, M> |
9 | 9 | ||
10 | // ############################################################################ | 10 | // ############################################################################ |
11 | 11 | ||
12 | export type MActor = Omit<ActorModel, 'Account' | 'VideoChannel' | 'ActorFollowing' | 'Avatar' | 'ActorFollowers' | 'Server'> | 12 | export type MActor = Omit<ActorModel, 'Account' | 'VideoChannel' | 'ActorFollowing' | 'Avatar' | 'ActorFollowers' | 'Server' | 'Banner'> |
13 | 13 | ||
14 | // ############################################################################ | 14 | // ############################################################################ |
15 | 15 | ||
@@ -34,7 +34,7 @@ export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServ | |||
34 | export type MActorDefaultLight = | 34 | export type MActorDefaultLight = |
35 | MActorLight & | 35 | MActorLight & |
36 | Use<'Server', MServerHost> & | 36 | Use<'Server', MServerHost> & |
37 | Use<'Avatar', MAvatar> | 37 | Use<'Avatar', MActorImage> |
38 | 38 | ||
39 | export type MActorAccountId = | 39 | export type MActorAccountId = |
40 | MActor & | 40 | MActor & |
@@ -78,7 +78,7 @@ export type MActorServer = | |||
78 | export type MActorDefault = | 78 | export type MActorDefault = |
79 | MActor & | 79 | MActor & |
80 | Use<'Server', MServer> & | 80 | Use<'Server', MServer> & |
81 | Use<'Avatar', MAvatar> | 81 | Use<'Avatar', MActorImage> |
82 | 82 | ||
83 | // Actor with channel that is associated to an account and its actor | 83 | // Actor with channel that is associated to an account and its actor |
84 | // Actor -> VideoChannel -> Account -> Actor | 84 | // Actor -> VideoChannel -> Account -> Actor |
@@ -89,7 +89,7 @@ export type MActorChannelAccountActor = | |||
89 | export type MActorFull = | 89 | export type MActorFull = |
90 | MActor & | 90 | MActor & |
91 | Use<'Server', MServer> & | 91 | Use<'Server', MServer> & |
92 | Use<'Avatar', MAvatar> & | 92 | Use<'Avatar', MActorImage> & |
93 | Use<'Account', MAccount> & | 93 | Use<'Account', MAccount> & |
94 | Use<'VideoChannel', MChannelAccountActor> | 94 | Use<'VideoChannel', MChannelAccountActor> |
95 | 95 | ||
@@ -97,7 +97,7 @@ export type MActorFull = | |||
97 | export type MActorFullActor = | 97 | export type MActorFullActor = |
98 | MActor & | 98 | MActor & |
99 | Use<'Server', MServer> & | 99 | Use<'Server', MServer> & |
100 | Use<'Avatar', MAvatar> & | 100 | Use<'Avatar', MActorImage> & |
101 | Use<'Account', MAccountDefault> & | 101 | Use<'Account', MAccountDefault> & |
102 | Use<'VideoChannel', MChannelAccountDefault> | 102 | Use<'VideoChannel', MChannelAccountDefault> |
103 | 103 | ||
@@ -109,7 +109,7 @@ export type MActorSummary = | |||
109 | FunctionProperties<MActor> & | 109 | FunctionProperties<MActor> & |
110 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & | 110 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & |
111 | Use<'Server', MServerHost> & | 111 | Use<'Server', MServerHost> & |
112 | Use<'Avatar', MAvatar> | 112 | Use<'Avatar', MActorImage> |
113 | 113 | ||
114 | export type MActorSummaryBlocks = | 114 | export type MActorSummaryBlocks = |
115 | MActorSummary & | 115 | MActorSummary & |
@@ -127,7 +127,7 @@ export type MActorSummaryFormattable = | |||
127 | FunctionProperties<MActor> & | 127 | FunctionProperties<MActor> & |
128 | Pick<MActor, 'url' | 'preferredUsername'> & | 128 | Pick<MActor, 'url' | 'preferredUsername'> & |
129 | Use<'Server', MServerHost> & | 129 | Use<'Server', MServerHost> & |
130 | Use<'Avatar', MAvatarFormattable> | 130 | Use<'Avatar', MActorImageFormattable> |
131 | 131 | ||
132 | export type MActorFormattable = | 132 | export type MActorFormattable = |
133 | MActorSummaryFormattable & | 133 | MActorSummaryFormattable & |
@@ -136,4 +136,4 @@ export type MActorFormattable = | |||
136 | 136 | ||
137 | export type MActorAP = | 137 | export type MActorAP = |
138 | MActor & | 138 | MActor & |
139 | Use<'Avatar', MAvatar> | 139 | Use<'Avatar', MActorImage> |
diff --git a/server/types/models/account/avatar.ts b/server/types/models/account/avatar.ts deleted file mode 100644 index 0489a8599..000000000 --- a/server/types/models/account/avatar.ts +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | import { AvatarModel } from '../../../models/avatar/avatar' | ||
2 | import { FunctionProperties } from '@shared/core-utils' | ||
3 | |||
4 | export type MAvatar = AvatarModel | ||
5 | |||
6 | // ############################################################################ | ||
7 | |||
8 | // Format for API or AP object | ||
9 | |||
10 | export type MAvatarFormattable = | ||
11 | FunctionProperties<MAvatar> & | ||
12 | Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> | ||
diff --git a/server/types/models/account/index.ts b/server/types/models/account/index.ts index 513c09c40..e3fc00f94 100644 --- a/server/types/models/account/index.ts +++ b/server/types/models/account/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './account' | 1 | export * from './account' |
2 | export * from './account-blocklist' | 2 | export * from './account-blocklist' |
3 | export * from './actor' | ||
4 | export * from './actor-follow' | 3 | export * from './actor-follow' |
5 | export * from './avatar' | 4 | export * from './actor-image' |
5 | export * from './actor' | ||
diff --git a/server/types/models/user/user-notification.ts b/server/types/models/user/user-notification.ts index 6988086f1..7ebb0485d 100644 --- a/server/types/models/user/user-notification.ts +++ b/server/types/models/user/user-notification.ts | |||
@@ -5,10 +5,10 @@ import { PluginModel } from '@server/models/server/plugin' | |||
5 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 5 | import { PickWith, PickWithOpt } from '@shared/core-utils' |
6 | import { AbuseModel } from '../../../models/abuse/abuse' | 6 | import { AbuseModel } from '../../../models/abuse/abuse' |
7 | import { AccountModel } from '../../../models/account/account' | 7 | import { AccountModel } from '../../../models/account/account' |
8 | import { ActorImageModel } from '../../../models/account/actor-image' | ||
8 | import { UserNotificationModel } from '../../../models/account/user-notification' | 9 | import { UserNotificationModel } from '../../../models/account/user-notification' |
9 | import { ActorModel } from '../../../models/activitypub/actor' | 10 | import { ActorModel } from '../../../models/activitypub/actor' |
10 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 11 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
11 | import { AvatarModel } from '../../../models/avatar/avatar' | ||
12 | import { ServerModel } from '../../../models/server/server' | 12 | import { ServerModel } from '../../../models/server/server' |
13 | import { VideoModel } from '../../../models/video/video' | 13 | import { VideoModel } from '../../../models/video/video' |
14 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' | 14 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' |
@@ -29,7 +29,7 @@ export module UserNotificationIncludes { | |||
29 | 29 | ||
30 | export type ActorInclude = | 30 | export type ActorInclude = |
31 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 31 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & |
32 | PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & | 32 | PickWith<ActorModel, 'Avatar', Pick<ActorImageModel, 'filename' | 'getStaticPath'>> & |
33 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> | 33 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> |
34 | 34 | ||
35 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> | 35 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> |
@@ -75,7 +75,7 @@ export module UserNotificationIncludes { | |||
75 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 75 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & |
76 | PickWith<ActorModel, 'Account', AccountInclude> & | 76 | PickWith<ActorModel, 'Account', AccountInclude> & |
77 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & | 77 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & |
78 | PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> | 78 | PickWithOpt<ActorModel, 'Avatar', Pick<ActorImageModel, 'filename' | 'getStaticPath'>> |
79 | 79 | ||
80 | export type ActorFollowing = | 80 | export type ActorFollowing = |
81 | Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & | 81 | Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & |