]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Stronger actor association typing in AP functions
authorChocobozzz <me@florianbigard.com>
Fri, 9 Aug 2019 06:17:16 +0000 (08:17 +0200)
committerChocobozzz <me@florianbigard.com>
Fri, 9 Aug 2019 06:17:16 +0000 (08:17 +0200)
31 files changed:
server/controllers/activitypub/inbox.ts
server/lib/activitypub/actor.ts
server/lib/activitypub/audience.ts
server/lib/activitypub/playlist.ts
server/lib/activitypub/process/process-accept.ts
server/lib/activitypub/process/process-announce.ts
server/lib/activitypub/process/process-create.ts
server/lib/activitypub/process/process-delete.ts
server/lib/activitypub/process/process-dislike.ts
server/lib/activitypub/process/process-flag.ts
server/lib/activitypub/process/process-follow.ts
server/lib/activitypub/process/process-like.ts
server/lib/activitypub/process/process-reject.ts
server/lib/activitypub/process/process-undo.ts
server/lib/activitypub/process/process-update.ts
server/lib/activitypub/process/process-view.ts
server/lib/activitypub/process/process.ts
server/lib/activitypub/send/send-accept.ts
server/lib/activitypub/send/send-announce.ts
server/lib/activitypub/send/send-follow.ts
server/lib/activitypub/send/send-reject.ts
server/lib/activitypub/send/utils.ts
server/lib/activitypub/url.ts
server/lib/activitypub/videos.ts
server/typings/activitypub-processor.model.ts
server/typings/express.ts
server/typings/models/actor-follow.ts [new file with mode: 0644]
server/typings/models/actor.ts [new file with mode: 0644]
server/typings/models/index.d.ts [new file with mode: 0644]
server/typings/models/video-share.ts [new file with mode: 0644]
server/typings/utils.ts [new file with mode: 0644]

index 38d5c51dfbf91386fb418695ac8eb7d05c838183..2d3eef22247bc726011017ba54ad61071ff7bb7a 100644 (file)
@@ -7,6 +7,7 @@ import { asyncMiddleware, checkSignature, localAccountValidator, localVideoChann
 import { activityPubValidator } from '../../middlewares/validators/activitypub/activity'
 import { queue } from 'async'
 import { ActorModel } from '../../models/activitypub/actor'
+import { SignatureActorModel } from '../../typings/models'
 
 const inboxRouter = express.Router()
 
@@ -40,7 +41,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-const inboxQueue = queue<{ activities: Activity[], signatureActor?: ActorModel, inboxActor?: ActorModel }, Error>((task, cb) => {
+const inboxQueue = queue<{ activities: Activity[], signatureActor?: SignatureActorModel, inboxActor?: ActorModel }, Error>((task, cb) => {
   const options = { signatureActor: task.signatureActor, inboxActor: task.inboxActor }
 
   processActivities(task.activities, options)
index 0e6596f103b34324cd1786686f5d6357dd87d3a5..04296864b96c88038ed4726ca166679a10558550 100644 (file)
@@ -195,7 +195,7 @@ async function fetchAvatarIfExists (actorJSON: ActivityPubActor) {
   return undefined
 }
 
-async function addFetchOutboxJob (actor: ActorModel) {
+async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) {
   // Don't fetch ourselves
   const serverActor = await getServerActor()
   if (serverActor.id === actor.id) {
index 771a01366dd91297aa3c3d2268bac6721bd2b6fa..0e3d78590dfa78be4bc1a65a9a3a9a1f18e2d61e 100644 (file)
@@ -5,6 +5,7 @@ import { ActorModel } from '../../models/activitypub/actor'
 import { VideoModel } from '../../models/video/video'
 import { VideoCommentModel } from '../../models/video/video-comment'
 import { VideoShareModel } from '../../models/video/video-share'
+import { ActorModelOnly } from '../../typings/models'
 
 function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience {
   return {
@@ -60,7 +61,7 @@ async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) {
   return actors
 }
 
-function getAudience (actorSender: ActorModel, isPublic = true) {
+function getAudience (actorSender: ActorModelOnly, isPublic = true) {
   return buildAudience([ actorSender.followersUrl ], isPublic)
 }
 
index f569d881cb4b81db8c505dc34499b431704efaed..c2e2a3283fe5e9fc16d0f73b3b616bec5a881ea4 100644 (file)
@@ -18,8 +18,9 @@ import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/vid
 import { sequelizeTypescript } from '../../initializers/database'
 import { createPlaylistMiniatureFromUrl } from '../thumbnail'
 import { FilteredModelAttributes } from '../../typings/sequelize'
+import { AccountModelId } from '../../typings/models'
 
-function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) {
+function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) {
   const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED
 
   return {
@@ -74,7 +75,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: AccountM
   }, { concurrency: CRAWL_REQUEST_CONCURRENCY })
 }
 
-async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) {
+async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) {
   const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to)
 
   if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) {
index 72bb1975e8ac502b831e1a293dc401cb0f86e063..cf27e6c32e6e5280684c05c85674e73545ebcdb7 100644 (file)
@@ -3,6 +3,7 @@ import { ActorModel } from '../../../models/activitypub/actor'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { addFetchOutboxJob } from '../actor'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) {
   const { byActor: targetActor, inboxActor } = options
@@ -19,7 +20,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processAccept (actor: ActorModel, targetActor: ActorModel) {
+async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) {
   const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id)
   if (!follow) throw new Error('Cannot find associated follow.')
 
index 7a59bb84dd8f0c36c8cbfbe7aaf0e18412bdb1a9..b3cdc4441cb0dbe9d8db63e3e376e6a33b3ed712 100644 (file)
@@ -1,7 +1,6 @@
 import { ActivityAnnounce } from '../../../../shared/models/activitypub'
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
 import { sequelizeTypescript } from '../../../initializers'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { VideoShareModel } from '../../../models/video/video-share'
 import { forwardVideoRelatedActivity } from '../send/utils'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
@@ -9,6 +8,7 @@ import { Notifier } from '../../notifier'
 import { VideoModel } from '../../../models/video/video'
 import { logger } from '../../../helpers/logger'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) {
   const { activity, byActor: actorAnnouncer } = options
@@ -26,7 +26,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce, notify: boolean) {
+async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) {
   const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
 
   let video: VideoModel
index b81021163386e83860de0f6cd6885d06fe2ed32a..6815c6997399398aed1bdd055d94332ccaa3f90b 100644 (file)
@@ -3,7 +3,6 @@ import { VideoCommentObject } from '../../../../shared/models/activitypub/object
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
 import { logger } from '../../../helpers/logger'
 import { sequelizeTypescript } from '../../../initializers'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { resolveThread } from '../video-comments'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { forwardVideoRelatedActivity } from '../send/utils'
@@ -14,6 +13,7 @@ import { createOrUpdateVideoPlaylist } from '../playlist'
 import { VideoModel } from '../../../models/video/video'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
 import { VideoCommentModel } from '../../../models/video/video-comment'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) {
   const { activity, byActor } = options
@@ -61,7 +61,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) {
   return video
 }
 
-async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorModel) {
+async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) {
   const cacheFile = activity.object as CacheFileObject
 
   const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object })
@@ -77,7 +77,7 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorM
   }
 }
 
-async function processCreateVideoComment (activity: ActivityCreate, byActor: ActorModel, notify: boolean) {
+async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) {
   const commentObject = activity.object as VideoCommentObject
   const byAccount = byActor.Account
 
@@ -110,7 +110,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act
   if (created && notify) Notifier.Instance.notifyOnNewComment(comment)
 }
 
-async function processCreatePlaylist (activity: ActivityCreate, byActor: ActorModel) {
+async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) {
   const playlistObject = activity.object as PlaylistObject
   const byAccount = byActor.Account
 
index 9fcfd9e3adc5001c6b064a4abc288754b9c4d9c3..344d14322686b9bedd77a541fb3a563302fe8004 100644 (file)
@@ -10,6 +10,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment'
 import { forwardVideoRelatedActivity } from '../send/utils'
 import { VideoPlaylistModel } from '../../../models/video/video-playlist'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) {
   const { activity, byActor } = options
@@ -117,7 +118,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode
   logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url)
 }
 
-function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
+function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
   logger.debug('Removing remote video comment "%s".', videoComment.url)
 
   return sequelizeTypescript.transaction(async t => {
index a457e5f17ac0a21becc8f354da448a1b95bc0dec..727fcfee0c7bef041f9a9b0567e2b7a39948d581 100644 (file)
@@ -3,11 +3,11 @@ import { DislikeObject } from '../../../../shared/models/activitypub/objects'
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
 import { sequelizeTypescript } from '../../../initializers'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { forwardVideoRelatedActivity } from '../send/utils'
 import { getVideoDislikeActivityPubUrl } from '../url'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) {
   const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: ActorModel) {
+async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) {
   const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object
   const byAccount = byActor.Account
 
index 532545e589ab627e40e6dd5b47b4ed28eb2e25b8..1f8a80c140bb29758c718971d75a20ffda9696ad 100644 (file)
@@ -3,12 +3,12 @@ import { VideoAbuseObject } from '../../../../shared/models/activitypub/objects'
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
 import { logger } from '../../../helpers/logger'
 import { sequelizeTypescript } from '../../../initializers'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { VideoAbuseModel } from '../../../models/video/video-abuse'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { Notifier } from '../../notifier'
 import { getAPId } from '../../../helpers/activitypub'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) {
   const { activity, byActor } = options
@@ -23,7 +23,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: ActorModel) {
+async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) {
   const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject)
 
   logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object))
index 8fe9975f64a0071ee2cb3cc5806ad96b9d0473fb..240aa57998bbaaf09ecf4cce846434326365b5d8 100644 (file)
@@ -10,6 +10,8 @@ import { getAPId } from '../../../helpers/activitypub'
 import { getServerActor } from '../../../helpers/utils'
 import { CONFIG } from '../../../initializers/config'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
+import { ActorFollowModelLight } from '../../../typings/models/actor-follow'
 
 async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) {
   const { activity, byActor } = options
@@ -26,7 +28,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processFollow (actor: ActorModel, targetActorURL: string) {
+async function processFollow (byActor: SignatureActorModel, targetActorURL: string) {
   const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => {
     const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t)
 
@@ -39,30 +41,30 @@ async function processFollow (actor: ActorModel, targetActorURL: string) {
     if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) {
       logger.info('Rejecting %s because instance followers are disabled.', targetActor.url)
 
-      await sendReject(actor, targetActor)
+      await sendReject(byActor, targetActor)
 
       return { actorFollow: undefined }
     }
 
     const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({
       where: {
-        actorId: actor.id,
+        actorId: byActor.id,
         targetActorId: targetActor.id
       },
       defaults: {
-        actorId: actor.id,
+        actorId: byActor.id,
         targetActorId: targetActor.id,
         state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted'
       },
       transaction: t
-    })
+    }) as [ ActorFollowModelLight, boolean ]
 
     if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) {
       actorFollow.state = 'accepted'
       await actorFollow.save({ transaction: t })
     }
 
-    actorFollow.ActorFollower = actor
+    actorFollow.ActorFollower = byActor
     actorFollow.ActorFollowing = targetActor
 
     // Target sends to actor he accepted the follow request
@@ -79,5 +81,5 @@ async function processFollow (actor: ActorModel, targetActorURL: string) {
     else Notifier.Instance.notifyOfNewUserFollow(actorFollow)
   }
 
-  logger.info('Actor %s is followed by actor %s.', targetActorURL, actor.url)
+  logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url)
 }
index 706e63c410b0c2c2346a0bc2d21fa7ce71e9c55a..cf559af721c4c65b816ce60acbf8f913f1ecf863 100644 (file)
@@ -2,12 +2,12 @@ import { ActivityLike } from '../../../../shared/models/activitypub'
 import { retryTransactionWrapper } from '../../../helpers/database-utils'
 import { sequelizeTypescript } from '../../../initializers'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { forwardVideoRelatedActivity } from '../send/utils'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { getVideoLikeActivityPubUrl } from '../url'
 import { getAPId } from '../../../helpers/activitypub'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processLikeActivity (options: APProcessorOptions<ActivityLike>) {
   const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) {
+async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) {
   const videoUrl = getAPId(activity.object)
 
   const byAccount = byActor.Account
index 9181906b45efdc97bcebe97957dbd1b6e2af9838..22e311cebf1e6bc9151b15d9c89c0e0c7b17c206 100644 (file)
@@ -1,8 +1,8 @@
 import { ActivityReject } from '../../../../shared/models/activitypub/activity'
 import { sequelizeTypescript } from '../../../initializers'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { ActorModelOnly } from '../../../typings/models'
 
 async function processRejectActivity (options: APProcessorOptions<ActivityReject>) {
   const { byActor: targetActor, inboxActor } = options
@@ -19,7 +19,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processReject (follower: ActorModel, targetActor: ActorModel) {
+async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) {
   return sequelizeTypescript.transaction(async t => {
     const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t)
 
index 7a0f90adfc3821d6fab4c364269fb986310f7fad..c37ee38bb7b008e8ac82f345798c810b72c2d4fb 100644 (file)
@@ -11,6 +11,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { VideoShareModel } from '../../../models/video/video-share'
 import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) {
   const { activity, byActor } = options
@@ -53,7 +54,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) {
+async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) {
   const likeActivity = activity.object as ActivityLike
 
   const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object })
@@ -76,7 +77,7 @@ async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) {
   })
 }
 
-async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo) {
+async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) {
   const dislike = activity.object.type === 'Dislike'
     ? activity.object
     : activity.object.object as DislikeObject
@@ -101,7 +102,7 @@ async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo)
   })
 }
 
-async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo) {
+async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) {
   const cacheFileObject = activity.object.object as CacheFileObject
 
   const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object })
@@ -126,7 +127,7 @@ async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo
   })
 }
 
-function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow) {
+function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) {
   return sequelizeTypescript.transaction(async t => {
     const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t)
     const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t)
@@ -139,7 +140,7 @@ function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow
   })
 }
 
-function processUndoAnnounce (byActor: ActorModel, announceActivity: ActivityAnnounce) {
+function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) {
   return sequelizeTypescript.transaction(async t => {
     const share = await VideoShareModel.loadByUrl(announceActivity.id, t)
     if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`)
index 1e11dd1fdfa7c756578e86749775d5b4ada4acfa..e3c862221acb567f59ef54c4ca138179c92370dc 100644 (file)
@@ -15,6 +15,7 @@ import { forwardVideoRelatedActivity } from '../send/utils'
 import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
 import { createOrUpdateVideoPlaylist } from '../playlist'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) {
   const { activity, byActor } = options
@@ -52,7 +53,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
+async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) {
   const videoObject = activity.object as VideoTorrentObject
 
   if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) {
@@ -73,7 +74,7 @@ async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate)
   return updateVideoFromAP(updateOptions)
 }
 
-async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUpdate) {
+async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) {
   const cacheFileObject = activity.object as CacheFileObject
 
   if (!isCacheFileObjectValid(cacheFileObject)) {
@@ -147,7 +148,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate)
   }
 }
 
-async function processUpdatePlaylist (byActor: ActorModel, activity: ActivityUpdate) {
+async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) {
   const playlistObject = activity.object as PlaylistObject
   const byAccount = byActor.Account
 
index 0170b74f4502492a8cf438a27fd6e8bc4d185b8b..e4997b8282a492d606e56cca6cf08d0bb3cab5d1 100644 (file)
@@ -1,9 +1,9 @@
-import { ActorModel } from '../../../models/activitypub/actor'
 import { getOrCreateVideoAndAccountAndChannel } from '../videos'
 import { forwardVideoRelatedActivity } from '../send/utils'
 import { Redis } from '../../redis'
 import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) {
   const { activity, byActor } = options
@@ -18,7 +18,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function processCreateView (activity: ActivityView | ActivityCreate, byActor: ActorModel) {
+async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) {
   const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object
 
   const options = {
index f4a92e341dc022f3846bd1de0759b8586e23a955..d108fe321b4e9a59c88bdaccf42c88ace93d0628 100644 (file)
@@ -16,6 +16,7 @@ import { processDislikeActivity } from './process-dislike'
 import { processFlagActivity } from './process-flag'
 import { processViewActivity } from './process-view'
 import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
+import { SignatureActorModel } from '../../../typings/models'
 
 const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = {
   Create: processCreateActivity,
@@ -35,7 +36,7 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Act
 async function processActivities (
   activities: Activity[],
   options: {
-    signatureActor?: ActorModel
+    signatureActor?: SignatureActorModel
     inboxActor?: ActorModel
     outboxUrl?: string
     fromFetch?: boolean
@@ -43,7 +44,7 @@ async function processActivities (
 ) {
   const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options
 
-  const actorsCache: { [ url: string ]: ActorModel } = {}
+  const actorsCache: { [ url: string ]: SignatureActorModel } = {}
 
   for (const activity of activities) {
     if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) {
index 388a9ed2346285269d7bb9be3f0f4a27e9583b20..813c42e15dc643e2270369c6f970bdba45a6ad7a 100644 (file)
@@ -1,12 +1,12 @@
 import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub'
-import { ActorModel } from '../../../models/activitypub/actor'
-import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url'
 import { unicastTo } from './utils'
 import { buildFollowActivity } from './send-follow'
 import { logger } from '../../../helpers/logger'
+import { ActorFollowModelLight } from '../../../typings/models/actor-follow'
+import { ActorModelOnly } from '../../../typings/models'
 
-async function sendAccept (actorFollow: ActorFollowModel) {
+async function sendAccept (actorFollow: ActorFollowModelLight) {
   const follower = actorFollow.ActorFollower
   const me = actorFollow.ActorFollowing
 
@@ -34,7 +34,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-function buildAcceptActivity (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityAccept {
+function buildAcceptActivity (url: string, byActor: ActorModelOnly, followActivityData: ActivityFollow): ActivityAccept {
   return {
     type: 'Accept',
     id: url,
index cd0cab7ee5a034a62c7658c63ee566a47aeeb467..7fe4ca180f5f46b9e53b8a9e503b1982e56b55b1 100644 (file)
@@ -1,13 +1,18 @@
 import { Transaction } from 'sequelize'
 import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { VideoModel } from '../../../models/video/video'
-import { VideoShareModel } from '../../../models/video/video-share'
 import { broadcastToFollowers } from './utils'
 import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience'
 import { logger } from '../../../helpers/logger'
-
-async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) {
+import { ActorModelOnly } from '../../../typings/models'
+import { VideoShareModelOnly } from '../../../typings/models/video-share'
+
+async function buildAnnounceWithVideoAudience (
+  byActor: ActorModelOnly,
+  videoShare: VideoShareModelOnly,
+  video: VideoModel,
+  t: Transaction
+) {
   const announcedObject = video.url
 
   const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t)
@@ -18,7 +23,7 @@ async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare:
   return { activity, actorsInvolvedInVideo }
 }
 
-async function sendVideoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) {
+async function sendVideoAnnounce (byActor: ActorModelOnly, videoShare: VideoShareModelOnly, video: VideoModel, t: Transaction) {
   const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t)
 
   logger.info('Creating job to send announce %s.', videoShare.url)
@@ -27,7 +32,7 @@ async function sendVideoAnnounce (byActor: ActorModel, videoShare: VideoShareMod
   return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException)
 }
 
-function buildAnnounceActivity (url: string, byActor: ActorModel, object: string, audience?: ActivityAudience): ActivityAnnounce {
+function buildAnnounceActivity (url: string, byActor: ActorModelOnly, object: string, audience?: ActivityAudience): ActivityAnnounce {
   if (!audience) audience = getAudience(byActor)
 
   return audiencify({
index c6e7fe83d81946f8af1f608a238bb1ebbfc9d3cd..a59ed50cf9d9d9d52523e19dce36cb291cb3dc56 100644 (file)
@@ -1,10 +1,10 @@
 import { ActivityFollow } from '../../../../shared/models/activitypub'
-import { ActorModel } from '../../../models/activitypub/actor'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { getActorFollowActivityPubUrl } from '../url'
 import { unicastTo } from './utils'
 import { logger } from '../../../helpers/logger'
 import { Transaction } from 'sequelize'
+import { ActorModelOnly } from '../../../typings/models'
 
 function sendFollow (actorFollow: ActorFollowModel, t: Transaction) {
   const me = actorFollow.ActorFollower
@@ -21,7 +21,7 @@ function sendFollow (actorFollow: ActorFollowModel, t: Transaction) {
   t.afterCommit(() => unicastTo(data, me, following.inboxUrl))
 }
 
-function buildFollowActivity (url: string, byActor: ActorModel, targetActor: ActorModel): ActivityFollow {
+function buildFollowActivity (url: string, byActor: ActorModelOnly, targetActor: ActorModelOnly): ActivityFollow {
   return {
     type: 'Follow',
     id: url,
index bac7ff556d96e153262fc53cfecfabc94f244dfc..63110b43395dbfa7e7941ad1c142d00ab5e08d38 100644 (file)
@@ -4,8 +4,9 @@ import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from
 import { unicastTo } from './utils'
 import { buildFollowActivity } from './send-follow'
 import { logger } from '../../../helpers/logger'
+import { SignatureActorModel } from '../../../typings/models'
 
-async function sendReject (follower: ActorModel, following: ActorModel) {
+async function sendReject (follower: SignatureActorModel, following: ActorModel) {
   if (!follower.serverId) { // This should never happen
     logger.warn('Do not sending reject to local follower.')
     return
index 1faae1d84fe986d9acf644c76c680d96e20dcda4..4f69afb00098efd3683916ebd7691615f032112c 100644 (file)
@@ -8,21 +8,24 @@ import { VideoModel } from '../../../models/video/video'
 import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
 import { getServerActor } from '../../../helpers/utils'
 import { afterCommitIfTransaction } from '../../../helpers/database-utils'
+import { ActorFollowerException, ActorModelId, ActorModelOnly } from '../../../typings/models'
 
 async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
-  byActor: ActorModel,
+  byActor: ActorModelOnly,
   video: VideoModel,
   transaction?: Transaction
 }) {
-  const actorsInvolvedInVideo = await getActorsInvolvedInVideo(options.video, options.transaction)
+  const { byActor, video, transaction } = options
+
+  const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
 
   // Send to origin
-  if (options.video.isOwned() === false) {
-    const audience = getRemoteVideoAudience(options.video, actorsInvolvedInVideo)
+  if (video.isOwned() === false) {
+    const audience = getRemoteVideoAudience(video, actorsInvolvedInVideo)
     const activity = activityBuilder(audience)
 
-    return afterCommitIfTransaction(options.transaction, () => {
-      return unicastTo(activity, options.byActor, options.video.VideoChannel.Account.Actor.sharedInboxUrl)
+    return afterCommitIfTransaction(transaction, () => {
+      return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl)
     })
   }
 
@@ -30,15 +33,15 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
   const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo)
   const activity = activityBuilder(audience)
 
-  const actorsException = [ options.byActor ]
+  const actorsException = [ byActor ]
 
-  return broadcastToFollowers(activity, options.byActor, actorsInvolvedInVideo, options.transaction, actorsException)
+  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException)
 }
 
 async function forwardVideoRelatedActivity (
   activity: Activity,
   t: Transaction,
-  followersException: ActorModel[] = [],
+  followersException: ActorFollowerException[] = [],
   video: VideoModel
 ) {
   // Mastodon does not add our announces in audience, so we forward to them manually
@@ -51,7 +54,7 @@ async function forwardVideoRelatedActivity (
 async function forwardActivity (
   activity: Activity,
   t: Transaction,
-  followersException: ActorModel[] = [],
+  followersException: ActorFollowerException[] = [],
   additionalFollowerUrls: string[] = []
 ) {
   logger.info('Forwarding activity %s.', activity.id)
@@ -85,10 +88,10 @@ async function forwardActivity (
 
 async function broadcastToFollowers (
   data: any,
-  byActor: ActorModel,
-  toFollowersOf: ActorModel[],
+  byActor: ActorModelId,
+  toFollowersOf: ActorModelId[],
   t: Transaction,
-  actorsException: ActorModel[] = []
+  actorsException: ActorFollowerException[] = []
 ) {
   const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
 
@@ -97,16 +100,16 @@ async function broadcastToFollowers (
 
 async function broadcastToActors (
   data: any,
-  byActor: ActorModel,
-  toActors: ActorModel[],
+  byActor: ActorModelId,
+  toActors: ActorModelOnly[],
   t?: Transaction,
-  actorsException: ActorModel[] = []
+  actorsException: ActorFollowerException[] = []
 ) {
   const uris = await computeUris(toActors, actorsException)
   return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor))
 }
 
-function broadcastTo (uris: string[], data: any, byActor: ActorModel) {
+function broadcastTo (uris: string[], data: any, byActor: ActorModelId) {
   if (uris.length === 0) return undefined
 
   logger.debug('Creating broadcast job.', { uris })
@@ -120,7 +123,7 @@ function broadcastTo (uris: string[], data: any, byActor: ActorModel) {
   return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
 }
 
-function unicastTo (data: any, byActor: ActorModel, toActorUrl: string) {
+function unicastTo (data: any, byActor: ActorModelId, toActorUrl: string) {
   logger.debug('Creating unicast job.', { uri: toActorUrl })
 
   const payload = {
@@ -145,7 +148,7 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException: ActorModel[], t: Transaction) {
+async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsException: ActorFollowerException[], t: Transaction) {
   const toActorFollowerIds = toFollowersOf.map(a => a.id)
 
   const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t)
@@ -154,7 +157,7 @@ async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException
   return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
 }
 
-async function computeUris (toActors: ActorModel[], actorsException: ActorModel[] = []) {
+async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFollowerException[] = []) {
   const serverActor = await getServerActor()
   const targetUrls = toActors
     .filter(a => a.id !== serverActor.id) // Don't send to ourselves
@@ -167,7 +170,7 @@ async function computeUris (toActors: ActorModel[], actorsException: ActorModel[
               .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
 }
 
-async function buildSharedInboxesException (actorsException: ActorModel[]) {
+async function buildSharedInboxesException (actorsException: ActorFollowerException[]) {
   const serverActor = await getServerActor()
 
   return actorsException
index bcb7a4ee2f59404715218ef30bc9066a23e1fd70..dfcb3c6688192c769b59dfc8cd88fcb3c641ecf0 100644 (file)
@@ -1,12 +1,12 @@
 import { WEBSERVER } from '../../initializers/constants'
-import { ActorModel } from '../../models/activitypub/actor'
-import { ActorFollowModel } from '../../models/activitypub/actor-follow'
 import { VideoModel } from '../../models/video/video'
 import { VideoAbuseModel } from '../../models/video/video-abuse'
 import { VideoCommentModel } from '../../models/video/video-comment'
 import { VideoFileModel } from '../../models/video/video-file'
 import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist'
 import { VideoPlaylistModel } from '../../models/video/video-playlist'
+import { ActorModelOnly, ActorModelUrl } from '../../typings/models'
+import { ActorFollowModelLight } from '../../typings/models/actor-follow'
 
 function getVideoActivityPubUrl (video: VideoModel) {
   return WEBSERVER.URL + '/videos/watch/' + video.uuid
@@ -46,15 +46,15 @@ function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) {
   return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id
 }
 
-function getVideoViewActivityPubUrl (byActor: ActorModel, video: VideoModel) {
+function getVideoViewActivityPubUrl (byActor: ActorModelUrl, video: VideoModel) {
   return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString()
 }
 
-function getVideoLikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) {
+function getVideoLikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) {
   return byActor.url + '/likes/' + video.id
 }
 
-function getVideoDislikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) {
+function getVideoDislikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) {
   return byActor.url + '/dislikes/' + video.id
 }
 
@@ -74,22 +74,22 @@ function getVideoDislikesActivityPubUrl (video: VideoModel) {
   return video.url + '/dislikes'
 }
 
-function getActorFollowActivityPubUrl (follower: ActorModel, following: ActorModel) {
+function getActorFollowActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) {
   return follower.url + '/follows/' + following.id
 }
 
-function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModel) {
+function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModelLight) {
   const follower = actorFollow.ActorFollower
   const me = actorFollow.ActorFollowing
 
   return follower.url + '/accepts/follows/' + me.id
 }
 
-function getActorFollowRejectActivityPubUrl (follower: ActorModel, following: ActorModel) {
+function getActorFollowRejectActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) {
   return follower.url + '/rejects/follows/' + following.id
 }
 
-function getVideoAnnounceActivityPubUrl (byActor: ActorModel, video: VideoModel) {
+function getVideoAnnounceActivityPubUrl (byActor: ActorModelOnly, video: VideoModel) {
   return video.url + '/announces/' + byActor.id
 }
 
index 2102702e19eac5d0589226b4be014bcb1eebb5a9..3a8451a326116c91c78bfcf04a40dc4d2efdebc9 100644 (file)
@@ -27,7 +27,6 @@ import {
 import { ActorModel } from '../../models/activitypub/actor'
 import { TagModel } from '../../models/video/tag'
 import { VideoModel } from '../../models/video/video'
-import { VideoChannelModel } from '../../models/video/video-channel'
 import { VideoFileModel } from '../../models/video/video-file'
 import { getOrCreateActorAndServerAndModel } from './actor'
 import { addVideoComments } from './video-comments'
@@ -54,9 +53,9 @@ import { ThumbnailModel } from '../../models/video/thumbnail'
 import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
 import { join } from 'path'
 import { FilteredModelAttributes } from '../../typings/sequelize'
-import { Hooks } from '../plugins/hooks'
 import { autoBlacklistVideoIfNeeded } from '../video-blacklist'
 import { ActorFollowScoreCache } from '../files-cache'
+import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models'
 
 async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) {
   if (
@@ -239,8 +238,8 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
 async function updateVideoFromAP (options: {
   video: VideoModel,
   videoObject: VideoTorrentObject,
-  account: AccountModel,
-  channel: VideoChannelModel,
+  account: AccountModelIdActor,
+  channel: VideoChannelModelIdActor,
   overrideTo?: string[]
 }) {
   const { video, videoObject, account, channel, overrideTo } = options
@@ -550,7 +549,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
 }
 
 async function videoActivityObjectToDBAttributes (
-  videoChannel: VideoChannelModel,
+  videoChannel: VideoChannelModelId,
   videoObject: VideoTorrentObject,
   to: string[] = []
 ) {
index 7c70251cabbc2427211e2490e3e34b616a1db8ad..37b2859dec301addd0f1cf1a22f5c6fa937625f4 100644 (file)
@@ -1,9 +1,10 @@
 import { Activity } from '../../shared/models/activitypub'
 import { ActorModel } from '../models/activitypub/actor'
+import { SignatureActorModel } from './models'
 
 export type APProcessorOptions<T extends Activity> = {
   activity: T
-  byActor: ActorModel
+  byActor: SignatureActorModel
   inboxActor?: ActorModel
   fromFetch?: boolean
 }
index 3bffc1e9a589631190c157ce11c22249f99de023..f7da55ab0e8ed5e1c738f3717c5c7f69cf65f799 100644 (file)
@@ -22,6 +22,7 @@ import { VideoCaptionModel } from '../models/video/video-caption'
 import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
 import { RegisteredPlugin } from '../lib/plugins/plugin-manager'
 import { PluginModel } from '../models/server/plugin'
+import { SignatureActorModel } from './models'
 
 declare module 'express' {
 
@@ -75,7 +76,7 @@ declare module 'express' {
       }
 
       signature?: {
-        actor: ActorModel
+        actor: SignatureActorModel
       }
 
       authenticated?: boolean
diff --git a/server/typings/models/actor-follow.ts b/server/typings/models/actor-follow.ts
new file mode 100644 (file)
index 0000000..952ef87
--- /dev/null
@@ -0,0 +1,8 @@
+import { ActorFollowModel } from '../../models/activitypub/actor-follow'
+import { ActorModelOnly } from './actor'
+
+export type ActorFollowModelOnly = Omit<ActorFollowModel, 'ActorFollower' | 'ActorFollowing'>
+export type ActorFollowModelLight = ActorFollowModelOnly & {
+  ActorFollower: ActorModelOnly
+  ActorFollowing: ActorModelOnly
+}
diff --git a/server/typings/models/actor.ts b/server/typings/models/actor.ts
new file mode 100644 (file)
index 0000000..2656c7b
--- /dev/null
@@ -0,0 +1,22 @@
+import { ActorModel } from '../../models/activitypub/actor'
+import { VideoChannelModel } from '../../models/video/video-channel'
+import { AccountModel } from '../../models/account/account'
+import { FunctionProperties } from '../utils'
+
+export type VideoChannelModelId = FunctionProperties<VideoChannelModel>
+export type AccountModelId = FunctionProperties<AccountModel> | Pick<AccountModel, 'id'>
+
+export type VideoChannelModelIdActor = VideoChannelModelId & Pick<VideoChannelModel, 'Actor'>
+export type AccountModelIdActor = AccountModelId & Pick<AccountModel, 'Actor'>
+
+export type ActorModelUrl = Pick<ActorModel, 'url'>
+export type ActorModelOnly = Omit<ActorModel, 'Account' | 'VideoChannel' | 'ActorFollowing' | 'Avatar' | 'ActorFollowers' | 'Server'>
+export type ActorModelId = Pick<ActorModelOnly, 'id'>
+
+export type SignatureActorModel = ActorModelOnly & {
+  VideoChannel: VideoChannelModelIdActor
+
+  Account: AccountModelIdActor
+}
+
+export type ActorFollowerException = Pick<ActorModel, 'sharedInboxUrl' | 'inboxUrl'>
diff --git a/server/typings/models/index.d.ts b/server/typings/models/index.d.ts
new file mode 100644 (file)
index 0000000..c906569
--- /dev/null
@@ -0,0 +1 @@
+export * from './actor'
diff --git a/server/typings/models/video-share.ts b/server/typings/models/video-share.ts
new file mode 100644 (file)
index 0000000..1406749
--- /dev/null
@@ -0,0 +1,3 @@
+import { VideoShareModel } from '../../models/video/video-share'
+
+export type VideoShareModelOnly = Omit<VideoShareModel, 'Actor' | 'Video'>
diff --git a/server/typings/utils.ts b/server/typings/utils.ts
new file mode 100644 (file)
index 0000000..a86b05b
--- /dev/null
@@ -0,0 +1,3 @@
+export type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]
+
+export type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>