mirror of https://github.com/Chocobozzz/PeerTube
Remove references to author
parent
0d0e8dd090
commit
38fa206583
|
@ -32,8 +32,8 @@
|
|||
// RemoteVideoChannelCreateData,
|
||||
// RemoteVideoChannelUpdateData,
|
||||
// RemoteVideoChannelRemoveData,
|
||||
// RemoteVideoAuthorRemoveData,
|
||||
// RemoteVideoAuthorCreateData
|
||||
// RemoteVideoAccountRemoveData,
|
||||
// RemoteVideoAccountCreateData
|
||||
// } from '../../../../shared'
|
||||
// import { VideoInstance } from '../../../models/video/video-interface'
|
||||
//
|
||||
|
@ -49,8 +49,8 @@
|
|||
// functionsHash[ENDPOINT_ACTIONS.UPDATE_CHANNEL] = updateRemoteVideoChannelRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.REMOVE_CHANNEL] = removeRemoteVideoChannelRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideoRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.ADD_AUTHOR] = addRemoteVideoAuthorRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.REMOVE_AUTHOR] = removeRemoteVideoAuthorRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.ADD_ACCOUNT] = addRemoteVideoAccountRetryWrapper
|
||||
// functionsHash[ENDPOINT_ACTIONS.REMOVE_ACCOUNT] = removeRemoteVideoAccountRetryWrapper
|
||||
//
|
||||
// const remoteVideosRouter = express.Router()
|
||||
//
|
||||
|
@ -245,24 +245,24 @@
|
|||
// logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid)
|
||||
// }
|
||||
//
|
||||
// async function removeRemoteVideoAuthorRetryWrapper (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
// async function removeRemoteVideoAccountRetryWrapper (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) {
|
||||
// const options = {
|
||||
// arguments: [ authorAttributesToRemove, fromPod ],
|
||||
// errorMessage: 'Cannot remove the remote video author with many retries.'
|
||||
// arguments: [ accountAttributesToRemove, fromPod ],
|
||||
// errorMessage: 'Cannot remove the remote video account with many retries.'
|
||||
// }
|
||||
//
|
||||
// await retryTransactionWrapper(removeRemoteVideoAuthor, options)
|
||||
// await retryTransactionWrapper(removeRemoteVideoAccount, options)
|
||||
// }
|
||||
//
|
||||
// async function removeRemoteVideoAuthor (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
// logger.debug('Removing remote video author "%s".', authorAttributesToRemove.uuid)
|
||||
// async function removeRemoteVideoAccount (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) {
|
||||
// logger.debug('Removing remote video account "%s".', accountAttributesToRemove.uuid)
|
||||
//
|
||||
// await db.sequelize.transaction(async t => {
|
||||
// const videoAuthor = await db.Author.loadAuthorByPodAndUUID(authorAttributesToRemove.uuid, fromPod.id, t)
|
||||
// await videoAuthor.destroy({ transaction: t })
|
||||
// const videoAccount = await db.Account.loadAccountByPodAndUUID(accountAttributesToRemove.uuid, fromPod.id, t)
|
||||
// await videoAccount.destroy({ transaction: t })
|
||||
// })
|
||||
//
|
||||
// logger.info('Remote video author with uuid %s removed.', authorAttributesToRemove.uuid)
|
||||
// logger.info('Remote video account with uuid %s removed.', accountAttributesToRemove.uuid)
|
||||
// }
|
||||
//
|
||||
// async function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
UserRole,
|
||||
UserRight
|
||||
} from '../../../shared'
|
||||
import { createUserAuthorAndChannel } from '../../lib'
|
||||
import { createUserAccountAndChannel } from '../../lib'
|
||||
import { UserInstance } from '../../models'
|
||||
import { videosSortValidator } from '../../middlewares/validators/sort'
|
||||
import { setVideosSort } from '../../middlewares/sort'
|
||||
|
@ -142,9 +142,9 @@ async function createUser (req: express.Request, res: express.Response, next: ex
|
|||
videoQuota: body.videoQuota
|
||||
})
|
||||
|
||||
await createUserAuthorAndChannel(user)
|
||||
await createUserAccountAndChannel(user)
|
||||
|
||||
logger.info('User %s with its channel and author created.', body.username)
|
||||
logger.info('User %s with its channel and account created.', body.username)
|
||||
}
|
||||
|
||||
async function registerUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
|
@ -159,7 +159,7 @@ async function registerUser (req: express.Request, res: express.Response, next:
|
|||
videoQuota: CONFIG.USER.VIDEO_QUOTA
|
||||
})
|
||||
|
||||
await createUserAuthorAndChannel(user)
|
||||
await createUserAccountAndChannel(user)
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,14 +17,14 @@ import {
|
|||
videoChannelsRemoveValidator,
|
||||
videoChannelGetValidator,
|
||||
videoChannelsUpdateValidator,
|
||||
listVideoAuthorChannelsValidator,
|
||||
listVideoAccountChannelsValidator,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
createVideoChannel,
|
||||
updateVideoChannelToFriends
|
||||
} from '../../../lib'
|
||||
import { VideoChannelInstance, AuthorInstance } from '../../../models'
|
||||
import { VideoChannelInstance, AccountInstance } from '../../../models'
|
||||
import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
|
||||
|
||||
const videoChannelRouter = express.Router()
|
||||
|
@ -37,9 +37,9 @@ videoChannelRouter.get('/channels',
|
|||
asyncMiddleware(listVideoChannels)
|
||||
)
|
||||
|
||||
videoChannelRouter.get('/authors/:authorId/channels',
|
||||
listVideoAuthorChannelsValidator,
|
||||
asyncMiddleware(listVideoAuthorChannels)
|
||||
videoChannelRouter.get('/accounts/:accountId/channels',
|
||||
listVideoAccountChannelsValidator,
|
||||
asyncMiddleware(listVideoAccountChannels)
|
||||
)
|
||||
|
||||
videoChannelRouter.post('/channels',
|
||||
|
@ -79,8 +79,8 @@ async function listVideoChannels (req: express.Request, res: express.Response, n
|
|||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
async function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.VideoChannel.listByAuthor(res.locals.author.id)
|
||||
async function listVideoAccountChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.VideoChannel.listByAccount(res.locals.account.id)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
@ -101,11 +101,11 @@ async function addVideoChannelRetryWrapper (req: express.Request, res: express.R
|
|||
|
||||
async function addVideoChannel (req: express.Request, res: express.Response) {
|
||||
const videoChannelInfo: VideoChannelCreate = req.body
|
||||
const author: AuthorInstance = res.locals.oauth.token.User.Author
|
||||
const account: AccountInstance = res.locals.oauth.token.User.Account
|
||||
let videoChannelCreated: VideoChannelInstance
|
||||
|
||||
await db.sequelize.transaction(async t => {
|
||||
videoChannelCreated = await createVideoChannel(videoChannelInfo, author, t)
|
||||
videoChannelCreated = await createVideoChannel(videoChannelInfo, account, t)
|
||||
})
|
||||
|
||||
logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid)
|
||||
|
@ -179,7 +179,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
|
|||
}
|
||||
|
||||
async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id)
|
||||
const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAccountAndVideos(res.locals.videoChannel.id)
|
||||
|
||||
return res.json(videoChannelWithVideos.toFormattedJSON())
|
||||
}
|
||||
|
|
|
@ -395,7 +395,7 @@ async function removeVideo (req: express.Request, res: express.Response) {
|
|||
}
|
||||
|
||||
async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.Video.searchAndPopulateAuthorAndPodAndTags(
|
||||
const resultList = await db.Video.searchAndPopulateAccountAndPodAndTags(
|
||||
req.params.value,
|
||||
req.query.field,
|
||||
req.query.start,
|
||||
|
|
|
@ -110,9 +110,9 @@ async function generateWatchHtmlPage (req: express.Request, res: express.Respons
|
|||
|
||||
// Let Angular application handle errors
|
||||
if (validator.isUUID(videoId, 4)) {
|
||||
videoPromise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(videoId)
|
||||
videoPromise = db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(videoId)
|
||||
} else if (validator.isInt(videoId)) {
|
||||
videoPromise = db.Video.loadAndPopulateAuthorAndPodAndTags(+videoId)
|
||||
videoPromise = db.Video.loadAndPopulateAccountAndPodAndTags(+videoId)
|
||||
} else {
|
||||
return res.sendFile(indexPath)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ function generateOEmbed (req: express.Request, res: express.Response, next: expr
|
|||
width: embedWidth,
|
||||
height: embedHeight,
|
||||
title: video.name,
|
||||
author_name: video.VideoChannel.Author.name,
|
||||
author_name: video.VideoChannel.Account.name,
|
||||
provider_name: 'PeerTube',
|
||||
provider_url: webserverUrl
|
||||
}
|
||||
|
|
|
@ -3,5 +3,6 @@ export * from './misc'
|
|||
export * from './pods'
|
||||
export * from './pods'
|
||||
export * from './users'
|
||||
export * from './video-accounts'
|
||||
export * from './video-channels'
|
||||
export * from './videos'
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import * as Promise from 'bluebird'
|
||||
import * as validator from 'validator'
|
||||
import * as express from 'express'
|
||||
import 'express-validator'
|
||||
|
||||
import { database as db } from '../../initializers'
|
||||
import { AccountInstance } from '../../models'
|
||||
import { logger } from '../logger'
|
||||
|
||||
import { isUserUsernameValid } from './users'
|
||||
|
||||
function isVideoAccountNameValid (value: string) {
|
||||
return isUserUsernameValid(value)
|
||||
}
|
||||
|
||||
function checkVideoAccountExists (id: string, res: express.Response, callback: () => void) {
|
||||
let promise: Promise<AccountInstance>
|
||||
if (validator.isInt(id)) {
|
||||
promise = db.Account.load(+id)
|
||||
} else { // UUID
|
||||
promise = db.Account.loadByUUID(id)
|
||||
}
|
||||
|
||||
promise.then(account => {
|
||||
if (!account) {
|
||||
return res.status(404)
|
||||
.json({ error: 'Video account not found' })
|
||||
.end()
|
||||
}
|
||||
|
||||
res.locals.account = account
|
||||
callback()
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Error in video account request validator.', err)
|
||||
return res.sendStatus(500)
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
checkVideoAccountExists,
|
||||
isVideoAccountNameValid
|
||||
}
|
|
@ -26,9 +26,9 @@ function isVideoChannelUUIDValid (value: string) {
|
|||
function checkVideoChannelExists (id: string, res: express.Response, callback: () => void) {
|
||||
let promise: Promise<VideoChannelInstance>
|
||||
if (validator.isInt(id)) {
|
||||
promise = db.VideoChannel.loadAndPopulateAuthor(+id)
|
||||
promise = db.VideoChannel.loadAndPopulateAccount(+id)
|
||||
} else { // UUID
|
||||
promise = db.VideoChannel.loadByUUIDAndPopulateAuthor(id)
|
||||
promise = db.VideoChannel.loadByUUIDAndPopulateAccount(id)
|
||||
}
|
||||
|
||||
promise.then(videoChannel => {
|
||||
|
|
|
@ -166,9 +166,9 @@ function isVideoFileInfoHashValid (value: string) {
|
|||
function checkVideoExists (id: string, res: express.Response, callback: () => void) {
|
||||
let promise: Promise<VideoInstance>
|
||||
if (validator.isInt(id)) {
|
||||
promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id)
|
||||
promise = db.Video.loadAndPopulateAccountAndPodAndTags(+id)
|
||||
} else { // UUID
|
||||
promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id)
|
||||
promise = db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(id)
|
||||
}
|
||||
|
||||
promise.then(video => {
|
||||
|
|
|
@ -29,7 +29,7 @@ const PAGINATION_COUNT_DEFAULT = 15
|
|||
|
||||
// Sortable columns per schema
|
||||
const SEARCHABLE_COLUMNS = {
|
||||
VIDEOS: [ 'name', 'magnetUri', 'host', 'author', 'tags' ]
|
||||
VIDEOS: [ 'name', 'magnetUri', 'host', 'account', 'tags' ]
|
||||
}
|
||||
|
||||
// Sortable columns per schema
|
||||
|
|
|
@ -44,10 +44,6 @@ const database: {
|
|||
OAuthClient?: OAuthClientModel,
|
||||
OAuthToken?: OAuthTokenModel,
|
||||
Pod?: PodModel,
|
||||
RequestToPod?: RequestToPodModel,
|
||||
RequestVideoEvent?: RequestVideoEventModel,
|
||||
RequestVideoQadu?: RequestVideoQaduModel,
|
||||
Request?: RequestModel,
|
||||
Tag?: TagModel,
|
||||
AccountVideoRate?: AccountVideoRateModel,
|
||||
AccountFollow?: AccountFollowModel,
|
||||
|
|
|
@ -5,7 +5,7 @@ import { database as db } from './database'
|
|||
import { CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants'
|
||||
import { clientsExist, usersExist } from './checker'
|
||||
import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers'
|
||||
import { createUserAuthorAndChannel } from '../lib'
|
||||
import { createUserAccountAndChannel } from '../lib'
|
||||
import { UserRole } from '../../shared'
|
||||
|
||||
async function installApplication () {
|
||||
|
@ -117,7 +117,7 @@ async function createOAuthAdminIfNotExist () {
|
|||
}
|
||||
const user = db.User.build(userData)
|
||||
|
||||
await createUserAuthorAndChannel(user, validatePassword)
|
||||
await createUserAccountAndChannel(user, validatePassword)
|
||||
logger.info('Username: ' + username)
|
||||
logger.info('User password: ' + password)
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class VideosPreviewCache {
|
|||
}
|
||||
|
||||
private async loadPreviews (key: string) {
|
||||
const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(key)
|
||||
const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(key)
|
||||
if (!video) return undefined
|
||||
|
||||
if (video.isOwned()) return join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName())
|
||||
|
|
|
@ -1,567 +0,0 @@
|
|||
import * as request from 'request'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { join } from 'path'
|
||||
|
||||
import { database as db } from '../initializers/database'
|
||||
import {
|
||||
API_VERSION,
|
||||
CONFIG,
|
||||
REQUESTS_IN_PARALLEL,
|
||||
REQUEST_ENDPOINTS,
|
||||
REQUEST_ENDPOINT_ACTIONS,
|
||||
REMOTE_SCHEME,
|
||||
STATIC_PATHS
|
||||
} from '../initializers'
|
||||
import {
|
||||
logger,
|
||||
getMyPublicCert,
|
||||
makeSecureRequest,
|
||||
makeRetryRequest
|
||||
} from '../helpers'
|
||||
import {
|
||||
RequestScheduler,
|
||||
RequestSchedulerOptions,
|
||||
|
||||
RequestVideoQaduScheduler,
|
||||
RequestVideoQaduSchedulerOptions,
|
||||
|
||||
RequestVideoEventScheduler,
|
||||
RequestVideoEventSchedulerOptions
|
||||
} from './request'
|
||||
import {
|
||||
PodInstance,
|
||||
VideoInstance
|
||||
} from '../models'
|
||||
import {
|
||||
RequestEndpoint,
|
||||
RequestVideoEventType,
|
||||
RequestVideoQaduType,
|
||||
RemoteVideoCreateData,
|
||||
RemoteVideoUpdateData,
|
||||
RemoteVideoRemoveData,
|
||||
RemoteVideoReportAbuseData,
|
||||
ResultList,
|
||||
RemoteVideoRequestType,
|
||||
Pod as FormattedPod,
|
||||
RemoteVideoChannelCreateData,
|
||||
RemoteVideoChannelUpdateData,
|
||||
RemoteVideoChannelRemoveData,
|
||||
RemoteVideoAuthorCreateData,
|
||||
RemoteVideoAuthorRemoveData
|
||||
} from '../../shared'
|
||||
|
||||
type QaduParam = { videoId: number, type: RequestVideoQaduType }
|
||||
type EventParam = { videoId: number, type: RequestVideoEventType }
|
||||
|
||||
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
|
||||
|
||||
const requestScheduler = new RequestScheduler()
|
||||
const requestVideoQaduScheduler = new RequestVideoQaduScheduler()
|
||||
const requestVideoEventScheduler = new RequestVideoEventScheduler()
|
||||
|
||||
function activateSchedulers () {
|
||||
requestScheduler.activate()
|
||||
requestVideoQaduScheduler.activate()
|
||||
requestVideoEventScheduler.activate()
|
||||
}
|
||||
|
||||
function addVideoToFriends (videoData: RemoteVideoCreateData, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.ADD_VIDEO,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function updateVideoToFriends (videoData: RemoteVideoUpdateData, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.UPDATE_VIDEO,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function removeVideoToFriends (videoParams: RemoteVideoRemoveData, transaction?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.REMOVE_VIDEO,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoParams,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function addVideoAuthorToFriends (authorData: RemoteVideoAuthorCreateData, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.ADD_AUTHOR,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: authorData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function removeVideoAuthorToFriends (authorData: RemoteVideoAuthorRemoveData, transaction?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.REMOVE_AUTHOR,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: authorData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function addVideoChannelToFriends (videoChannelData: RemoteVideoChannelCreateData, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.ADD_CHANNEL,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoChannelData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function updateVideoChannelToFriends (videoChannelData: RemoteVideoChannelUpdateData, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.UPDATE_CHANNEL,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoChannelData,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function removeVideoChannelToFriends (videoChannelParams: RemoteVideoChannelRemoveData, transaction?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.REMOVE_CHANNEL,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: videoChannelParams,
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function reportAbuseVideoToFriend (reportData: RemoteVideoReportAbuseData, video: VideoInstance, transaction: Sequelize.Transaction) {
|
||||
const options = {
|
||||
type: ENDPOINT_ACTIONS.REPORT_ABUSE,
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: reportData,
|
||||
toIds: [ video.VideoChannel.Author.podId ],
|
||||
transaction
|
||||
}
|
||||
return createRequest(options)
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdateVideoToFriends (qaduParam: QaduParam, transaction?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
videoId: qaduParam.videoId,
|
||||
type: qaduParam.type,
|
||||
transaction
|
||||
}
|
||||
return createVideoQaduRequest(options)
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdatesVideoToFriends (qadusParams: QaduParam[], transaction: Sequelize.Transaction) {
|
||||
const tasks = []
|
||||
|
||||
qadusParams.forEach(qaduParams => {
|
||||
tasks.push(quickAndDirtyUpdateVideoToFriends(qaduParams, transaction))
|
||||
})
|
||||
|
||||
return Promise.all(tasks)
|
||||
}
|
||||
|
||||
function addEventToRemoteVideo (eventParam: EventParam, transaction?: Sequelize.Transaction) {
|
||||
const options = {
|
||||
videoId: eventParam.videoId,
|
||||
type: eventParam.type,
|
||||
transaction
|
||||
}
|
||||
return createVideoEventRequest(options)
|
||||
}
|
||||
|
||||
function addEventsToRemoteVideo (eventsParams: EventParam[], transaction: Sequelize.Transaction) {
|
||||
const tasks = []
|
||||
|
||||
for (const eventParams of eventsParams) {
|
||||
tasks.push(addEventToRemoteVideo(eventParams, transaction))
|
||||
}
|
||||
|
||||
return Promise.all(tasks)
|
||||
}
|
||||
|
||||
async function hasFriends () {
|
||||
const count = await db.Pod.countAll()
|
||||
|
||||
return count !== 0
|
||||
}
|
||||
|
||||
async function makeFriends (hosts: string[]) {
|
||||
const podsScore = {}
|
||||
|
||||
logger.info('Make friends!')
|
||||
const cert = await getMyPublicCert()
|
||||
|
||||
for (const host of hosts) {
|
||||
await computeForeignPodsList(host, podsScore)
|
||||
}
|
||||
|
||||
logger.debug('Pods scores computed.', { podsScore: podsScore })
|
||||
|
||||
const podsList = computeWinningPods(hosts, podsScore)
|
||||
logger.debug('Pods that we keep.', { podsToKeep: podsList })
|
||||
|
||||
return makeRequestsToWinningPods(cert, podsList)
|
||||
}
|
||||
|
||||
async function quitFriends () {
|
||||
// Stop pool requests
|
||||
requestScheduler.deactivate()
|
||||
|
||||
try {
|
||||
await requestScheduler.flush()
|
||||
|
||||
await requestVideoQaduScheduler.flush()
|
||||
|
||||
const pods = await db.Pod.list()
|
||||
const requestParams = {
|
||||
method: 'POST' as 'POST',
|
||||
path: '/api/' + API_VERSION + '/remote/pods/remove',
|
||||
toPod: null
|
||||
}
|
||||
|
||||
// Announce we quit them
|
||||
// We don't care if the request fails
|
||||
// The other pod will exclude us automatically after a while
|
||||
try {
|
||||
await Bluebird.map(pods, pod => {
|
||||
requestParams.toPod = pod
|
||||
|
||||
return makeSecureRequest(requestParams)
|
||||
}, { concurrency: REQUESTS_IN_PARALLEL })
|
||||
} catch (err) { // Don't stop the process
|
||||
logger.error('Some errors while quitting friends.', err)
|
||||
}
|
||||
|
||||
const tasks = []
|
||||
for (const pod of pods) {
|
||||
tasks.push(pod.destroy())
|
||||
}
|
||||
await Promise.all(pods)
|
||||
|
||||
logger.info('Removed all remote videos.')
|
||||
|
||||
requestScheduler.activate()
|
||||
} catch (err) {
|
||||
// Don't forget to re activate the scheduler, even if there was an error
|
||||
requestScheduler.activate()
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function sendOwnedDataToPod (podId: number) {
|
||||
// First send authors
|
||||
await sendOwnedAuthorsToPod(podId)
|
||||
await sendOwnedChannelsToPod(podId)
|
||||
await sendOwnedVideosToPod(podId)
|
||||
}
|
||||
|
||||
async function sendOwnedChannelsToPod (podId: number) {
|
||||
const videoChannels = await db.VideoChannel.listOwned()
|
||||
|
||||
const tasks: Promise<any>[] = []
|
||||
for (const videoChannel of videoChannels) {
|
||||
const remoteVideoChannel = videoChannel.toAddRemoteJSON()
|
||||
const options = {
|
||||
type: 'add-channel' as 'add-channel',
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: remoteVideoChannel,
|
||||
toIds: [ podId ],
|
||||
transaction: null
|
||||
}
|
||||
|
||||
const p = createRequest(options)
|
||||
tasks.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
|
||||
async function sendOwnedAuthorsToPod (podId: number) {
|
||||
const authors = await db.Author.listOwned()
|
||||
const tasks: Promise<any>[] = []
|
||||
|
||||
for (const author of authors) {
|
||||
const remoteAuthor = author.toAddRemoteJSON()
|
||||
const options = {
|
||||
type: 'add-author' as 'add-author',
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: remoteAuthor,
|
||||
toIds: [ podId ],
|
||||
transaction: null
|
||||
}
|
||||
|
||||
const p = createRequest(options)
|
||||
tasks.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
|
||||
async function sendOwnedVideosToPod (podId: number) {
|
||||
const videosList = await db.Video.listOwnedAndPopulateAuthorAndTags()
|
||||
const tasks: Bluebird<any>[] = []
|
||||
|
||||
for (const video of videosList) {
|
||||
const promise = video.toAddRemoteJSON()
|
||||
.then(remoteVideo => {
|
||||
const options = {
|
||||
type: 'add-video' as 'add-video',
|
||||
endpoint: REQUEST_ENDPOINTS.VIDEOS,
|
||||
data: remoteVideo,
|
||||
toIds: [ podId ],
|
||||
transaction: null
|
||||
}
|
||||
return createRequest(options)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot convert video to remote.', err)
|
||||
// Don't break the process
|
||||
return undefined
|
||||
})
|
||||
|
||||
tasks.push(promise)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
|
||||
function fetchRemotePreview (video: VideoInstance) {
|
||||
const host = video.VideoChannel.Author.Pod.host
|
||||
const path = join(STATIC_PATHS.PREVIEWS, video.getPreviewName())
|
||||
|
||||
return request.get(REMOTE_SCHEME.HTTP + '://' + host + path)
|
||||
}
|
||||
|
||||
function fetchRemoteDescription (video: VideoInstance) {
|
||||
const host = video.VideoChannel.Author.Pod.host
|
||||
const path = video.getDescriptionPath()
|
||||
|
||||
const requestOptions = {
|
||||
url: REMOTE_SCHEME.HTTP + '://' + host + path,
|
||||
json: true
|
||||
}
|
||||
|
||||
return new Promise<string>((res, rej) => {
|
||||
request.get(requestOptions, (err, response, body) => {
|
||||
if (err) return rej(err)
|
||||
|
||||
return res(body.description ? body.description : '')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function removeFriend (pod: PodInstance) {
|
||||
const requestParams = {
|
||||
method: 'POST' as 'POST',
|
||||
path: '/api/' + API_VERSION + '/remote/pods/remove',
|
||||
toPod: pod
|
||||
}
|
||||
|
||||
try {
|
||||
await makeSecureRequest(requestParams)
|
||||
} catch (err) {
|
||||
logger.warn('Cannot notify friends %s we are quitting him.', pod.host, err)
|
||||
}
|
||||
|
||||
try {
|
||||
await pod.destroy()
|
||||
|
||||
logger.info('Removed friend %s.', pod.host)
|
||||
} catch (err) {
|
||||
logger.error('Cannot destroy friend %s.', pod.host, err)
|
||||
}
|
||||
}
|
||||
|
||||
function getRequestScheduler () {
|
||||
return requestScheduler
|
||||
}
|
||||
|
||||
function getRequestVideoQaduScheduler () {
|
||||
return requestVideoQaduScheduler
|
||||
}
|
||||
|
||||
function getRequestVideoEventScheduler () {
|
||||
return requestVideoEventScheduler
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
activateSchedulers,
|
||||
addVideoToFriends,
|
||||
removeVideoAuthorToFriends,
|
||||
updateVideoToFriends,
|
||||
addVideoAuthorToFriends,
|
||||
reportAbuseVideoToFriend,
|
||||
quickAndDirtyUpdateVideoToFriends,
|
||||
quickAndDirtyUpdatesVideoToFriends,
|
||||
addEventToRemoteVideo,
|
||||
addEventsToRemoteVideo,
|
||||
hasFriends,
|
||||
makeFriends,
|
||||
quitFriends,
|
||||
removeFriend,
|
||||
removeVideoToFriends,
|
||||
sendOwnedDataToPod,
|
||||
getRequestScheduler,
|
||||
getRequestVideoQaduScheduler,
|
||||
getRequestVideoEventScheduler,
|
||||
fetchRemotePreview,
|
||||
addVideoChannelToFriends,
|
||||
fetchRemoteDescription,
|
||||
updateVideoChannelToFriends,
|
||||
removeVideoChannelToFriends
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function computeForeignPodsList (host: string, podsScore: { [ host: string ]: number }) {
|
||||
const result = await getForeignPodsList(host)
|
||||
const foreignPodsList: { host: string }[] = result.data
|
||||
|
||||
// Let's give 1 point to the pod we ask the friends list
|
||||
foreignPodsList.push({ host })
|
||||
|
||||
for (const foreignPod of foreignPodsList) {
|
||||
const foreignPodHost = foreignPod.host
|
||||
|
||||
if (podsScore[foreignPodHost]) podsScore[foreignPodHost]++
|
||||
else podsScore[foreignPodHost] = 1
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function computeWinningPods (hosts: string[], podsScore: { [ host: string ]: number }) {
|
||||
// Build the list of pods to add
|
||||
// Only add a pod if it exists in more than a half base pods
|
||||
const podsList = []
|
||||
const baseScore = hosts.length / 2
|
||||
|
||||
for (const podHost of Object.keys(podsScore)) {
|
||||
// If the pod is not me and with a good score we add it
|
||||
if (isMe(podHost) === false && podsScore[podHost] > baseScore) {
|
||||
podsList.push({ host: podHost })
|
||||
}
|
||||
}
|
||||
|
||||
return podsList
|
||||
}
|
||||
|
||||
function getForeignPodsList (host: string) {
|
||||
return new Promise< ResultList<FormattedPod> >((res, rej) => {
|
||||
const path = '/api/' + API_VERSION + '/remote/pods/list'
|
||||
|
||||
request.post(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => {
|
||||
if (err) return rej(err)
|
||||
|
||||
try {
|
||||
const json: ResultList<FormattedPod> = JSON.parse(body)
|
||||
return res(json)
|
||||
} catch (err) {
|
||||
return rej(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function makeRequestsToWinningPods (cert: string, podsList: PodInstance[]) {
|
||||
// Stop pool requests
|
||||
requestScheduler.deactivate()
|
||||
// Flush pool requests
|
||||
requestScheduler.forceSend()
|
||||
|
||||
try {
|
||||
await Bluebird.map(podsList, async pod => {
|
||||
const params = {
|
||||
url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/remote/pods/add',
|
||||
method: 'POST' as 'POST',
|
||||
json: {
|
||||
host: CONFIG.WEBSERVER.HOST,
|
||||
email: CONFIG.ADMIN.EMAIL,
|
||||
publicKey: cert
|
||||
}
|
||||
}
|
||||
|
||||
const { response, body } = await makeRetryRequest(params)
|
||||
const typedBody = body as { cert: string, email: string }
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
const podObj = db.Pod.build({ host: pod.host, publicKey: typedBody.cert, email: typedBody.email })
|
||||
|
||||
let podCreated: PodInstance
|
||||
try {
|
||||
podCreated = await podObj.save()
|
||||
} catch (err) {
|
||||
logger.error('Cannot add friend %s pod.', pod.host, err)
|
||||
}
|
||||
|
||||
// Add our videos to the request scheduler
|
||||
sendOwnedDataToPod(podCreated.id)
|
||||
.catch(err => logger.warn('Cannot send owned data to pod %d.', podCreated.id, err))
|
||||
} else {
|
||||
logger.error('Status not 200 for %s pod.', pod.host)
|
||||
}
|
||||
}, { concurrency: REQUESTS_IN_PARALLEL })
|
||||
|
||||
logger.debug('makeRequestsToWinningPods finished.')
|
||||
|
||||
requestScheduler.activate()
|
||||
} catch (err) {
|
||||
// Final callback, we've ended all the requests
|
||||
// Now we made new friends, we can re activate the pool of requests
|
||||
requestScheduler.activate()
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper that populate "toIds" argument with all our friends if it is not specified
|
||||
type CreateRequestOptions = {
|
||||
type: RemoteVideoRequestType
|
||||
endpoint: RequestEndpoint
|
||||
data: Object
|
||||
toIds?: number[]
|
||||
transaction: Sequelize.Transaction
|
||||
}
|
||||
async function createRequest (options: CreateRequestOptions) {
|
||||
if (options.toIds !== undefined) {
|
||||
await requestScheduler.createRequest(options as RequestSchedulerOptions)
|
||||
return undefined
|
||||
}
|
||||
|
||||
// If the "toIds" pods is not specified, we send the request to all our friends
|
||||
const podIds = await db.Pod.listAllIds(options.transaction)
|
||||
|
||||
const newOptions = Object.assign(options, { toIds: podIds })
|
||||
await requestScheduler.createRequest(newOptions)
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function createVideoQaduRequest (options: RequestVideoQaduSchedulerOptions) {
|
||||
return requestVideoQaduScheduler.createRequest(options)
|
||||
}
|
||||
|
||||
function createVideoEventRequest (options: RequestVideoEventSchedulerOptions) {
|
||||
return requestVideoEventScheduler.createRequest(options)
|
||||
}
|
||||
|
||||
function isMe (host: string) {
|
||||
return host === CONFIG.WEBSERVER.HOST
|
||||
}
|
|
@ -7,7 +7,7 @@ import { addVideoToFriends } from '../../friends'
|
|||
import { JobScheduler } from '../job-scheduler'
|
||||
|
||||
async function process (data: { videoUUID: string }, jobId: number) {
|
||||
const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(data.videoUUID)
|
||||
const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID)
|
||||
// No video, maybe deleted?
|
||||
if (!video) {
|
||||
logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid })
|
||||
|
@ -30,7 +30,7 @@ async function onSuccess (jobId: number, video: VideoInstance) {
|
|||
logger.info('Job %d is a success.', jobId)
|
||||
|
||||
// Maybe the video changed in database, refresh it
|
||||
const videoDatabase = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(video.uuid)
|
||||
const videoDatabase = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(video.uuid)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { VideoInstance } from '../../../models'
|
|||
import { VideoResolution } from '../../../../shared'
|
||||
|
||||
async function process (data: { videoUUID: string, resolution: VideoResolution }, jobId: number) {
|
||||
const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(data.videoUUID)
|
||||
const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID)
|
||||
// No video, maybe deleted?
|
||||
if (!video) {
|
||||
logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid })
|
||||
|
@ -28,7 +28,7 @@ async function onSuccess (jobId: number, video: VideoInstance) {
|
|||
logger.info('Job %d is a success.', jobId)
|
||||
|
||||
// Maybe the video changed in database, refresh it
|
||||
const videoDatabase = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(video.uuid)
|
||||
const videoDatabase = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(video.uuid)
|
||||
// Video does not exist anymore
|
||||
if (!videoDatabase) return undefined
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account
|
|||
name: videoChannelInfo.name,
|
||||
description: videoChannelInfo.description,
|
||||
remote: false,
|
||||
authorId: account.id
|
||||
accountId: account.id
|
||||
}
|
||||
|
||||
const videoChannel = db.VideoChannel.build(videoChannelData)
|
||||
|
|
|
@ -9,19 +9,19 @@ import {
|
|||
isVideoChannelDescriptionValid,
|
||||
isVideoChannelNameValid,
|
||||
checkVideoChannelExists,
|
||||
checkVideoAuthorExists
|
||||
checkVideoAccountExists
|
||||
} from '../../helpers'
|
||||
import { UserInstance } from '../../models'
|
||||
import { UserRight } from '../../../shared'
|
||||
|
||||
const listVideoAuthorChannelsValidator = [
|
||||
param('authorId').custom(isIdOrUUIDValid).withMessage('Should have a valid author id'),
|
||||
const listVideoAccountChannelsValidator = [
|
||||
param('accountId').custom(isIdOrUUIDValid).withMessage('Should have a valid account id'),
|
||||
|
||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
logger.debug('Checking listVideoAuthorChannelsValidator parameters', { parameters: req.body })
|
||||
logger.debug('Checking listVideoAccountChannelsValidator parameters', { parameters: req.body })
|
||||
|
||||
checkErrors(req, res, () => {
|
||||
checkVideoAuthorExists(req.params.authorId, res, next)
|
||||
checkVideoAccountExists(req.params.accountId, res, next)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
@ -54,7 +54,7 @@ const videoChannelsUpdateValidator = [
|
|||
.end()
|
||||
}
|
||||
|
||||
if (res.locals.videoChannel.Author.userId !== res.locals.oauth.token.User.id) {
|
||||
if (res.locals.videoChannel.Account.userId !== res.locals.oauth.token.User.id) {
|
||||
return res.status(403)
|
||||
.json({ error: 'Cannot update video channel of another user' })
|
||||
.end()
|
||||
|
@ -98,7 +98,7 @@ const videoChannelGetValidator = [
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
listVideoAuthorChannelsValidator,
|
||||
listVideoAccountChannelsValidator,
|
||||
videoChannelsAddValidator,
|
||||
videoChannelsUpdateValidator,
|
||||
videoChannelsRemoveValidator,
|
||||
|
@ -119,8 +119,8 @@ function checkUserCanDeleteVideoChannel (res: express.Response, callback: () =>
|
|||
|
||||
// Check if the user can delete the video channel
|
||||
// The user can delete it if s/he is an admin
|
||||
// Or if s/he is the video channel's author
|
||||
if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && res.locals.videoChannel.Author.userId !== user.id) {
|
||||
// Or if s/he is the video channel's account
|
||||
if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && res.locals.videoChannel.Account.userId !== user.id) {
|
||||
return res.status(403)
|
||||
.json({ error: 'Cannot remove video channel of another user' })
|
||||
.end()
|
||||
|
@ -131,7 +131,7 @@ function checkUserCanDeleteVideoChannel (res: express.Response, callback: () =>
|
|||
}
|
||||
|
||||
function checkVideoChannelIsNotTheLastOne (res: express.Response, callback: () => void) {
|
||||
db.VideoChannel.countByAuthor(res.locals.oauth.token.User.Author.id)
|
||||
db.VideoChannel.countByAccount(res.locals.oauth.token.User.Account.id)
|
||||
.then(count => {
|
||||
if (count <= 1) {
|
||||
return res.status(409)
|
||||
|
|
|
@ -48,11 +48,11 @@ const videosAddValidator = [
|
|||
const videoFile: Express.Multer.File = req.files['videofile'][0]
|
||||
const user = res.locals.oauth.token.User
|
||||
|
||||
return db.VideoChannel.loadByIdAndAuthor(req.body.channelId, user.Author.id)
|
||||
return db.VideoChannel.loadByIdAndAccount(req.body.channelId, user.Account.id)
|
||||
.then(videoChannel => {
|
||||
if (!videoChannel) {
|
||||
res.status(400)
|
||||
.json({ error: 'Unknown video video channel for this author.' })
|
||||
.json({ error: 'Unknown video video channel for this account.' })
|
||||
.end()
|
||||
|
||||
return undefined
|
||||
|
@ -131,7 +131,7 @@ const videosUpdateValidator = [
|
|||
.end()
|
||||
}
|
||||
|
||||
if (video.VideoChannel.Author.userId !== res.locals.oauth.token.User.id) {
|
||||
if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) {
|
||||
return res.status(403)
|
||||
.json({ error: 'Cannot update video of another user' })
|
||||
.end()
|
||||
|
@ -163,7 +163,7 @@ const videosGetValidator = [
|
|||
if (video.privacy !== VideoPrivacy.PRIVATE) return next()
|
||||
|
||||
authenticate(req, res, () => {
|
||||
if (video.VideoChannel.Author.userId !== res.locals.oauth.token.User.id) {
|
||||
if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) {
|
||||
return res.status(403)
|
||||
.json({ error: 'Cannot get this private video of another user' })
|
||||
.end()
|
||||
|
@ -256,10 +256,10 @@ function checkUserCanDeleteVideo (userId: number, res: express.Response, callbac
|
|||
|
||||
// Check if the user can delete the video
|
||||
// The user can delete it if s/he is an admin
|
||||
// Or if s/he is the video's author
|
||||
const author = res.locals.video.VideoChannel.Author
|
||||
// Or if s/he is the video's account
|
||||
const account = res.locals.video.VideoChannel.Account
|
||||
const user = res.locals.oauth.token.User
|
||||
if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && author.userId !== user.id) {
|
||||
if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && account.userId !== user.id) {
|
||||
return res.status(403)
|
||||
.json({ error: 'Cannot remove video of another user' })
|
||||
.end()
|
||||
|
|
|
@ -164,7 +164,7 @@ toFormattedJSON = function (this: UserInstance) {
|
|||
roleLabel: USER_ROLE_LABELS[this.role],
|
||||
videoQuota: this.videoQuota,
|
||||
createdAt: this.createdAt,
|
||||
author: {
|
||||
account: {
|
||||
id: this.Account.id,
|
||||
uuid: this.Account.uuid
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ function getOriginalVideoFileTotalFromUser (user: UserInstance) {
|
|||
'(SELECT MAX("VideoFiles"."size") AS "size" FROM "VideoFiles" ' +
|
||||
'INNER JOIN "Videos" ON "VideoFiles"."videoId" = "Videos"."id" ' +
|
||||
'INNER JOIN "VideoChannels" ON "VideoChannels"."id" = "Videos"."channelId" ' +
|
||||
'INNER JOIN "Accounts" ON "VideoChannels"."authorId" = "Accounts"."id" ' +
|
||||
'INNER JOIN "Accounts" ON "VideoChannels"."accountId" = "Accounts"."id" ' +
|
||||
'INNER JOIN "Users" ON "Accounts"."userId" = "Users"."id" ' +
|
||||
'WHERE "Users"."id" = $userId GROUP BY "Videos"."id") t'
|
||||
|
||||
|
|
|
@ -2,6 +2,5 @@ export * from './application'
|
|||
export * from './job'
|
||||
export * from './oauth'
|
||||
export * from './pod'
|
||||
export * from './request'
|
||||
export * from './account'
|
||||
export * from './video'
|
||||
|
|
|
@ -131,7 +131,7 @@ getByTokenAndPopulateUser = function (bearerToken: string) {
|
|||
model: OAuthToken['sequelize'].models.User,
|
||||
include: [
|
||||
{
|
||||
model: OAuthToken['sequelize'].models.Author,
|
||||
model: OAuthToken['sequelize'].models.Account,
|
||||
required: true
|
||||
}
|
||||
]
|
||||
|
@ -156,7 +156,7 @@ getByRefreshTokenAndPopulateUser = function (refreshToken: string) {
|
|||
model: OAuthToken['sequelize'].models.User,
|
||||
include: [
|
||||
{
|
||||
model: OAuthToken['sequelize'].models.Author,
|
||||
model: OAuthToken['sequelize'].models.Account,
|
||||
required: true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import * as Promise from 'bluebird'
|
||||
|
||||
export interface AbstractRequestClass <T> {
|
||||
countTotalRequests: () => Promise<number>
|
||||
listWithLimitAndRandom: (limitPods: number, limitRequestsPerPod: number) => Promise<T>
|
||||
removeWithEmptyTo: () => Promise<number>
|
||||
removeAll: () => Promise<void>
|
||||
}
|
||||
|
||||
export interface AbstractRequestToPodClass {
|
||||
removeByRequestIdsAndPod: (ids: number[], podId: number) => Promise<number>
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export * from './abstract-request-interface'
|
||||
export * from './request-interface'
|
||||
export * from './request-to-pod-interface'
|
||||
export * from './request-video-event-interface'
|
||||
export * from './request-video-qadu-interface'
|
|
@ -1,46 +0,0 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { AbstractRequestClass } from './abstract-request-interface'
|
||||
import { PodInstance, PodAttributes } from '../pod/pod-interface'
|
||||
import { RequestEndpoint } from '../../../shared/models/request-scheduler.model'
|
||||
|
||||
export type RequestsGrouped = {
|
||||
[ podId: number ]: {
|
||||
request: RequestInstance,
|
||||
pod: PodInstance
|
||||
}[]
|
||||
}
|
||||
|
||||
export namespace RequestMethods {
|
||||
export type CountTotalRequests = () => Promise<number>
|
||||
|
||||
export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsGrouped>
|
||||
|
||||
export type RemoveWithEmptyTo = () => Promise<number>
|
||||
|
||||
export type RemoveAll = () => Promise<void>
|
||||
}
|
||||
|
||||
export interface RequestClass extends AbstractRequestClass<RequestsGrouped> {
|
||||
countTotalRequests: RequestMethods.CountTotalRequests
|
||||
listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom
|
||||
removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo
|
||||
removeAll: RequestMethods.RemoveAll
|
||||
}
|
||||
|
||||
export interface RequestAttributes {
|
||||
request: object
|
||||
endpoint: RequestEndpoint
|
||||
}
|
||||
|
||||
export interface RequestInstance extends RequestClass, RequestAttributes, Sequelize.Instance<RequestAttributes> {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
|
||||
setPods: Sequelize.HasManySetAssociationsMixin<PodAttributes, number>
|
||||
Pods: PodInstance[]
|
||||
}
|
||||
|
||||
export interface RequestModel extends RequestClass, Sequelize.Model<RequestInstance, RequestAttributes> {}
|
|
@ -1,23 +0,0 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { AbstractRequestToPodClass } from './abstract-request-interface'
|
||||
|
||||
export namespace RequestToPodMethods {
|
||||
export type RemoveByRequestIdsAndPod = (requestsIds: number[], podId: number) => Promise<number>
|
||||
}
|
||||
|
||||
export interface RequestToPodClass extends AbstractRequestToPodClass {
|
||||
removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod
|
||||
}
|
||||
|
||||
export interface RequestToPodAttributes {
|
||||
}
|
||||
|
||||
export interface RequestToPodInstance extends RequestToPodClass, RequestToPodAttributes, Sequelize.Instance<RequestToPodAttributes> {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
export interface RequestToPodModel extends RequestToPodClass, Sequelize.Model<RequestToPodInstance, RequestToPodAttributes> {}
|
|
@ -1,51 +0,0 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import {
|
||||
RequestToPodInstance,
|
||||
RequestToPodAttributes,
|
||||
|
||||
RequestToPodMethods
|
||||
} from './request-to-pod-interface'
|
||||
|
||||
let RequestToPod: Sequelize.Model<RequestToPodInstance, RequestToPodAttributes>
|
||||
let removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
RequestToPod = sequelize.define<RequestToPodInstance, RequestToPodAttributes>('RequestToPod', {}, {
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'requestId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'podId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'requestId', 'podId' ],
|
||||
unique: true
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const classMethods = [
|
||||
removeByRequestIdsAndPod
|
||||
]
|
||||
addMethodsToModel(RequestToPod, classMethods)
|
||||
|
||||
return RequestToPod
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
removeByRequestIdsAndPod = function (requestsIds: number[], podId: number) {
|
||||
const query = {
|
||||
where: {
|
||||
requestId: {
|
||||
[Sequelize.Op.in]: requestsIds
|
||||
},
|
||||
podId: podId
|
||||
}
|
||||
}
|
||||
|
||||
return RequestToPod.destroy(query)
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface'
|
||||
import { VideoInstance } from '../video/video-interface'
|
||||
import { PodInstance } from '../pod/pod-interface'
|
||||
|
||||
import { RequestVideoEventType } from '../../../shared/models/request-scheduler.model'
|
||||
|
||||
export type RequestsVideoEventGrouped = {
|
||||
[ podId: number ]: {
|
||||
id: number
|
||||
type: RequestVideoEventType
|
||||
count: number
|
||||
video: VideoInstance
|
||||
pod: PodInstance
|
||||
}[]
|
||||
}
|
||||
|
||||
export namespace RequestVideoEventMethods {
|
||||
export type CountTotalRequests = () => Promise<number>
|
||||
|
||||
export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsVideoEventGrouped>
|
||||
|
||||
export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise<number>
|
||||
|
||||
export type RemoveAll = () => Promise<void>
|
||||
}
|
||||
|
||||
export interface RequestVideoEventClass extends AbstractRequestClass<RequestsVideoEventGrouped>, AbstractRequestToPodClass {
|
||||
countTotalRequests: RequestVideoEventMethods.CountTotalRequests
|
||||
listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom
|
||||
removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod
|
||||
removeAll: RequestVideoEventMethods.RemoveAll
|
||||
}
|
||||
|
||||
export interface RequestVideoEventAttributes {
|
||||
type: RequestVideoEventType
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface RequestVideoEventInstance
|
||||
extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance<RequestVideoEventAttributes> {
|
||||
id: number
|
||||
|
||||
Video: VideoInstance
|
||||
}
|
||||
|
||||
export interface RequestVideoEventModel
|
||||
extends RequestVideoEventClass, Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> {}
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
Request Video events (likes, dislikes, views...)
|
||||
*/
|
||||
|
||||
import { values } from 'lodash'
|
||||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { REQUEST_VIDEO_EVENT_TYPES } from '../../initializers'
|
||||
import { isVideoEventCountValid } from '../../helpers'
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import {
|
||||
RequestVideoEventInstance,
|
||||
RequestVideoEventAttributes,
|
||||
|
||||
RequestVideoEventMethods,
|
||||
RequestsVideoEventGrouped
|
||||
} from './request-video-event-interface'
|
||||
|
||||
let RequestVideoEvent: Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes>
|
||||
let countTotalRequests: RequestVideoEventMethods.CountTotalRequests
|
||||
let listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom
|
||||
let removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod
|
||||
let removeAll: RequestVideoEventMethods.RemoveAll
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
RequestVideoEvent = sequelize.define<RequestVideoEventInstance, RequestVideoEventAttributes>('RequestVideoEvent',
|
||||
{
|
||||
type: {
|
||||
type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)),
|
||||
allowNull: false
|
||||
},
|
||||
count: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
countValid: function (value) {
|
||||
const res = isVideoEventCountValid(value)
|
||||
if (res === false) throw new Error('Video event count is not valid.')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
updatedAt: false,
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'videoId' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
const classMethods = [
|
||||
associate,
|
||||
|
||||
listWithLimitAndRandom,
|
||||
countTotalRequests,
|
||||
removeAll,
|
||||
removeByRequestIdsAndPod
|
||||
]
|
||||
addMethodsToModel(RequestVideoEvent, classMethods)
|
||||
|
||||
return RequestVideoEvent
|
||||
}
|
||||
|
||||
// ------------------------------ STATICS ------------------------------
|
||||
|
||||
function associate (models) {
|
||||
RequestVideoEvent.belongsTo(models.Video, {
|
||||
foreignKey: {
|
||||
name: 'videoId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
}
|
||||
|
||||
countTotalRequests = function () {
|
||||
const query = {}
|
||||
return RequestVideoEvent.count(query)
|
||||
}
|
||||
|
||||
listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) {
|
||||
const Pod = db.Pod
|
||||
|
||||
// We make a join between videos and authors to find the podId of our video event requests
|
||||
const podJoins = 'INNER JOIN "VideoChannels" ON "VideoChannels"."authorId" = "Authors"."id" ' +
|
||||
'INNER JOIN "Videos" ON "Videos"."channelId" = "VideoChannels"."id" ' +
|
||||
'INNER JOIN "RequestVideoEvents" ON "RequestVideoEvents"."videoId" = "Videos"."id"'
|
||||
|
||||
return Pod.listRandomPodIdsWithRequest(limitPods, 'Authors', podJoins).then(podIds => {
|
||||
// We don't have friends that have requests
|
||||
if (podIds.length === 0) return []
|
||||
|
||||
const query = {
|
||||
order: [
|
||||
[ 'id', 'ASC' ]
|
||||
],
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.Video,
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.VideoChannel,
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.Author,
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.Pod,
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: podIds
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return RequestVideoEvent.findAll(query).then(requests => {
|
||||
const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod)
|
||||
return requestsGrouped
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
removeByRequestIdsAndPod = function (ids: number[], podId: number) {
|
||||
const query = {
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: ids
|
||||
}
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.Video,
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.VideoChannel,
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoEvent['sequelize'].models.Author,
|
||||
where: {
|
||||
podId
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return RequestVideoEvent.destroy(query)
|
||||
}
|
||||
|
||||
removeAll = function () {
|
||||
// Delete all requests
|
||||
return RequestVideoEvent.truncate({ cascade: true })
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function groupAndTruncateRequests (events: RequestVideoEventInstance[], limitRequestsPerPod: number) {
|
||||
const eventsGrouped: RequestsVideoEventGrouped = {}
|
||||
|
||||
events.forEach(event => {
|
||||
const pod = event.Video.VideoChannel.Author.Pod
|
||||
|
||||
if (!eventsGrouped[pod.id]) eventsGrouped[pod.id] = []
|
||||
|
||||
if (eventsGrouped[pod.id].length < limitRequestsPerPod) {
|
||||
eventsGrouped[pod.id].push({
|
||||
id: event.id,
|
||||
type: event.type,
|
||||
count: event.count,
|
||||
video: event.Video,
|
||||
pod
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return eventsGrouped
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface'
|
||||
import { VideoInstance } from '../video/video-interface'
|
||||
import { PodInstance } from '../pod/pod-interface'
|
||||
|
||||
import { RequestVideoQaduType } from '../../../shared/models/request-scheduler.model'
|
||||
|
||||
export type RequestsVideoQaduGrouped = {
|
||||
[ podId: number ]: {
|
||||
request: RequestVideoQaduInstance
|
||||
video: VideoInstance
|
||||
pod: PodInstance
|
||||
}
|
||||
}
|
||||
|
||||
export namespace RequestVideoQaduMethods {
|
||||
export type CountTotalRequests = () => Promise<number>
|
||||
|
||||
export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsVideoQaduGrouped>
|
||||
|
||||
export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise<number>
|
||||
|
||||
export type RemoveAll = () => Promise<void>
|
||||
}
|
||||
|
||||
export interface RequestVideoQaduClass extends AbstractRequestClass<RequestsVideoQaduGrouped>, AbstractRequestToPodClass {
|
||||
countTotalRequests: RequestVideoQaduMethods.CountTotalRequests
|
||||
listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom
|
||||
removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod
|
||||
removeAll: RequestVideoQaduMethods.RemoveAll
|
||||
}
|
||||
|
||||
export interface RequestVideoQaduAttributes {
|
||||
type: RequestVideoQaduType
|
||||
}
|
||||
|
||||
export interface RequestVideoQaduInstance
|
||||
extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance<RequestVideoQaduAttributes> {
|
||||
id: number
|
||||
|
||||
Pod: PodInstance
|
||||
Video: VideoInstance
|
||||
}
|
||||
|
||||
export interface RequestVideoQaduModel
|
||||
extends RequestVideoQaduClass, Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> {}
|
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
Request Video for Quick And Dirty Updates like:
|
||||
- views
|
||||
- likes
|
||||
- dislikes
|
||||
|
||||
We can't put it in the same system than basic requests for efficiency.
|
||||
Moreover we don't want to slow down the basic requests with a lot of views/likes/dislikes requests.
|
||||
So we put it an independant request scheduler.
|
||||
*/
|
||||
|
||||
import { values } from 'lodash'
|
||||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { REQUEST_VIDEO_QADU_TYPES } from '../../initializers'
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import {
|
||||
RequestVideoQaduInstance,
|
||||
RequestVideoQaduAttributes,
|
||||
|
||||
RequestVideoQaduMethods
|
||||
} from './request-video-qadu-interface'
|
||||
|
||||
let RequestVideoQadu: Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes>
|
||||
let countTotalRequests: RequestVideoQaduMethods.CountTotalRequests
|
||||
let listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom
|
||||
let removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod
|
||||
let removeAll: RequestVideoQaduMethods.RemoveAll
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
RequestVideoQadu = sequelize.define<RequestVideoQaduInstance, RequestVideoQaduAttributes>('RequestVideoQadu',
|
||||
{
|
||||
type: {
|
||||
type: DataTypes.ENUM(values(REQUEST_VIDEO_QADU_TYPES)),
|
||||
allowNull: false
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: false,
|
||||
indexes: [
|
||||
{
|
||||
fields: [ 'podId' ]
|
||||
},
|
||||
{
|
||||
fields: [ 'videoId' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
const classMethods = [
|
||||
associate,
|
||||
|
||||
listWithLimitAndRandom,
|
||||
countTotalRequests,
|
||||
removeAll,
|
||||
removeByRequestIdsAndPod
|
||||
]
|
||||
addMethodsToModel(RequestVideoQadu, classMethods)
|
||||
|
||||
return RequestVideoQadu
|
||||
}
|
||||
|
||||
// ------------------------------ STATICS ------------------------------
|
||||
|
||||
function associate (models) {
|
||||
RequestVideoQadu.belongsTo(models.Pod, {
|
||||
foreignKey: {
|
||||
name: 'podId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
|
||||
RequestVideoQadu.belongsTo(models.Video, {
|
||||
foreignKey: {
|
||||
name: 'videoId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
}
|
||||
|
||||
countTotalRequests = function () {
|
||||
const query = {}
|
||||
return RequestVideoQadu.count(query)
|
||||
}
|
||||
|
||||
listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) {
|
||||
const Pod = db.Pod
|
||||
const tableJoin = ''
|
||||
|
||||
return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', tableJoin).then(podIds => {
|
||||
// We don't have friends that have requests
|
||||
if (podIds.length === 0) return []
|
||||
|
||||
const query = {
|
||||
include: [
|
||||
{
|
||||
model: RequestVideoQadu['sequelize'].models.Pod,
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: podIds
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
model: RequestVideoQadu['sequelize'].models.Video
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return RequestVideoQadu.findAll(query).then(requests => {
|
||||
const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod)
|
||||
return requestsGrouped
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
removeByRequestIdsAndPod = function (ids: number[], podId: number) {
|
||||
const query = {
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: ids
|
||||
},
|
||||
podId
|
||||
}
|
||||
}
|
||||
|
||||
return RequestVideoQadu.destroy(query)
|
||||
}
|
||||
|
||||
removeAll = function () {
|
||||
// Delete all requests
|
||||
return RequestVideoQadu.truncate({ cascade: true })
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function groupAndTruncateRequests (requests: RequestVideoQaduInstance[], limitRequestsPerPod: number) {
|
||||
const requestsGrouped = {}
|
||||
|
||||
requests.forEach(request => {
|
||||
const pod = request.Pod
|
||||
|
||||
if (!requestsGrouped[pod.id]) requestsGrouped[pod.id] = []
|
||||
|
||||
if (requestsGrouped[pod.id].length < limitRequestsPerPod) {
|
||||
requestsGrouped[pod.id].push({
|
||||
request: request,
|
||||
video: request.Video,
|
||||
pod
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return requestsGrouped
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
import { values } from 'lodash'
|
||||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { REQUEST_ENDPOINTS } from '../../initializers'
|
||||
import { addMethodsToModel } from '../utils'
|
||||
import {
|
||||
RequestInstance,
|
||||
RequestAttributes,
|
||||
|
||||
RequestMethods,
|
||||
RequestsGrouped
|
||||
} from './request-interface'
|
||||
|
||||
let Request: Sequelize.Model<RequestInstance, RequestAttributes>
|
||||
let countTotalRequests: RequestMethods.CountTotalRequests
|
||||
let listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom
|
||||
let removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo
|
||||
let removeAll: RequestMethods.RemoveAll
|
||||
|
||||
export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
|
||||
Request = sequelize.define<RequestInstance, RequestAttributes>('Request',
|
||||
{
|
||||
request: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false
|
||||
},
|
||||
endpoint: {
|
||||
type: DataTypes.ENUM(values(REQUEST_ENDPOINTS)),
|
||||
allowNull: false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const classMethods = [
|
||||
associate,
|
||||
|
||||
listWithLimitAndRandom,
|
||||
|
||||
countTotalRequests,
|
||||
removeAll,
|
||||
removeWithEmptyTo
|
||||
]
|
||||
addMethodsToModel(Request, classMethods)
|
||||
|
||||
return Request
|
||||
}
|
||||
|
||||
// ------------------------------ STATICS ------------------------------
|
||||
|
||||
function associate (models) {
|
||||
Request.belongsToMany(models.Pod, {
|
||||
foreignKey: {
|
||||
name: 'requestId',
|
||||
allowNull: false
|
||||
},
|
||||
through: models.RequestToPod,
|
||||
onDelete: 'CASCADE'
|
||||
})
|
||||
}
|
||||
|
||||
countTotalRequests = function () {
|
||||
// We need to include Pod because there are no cascade delete when a pod is removed
|
||||
// So we could count requests that do not have existing pod anymore
|
||||
const query = {
|
||||
include: [ Request['sequelize'].models.Pod ]
|
||||
}
|
||||
|
||||
return Request.count(query)
|
||||
}
|
||||
|
||||
listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) {
|
||||
const Pod = db.Pod
|
||||
const tableJoin = ''
|
||||
|
||||
return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', tableJoin).then(podIds => {
|
||||
// We don't have friends that have requests
|
||||
if (podIds.length === 0) return []
|
||||
|
||||
// The first x requests of these pods
|
||||
// It is very important to sort by id ASC to keep the requests order!
|
||||
const query = {
|
||||
order: [
|
||||
[ 'id', 'ASC' ]
|
||||
],
|
||||
include: [
|
||||
{
|
||||
model: Request['sequelize'].models.Pod,
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.in]: podIds
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return Request.findAll(query).then(requests => {
|
||||
|
||||
const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod)
|
||||
return requestsGrouped
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
removeAll = function () {
|
||||
// Delete all requests
|
||||
return Request.truncate({ cascade: true })
|
||||
}
|
||||
|
||||
removeWithEmptyTo = function () {
|
||||
const query = {
|
||||
where: {
|
||||
id: {
|
||||
[Sequelize.Op.notIn]: [
|
||||
Sequelize.literal('SELECT "requestId" FROM "RequestToPods"')
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Request.destroy(query)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function groupAndTruncateRequests (requests: RequestInstance[], limitRequestsPerPod: number) {
|
||||
const requestsGrouped: RequestsGrouped = {}
|
||||
|
||||
requests.forEach(request => {
|
||||
request.Pods.forEach(pod => {
|
||||
if (!requestsGrouped[pod.id]) requestsGrouped[pod.id] = []
|
||||
|
||||
if (requestsGrouped[pod.id].length < limitRequestsPerPod) {
|
||||
requestsGrouped[pod.id].push({
|
||||
request,
|
||||
pod
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return requestsGrouped
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
export * from './author-interface'
|
||||
export * from './tag-interface'
|
||||
export * from './video-abuse-interface'
|
||||
export * from './video-blacklist-interface'
|
||||
|
|
Loading…
Reference in New Issue