Handle follow/accept
This commit is contained in:
parent
571389d43b
commit
7a7724e66e
|
@ -15,4 +15,4 @@
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html
|
</html>
|
||||||
|
|
|
@ -16,12 +16,12 @@ activityPubClientRouter.get('/account/:name',
|
||||||
executeIfActivityPub(asyncMiddleware(accountController))
|
executeIfActivityPub(asyncMiddleware(accountController))
|
||||||
)
|
)
|
||||||
|
|
||||||
activityPubClientRouter.get('/account/:name/followers',
|
activityPubClientRouter.get('/account/:nameWithHost/followers',
|
||||||
executeIfActivityPub(localAccountValidator),
|
executeIfActivityPub(localAccountValidator),
|
||||||
executeIfActivityPub(asyncMiddleware(accountFollowersController))
|
executeIfActivityPub(asyncMiddleware(accountFollowersController))
|
||||||
)
|
)
|
||||||
|
|
||||||
activityPubClientRouter.get('/account/:name/following',
|
activityPubClientRouter.get('/account/:nameWithHost/following',
|
||||||
executeIfActivityPub(localAccountValidator),
|
executeIfActivityPub(localAccountValidator),
|
||||||
executeIfActivityPub(asyncMiddleware(accountFollowingController))
|
executeIfActivityPub(asyncMiddleware(accountFollowingController))
|
||||||
)
|
)
|
||||||
|
@ -46,7 +46,7 @@ async function accountFollowersController (req: express.Request, res: express.Re
|
||||||
const page = req.params.page || 1
|
const page = req.params.page || 1
|
||||||
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
||||||
|
|
||||||
const result = await db.Account.listFollowerUrlsForApi(account.name, start, count)
|
const result = await db.Account.listFollowerUrlsForApi(account.id, start, count)
|
||||||
const activityPubResult = activityPubCollectionPagination(req.url, page, result)
|
const activityPubResult = activityPubCollectionPagination(req.url, page, result)
|
||||||
|
|
||||||
return res.json(activityPubResult)
|
return res.json(activityPubResult)
|
||||||
|
@ -58,7 +58,7 @@ async function accountFollowingController (req: express.Request, res: express.Re
|
||||||
const page = req.params.page || 1
|
const page = req.params.page || 1
|
||||||
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
||||||
|
|
||||||
const result = await db.Account.listFollowingUrlsForApi(account.name, start, count)
|
const result = await db.Account.listFollowingUrlsForApi(account.id, start, count)
|
||||||
const activityPubResult = activityPubCollectionPagination(req.url, page, result)
|
const activityPubResult = activityPubCollectionPagination(req.url, page, result)
|
||||||
|
|
||||||
return res.json(activityPubResult)
|
return res.json(activityPubResult)
|
||||||
|
|
|
@ -3,26 +3,41 @@ import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, Activity
|
||||||
import { logger } from '../../helpers'
|
import { logger } from '../../helpers'
|
||||||
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity'
|
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity'
|
||||||
import { processCreateActivity, processFlagActivity, processUpdateActivity } from '../../lib'
|
import { processCreateActivity, processFlagActivity, processUpdateActivity } from '../../lib'
|
||||||
|
import { processAcceptActivity } from '../../lib/activitypub/process-accept'
|
||||||
import { processAddActivity } from '../../lib/activitypub/process-add'
|
import { processAddActivity } from '../../lib/activitypub/process-add'
|
||||||
import { asyncMiddleware, checkSignature, signatureValidator } from '../../middlewares'
|
import { processDeleteActivity } from '../../lib/activitypub/process-delete'
|
||||||
|
import { processFollowActivity } from '../../lib/activitypub/process-follow'
|
||||||
|
import { asyncMiddleware, checkSignature, localAccountValidator, signatureValidator } from '../../middlewares'
|
||||||
import { activityPubValidator } from '../../middlewares/validators/activitypub/activity'
|
import { activityPubValidator } from '../../middlewares/validators/activitypub/activity'
|
||||||
|
import { AccountInstance } from '../../models/account/account-interface'
|
||||||
|
|
||||||
const processActivity: { [ P in ActivityType ]: (activity: Activity) => Promise<any> } = {
|
const processActivity: { [ P in ActivityType ]: (activity: Activity, inboxAccount?: AccountInstance) => Promise<any> } = {
|
||||||
Create: processCreateActivity,
|
Create: processCreateActivity,
|
||||||
Add: processAddActivity,
|
Add: processAddActivity,
|
||||||
Update: processUpdateActivity,
|
Update: processUpdateActivity,
|
||||||
Flag: processFlagActivity
|
Flag: processFlagActivity,
|
||||||
|
Delete: processDeleteActivity,
|
||||||
|
Follow: processFollowActivity,
|
||||||
|
Accept: processAcceptActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
const inboxRouter = express.Router()
|
const inboxRouter = express.Router()
|
||||||
|
|
||||||
inboxRouter.post('/',
|
inboxRouter.post('/inbox',
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
activityPubValidator,
|
activityPubValidator,
|
||||||
asyncMiddleware(inboxController)
|
asyncMiddleware(inboxController)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
inboxRouter.post('/:nameWithHost/inbox',
|
||||||
|
signatureValidator,
|
||||||
|
asyncMiddleware(checkSignature),
|
||||||
|
localAccountValidator,
|
||||||
|
activityPubValidator,
|
||||||
|
asyncMiddleware(inboxController)
|
||||||
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -46,12 +61,12 @@ async function inboxController (req: express.Request, res: express.Response, nex
|
||||||
// Only keep activities we are able to process
|
// Only keep activities we are able to process
|
||||||
activities = activities.filter(a => isActivityValid(a))
|
activities = activities.filter(a => isActivityValid(a))
|
||||||
|
|
||||||
await processActivities(activities)
|
await processActivities(activities, res.locals.account)
|
||||||
|
|
||||||
res.status(204).end()
|
res.status(204).end()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processActivities (activities: Activity[]) {
|
async function processActivities (activities: Activity[], inboxAccount?: AccountInstance) {
|
||||||
for (const activity of activities) {
|
for (const activity of activities) {
|
||||||
const activityProcessor = processActivity[activity.type]
|
const activityProcessor = processActivity[activity.type]
|
||||||
if (activityProcessor === undefined) {
|
if (activityProcessor === undefined) {
|
||||||
|
@ -59,6 +74,6 @@ async function processActivities (activities: Activity[]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
await activityProcessor(activity)
|
await activityProcessor(activity, inboxAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { activityPubClientRouter } from './client'
|
||||||
|
|
||||||
const remoteRouter = express.Router()
|
const remoteRouter = express.Router()
|
||||||
|
|
||||||
remoteRouter.use('/inbox', inboxRouter)
|
remoteRouter.use('/', inboxRouter)
|
||||||
remoteRouter.use('/', activityPubClientRouter)
|
remoteRouter.use('/', activityPubClientRouter)
|
||||||
remoteRouter.use('/*', badRequest)
|
remoteRouter.use('/*', badRequest)
|
||||||
|
|
||||||
|
|
|
@ -224,67 +224,6 @@
|
||||||
// logger.info('Remote video with uuid %s quick and dirty updated', videoUUID)
|
// logger.info('Remote video with uuid %s quick and dirty updated', videoUUID)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// async function removeRemoteVideoRetryWrapper (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
|
||||||
// const options = {
|
|
||||||
// arguments: [ videoToRemoveData, fromPod ],
|
|
||||||
// errorMessage: 'Cannot remove the remote video channel with many retries.'
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// await retryTransactionWrapper(removeRemoteVideo, options)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
|
||||||
// logger.debug('Removing remote video "%s".', videoToRemoveData.uuid)
|
|
||||||
//
|
|
||||||
// await db.sequelize.transaction(async t => {
|
|
||||||
// // We need the instance because we have to remove some other stuffs (thumbnail etc)
|
|
||||||
// const videoInstance = await fetchVideoByHostAndUUID(fromPod.host, videoToRemoveData.uuid, t)
|
|
||||||
// await videoInstance.destroy({ transaction: t })
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function removeRemoteVideoAccountRetryWrapper (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) {
|
|
||||||
// const options = {
|
|
||||||
// arguments: [ accountAttributesToRemove, fromPod ],
|
|
||||||
// errorMessage: 'Cannot remove the remote video account with many retries.'
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// await retryTransactionWrapper(removeRemoteVideoAccount, options)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function removeRemoteVideoAccount (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) {
|
|
||||||
// logger.debug('Removing remote video account "%s".', accountAttributesToRemove.uuid)
|
|
||||||
//
|
|
||||||
// await db.sequelize.transaction(async t => {
|
|
||||||
// const videoAccount = await db.Account.loadAccountByPodAndUUID(accountAttributesToRemove.uuid, fromPod.id, t)
|
|
||||||
// await videoAccount.destroy({ transaction: t })
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// logger.info('Remote video account with uuid %s removed.', accountAttributesToRemove.uuid)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
|
||||||
// const options = {
|
|
||||||
// arguments: [ videoChannelAttributesToRemove, fromPod ],
|
|
||||||
// errorMessage: 'Cannot remove the remote video channel with many retries.'
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// await retryTransactionWrapper(removeRemoteVideoChannel, options)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function removeRemoteVideoChannel (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
|
||||||
// logger.debug('Removing remote video channel "%s".', videoChannelAttributesToRemove.uuid)
|
|
||||||
//
|
|
||||||
// await db.sequelize.transaction(async t => {
|
|
||||||
// const videoChannel = await fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToRemove.uuid, t)
|
|
||||||
// await videoChannel.destroy({ transaction: t })
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// logger.info('Remote video channel with uuid %s removed.', videoChannelAttributesToRemove.uuid)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async function reportAbuseRemoteVideoRetryWrapper (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
// async function reportAbuseRemoteVideoRetryWrapper (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
||||||
// const options = {
|
// const options = {
|
||||||
// arguments: [ reportData, fromPod ],
|
// arguments: [ reportData, fromPod ],
|
||||||
|
|
|
@ -1,16 +1,27 @@
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
import { getFormattedObjects } from '../../helpers'
|
import { getFormattedObjects } from '../../helpers'
|
||||||
|
import { getApplicationAccount } from '../../helpers/utils'
|
||||||
import { database as db } from '../../initializers/database'
|
import { database as db } from '../../initializers/database'
|
||||||
import { asyncMiddleware, paginationValidator, podsSortValidator, setPagination, setPodsSort } from '../../middlewares'
|
import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../middlewares'
|
||||||
|
import { setFollowingSort } from '../../middlewares/sort'
|
||||||
|
import { followersSortValidator, followingSortValidator } from '../../middlewares/validators/sort'
|
||||||
|
|
||||||
const podsRouter = express.Router()
|
const podsRouter = express.Router()
|
||||||
|
|
||||||
podsRouter.get('/',
|
podsRouter.get('/following',
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
podsSortValidator,
|
followingSortValidator,
|
||||||
setPodsSort,
|
setFollowingSort,
|
||||||
setPagination,
|
setPagination,
|
||||||
asyncMiddleware(listPods)
|
asyncMiddleware(listFollowing)
|
||||||
|
)
|
||||||
|
|
||||||
|
podsRouter.get('/followers',
|
||||||
|
paginationValidator,
|
||||||
|
followersSortValidator,
|
||||||
|
setFollowersSort,
|
||||||
|
setPagination,
|
||||||
|
asyncMiddleware(listFollowers)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -21,8 +32,16 @@ export {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async function listPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const resultList = await db.Pod.listForApi(req.query.start, req.query.count, req.query.sort)
|
const applicationAccount = await getApplicationAccount()
|
||||||
|
const resultList = await db.Account.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort)
|
||||||
|
|
||||||
|
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
|
const applicationAccount = await getApplicationAccount()
|
||||||
|
const resultList = await db.Account.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort)
|
||||||
|
|
||||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,18 @@ import { AccountInstance } from '../../models'
|
||||||
import { logger } from '../logger'
|
import { logger } from '../logger'
|
||||||
|
|
||||||
import { isUserUsernameValid } from './users'
|
import { isUserUsernameValid } from './users'
|
||||||
|
import { isHostValid } from './pods'
|
||||||
|
|
||||||
function isVideoAccountNameValid (value: string) {
|
function isVideoAccountNameValid (value: string) {
|
||||||
return isUserUsernameValid(value)
|
return isUserUsernameValid(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAccountNameWithHostValid (value: string) {
|
||||||
|
const [ name, host ] = value.split('@')
|
||||||
|
|
||||||
|
return isVideoAccountNameValid(name) && isHostValid(host)
|
||||||
|
}
|
||||||
|
|
||||||
function checkVideoAccountExists (id: string, res: express.Response, callback: () => void) {
|
function checkVideoAccountExists (id: string, res: express.Response, callback: () => void) {
|
||||||
let promise: Promise<AccountInstance>
|
let promise: Promise<AccountInstance>
|
||||||
if (validator.isInt(id)) {
|
if (validator.isInt(id)) {
|
||||||
|
@ -41,5 +48,6 @@ function checkVideoAccountExists (id: string, res: express.Response, callback: (
|
||||||
|
|
||||||
export {
|
export {
|
||||||
checkVideoAccountExists,
|
checkVideoAccountExists,
|
||||||
|
isAccountNameWithHostValid,
|
||||||
isVideoAccountNameValid
|
isVideoAccountNameValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { pseudoRandomBytesPromise } from './core-utils'
|
||||||
import { CONFIG, database as db } from '../initializers'
|
import { CONFIG, database as db } from '../initializers'
|
||||||
import { ResultList } from '../../shared'
|
import { ResultList } from '../../shared'
|
||||||
import { VideoResolution } from '../../shared/models/videos/video-resolution.enum'
|
import { VideoResolution } from '../../shared/models/videos/video-resolution.enum'
|
||||||
|
import { AccountInstance } from '../models/account/account-interface'
|
||||||
|
|
||||||
function badRequest (req: express.Request, res: express.Response, next: express.NextFunction) {
|
function badRequest (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
return res.type('json').status(400).end()
|
return res.type('json').status(400).end()
|
||||||
|
@ -78,6 +79,15 @@ function resetSequelizeInstance (instance: Sequelize.Instance<any>, savedFields:
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let applicationAccount: AccountInstance
|
||||||
|
async function getApplicationAccount () {
|
||||||
|
if (applicationAccount === undefined) {
|
||||||
|
applicationAccount = await db.Account.loadApplication()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(applicationAccount)
|
||||||
|
}
|
||||||
|
|
||||||
type SortType = { sortModel: any, sortValue: string }
|
type SortType = { sortModel: any, sortValue: string }
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -89,5 +99,6 @@ export {
|
||||||
isSignupAllowed,
|
isSignupAllowed,
|
||||||
computeResolutionsToTranscode,
|
computeResolutionsToTranscode,
|
||||||
resetSequelizeInstance,
|
resetSequelizeInstance,
|
||||||
|
getApplicationAccount,
|
||||||
SortType
|
SortType
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
JobCategory
|
JobCategory
|
||||||
} from '../../shared/models'
|
} from '../../shared/models'
|
||||||
import { VideoPrivacy } from '../../shared/models/videos/video-privacy.enum'
|
import { VideoPrivacy } from '../../shared/models/videos/video-privacy.enum'
|
||||||
|
import { FollowState } from '../../shared/models/accounts/follow.model'
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -34,12 +35,13 @@ const SEARCHABLE_COLUMNS = {
|
||||||
|
|
||||||
// Sortable columns per schema
|
// Sortable columns per schema
|
||||||
const SORTABLE_COLUMNS = {
|
const SORTABLE_COLUMNS = {
|
||||||
PODS: [ 'id', 'host', 'score', 'createdAt' ],
|
|
||||||
USERS: [ 'id', 'username', 'createdAt' ],
|
USERS: [ 'id', 'username', 'createdAt' ],
|
||||||
VIDEO_ABUSES: [ 'id', 'createdAt' ],
|
VIDEO_ABUSES: [ 'id', 'createdAt' ],
|
||||||
VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ],
|
VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ],
|
||||||
VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ],
|
VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ],
|
||||||
BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ]
|
BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ],
|
||||||
|
FOLLOWERS: [ 'createdAt' ],
|
||||||
|
FOLLOWING: [ 'createdAt' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
const OAUTH_LIFETIME = {
|
const OAUTH_LIFETIME = {
|
||||||
|
@ -236,27 +238,10 @@ const PODS_SCORE = {
|
||||||
BONUS: 10
|
BONUS: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time to wait between requests to the friends (10 min)
|
const FOLLOW_STATES: { [ id: string ]: FollowState } = {
|
||||||
let REQUESTS_INTERVAL = 600000
|
PENDING: 'pending',
|
||||||
|
ACCEPTED: 'accepted'
|
||||||
// Number of requests in parallel we can make
|
}
|
||||||
const REQUESTS_IN_PARALLEL = 10
|
|
||||||
|
|
||||||
// To how many pods we send requests
|
|
||||||
const REQUESTS_LIMIT_PODS = 10
|
|
||||||
// How many requests we send to a pod per interval
|
|
||||||
const REQUESTS_LIMIT_PER_POD = 5
|
|
||||||
|
|
||||||
const REQUESTS_VIDEO_QADU_LIMIT_PODS = 10
|
|
||||||
// The QADU requests are not big
|
|
||||||
const REQUESTS_VIDEO_QADU_LIMIT_PER_POD = 50
|
|
||||||
|
|
||||||
const REQUESTS_VIDEO_EVENT_LIMIT_PODS = 10
|
|
||||||
// The EVENTS requests are not big
|
|
||||||
const REQUESTS_VIDEO_EVENT_LIMIT_PER_POD = 50
|
|
||||||
|
|
||||||
// Number of requests to retry for replay requests module
|
|
||||||
const RETRY_REQUESTS = 5
|
|
||||||
|
|
||||||
const REMOTE_SCHEME = {
|
const REMOTE_SCHEME = {
|
||||||
HTTP: 'https',
|
HTTP: 'https',
|
||||||
|
@ -333,7 +318,6 @@ const OPENGRAPH_AND_OEMBED_COMMENT = '<!-- open graph and oembed tags -->'
|
||||||
if (isTestInstance() === true) {
|
if (isTestInstance() === true) {
|
||||||
CONSTRAINTS_FIELDS.VIDEOS.DURATION.max = 14
|
CONSTRAINTS_FIELDS.VIDEOS.DURATION.max = 14
|
||||||
FRIEND_SCORE.BASE = 20
|
FRIEND_SCORE.BASE = 20
|
||||||
REQUESTS_INTERVAL = 10000
|
|
||||||
JOBS_FETCHING_INTERVAL = 10000
|
JOBS_FETCHING_INTERVAL = 10000
|
||||||
REMOTE_SCHEME.HTTP = 'http'
|
REMOTE_SCHEME.HTTP = 'http'
|
||||||
REMOTE_SCHEME.WS = 'ws'
|
REMOTE_SCHEME.WS = 'ws'
|
||||||
|
@ -361,15 +345,7 @@ export {
|
||||||
PODS_SCORE,
|
PODS_SCORE,
|
||||||
PREVIEWS_SIZE,
|
PREVIEWS_SIZE,
|
||||||
REMOTE_SCHEME,
|
REMOTE_SCHEME,
|
||||||
REQUESTS_IN_PARALLEL,
|
FOLLOW_STATES,
|
||||||
REQUESTS_INTERVAL,
|
|
||||||
REQUESTS_LIMIT_PER_POD,
|
|
||||||
REQUESTS_LIMIT_PODS,
|
|
||||||
REQUESTS_VIDEO_EVENT_LIMIT_PER_POD,
|
|
||||||
REQUESTS_VIDEO_EVENT_LIMIT_PODS,
|
|
||||||
REQUESTS_VIDEO_QADU_LIMIT_PER_POD,
|
|
||||||
REQUESTS_VIDEO_QADU_LIMIT_PODS,
|
|
||||||
RETRY_REQUESTS,
|
|
||||||
SEARCHABLE_COLUMNS,
|
SEARCHABLE_COLUMNS,
|
||||||
PRIVATE_RSA_KEY_SIZE,
|
PRIVATE_RSA_KEY_SIZE,
|
||||||
SORTABLE_COLUMNS,
|
SORTABLE_COLUMNS,
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { ActivityAccept } from '../../../shared/models/activitypub/activity'
|
||||||
|
import { database as db } from '../../initializers'
|
||||||
|
import { AccountInstance } from '../../models/account/account-interface'
|
||||||
|
|
||||||
|
async function processAcceptActivity (activity: ActivityAccept, inboxAccount?: AccountInstance) {
|
||||||
|
if (inboxAccount === undefined) throw new Error('Need to accept on explicit inbox.')
|
||||||
|
|
||||||
|
const targetAccount = await db.Account.loadByUrl(activity.actor)
|
||||||
|
|
||||||
|
return processFollow(inboxAccount, targetAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
processAcceptActivity
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function processFollow (account: AccountInstance, targetAccount: AccountInstance) {
|
||||||
|
const follow = await db.AccountFollow.loadByAccountAndTarget(account.id, targetAccount.id)
|
||||||
|
if (!follow) throw new Error('Cannot find associated follow.')
|
||||||
|
|
||||||
|
follow.set('state', 'accepted')
|
||||||
|
return follow.save()
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
import { ActivityDelete } from '../../../shared/models/activitypub/activity'
|
||||||
|
import { getOrCreateAccount } from '../../helpers/activitypub'
|
||||||
|
import { retryTransactionWrapper } from '../../helpers/database-utils'
|
||||||
|
import { logger } from '../../helpers/logger'
|
||||||
|
import { database as db } from '../../initializers'
|
||||||
|
import { AccountInstance } from '../../models/account/account-interface'
|
||||||
|
import { VideoChannelInstance } from '../../models/video/video-channel-interface'
|
||||||
|
import { VideoInstance } from '../../models/video/video-interface'
|
||||||
|
|
||||||
|
async function processDeleteActivity (activity: ActivityDelete) {
|
||||||
|
const account = await getOrCreateAccount(activity.actor)
|
||||||
|
|
||||||
|
if (account.url === activity.id) {
|
||||||
|
return processDeleteAccount(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let videoObject = await db.Video.loadByUrl(activity.id)
|
||||||
|
if (videoObject !== undefined) {
|
||||||
|
return processDeleteVideo(account, videoObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let videoChannelObject = await db.VideoChannel.loadByUrl(activity.id)
|
||||||
|
if (videoChannelObject !== undefined) {
|
||||||
|
return processDeleteVideoChannel(account, videoChannelObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
processDeleteActivity
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function processDeleteVideo (account: AccountInstance, videoToDelete: VideoInstance) {
|
||||||
|
const options = {
|
||||||
|
arguments: [ account, videoToDelete ],
|
||||||
|
errorMessage: 'Cannot remove the remote video with many retries.'
|
||||||
|
}
|
||||||
|
|
||||||
|
await retryTransactionWrapper(deleteRemoteVideo, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteRemoteVideo (account: AccountInstance, videoToDelete: VideoInstance) {
|
||||||
|
logger.debug('Removing remote video "%s".', videoToDelete.uuid)
|
||||||
|
|
||||||
|
await db.sequelize.transaction(async t => {
|
||||||
|
if (videoToDelete.VideoChannel.Account.id !== account.id) {
|
||||||
|
throw new Error('Account ' + account.url + ' does not own video channel ' + videoToDelete.VideoChannel.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
await videoToDelete.destroy({ transaction: t })
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info('Remote video with uuid %s removed.', videoToDelete.uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processDeleteVideoChannel (account: AccountInstance, videoChannelToRemove: VideoChannelInstance) {
|
||||||
|
const options = {
|
||||||
|
arguments: [ account, videoChannelToRemove ],
|
||||||
|
errorMessage: 'Cannot remove the remote video channel with many retries.'
|
||||||
|
}
|
||||||
|
|
||||||
|
await retryTransactionWrapper(deleteRemoteVideoChannel, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteRemoteVideoChannel (account: AccountInstance, videoChannelToRemove: VideoChannelInstance) {
|
||||||
|
logger.debug('Removing remote video channel "%s".', videoChannelToRemove.uuid)
|
||||||
|
|
||||||
|
await db.sequelize.transaction(async t => {
|
||||||
|
if (videoChannelToRemove.Account.id !== account.id) {
|
||||||
|
throw new Error('Account ' + account.url + ' does not own video channel ' + videoChannelToRemove.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
await videoChannelToRemove.destroy({ transaction: t })
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processDeleteAccount (accountToRemove: AccountInstance) {
|
||||||
|
const options = {
|
||||||
|
arguments: [ accountToRemove ],
|
||||||
|
errorMessage: 'Cannot remove the remote account with many retries.'
|
||||||
|
}
|
||||||
|
|
||||||
|
await retryTransactionWrapper(deleteRemoteAccount, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteRemoteAccount (accountToRemove: AccountInstance) {
|
||||||
|
logger.debug('Removing remote account "%s".', accountToRemove.uuid)
|
||||||
|
|
||||||
|
await db.sequelize.transaction(async t => {
|
||||||
|
await accountToRemove.destroy({ transaction: t })
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info('Remote account with uuid %s removed.', accountToRemove.uuid)
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { ActivityFollow } from '../../../shared/models/activitypub/activity'
|
||||||
|
import { getOrCreateAccount } from '../../helpers'
|
||||||
|
import { database as db } from '../../initializers'
|
||||||
|
import { AccountInstance } from '../../models/account/account-interface'
|
||||||
|
|
||||||
|
async function processFollowActivity (activity: ActivityFollow) {
|
||||||
|
const activityObject = activity.object
|
||||||
|
const account = await getOrCreateAccount(activity.actor)
|
||||||
|
|
||||||
|
return processFollow(account, activityObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
processFollowActivity
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function processFollow (account: AccountInstance, targetAccountURL: string) {
|
||||||
|
const targetAccount = await db.Account.loadByUrl(targetAccountURL)
|
||||||
|
|
||||||
|
if (targetAccount === undefined) throw new Error('Unknown account')
|
||||||
|
if (targetAccount.isOwned() === false) throw new Error('This is not a local account.')
|
||||||
|
|
||||||
|
return db.AccountFollow.create({
|
||||||
|
accountId: account.id,
|
||||||
|
targetAccountId: targetAccount.id,
|
||||||
|
state: 'accepted'
|
||||||
|
})
|
||||||
|
}
|
|
@ -25,8 +25,7 @@ function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Sequeliz
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
|
function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
|
||||||
const videoChannelObject = videoChannel.toActivityPubObject()
|
const data = deleteActivityData(videoChannel.url, videoChannel.Account)
|
||||||
const data = deleteActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
|
|
||||||
|
|
||||||
return broadcastToFollowers(data, videoChannel.Account, t)
|
return broadcastToFollowers(data, videoChannel.Account, t)
|
||||||
}
|
}
|
||||||
|
@ -46,12 +45,17 @@ function sendUpdateVideo (video: VideoInstance, t: Sequelize.Transaction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) {
|
function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) {
|
||||||
const videoObject = video.toActivityPubObject()
|
const data = deleteActivityData(video.url, video.VideoChannel.Account)
|
||||||
const data = deleteActivityData(video.url, video.VideoChannel.Account, videoObject)
|
|
||||||
|
|
||||||
return broadcastToFollowers(data, video.VideoChannel.Account, t)
|
return broadcastToFollowers(data, video.VideoChannel.Account, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendDeleteAccount (account: AccountInstance, t: Sequelize.Transaction) {
|
||||||
|
const data = deleteActivityData(account.url, account)
|
||||||
|
|
||||||
|
return broadcastToFollowers(data, account, t)
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -60,13 +64,14 @@ export {
|
||||||
sendDeleteVideoChannel,
|
sendDeleteVideoChannel,
|
||||||
sendAddVideo,
|
sendAddVideo,
|
||||||
sendUpdateVideo,
|
sendUpdateVideo,
|
||||||
sendDeleteVideo
|
sendDeleteVideo,
|
||||||
|
sendDeleteAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
|
async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
|
||||||
const result = await db.Account.listFollowerUrlsForApi(fromAccount.name, 0)
|
const result = await db.Account.listFollowerUrlsForApi(fromAccount.id, 0)
|
||||||
|
|
||||||
const jobPayload = {
|
const jobPayload = {
|
||||||
uris: result.data,
|
uris: result.data,
|
||||||
|
@ -114,14 +119,11 @@ async function updateActivityData (url: string, byAccount: AccountInstance, obje
|
||||||
return buildSignedActivity(byAccount, base)
|
return buildSignedActivity(byAccount, base)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteActivityData (url: string, byAccount: AccountInstance, object: any) {
|
async function deleteActivityData (url: string, byAccount: AccountInstance) {
|
||||||
const to = await getPublicActivityTo(byAccount)
|
|
||||||
const base = {
|
const base = {
|
||||||
type: 'Update',
|
type: 'Delete',
|
||||||
id: url,
|
id: url,
|
||||||
actor: byAccount.url,
|
actor: byAccount.url
|
||||||
to,
|
|
||||||
object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildSignedActivity(byAccount, base)
|
return buildSignedActivity(byAccount, base)
|
||||||
|
|
|
@ -34,6 +34,18 @@ function setVideosSort (req: express.Request, res: express.Response, next: expre
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setFollowersSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
|
if (!req.query.sort) req.query.sort = '-createdAt'
|
||||||
|
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFollowingSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
|
if (!req.query.sort) req.query.sort = '-createdAt'
|
||||||
|
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
let newSort: SortType = { sortModel: undefined, sortValue: undefined }
|
let newSort: SortType = { sortModel: undefined, sortValue: undefined }
|
||||||
|
|
||||||
|
@ -63,5 +75,7 @@ export {
|
||||||
setVideoAbusesSort,
|
setVideoAbusesSort,
|
||||||
setVideoChannelsSort,
|
setVideoChannelsSort,
|
||||||
setVideosSort,
|
setVideosSort,
|
||||||
setBlacklistSort
|
setBlacklistSort,
|
||||||
|
setFollowersSort,
|
||||||
|
setFollowingSort
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
import { param } from 'express-validator/check'
|
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
|
import { param } from 'express-validator/check'
|
||||||
import { database as db } from '../../initializers/database'
|
|
||||||
import { checkErrors } from './utils'
|
|
||||||
import {
|
import {
|
||||||
logger,
|
|
||||||
isUserUsernameValid,
|
|
||||||
isUserPasswordValid,
|
|
||||||
isUserVideoQuotaValid,
|
|
||||||
isUserDisplayNSFWValid,
|
isUserDisplayNSFWValid,
|
||||||
|
isUserPasswordValid,
|
||||||
isUserRoleValid,
|
isUserRoleValid,
|
||||||
isAccountNameValid
|
isUserUsernameValid,
|
||||||
|
isUserVideoQuotaValid,
|
||||||
|
logger
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
|
import { isAccountNameWithHostValid } from '../../helpers/custom-validators/video-accounts'
|
||||||
|
import { database as db } from '../../initializers/database'
|
||||||
import { AccountInstance } from '../../models'
|
import { AccountInstance } from '../../models'
|
||||||
|
import { checkErrors } from './utils'
|
||||||
|
|
||||||
const localAccountValidator = [
|
const localAccountValidator = [
|
||||||
param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'),
|
param('nameWithHost').custom(isAccountNameWithHostValid).withMessage('Should have a valid account with domain name (myuser@domain.tld)'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking localAccountValidator parameters', { parameters: req.params })
|
logger.debug('Checking localAccountValidator parameters', { parameters: req.params })
|
||||||
|
@ -34,8 +33,10 @@ export {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function checkLocalAccountExists (name: string, res: express.Response, callback: (err: Error, account: AccountInstance) => void) {
|
function checkLocalAccountExists (nameWithHost: string, res: express.Response, callback: (err: Error, account: AccountInstance) => void) {
|
||||||
db.Account.loadLocalAccountByName(name)
|
const [ name, host ] = nameWithHost.split('@')
|
||||||
|
|
||||||
|
db.Account.loadLocalAccountByNameAndPod(name, host)
|
||||||
.then(account => {
|
.then(account => {
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return res.status(404)
|
return res.status(404)
|
||||||
|
|
|
@ -6,29 +6,32 @@ import { logger } from '../../helpers'
|
||||||
import { SORTABLE_COLUMNS } from '../../initializers'
|
import { SORTABLE_COLUMNS } from '../../initializers'
|
||||||
|
|
||||||
// Initialize constants here for better performances
|
// Initialize constants here for better performances
|
||||||
const SORTABLE_PODS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PODS)
|
|
||||||
const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS)
|
const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS)
|
||||||
const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES)
|
const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES)
|
||||||
const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS)
|
const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS)
|
||||||
const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS)
|
const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS)
|
||||||
const SORTABLE_VIDEO_CHANNELS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS)
|
const SORTABLE_VIDEO_CHANNELS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_CHANNELS)
|
||||||
|
const SORTABLE_FOLLOWERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWERS)
|
||||||
|
const SORTABLE_FOLLOWING_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.FOLLOWING)
|
||||||
|
|
||||||
const podsSortValidator = checkSort(SORTABLE_PODS_COLUMNS)
|
|
||||||
const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS)
|
const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS)
|
||||||
const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS)
|
const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS)
|
||||||
const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS)
|
const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS)
|
||||||
const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS)
|
const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS)
|
||||||
const videoChannelsSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_COLUMNS)
|
const videoChannelsSortValidator = checkSort(SORTABLE_VIDEO_CHANNELS_COLUMNS)
|
||||||
|
const followersSortValidator = checkSort(SORTABLE_FOLLOWERS_COLUMNS)
|
||||||
|
const followingSortValidator = checkSort(SORTABLE_FOLLOWING_COLUMNS)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
podsSortValidator,
|
|
||||||
usersSortValidator,
|
usersSortValidator,
|
||||||
videoAbusesSortValidator,
|
videoAbusesSortValidator,
|
||||||
videoChannelsSortValidator,
|
videoChannelsSortValidator,
|
||||||
videosSortValidator,
|
videosSortValidator,
|
||||||
blacklistSortValidator
|
blacklistSortValidator,
|
||||||
|
followersSortValidator,
|
||||||
|
followingSortValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Bluebird from 'bluebird'
|
||||||
|
import { FollowState } from '../../../shared/models/accounts/follow.model'
|
||||||
import { VideoRateType } from '../../../shared/models/videos/video-rate.type'
|
|
||||||
|
|
||||||
export namespace AccountFollowMethods {
|
export namespace AccountFollowMethods {
|
||||||
|
export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountFollowClass {
|
export interface AccountFollowClass {
|
||||||
|
loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountFollowAttributes {
|
export interface AccountFollowAttributes {
|
||||||
accountId: number
|
accountId: number
|
||||||
targetAccountId: number
|
targetAccountId: number
|
||||||
|
state: FollowState
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountFollowInstance extends AccountFollowClass, AccountFollowAttributes, Sequelize.Instance<AccountFollowAttributes> {
|
export interface AccountFollowInstance extends AccountFollowClass, AccountFollowAttributes, Sequelize.Instance<AccountFollowAttributes> {
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
|
import { values } from 'lodash'
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
|
|
||||||
import { addMethodsToModel } from '../utils'
|
import { addMethodsToModel } from '../utils'
|
||||||
import {
|
import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface'
|
||||||
AccountFollowInstance,
|
import { FOLLOW_STATES } from '../../initializers/constants'
|
||||||
AccountFollowAttributes,
|
|
||||||
|
|
||||||
AccountFollowMethods
|
|
||||||
} from './account-follow-interface'
|
|
||||||
|
|
||||||
let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes>
|
let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes>
|
||||||
|
let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
|
||||||
|
|
||||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||||
AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow',
|
AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow',
|
||||||
{ },
|
{
|
||||||
|
state: {
|
||||||
|
type: DataTypes.ENUM(values(FOLLOW_STATES)),
|
||||||
|
allowNull: false
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
indexes: [
|
indexes: [
|
||||||
{
|
{
|
||||||
|
@ -43,6 +46,7 @@ function associate (models) {
|
||||||
name: 'accountId',
|
name: 'accountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
as: 'followers',
|
||||||
onDelete: 'CASCADE'
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -51,6 +55,18 @@ function associate (models) {
|
||||||
name: 'targetAccountId',
|
name: 'targetAccountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
as: 'following',
|
||||||
onDelete: 'CASCADE'
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadByAccountAndTarget = function (accountId: number, targetAccountId: number) {
|
||||||
|
const query = {
|
||||||
|
where: {
|
||||||
|
accountId,
|
||||||
|
targetAccountId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccountFollow.findOne(query)
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
import * as Sequelize from 'sequelize'
|
|
||||||
import * as Bluebird from 'bluebird'
|
import * as Bluebird from 'bluebird'
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
import { Account as FormattedAccount, ActivityPubActor } from '../../../shared'
|
||||||
|
import { ResultList } from '../../../shared/models/result-list.model'
|
||||||
import { PodInstance } from '../pod/pod-interface'
|
import { PodInstance } from '../pod/pod-interface'
|
||||||
import { VideoChannelInstance } from '../video/video-channel-interface'
|
import { VideoChannelInstance } from '../video/video-channel-interface'
|
||||||
import { ActivityPubActor } from '../../../shared'
|
|
||||||
import { ResultList } from '../../../shared/models/result-list.model'
|
|
||||||
|
|
||||||
export namespace AccountMethods {
|
export namespace AccountMethods {
|
||||||
|
export type LoadApplication = () => Bluebird<AccountInstance>
|
||||||
|
|
||||||
export type Load = (id: number) => Bluebird<AccountInstance>
|
export type Load = (id: number) => Bluebird<AccountInstance>
|
||||||
export type LoadByUUID = (uuid: string) => Bluebird<AccountInstance>
|
export type LoadByUUID = (uuid: string) => Bluebird<AccountInstance>
|
||||||
export type LoadByUrl = (url: string) => Bluebird<AccountInstance>
|
export type LoadByUrl = (url: string) => Bluebird<AccountInstance>
|
||||||
export type LoadAccountByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Bluebird<AccountInstance>
|
export type LoadAccountByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Bluebird<AccountInstance>
|
||||||
export type LoadLocalAccountByName = (name: string) => Bluebird<AccountInstance>
|
export type LoadLocalAccountByNameAndPod = (name: string, host: string) => Bluebird<AccountInstance>
|
||||||
export type ListOwned = () => Bluebird<AccountInstance[]>
|
export type ListOwned = () => Bluebird<AccountInstance[]>
|
||||||
export type ListFollowerUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> >
|
export type ListFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
|
||||||
export type ListFollowingUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> >
|
export type ListFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
|
||||||
|
export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
|
||||||
|
export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
|
||||||
|
|
||||||
export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor
|
export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor
|
||||||
|
export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount
|
||||||
export type IsOwned = (this: AccountInstance) => boolean
|
export type IsOwned = (this: AccountInstance) => boolean
|
||||||
export type GetFollowerSharedInboxUrls = (this: AccountInstance) => Bluebird<string[]>
|
export type GetFollowerSharedInboxUrls = (this: AccountInstance) => Bluebird<string[]>
|
||||||
export type GetFollowingUrl = (this: AccountInstance) => string
|
export type GetFollowingUrl = (this: AccountInstance) => string
|
||||||
|
@ -25,14 +29,17 @@ export namespace AccountMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountClass {
|
export interface AccountClass {
|
||||||
|
loadApplication: AccountMethods.LoadApplication
|
||||||
loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
||||||
load: AccountMethods.Load
|
load: AccountMethods.Load
|
||||||
loadByUUID: AccountMethods.LoadByUUID
|
loadByUUID: AccountMethods.LoadByUUID
|
||||||
loadByUrl: AccountMethods.LoadByUrl
|
loadByUrl: AccountMethods.LoadByUrl
|
||||||
loadLocalAccountByName: AccountMethods.LoadLocalAccountByName
|
loadLocalAccountByNameAndPod: AccountMethods.LoadLocalAccountByNameAndPod
|
||||||
listOwned: AccountMethods.ListOwned
|
listOwned: AccountMethods.ListOwned
|
||||||
listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
|
listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
|
||||||
listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
|
listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
|
||||||
|
listFollowingForApi: AccountMethods.ListFollowingForApi
|
||||||
|
listFollowersForApi: AccountMethods.ListFollowersForApi
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountAttributes {
|
export interface AccountAttributes {
|
||||||
|
@ -58,6 +65,7 @@ export interface AccountAttributes {
|
||||||
export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> {
|
export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> {
|
||||||
isOwned: AccountMethods.IsOwned
|
isOwned: AccountMethods.IsOwned
|
||||||
toActivityPubObject: AccountMethods.ToActivityPubObject
|
toActivityPubObject: AccountMethods.ToActivityPubObject
|
||||||
|
toFormattedJSON: AccountMethods.ToFormattedJSON
|
||||||
getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
|
getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
|
||||||
getFollowingUrl: AccountMethods.GetFollowingUrl
|
getFollowingUrl: AccountMethods.GetFollowingUrl
|
||||||
getFollowersUrl: AccountMethods.GetFollowersUrl
|
getFollowersUrl: AccountMethods.GetFollowersUrl
|
||||||
|
|
|
@ -15,25 +15,31 @@ import {
|
||||||
activityPubContextify
|
activityPubContextify
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
|
|
||||||
import { addMethodsToModel } from '../utils'
|
import { addMethodsToModel, getSort } from '../utils'
|
||||||
import {
|
import {
|
||||||
AccountInstance,
|
AccountInstance,
|
||||||
AccountAttributes,
|
AccountAttributes,
|
||||||
|
|
||||||
AccountMethods
|
AccountMethods
|
||||||
} from './account-interface'
|
} from './account-interface'
|
||||||
|
import LoadApplication = AccountMethods.LoadApplication
|
||||||
|
import { sendDeleteAccount } from '../../lib/activitypub/send-request'
|
||||||
|
|
||||||
let Account: Sequelize.Model<AccountInstance, AccountAttributes>
|
let Account: Sequelize.Model<AccountInstance, AccountAttributes>
|
||||||
let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
|
||||||
let load: AccountMethods.Load
|
let load: AccountMethods.Load
|
||||||
|
let loadApplication: AccountMethods.LoadApplication
|
||||||
let loadByUUID: AccountMethods.LoadByUUID
|
let loadByUUID: AccountMethods.LoadByUUID
|
||||||
let loadByUrl: AccountMethods.LoadByUrl
|
let loadByUrl: AccountMethods.LoadByUrl
|
||||||
let loadLocalAccountByName: AccountMethods.LoadLocalAccountByName
|
let loadLocalAccountByNameAndPod: AccountMethods.LoadLocalAccountByNameAndPod
|
||||||
let listOwned: AccountMethods.ListOwned
|
let listOwned: AccountMethods.ListOwned
|
||||||
let listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
|
let listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
|
||||||
let listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
|
let listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
|
||||||
|
let listFollowingForApi: AccountMethods.ListFollowingForApi
|
||||||
|
let listFollowersForApi: AccountMethods.ListFollowersForApi
|
||||||
let isOwned: AccountMethods.IsOwned
|
let isOwned: AccountMethods.IsOwned
|
||||||
let toActivityPubObject: AccountMethods.ToActivityPubObject
|
let toActivityPubObject: AccountMethods.ToActivityPubObject
|
||||||
|
let toFormattedJSON: AccountMethods.ToFormattedJSON
|
||||||
let getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
|
let getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
|
||||||
let getFollowingUrl: AccountMethods.GetFollowingUrl
|
let getFollowingUrl: AccountMethods.GetFollowingUrl
|
||||||
let getFollowersUrl: AccountMethods.GetFollowersUrl
|
let getFollowersUrl: AccountMethods.GetFollowersUrl
|
||||||
|
@ -189,16 +195,20 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
|
||||||
const classMethods = [
|
const classMethods = [
|
||||||
associate,
|
associate,
|
||||||
loadAccountByPodAndUUID,
|
loadAccountByPodAndUUID,
|
||||||
|
loadApplication,
|
||||||
load,
|
load,
|
||||||
loadByUUID,
|
loadByUUID,
|
||||||
loadLocalAccountByName,
|
loadLocalAccountByNameAndPod,
|
||||||
listOwned,
|
listOwned,
|
||||||
listFollowerUrlsForApi,
|
listFollowerUrlsForApi,
|
||||||
listFollowingUrlsForApi
|
listFollowingUrlsForApi,
|
||||||
|
listFollowingForApi,
|
||||||
|
listFollowersForApi
|
||||||
]
|
]
|
||||||
const instanceMethods = [
|
const instanceMethods = [
|
||||||
isOwned,
|
isOwned,
|
||||||
toActivityPubObject,
|
toActivityPubObject,
|
||||||
|
toFormattedJSON,
|
||||||
getFollowerSharedInboxUrls,
|
getFollowerSharedInboxUrls,
|
||||||
getFollowingUrl,
|
getFollowingUrl,
|
||||||
getFollowersUrl,
|
getFollowersUrl,
|
||||||
|
@ -250,6 +260,7 @@ function associate (models) {
|
||||||
name: 'accountId',
|
name: 'accountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
as: 'following',
|
||||||
onDelete: 'cascade'
|
onDelete: 'cascade'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -258,23 +269,29 @@ function associate (models) {
|
||||||
name: 'targetAccountId',
|
name: 'targetAccountId',
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
as: 'followers',
|
||||||
onDelete: 'cascade'
|
onDelete: 'cascade'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterDestroy (account: AccountInstance) {
|
function afterDestroy (account: AccountInstance) {
|
||||||
if (account.isOwned()) {
|
if (account.isOwned()) {
|
||||||
const removeVideoAccountToFriendsParams = {
|
return sendDeleteAccount(account, undefined)
|
||||||
uuid: account.uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: remove account in followers
|
|
||||||
// return removeVideoAccountToFriends(removeVideoAccountToFriendsParams)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toFormattedJSON = function (this: AccountInstance) {
|
||||||
|
const json = {
|
||||||
|
id: this.id,
|
||||||
|
host: this.Pod.host,
|
||||||
|
name: this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
toActivityPubObject = function (this: AccountInstance) {
|
toActivityPubObject = function (this: AccountInstance) {
|
||||||
const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
|
const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
|
||||||
|
|
||||||
|
@ -347,12 +364,85 @@ listOwned = function () {
|
||||||
return Account.findAll(query)
|
return Account.findAll(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
listFollowerUrlsForApi = function (name: string, start: number, count?: number) {
|
listFollowerUrlsForApi = function (id: number, start: number, count?: number) {
|
||||||
return createListFollowForApiQuery('followers', name, start, count)
|
return createListFollowForApiQuery('followers', id, start, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
listFollowingUrlsForApi = function (name: string, start: number, count?: number) {
|
listFollowingUrlsForApi = function (id: number, start: number, count?: number) {
|
||||||
return createListFollowForApiQuery('following', name, start, count)
|
return createListFollowForApiQuery('following', id, start, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
|
||||||
|
const query = {
|
||||||
|
distinct: true,
|
||||||
|
offset: start,
|
||||||
|
limit: count,
|
||||||
|
order: [ getSort(sort) ],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].models.AccountFollow,
|
||||||
|
required: true,
|
||||||
|
as: 'following',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].models.Account,
|
||||||
|
as: 'following',
|
||||||
|
required: true,
|
||||||
|
include: [ Account['sequelize'].models.Pod ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return Account.findAndCountAll(query).then(({ rows, count }) => {
|
||||||
|
return {
|
||||||
|
data: rows,
|
||||||
|
total: count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
|
||||||
|
const query = {
|
||||||
|
distinct: true,
|
||||||
|
offset: start,
|
||||||
|
limit: count,
|
||||||
|
order: [ getSort(sort) ],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].models.AccountFollow,
|
||||||
|
required: true,
|
||||||
|
as: 'followers',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].models.Account,
|
||||||
|
as: 'followers',
|
||||||
|
required: true,
|
||||||
|
include: [ Account['sequelize'].models.Pod ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return Account.findAndCountAll(query).then(({ rows, count }) => {
|
||||||
|
return {
|
||||||
|
data: rows,
|
||||||
|
total: count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
loadApplication = function () {
|
||||||
|
return Account.findOne({
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].model.Application,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
load = function (id: number) {
|
load = function (id: number) {
|
||||||
|
@ -369,14 +459,22 @@ loadByUUID = function (uuid: string) {
|
||||||
return Account.findOne(query)
|
return Account.findOne(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLocalAccountByName = function (name: string) {
|
loadLocalAccountByNameAndPod = function (name: string, host: string) {
|
||||||
const query: Sequelize.FindOptions<AccountAttributes> = {
|
const query: Sequelize.FindOptions<AccountAttributes> = {
|
||||||
where: {
|
where: {
|
||||||
name,
|
name,
|
||||||
userId: {
|
userId: {
|
||||||
[Sequelize.Op.ne]: null
|
[Sequelize.Op.ne]: null
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Account['sequelize'].models.Pod,
|
||||||
|
where: {
|
||||||
|
host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
return Account.findOne(query)
|
return Account.findOne(query)
|
||||||
|
@ -406,7 +504,7 @@ loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Se
|
||||||
|
|
||||||
// ------------------------------ UTILS ------------------------------
|
// ------------------------------ UTILS ------------------------------
|
||||||
|
|
||||||
async function createListFollowForApiQuery (type: 'followers' | 'following', name: string, start: number, count?: number) {
|
async function createListFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
|
||||||
let firstJoin: string
|
let firstJoin: string
|
||||||
let secondJoin: string
|
let secondJoin: string
|
||||||
|
|
||||||
|
@ -424,14 +522,14 @@ async function createListFollowForApiQuery (type: 'followers' | 'following', nam
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
let query = 'SELECT ' + selection + ' FROM "Account" ' +
|
let query = 'SELECT ' + selection + ' FROM "Account" ' +
|
||||||
'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
|
'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
|
||||||
'INNER JOIN "Account" AS "Followers" ON "Followers"."id" = "AccountFollower"."' + secondJoin + '" ' +
|
'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
|
||||||
'WHERE "Account"."name" = \'$name\' ' +
|
'WHERE "Account"."id" = $id ' +
|
||||||
'LIMIT ' + start
|
'LIMIT ' + start
|
||||||
|
|
||||||
if (count !== undefined) query += ', ' + count
|
if (count !== undefined) query += ', ' + count
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
bind: { name },
|
bind: { id },
|
||||||
type: Sequelize.QueryTypes.SELECT
|
type: Sequelize.QueryTypes.SELECT
|
||||||
}
|
}
|
||||||
tasks.push(Account['sequelize'].query(query, options))
|
tasks.push(Account['sequelize'].query(query, options))
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
|
|
||||||
VideoChannelMethods
|
VideoChannelMethods
|
||||||
} from './video-channel-interface'
|
} from './video-channel-interface'
|
||||||
|
import { sendDeleteVideoChannel } from '../../lib/activitypub/send-request'
|
||||||
|
|
||||||
let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes>
|
let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes>
|
||||||
let toFormattedJSON: VideoChannelMethods.ToFormattedJSON
|
let toFormattedJSON: VideoChannelMethods.ToFormattedJSON
|
||||||
|
@ -176,11 +177,7 @@ function associate (models) {
|
||||||
|
|
||||||
function afterDestroy (videoChannel: VideoChannelInstance) {
|
function afterDestroy (videoChannel: VideoChannelInstance) {
|
||||||
if (videoChannel.isOwned()) {
|
if (videoChannel.isOwned()) {
|
||||||
const removeVideoChannelToFriendsParams = {
|
return sendDeleteVideoChannel(videoChannel, undefined)
|
||||||
uuid: videoChannel.uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: send remove event to followers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
import * as Sequelize from 'sequelize'
|
|
||||||
import * as Bluebird from 'bluebird'
|
import * as Bluebird from 'bluebird'
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects/video-torrent-object'
|
||||||
|
import { ResultList } from '../../../shared/models/result-list.model'
|
||||||
|
import { Video as FormattedVideo, VideoDetails as FormattedDetailsVideo } from '../../../shared/models/videos/video.model'
|
||||||
|
|
||||||
import { TagAttributes, TagInstance } from './tag-interface'
|
import { TagAttributes, TagInstance } from './tag-interface'
|
||||||
import { VideoFileAttributes, VideoFileInstance } from './video-file-interface'
|
|
||||||
|
|
||||||
// Don't use barrel, import just what we need
|
|
||||||
import {
|
|
||||||
Video as FormattedVideo,
|
|
||||||
VideoDetails as FormattedDetailsVideo
|
|
||||||
} from '../../../shared/models/videos/video.model'
|
|
||||||
import { RemoteVideoUpdateData } from '../../../shared/models/pods/remote-video/remote-video-update-request.model'
|
|
||||||
import { RemoteVideoCreateData } from '../../../shared/models/pods/remote-video/remote-video-create-request.model'
|
|
||||||
import { ResultList } from '../../../shared/models/result-list.model'
|
|
||||||
import { VideoChannelInstance } from './video-channel-interface'
|
import { VideoChannelInstance } from './video-channel-interface'
|
||||||
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects/video-torrent-object'
|
import { VideoFileAttributes, VideoFileInstance } from './video-file-interface'
|
||||||
|
|
||||||
export namespace VideoMethods {
|
export namespace VideoMethods {
|
||||||
export type GetThumbnailName = (this: VideoInstance) => string
|
export type GetThumbnailName = (this: VideoInstance) => string
|
||||||
|
|
|
@ -45,6 +45,7 @@ import { addMethodsToModel, getSort } from '../utils'
|
||||||
import { TagInstance } from './tag-interface'
|
import { TagInstance } from './tag-interface'
|
||||||
import { VideoFileInstance, VideoFileModel } from './video-file-interface'
|
import { VideoFileInstance, VideoFileModel } from './video-file-interface'
|
||||||
import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
|
import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
|
||||||
|
import { sendDeleteVideo } from '../../lib/activitypub/send-request'
|
||||||
|
|
||||||
const Buffer = safeBuffer.Buffer
|
const Buffer = safeBuffer.Buffer
|
||||||
|
|
||||||
|
@ -363,13 +364,9 @@ function afterDestroy (video: VideoInstance) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if (video.isOwned()) {
|
if (video.isOwned()) {
|
||||||
const removeVideoToFriendsParams = {
|
|
||||||
uuid: video.uuid
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.push(
|
tasks.push(
|
||||||
video.removePreview()
|
video.removePreview(),
|
||||||
// FIXME: remove video for followers
|
sendDeleteVideo(video, undefined)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remove physical files and torrents
|
// Remove physical files and torrents
|
||||||
|
|
|
@ -3,7 +3,6 @@ import * as program from 'commander'
|
||||||
// /!\ Before imports /!\
|
// /!\ Before imports /!\
|
||||||
process.env.NODE_ENV = 'test'
|
process.env.NODE_ENV = 'test'
|
||||||
|
|
||||||
import { REQUESTS_INTERVAL } from '../../initializers/constants'
|
|
||||||
import { Video, VideoRateType, VideoFile } from '../../../shared'
|
import { Video, VideoRateType, VideoFile } from '../../../shared'
|
||||||
import {
|
import {
|
||||||
ServerInfo as DefaultServerInfo,
|
ServerInfo as DefaultServerInfo,
|
||||||
|
@ -137,7 +136,7 @@ async function start () {
|
||||||
initializeRequestsPerServer(servers)
|
initializeRequestsPerServer(servers)
|
||||||
checking = false
|
checking = false
|
||||||
clearInterval(waitingInterval)
|
clearInterval(waitingInterval)
|
||||||
}, REQUESTS_INTERVAL)
|
}, 10000)
|
||||||
}, integrityInterval)
|
}, integrityInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Account {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
host: string
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export type FollowState = 'pending' | 'accepted'
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './account.model'
|
||||||
|
export * from './follow.model'
|
|
@ -4,10 +4,11 @@ import {
|
||||||
} from './objects'
|
} from './objects'
|
||||||
import { ActivityPubSignature } from './activitypub-signature'
|
import { ActivityPubSignature } from './activitypub-signature'
|
||||||
|
|
||||||
export type Activity = ActivityCreate | ActivityAdd | ActivityUpdate | ActivityFlag
|
export type Activity = ActivityCreate | ActivityAdd | ActivityUpdate | ActivityFlag |
|
||||||
|
ActivityDelete | ActivityFollow | ActivityAccept
|
||||||
|
|
||||||
// Flag -> report abuse
|
// Flag -> report abuse
|
||||||
export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag'
|
export type ActivityType = 'Create' | 'Add' | 'Update' | 'Flag' | 'Delete' | 'Follow' | 'Accept'
|
||||||
|
|
||||||
export interface BaseActivity {
|
export interface BaseActivity {
|
||||||
'@context'?: any[]
|
'@context'?: any[]
|
||||||
|
@ -37,3 +38,16 @@ export interface ActivityFlag extends BaseActivity {
|
||||||
type: 'Flag'
|
type: 'Flag'
|
||||||
object: string
|
object: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ActivityDelete extends BaseActivity {
|
||||||
|
type: 'Delete'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActivityFollow extends BaseActivity {
|
||||||
|
type: 'Follow'
|
||||||
|
object: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActivityAccept extends BaseActivity {
|
||||||
|
type: 'Accept'
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from './accounts'
|
||||||
export * from './activitypub'
|
export * from './activitypub'
|
||||||
export * from './pods'
|
export * from './pods'
|
||||||
export * from './users'
|
export * from './users'
|
||||||
|
|
Loading…
Reference in New Issue