// RemoteVideoChannelCreateData,
// RemoteVideoChannelUpdateData,
// RemoteVideoChannelRemoveData,
-// RemoteVideoAuthorRemoveData,
-// RemoteVideoAuthorCreateData
+// RemoteVideoAccountRemoveData,
+// RemoteVideoAccountCreateData
// } from '../../../../shared'
// import { VideoInstance } from '../../../models/video/video-interface'
//
// 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()
//
// 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) {
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'
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) {
videoQuota: CONFIG.USER.VIDEO_QUOTA
})
- await createUserAuthorAndChannel(user)
+ await createUserAccountAndChannel(user)
return res.type('json').status(204).end()
}
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()
asyncMiddleware(listVideoChannels)
)
-videoChannelRouter.get('/authors/:authorId/channels',
- listVideoAuthorChannelsValidator,
- asyncMiddleware(listVideoAuthorChannels)
+videoChannelRouter.get('/accounts/:accountId/channels',
+ listVideoAccountChannelsValidator,
+ asyncMiddleware(listVideoAccountChannels)
)
videoChannelRouter.post('/channels',
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))
}
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)
}
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())
}
}
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,
// 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)
}
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
}
export * from './pods'
export * from './pods'
export * from './users'
+export * from './video-accounts'
export * from './video-channels'
export * from './videos'
--- /dev/null
+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
+}
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 => {
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 => {
// Sortable columns per schema
const SEARCHABLE_COLUMNS = {
- VIDEOS: [ 'name', 'magnetUri', 'host', 'author', 'tags' ]
+ VIDEOS: [ 'name', 'magnetUri', 'host', 'account', 'tags' ]
}
// Sortable columns per schema
OAuthClient?: OAuthClientModel,
OAuthToken?: OAuthTokenModel,
Pod?: PodModel,
- RequestToPod?: RequestToPodModel,
- RequestVideoEvent?: RequestVideoEventModel,
- RequestVideoQadu?: RequestVideoQaduModel,
- Request?: RequestModel,
Tag?: TagModel,
AccountVideoRate?: AccountVideoRateModel,
AccountFollow?: AccountFollowModel,
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 () {
}
const user = db.User.build(userData)
- await createUserAuthorAndChannel(user, validatePassword)
+ await createUserAccountAndChannel(user, validatePassword)
logger.info('Username: ' + username)
logger.info('User password: ' + password)
}
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())
+++ /dev/null
-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
-}
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 })
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
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 })
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
name: videoChannelInfo.name,
description: videoChannelInfo.description,
remote: false,
- authorId: account.id
+ accountId: account.id
}
const videoChannel = db.VideoChannel.build(videoChannelData)
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)
})
}
]
.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()
// ---------------------------------------------------------------------------
export {
- listVideoAuthorChannelsValidator,
+ listVideoAccountChannelsValidator,
videoChannelsAddValidator,
videoChannelsUpdateValidator,
videoChannelsRemoveValidator,
// 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()
}
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)
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
.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()
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()
// 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()
roleLabel: USER_ROLE_LABELS[this.role],
videoQuota: this.videoQuota,
createdAt: this.createdAt,
- author: {
+ account: {
id: this.Account.id,
uuid: this.Account.uuid
}
'(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'
export * from './job'
export * from './oauth'
export * from './pod'
-export * from './request'
export * from './account'
export * from './video'
model: OAuthToken['sequelize'].models.User,
include: [
{
- model: OAuthToken['sequelize'].models.Author,
+ model: OAuthToken['sequelize'].models.Account,
required: true
}
]
model: OAuthToken['sequelize'].models.User,
include: [
{
- model: OAuthToken['sequelize'].models.Author,
+ model: OAuthToken['sequelize'].models.Account,
required: true
}
]
+++ /dev/null
-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>
-}
+++ /dev/null
-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'
+++ /dev/null
-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> {}
+++ /dev/null
-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> {}
+++ /dev/null
-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)
-}
+++ /dev/null
-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> {}
+++ /dev/null
-/*
- 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
-}
+++ /dev/null
-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> {}
+++ /dev/null
-/*
- 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
-}
+++ /dev/null
-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
-}
-export * from './author-interface'
export * from './tag-interface'
export * from './video-abuse-interface'
export * from './video-blacklist-interface'