From 6fcd19ba737f1f5614a56c6925adb882dea43b8d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 5 Jul 2017 13:26:25 +0200 Subject: Move to promises Closes https://github.com/Chocobozzz/PeerTube/issues/74 --- server/models/application/application-interface.ts | 10 +- server/models/application/application.ts | 13 +- server/models/job/job-interface.ts | 4 +- server/models/job/job.ts | 5 +- server/models/oauth/oauth-client-interface.ts | 9 +- server/models/oauth/oauth-client.ts | 9 +- server/models/oauth/oauth-token-interface.ts | 11 +- server/models/oauth/oauth-token.ts | 5 +- server/models/pod/pod-interface.ts | 28 +- server/models/pod/pod.ts | 115 +++---- .../models/request/abstract-request-interface.ts | 12 + server/models/request/index.ts | 1 + server/models/request/request-interface.ts | 16 +- server/models/request/request-to-pod-interface.ts | 8 +- server/models/request/request-to-pod.ts | 7 +- .../request/request-video-event-interface.ts | 22 +- server/models/request/request-video-event.ts | 27 +- .../models/request/request-video-qadu-interface.ts | 22 +- server/models/request/request-video-qadu.ts | 27 +- server/models/request/request.ts | 28 +- server/models/user/user-interface.ts | 26 +- server/models/user/user-video-rate-interface.ts | 4 +- server/models/user/user-video-rate.ts | 5 +- server/models/user/user.ts | 47 ++- server/models/video/author-interface.ts | 9 +- server/models/video/author.ts | 23 +- server/models/video/tag-interface.ts | 4 +- server/models/video/tag.ts | 24 +- server/models/video/video-abuse-interface.ts | 5 +- server/models/video/video-abuse.ts | 11 +- server/models/video/video-blacklist-interface.ts | 24 +- server/models/video/video-blacklist.ts | 28 +- server/models/video/video-interface.ts | 70 ++-- server/models/video/video-tag.ts | 6 +- server/models/video/video.ts | 369 +++++++++------------ 35 files changed, 445 insertions(+), 589 deletions(-) create mode 100644 server/models/request/abstract-request-interface.ts (limited to 'server/models') diff --git a/server/models/application/application-interface.ts b/server/models/application/application-interface.ts index c03513db1..33254ba2d 100644 --- a/server/models/application/application-interface.ts +++ b/server/models/application/application-interface.ts @@ -1,11 +1,13 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' export namespace ApplicationMethods { - export type LoadMigrationVersionCallback = (err: Error, version: number) => void - export type LoadMigrationVersion = (callback: LoadMigrationVersionCallback) => void + export type LoadMigrationVersion = () => Promise - export type UpdateMigrationVersionCallback = (err: Error, applicationInstance: ApplicationAttributes) => void - export type UpdateMigrationVersion = (newVersion: number, transaction: Sequelize.Transaction, callback: UpdateMigrationVersionCallback) => void + export type UpdateMigrationVersion = ( + newVersion: number, + transaction: Sequelize.Transaction + ) => Promise<[ number, ApplicationInstance[] ]> } export interface ApplicationClass { diff --git a/server/models/application/application.ts b/server/models/application/application.ts index 0e9a1ebb3..507b7a843 100644 --- a/server/models/application/application.ts +++ b/server/models/application/application.ts @@ -2,7 +2,6 @@ import * as Sequelize from 'sequelize' import { addMethodsToModel } from '../utils' import { - ApplicationClass, ApplicationAttributes, ApplicationInstance, @@ -35,23 +34,19 @@ export default function defineApplication (sequelize: Sequelize.Sequelize, DataT // --------------------------------------------------------------------------- -loadMigrationVersion = function (callback: ApplicationMethods.LoadMigrationVersionCallback) { +loadMigrationVersion = function () { const query = { attributes: [ 'migrationVersion' ] } - return Application.findOne(query).asCallback(function (err, data) { - const version = data ? data.migrationVersion : null - - return callback(err, version) - }) + return Application.findOne(query).then(data => data ? data.migrationVersion : null) } -updateMigrationVersion = function (newVersion: number, transaction: Sequelize.Transaction, callback: ApplicationMethods.UpdateMigrationVersionCallback) { +updateMigrationVersion = function (newVersion: number, transaction: Sequelize.Transaction) { const options: Sequelize.UpdateOptions = { where: {}, transaction: transaction } - return Application.update({ migrationVersion: newVersion }, options).asCallback(callback) + return Application.update({ migrationVersion: newVersion }, options) } diff --git a/server/models/job/job-interface.ts b/server/models/job/job-interface.ts index 31b377367..ba5622977 100644 --- a/server/models/job/job-interface.ts +++ b/server/models/job/job-interface.ts @@ -1,10 +1,10 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { JobState } from '../../../shared/models/job.model' export namespace JobMethods { - export type ListWithLimitCallback = (err: Error, jobInstances: JobInstance[]) => void - export type ListWithLimit = (limit: number, state: JobState, callback: ListWithLimitCallback) => void + export type ListWithLimit = (limit: number, state: JobState) => Promise } export interface JobClass { diff --git a/server/models/job/job.ts b/server/models/job/job.ts index 38e4e8f30..968f9d71d 100644 --- a/server/models/job/job.ts +++ b/server/models/job/job.ts @@ -5,7 +5,6 @@ import { JOB_STATES } from '../../initializers' import { addMethodsToModel } from '../utils' import { - JobClass, JobInstance, JobAttributes, @@ -49,7 +48,7 @@ export default function defineJob (sequelize: Sequelize.Sequelize, DataTypes: Se // --------------------------------------------------------------------------- -listWithLimit = function (limit: number, state: JobState, callback: JobMethods.ListWithLimitCallback) { +listWithLimit = function (limit: number, state: JobState) { const query = { order: [ [ 'id', 'ASC' ] @@ -60,5 +59,5 @@ listWithLimit = function (limit: number, state: JobState, callback: JobMethods.L } } - return Job.findAll(query).asCallback(callback) + return Job.findAll(query) } diff --git a/server/models/oauth/oauth-client-interface.ts b/server/models/oauth/oauth-client-interface.ts index 3b4325740..3526e4159 100644 --- a/server/models/oauth/oauth-client-interface.ts +++ b/server/models/oauth/oauth-client-interface.ts @@ -1,13 +1,12 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' export namespace OAuthClientMethods { - export type CountTotalCallback = (err: Error, total: number) => void - export type CountTotal = (callback: CountTotalCallback) => void + export type CountTotal = () => Promise - export type LoadFirstClientCallback = (err: Error, client: OAuthClientInstance) => void - export type LoadFirstClient = (callback: LoadFirstClientCallback) => void + export type LoadFirstClient = () => Promise - export type GetByIdAndSecret = (clientId, clientSecret) => void + export type GetByIdAndSecret = (clientId: string, clientSecret: string) => Promise } export interface OAuthClientClass { diff --git a/server/models/oauth/oauth-client.ts b/server/models/oauth/oauth-client.ts index fbc2a3393..9cc68771d 100644 --- a/server/models/oauth/oauth-client.ts +++ b/server/models/oauth/oauth-client.ts @@ -2,7 +2,6 @@ import * as Sequelize from 'sequelize' import { addMethodsToModel } from '../utils' import { - OAuthClientClass, OAuthClientInstance, OAuthClientAttributes, @@ -67,12 +66,12 @@ function associate (models) { }) } -countTotal = function (callback: OAuthClientMethods.CountTotalCallback) { - return OAuthClient.count().asCallback(callback) +countTotal = function () { + return OAuthClient.count() } -loadFirstClient = function (callback: OAuthClientMethods.LoadFirstClientCallback) { - return OAuthClient.findOne().asCallback(callback) +loadFirstClient = function () { + return OAuthClient.findOne() } getByIdAndSecret = function (clientId: string, clientSecret: string) { diff --git a/server/models/oauth/oauth-token-interface.ts b/server/models/oauth/oauth-token-interface.ts index 815ad5eef..f2ddafa54 100644 --- a/server/models/oauth/oauth-token-interface.ts +++ b/server/models/oauth/oauth-token-interface.ts @@ -1,5 +1,5 @@ import * as Sequelize from 'sequelize' -import * as Bluebird from 'bluebird' +import * as Promise from 'bluebird' import { UserModel } from '../user' @@ -15,12 +15,11 @@ export type OAuthTokenInfo = { } export namespace OAuthTokenMethods { - export type GetByRefreshTokenAndPopulateClient = (refreshToken: string) => Bluebird - export type GetByTokenAndPopulateUser = (bearerToken: string) => Bluebird - export type GetByRefreshTokenAndPopulateUser = (refreshToken: string) => Bluebird + export type GetByRefreshTokenAndPopulateClient = (refreshToken: string) => Promise + export type GetByTokenAndPopulateUser = (bearerToken: string) => Promise + export type GetByRefreshTokenAndPopulateUser = (refreshToken: string) => Promise - export type RemoveByUserIdCallback = (err: Error) => void - export type RemoveByUserId = (userId, callback) => void + export type RemoveByUserId = (userId) => Promise } export interface OAuthTokenClass { diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index eab9cf858..8c6883465 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts @@ -4,7 +4,6 @@ import { logger } from '../../helpers' import { addMethodsToModel } from '../utils' import { - OAuthTokenClass, OAuthTokenInstance, OAuthTokenAttributes, @@ -149,12 +148,12 @@ getByRefreshTokenAndPopulateUser = function (refreshToken: string) { }) } -removeByUserId = function (userId, callback) { +removeByUserId = function (userId: number) { const query = { where: { userId: userId } } - return OAuthToken.destroy(query).asCallback(callback) + return OAuthToken.destroy(query) } diff --git a/server/models/pod/pod-interface.ts b/server/models/pod/pod-interface.ts index d88847c45..f6963d47e 100644 --- a/server/models/pod/pod-interface.ts +++ b/server/models/pod/pod-interface.ts @@ -1,4 +1,5 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' // Don't use barrel, import just what we need import { Pod as FormatedPod } from '../../../shared/models/pod.model' @@ -6,32 +7,23 @@ import { Pod as FormatedPod } from '../../../shared/models/pod.model' export namespace PodMethods { export type ToFormatedJSON = (this: PodInstance) => FormatedPod - export type CountAllCallback = (err: Error, total: number) => void - export type CountAll = (callback) => void + export type CountAll = () => Promise - export type IncrementScoresCallback = (err: Error) => void - export type IncrementScores = (ids: number[], value: number, callback?: IncrementScoresCallback) => void + export type IncrementScores = (ids: number[], value: number) => Promise<[ number, PodInstance[] ]> - export type ListCallback = (err: Error, podInstances?: PodInstance[]) => void - export type List = (callback: ListCallback) => void + export type List = () => Promise - export type ListAllIdsCallback = (err: Error, ids?: number[]) => void - export type ListAllIds = (transaction: Sequelize.Transaction, callback: ListAllIdsCallback) => void + export type ListAllIds = (transaction: Sequelize.Transaction) => Promise - export type ListRandomPodIdsWithRequestCallback = (err: Error, podInstanceIds?: number[]) => void - export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string, callback: ListRandomPodIdsWithRequestCallback) => void + export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string) => Promise - export type ListBadPodsCallback = (err: Error, podInstances?: PodInstance[]) => void - export type ListBadPods = (callback: ListBadPodsCallback) => void + export type ListBadPods = () => Promise - export type LoadCallback = (err: Error, podInstance: PodInstance) => void - export type Load = (id: number, callback: LoadCallback) => void + export type Load = (id: number) => Promise - export type LoadByHostCallback = (err: Error, podInstance: PodInstance) => void - export type LoadByHost = (host: string, callback: LoadByHostCallback) => void + export type LoadByHost = (host: string) => Promise - export type RemoveAllCallback = (err: Error) => void - export type RemoveAll = (callback: RemoveAllCallback) => void + export type RemoveAll = () => Promise export type UpdatePodsScore = (goodPods: number[], badPods: number[]) => void } diff --git a/server/models/pod/pod.ts b/server/models/pod/pod.ts index 4fe7fda1c..9209380fc 100644 --- a/server/models/pod/pod.ts +++ b/server/models/pod/pod.ts @@ -1,4 +1,3 @@ -import { each, waterfall } from 'async' import { map } from 'lodash' import * as Sequelize from 'sequelize' @@ -7,7 +6,6 @@ import { logger, isHostValid } from '../../helpers' import { addMethodsToModel } from '../utils' import { - PodClass, PodInstance, PodAttributes, @@ -118,13 +116,11 @@ function associate (models) { }) } -countAll = function (callback: PodMethods.CountAllCallback) { - return Pod.count().asCallback(callback) +countAll = function () { + return Pod.count() } -incrementScores = function (ids: number[], value: number, callback?: PodMethods.IncrementScoresCallback) { - if (!callback) callback = function () { /* empty */ } - +incrementScores = function (ids: number[], value: number) { const update = { score: Sequelize.literal('score +' + value) } @@ -139,33 +135,28 @@ incrementScores = function (ids: number[], value: number, callback?: PodMethods. validate: false } - return Pod.update(update, options).asCallback(callback) + return Pod.update(update, options) } -list = function (callback: PodMethods.ListCallback) { - return Pod.findAll().asCallback(callback) +list = function () { + return Pod.findAll() } -listAllIds = function (transaction: Sequelize.Transaction, callback: PodMethods.ListAllIdsCallback) { - const query: any = { - attributes: [ 'id' ] +listAllIds = function (transaction: Sequelize.Transaction) { + const query: Sequelize.FindOptions = { + attributes: [ 'id' ], + transaction } - if (transaction !== null) query.transaction = transaction - - return Pod.findAll(query).asCallback(function (err: Error, pods) { - if (err) return callback(err) - - return callback(null, map(pods, 'id')) + return Pod.findAll(query).then(pods => { + return map(pods, 'id') }) } -listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, tableWithPodsJoins: string, callback: PodMethods.ListRandomPodIdsWithRequestCallback) { - Pod.count().asCallback(function (err, count) { - if (err) return callback(err) - +listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, tableWithPodsJoins: string) { + return Pod.count().then(count => { // Optimization... - if (count === 0) return callback(null, []) + if (count === 0) return [] let start = Math.floor(Math.random() * count) - limit if (start < 0) start = 0 @@ -186,56 +177,55 @@ listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, ta } } - return Pod.findAll(query).asCallback(function (err, pods) { - if (err) return callback(err) - - return callback(null, map(pods, 'id')) + return Pod.findAll(query).then(pods => { + return map(pods, 'id') }) }) } -listBadPods = function (callback: PodMethods.ListBadPodsCallback) { +listBadPods = function () { const query = { where: { score: { $lte: 0 } } } - return Pod.findAll(query).asCallback(callback) + return Pod.findAll(query) } -load = function (id: number, callback: PodMethods.LoadCallback) { - return Pod.findById(id).asCallback(callback) +load = function (id: number) { + return Pod.findById(id) } -loadByHost = function (host: string, callback: PodMethods.LoadByHostCallback) { +loadByHost = function (host: string) { const query = { where: { host: host } } - return Pod.findOne(query).asCallback(callback) + return Pod.findOne(query) } -removeAll = function (callback: PodMethods.RemoveAllCallback) { - return Pod.destroy().asCallback(callback) +removeAll = function () { + return Pod.destroy() } updatePodsScore = function (goodPods: number[], badPods: number[]) { logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) if (goodPods.length !== 0) { - incrementScores(goodPods, PODS_SCORE.BONUS, function (err) { - if (err) logger.error('Cannot increment scores of good pods.', { error: err }) + incrementScores(goodPods, PODS_SCORE.BONUS).catch(err => { + logger.error('Cannot increment scores of good pods.', { error: err }) }) } if (badPods.length !== 0) { - incrementScores(badPods, PODS_SCORE.MALUS, function (err) { - if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) - removeBadPods() - }) + incrementScores(badPods, PODS_SCORE.MALUS) + .then(() => removeBadPods()) + .catch(err => { + if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) + }) } } @@ -243,32 +233,19 @@ updatePodsScore = function (goodPods: number[], badPods: number[]) { // Remove pods with a score of 0 (too many requests where they were unreachable) function removeBadPods () { - waterfall([ - function findBadPods (callback) { - listBadPods(function (err, pods) { - if (err) { - logger.error('Cannot find bad pods.', { error: err }) - return callback(err) - } - - return callback(null, pods) - }) - }, - - function removeTheseBadPods (pods, callback) { - each(pods, function (pod: any, callbackEach) { - pod.destroy().asCallback(callbackEach) - }, function (err) { - return callback(err, pods.length) - }) - } - ], function (err, numberOfPodsRemoved) { - if (err) { + return listBadPods() + .then(pods => { + const podsRemovePromises = pods.map(pod => pod.destroy()) + return Promise.all(podsRemovePromises).then(() => pods.length) + }) + .then(numberOfPodsRemoved => { + if (numberOfPodsRemoved) { + logger.info('Removed %d pods.', numberOfPodsRemoved) + } else { + logger.info('No need to remove bad pods.') + } + }) + .catch(err => { logger.error('Cannot remove bad pods.', { error: err }) - } else if (numberOfPodsRemoved) { - logger.info('Removed %d pods.', numberOfPodsRemoved) - } else { - logger.info('No need to remove bad pods.') - } - }) + }) } diff --git a/server/models/request/abstract-request-interface.ts b/server/models/request/abstract-request-interface.ts new file mode 100644 index 000000000..a384f4d27 --- /dev/null +++ b/server/models/request/abstract-request-interface.ts @@ -0,0 +1,12 @@ +import * as Promise from 'bluebird' + +export interface AbstractRequestClass { + countTotalRequests: () => Promise + listWithLimitAndRandom: (limitPods: number, limitRequestsPerPod: number) => Promise + removeWithEmptyTo: () => Promise + removeAll: () => Promise +} + +export interface AbstractRequestToPodClass { + removeByRequestIdsAndPod: (ids: number[], podId: number) => Promise +} diff --git a/server/models/request/index.ts b/server/models/request/index.ts index 824c140f5..3dd6aedc2 100644 --- a/server/models/request/index.ts +++ b/server/models/request/index.ts @@ -1,3 +1,4 @@ +export * from './abstract-request-interface' export * from './request-interface' export * from './request-to-pod-interface' export * from './request-video-event-interface' diff --git a/server/models/request/request-interface.ts b/server/models/request/request-interface.ts index 483850633..7b0ee4df9 100644 --- a/server/models/request/request-interface.ts +++ b/server/models/request/request-interface.ts @@ -1,5 +1,7 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' +import { AbstractRequestClass } from './abstract-request-interface' import { PodInstance, PodAttributes } from '../pod' import { RequestEndpoint } from '../../../shared/models/request-scheduler.model' @@ -11,20 +13,16 @@ export type RequestsGrouped = { } export namespace RequestMethods { - export type CountTotalRequestsCallback = (err: Error, total: number) => void - export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + export type CountTotalRequests = () => Promise - export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsGrouped) => void - export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback: ListWithLimitAndRandomCallback) => void + export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise - export type RemoveWithEmptyToCallback = (err: Error) => void - export type RemoveWithEmptyTo = (callback: RemoveWithEmptyToCallback) => void + export type RemoveWithEmptyTo = () => Promise - export type RemoveAllCallback = (err: Error) => void - export type RemoveAll = (callback: RemoveAllCallback) => void + export type RemoveAll = () => Promise } -export interface RequestClass { +export interface RequestClass extends AbstractRequestClass { countTotalRequests: RequestMethods.CountTotalRequests listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo diff --git a/server/models/request/request-to-pod-interface.ts b/server/models/request/request-to-pod-interface.ts index 6d75ca6e5..7ca99f4d4 100644 --- a/server/models/request/request-to-pod-interface.ts +++ b/server/models/request/request-to-pod-interface.ts @@ -1,11 +1,13 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' + +import { AbstractRequestToPodClass } from './abstract-request-interface' export namespace RequestToPodMethods { - export type RemoveByRequestIdsAndPodCallback = (err: Error) => void - export type RemoveByRequestIdsAndPod = (requestsIds: number[], podId: number, callback?: RemoveByRequestIdsAndPodCallback) => void + export type RemoveByRequestIdsAndPod = (requestsIds: number[], podId: number) => Promise } -export interface RequestToPodClass { +export interface RequestToPodClass extends AbstractRequestToPodClass { removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod } diff --git a/server/models/request/request-to-pod.ts b/server/models/request/request-to-pod.ts index 67331be1d..6678ed290 100644 --- a/server/models/request/request-to-pod.ts +++ b/server/models/request/request-to-pod.ts @@ -2,7 +2,6 @@ import * as Sequelize from 'sequelize' import { addMethodsToModel } from '../utils' import { - RequestToPodClass, RequestToPodInstance, RequestToPodAttributes, @@ -38,9 +37,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da // --------------------------------------------------------------------------- -removeByRequestIdsAndPod = function (requestsIds: number[], podId: number, callback?: RequestToPodMethods.RemoveByRequestIdsAndPodCallback) { - if (!callback) callback = function () { /* empty */ } - +removeByRequestIdsAndPod = function (requestsIds: number[], podId: number) { const query = { where: { requestId: { @@ -50,5 +47,5 @@ removeByRequestIdsAndPod = function (requestsIds: number[], podId: number, callb } } - RequestToPod.destroy(query).asCallback(callback) + return RequestToPod.destroy(query) } diff --git a/server/models/request/request-video-event-interface.ts b/server/models/request/request-video-event-interface.ts index 3ed03339a..a5032e1b1 100644 --- a/server/models/request/request-video-event-interface.ts +++ b/server/models/request/request-video-event-interface.ts @@ -1,5 +1,7 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' +import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface' import { VideoInstance } from '../video' import { PodInstance } from '../pod' @@ -16,20 +18,16 @@ export type RequestsVideoEventGrouped = { } export namespace RequestVideoEventMethods { - export type CountTotalRequestsCallback = (err: Error, total: number) => void - export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + export type CountTotalRequests = () => Promise - export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsVideoEventGrouped) => void - export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number, callback: ListWithLimitAndRandomCallback) => void + export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise - export type RemoveByRequestIdsAndPodCallback = () => void - export type RemoveByRequestIdsAndPod = (ids: number[], podId: number, callback: RemoveByRequestIdsAndPodCallback) => void + export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise - export type RemoveAllCallback = () => void - export type RemoveAll = (callback: RemoveAllCallback) => void + export type RemoveAll = () => Promise } -export interface RequestVideoEventClass { +export interface RequestVideoEventClass extends AbstractRequestClass, AbstractRequestToPodClass { countTotalRequests: RequestVideoEventMethods.CountTotalRequests listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod @@ -41,10 +39,12 @@ export interface RequestVideoEventAttributes { count: number } -export interface RequestVideoEventInstance extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance { +export interface RequestVideoEventInstance + extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance { id: number Video: VideoInstance } -export interface RequestVideoEventModel extends RequestVideoEventClass, Sequelize.Model {} +export interface RequestVideoEventModel + extends RequestVideoEventClass, Sequelize.Model {} diff --git a/server/models/request/request-video-event.ts b/server/models/request/request-video-event.ts index f552ef50b..90ea15702 100644 --- a/server/models/request/request-video-event.ts +++ b/server/models/request/request-video-event.ts @@ -10,7 +10,6 @@ import { REQUEST_VIDEO_EVENT_TYPES } from '../../initializers' import { isVideoEventCountValid } from '../../helpers' import { addMethodsToModel } from '../utils' import { - RequestVideoEventClass, RequestVideoEventInstance, RequestVideoEventAttributes, @@ -77,23 +76,21 @@ function associate (models) { }) } -countTotalRequests = function (callback: RequestVideoEventMethods.CountTotalRequestsCallback) { +countTotalRequests = function () { const query = {} - return RequestVideoEvent.count(query).asCallback(callback) + return RequestVideoEvent.count(query) } -listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestVideoEventMethods.ListWithLimitAndRandomCallback) { +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 "Videos" ON "Videos"."authorId" = "Authors"."id" ' + 'INNER JOIN "RequestVideoEvents" ON "RequestVideoEvents"."videoId" = "Videos"."id"' - Pod.listRandomPodIdsWithRequest(limitPods, 'Authors', podJoins, function (err, podIds) { - if (err) return callback(err) - + return Pod.listRandomPodIdsWithRequest(limitPods, 'Authors', podJoins).then(podIds => { // We don't have friends that have requests - if (podIds.length === 0) return callback(null, []) + if (podIds.length === 0) return [] const query = { order: [ @@ -121,16 +118,14 @@ listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: numbe ] } - RequestVideoEvent.findAll(query).asCallback(function (err, requests) { - if (err) return callback(err) - + return RequestVideoEvent.findAll(query).then(requests => { const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) - return callback(err, requestsGrouped) + return requestsGrouped }) }) } -removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: RequestVideoEventMethods.RemoveByRequestIdsAndPodCallback) { +removeByRequestIdsAndPod = function (ids: number[], podId: number) { const query = { where: { id: { @@ -152,12 +147,12 @@ removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: Req ] } - RequestVideoEvent.destroy(query).asCallback(callback) + return RequestVideoEvent.destroy(query) } -removeAll = function (callback: RequestVideoEventMethods.RemoveAllCallback) { +removeAll = function () { // Delete all requests - RequestVideoEvent.truncate({ cascade: true }).asCallback(callback) + return RequestVideoEvent.truncate({ cascade: true }) } // --------------------------------------------------------------------------- diff --git a/server/models/request/request-video-qadu-interface.ts b/server/models/request/request-video-qadu-interface.ts index 805771cda..9a172a4d4 100644 --- a/server/models/request/request-video-qadu-interface.ts +++ b/server/models/request/request-video-qadu-interface.ts @@ -1,5 +1,7 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' +import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface' import { VideoInstance } from '../video' import { PodInstance } from '../pod' @@ -14,20 +16,16 @@ export type RequestsVideoQaduGrouped = { } export namespace RequestVideoQaduMethods { - export type CountTotalRequestsCallback = (err: Error, total: number) => void - export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + export type CountTotalRequests = () => Promise - export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsVideoQaduGrouped) => void - export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number, callback: ListWithLimitAndRandomCallback) => void + export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise - export type RemoveByRequestIdsAndPodCallback = () => void - export type RemoveByRequestIdsAndPod = (ids: number[], podId: number, callback: RemoveByRequestIdsAndPodCallback) => void + export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise - export type RemoveAllCallback = () => void - export type RemoveAll = (callback: RemoveAllCallback) => void + export type RemoveAll = () => Promise } -export interface RequestVideoQaduClass { +export interface RequestVideoQaduClass extends AbstractRequestClass, AbstractRequestToPodClass { countTotalRequests: RequestVideoQaduMethods.CountTotalRequests listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod @@ -38,11 +36,13 @@ export interface RequestVideoQaduAttributes { type: RequestVideoQaduType } -export interface RequestVideoQaduInstance extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance { +export interface RequestVideoQaduInstance + extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance { id: number Pod: PodInstance Video: VideoInstance } -export interface RequestVideoQaduModel extends RequestVideoQaduClass, Sequelize.Model {} +export interface RequestVideoQaduModel + extends RequestVideoQaduClass, Sequelize.Model {} diff --git a/server/models/request/request-video-qadu.ts b/server/models/request/request-video-qadu.ts index da62239f5..74e28f129 100644 --- a/server/models/request/request-video-qadu.ts +++ b/server/models/request/request-video-qadu.ts @@ -16,7 +16,6 @@ import { database as db } from '../../initializers/database' import { REQUEST_VIDEO_QADU_TYPES } from '../../initializers' import { addMethodsToModel } from '../utils' import { - RequestVideoQaduClass, RequestVideoQaduInstance, RequestVideoQaduAttributes, @@ -83,20 +82,18 @@ function associate (models) { }) } -countTotalRequests = function (callback: RequestVideoQaduMethods.CountTotalRequestsCallback) { +countTotalRequests = function () { const query = {} - return RequestVideoQadu.count(query).asCallback(callback) + return RequestVideoQadu.count(query) } -listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestVideoQaduMethods.ListWithLimitAndRandomCallback) { +listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) { const Pod = db.Pod const tableJoin = '' - Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', tableJoin, function (err, podIds) { - if (err) return callback(err) - + return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', tableJoin).then(podIds => { // We don't have friends that have requests - if (podIds.length === 0) return callback(null, []) + if (podIds.length === 0) return [] const query = { include: [ @@ -114,16 +111,14 @@ listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: numbe ] } - RequestVideoQadu.findAll(query).asCallback(function (err, requests) { - if (err) return callback(err) - + return RequestVideoQadu.findAll(query).then(requests => { const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) - return callback(err, requestsGrouped) + return requestsGrouped }) }) } -removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: RequestVideoQaduMethods.RemoveByRequestIdsAndPodCallback) { +removeByRequestIdsAndPod = function (ids: number[], podId: number) { const query = { where: { id: { @@ -133,12 +128,12 @@ removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: Req } } - RequestVideoQadu.destroy(query).asCallback(callback) + return RequestVideoQadu.destroy(query) } -removeAll = function (callback: RequestVideoQaduMethods.RemoveAllCallback) { +removeAll = function () { // Delete all requests - RequestVideoQadu.truncate({ cascade: true }).asCallback(callback) + return RequestVideoQadu.truncate({ cascade: true }) } // --------------------------------------------------------------------------- diff --git a/server/models/request/request.ts b/server/models/request/request.ts index 66e7da845..c3ce2cd4e 100644 --- a/server/models/request/request.ts +++ b/server/models/request/request.ts @@ -5,7 +5,6 @@ import { database as db } from '../../initializers/database' import { REQUEST_ENDPOINTS } from '../../initializers' import { addMethodsToModel } from '../utils' import { - RequestClass, RequestInstance, RequestAttributes, @@ -60,25 +59,23 @@ function associate (models) { }) } -countTotalRequests = function (callback: RequestMethods.CountTotalRequestsCallback) { +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).asCallback(callback) + return Request.count(query) } -listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestMethods.ListWithLimitAndRandomCallback) { +listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) { const Pod = db.Pod const tableJoin = '' - Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', '', function (err, podIds) { - if (err) return callback(err) - + return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', tableJoin).then(podIds => { // We don't have friends that have requests - if (podIds.length === 0) return callback(null, []) + 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! @@ -98,23 +95,20 @@ listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: numbe ] } - Request.findAll(query).asCallback(function (err, requests) { - if (err) return callback(err) + return Request.findAll(query).then(requests => { const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) - return callback(err, requestsGrouped) + return requestsGrouped }) }) } -removeAll = function (callback: RequestMethods.RemoveAllCallback) { +removeAll = function () { // Delete all requests - Request.truncate({ cascade: true }).asCallback(callback) + return Request.truncate({ cascade: true }) } -removeWithEmptyTo = function (callback?: RequestMethods.RemoveWithEmptyToCallback) { - if (!callback) callback = function () { /* empty */ } - +removeWithEmptyTo = function () { const query = { where: { id: { @@ -125,7 +119,7 @@ removeWithEmptyTo = function (callback?: RequestMethods.RemoveWithEmptyToCallbac } } - Request.destroy(query).asCallback(callback) + return Request.destroy(query) } // --------------------------------------------------------------------------- diff --git a/server/models/user/user-interface.ts b/server/models/user/user-interface.ts index 48c67678b..f743945f8 100644 --- a/server/models/user/user-interface.ts +++ b/server/models/user/user-interface.ts @@ -1,35 +1,29 @@ import * as Sequelize from 'sequelize' -import * as Bluebird from 'bluebird' +import * as Promise from 'bluebird' // Don't use barrel, import just what we need import { UserRole, User as FormatedUser } from '../../../shared/models/user.model' +import { ResultList } from '../../../shared/models/result-list.model' export namespace UserMethods { - export type IsPasswordMatchCallback = (err: Error, same: boolean) => void - export type IsPasswordMatch = (this: UserInstance, password: string, callback: IsPasswordMatchCallback) => void + export type IsPasswordMatch = (this: UserInstance, password: string) => Promise export type ToFormatedJSON = (this: UserInstance) => FormatedUser export type IsAdmin = (this: UserInstance) => boolean - export type CountTotalCallback = (err: Error, total: number) => void - export type CountTotal = (callback: CountTotalCallback) => void + export type CountTotal = () => Promise - export type GetByUsername = (username: string) => Bluebird + export type GetByUsername = (username: string) => Promise - export type ListCallback = (err: Error, userInstances: UserInstance[]) => void - export type List = (callback: ListCallback) => void + export type List = () => Promise - export type ListForApiCallback = (err: Error, userInstances?: UserInstance[], total?: number) => void - export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList > - export type LoadByIdCallback = (err: Error, userInstance: UserInstance) => void - export type LoadById = (id: number, callback: LoadByIdCallback) => void + export type LoadById = (id: number) => Promise - export type LoadByUsernameCallback = (err: Error, userInstance: UserInstance) => void - export type LoadByUsername = (username: string, callback: LoadByUsernameCallback) => void + export type LoadByUsername = (username: string) => Promise - export type LoadByUsernameOrEmailCallback = (err: Error, userInstance: UserInstance) => void - export type LoadByUsernameOrEmail = (username: string, email: string, callback: LoadByUsernameOrEmailCallback) => void + export type LoadByUsernameOrEmail = (username: string, email: string) => Promise } export interface UserClass { diff --git a/server/models/user/user-video-rate-interface.ts b/server/models/user/user-video-rate-interface.ts index a726639b1..e0b65a13d 100644 --- a/server/models/user/user-video-rate-interface.ts +++ b/server/models/user/user-video-rate-interface.ts @@ -1,10 +1,10 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { VideoRateType } from '../../../shared/models/user-video-rate.model' export namespace UserVideoRateMethods { - export type LoadCallback = (err: Error, userVideoRateInstance: UserVideoRateInstance) => void - export type Load = (userId: number, videoId: string, transaction: Sequelize.Transaction, callback: LoadCallback) => void + export type Load = (userId: number, videoId: string, transaction: Sequelize.Transaction) => Promise } export interface UserVideoRateClass { diff --git a/server/models/user/user-video-rate.ts b/server/models/user/user-video-rate.ts index 4bdd35bc9..37d0222cf 100644 --- a/server/models/user/user-video-rate.ts +++ b/server/models/user/user-video-rate.ts @@ -8,7 +8,6 @@ import { VIDEO_RATE_TYPES } from '../../initializers' import { addMethodsToModel } from '../utils' import { - UserVideoRateClass, UserVideoRateInstance, UserVideoRateAttributes, @@ -66,7 +65,7 @@ function associate (models) { }) } -load = function (userId: number, videoId: string, transaction: Sequelize.Transaction, callback: UserVideoRateMethods.LoadCallback) { +load = function (userId: number, videoId: string, transaction: Sequelize.Transaction) { const options: Sequelize.FindOptions = { where: { userId, @@ -75,5 +74,5 @@ load = function (userId: number, videoId: string, transaction: Sequelize.Transac } if (transaction) options.transaction = transaction - return UserVideoRate.findOne(options).asCallback(callback) + return UserVideoRate.findOne(options) } diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 6b2410259..5ff81e741 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts @@ -13,7 +13,6 @@ import { import { addMethodsToModel } from '../utils' import { - UserClass, UserInstance, UserAttributes, @@ -118,21 +117,16 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da } function beforeCreateOrUpdate (user: UserInstance) { - return new Promise(function (resolve, reject) { - cryptPassword(user.password, function (err, hash) { - if (err) return reject(err) - - user.password = hash - - return resolve() - }) + return cryptPassword(user.password).then(hash => { + user.password = hash + return undefined }) } // ------------------------------ METHODS ------------------------------ -isPasswordMatch = function (this: UserInstance, password: string, callback: UserMethods.IsPasswordMatchCallback) { - return comparePassword(password, this.password, callback) +isPasswordMatch = function (this: UserInstance, password: string) { + return comparePassword(password, this.password) } toFormatedJSON = function (this: UserInstance) { @@ -164,8 +158,8 @@ function associate (models) { }) } -countTotal = function (callback: UserMethods.CountTotalCallback) { - return this.count().asCallback(callback) +countTotal = function () { + return this.count() } getByUsername = function (username: string) { @@ -178,44 +172,45 @@ getByUsername = function (username: string) { return User.findOne(query) } -list = function (callback: UserMethods.ListCallback) { - return User.find().asCallback(callback) +list = function () { + return User.findAll() } -listForApi = function (start: number, count: number, sort: string, callback: UserMethods.ListForApiCallback) { +listForApi = function (start: number, count: number, sort: string) { const query = { offset: start, limit: count, order: [ getSort(sort) ] } - return User.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) + return User.findAndCountAll(query).then(({ rows, count }) => { + return { + data: rows, + total: count + } }) } -loadById = function (id: number, callback: UserMethods.LoadByIdCallback) { - return User.findById(id).asCallback(callback) +loadById = function (id: number) { + return User.findById(id) } -loadByUsername = function (username: string, callback: UserMethods.LoadByUsernameCallback) { +loadByUsername = function (username: string) { const query = { where: { username: username } } - return User.findOne(query).asCallback(callback) + return User.findOne(query) } -loadByUsernameOrEmail = function (username: string, email: string, callback: UserMethods.LoadByUsernameOrEmailCallback) { +loadByUsernameOrEmail = function (username: string, email: string) { const query = { where: { $or: [ { username }, { email } ] } } - return User.findOne(query).asCallback(callback) + return User.findOne(query) } diff --git a/server/models/video/author-interface.ts b/server/models/video/author-interface.ts index c1b30848c..dbcb85b17 100644 --- a/server/models/video/author-interface.ts +++ b/server/models/video/author-interface.ts @@ -1,10 +1,15 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { PodInstance } from '../pod' export namespace AuthorMethods { - export type FindOrCreateAuthorCallback = (err: Error, authorInstance?: AuthorInstance) => void - export type FindOrCreateAuthor = (name: string, podId: number, userId: number, transaction: Sequelize.Transaction, callback: FindOrCreateAuthorCallback) => void + export type FindOrCreateAuthor = ( + name: string, + podId: number, + userId: number, + transaction: Sequelize.Transaction + ) => Promise } export interface AuthorClass { diff --git a/server/models/video/author.ts b/server/models/video/author.ts index 4a115e328..3222c4834 100644 --- a/server/models/video/author.ts +++ b/server/models/video/author.ts @@ -4,7 +4,6 @@ import { isUserUsernameValid } from '../../helpers' import { addMethodsToModel } from '../utils' import { - AuthorClass, AuthorInstance, AuthorAttributes, @@ -74,30 +73,18 @@ function associate (models) { }) } -findOrCreateAuthor = function ( - name: string, - podId: number, - userId: number, - transaction: Sequelize.Transaction, - callback: AuthorMethods.FindOrCreateAuthorCallback -) { +findOrCreateAuthor = function (name: string, podId: number, userId: number, transaction: Sequelize.Transaction) { const author = { name, podId, userId } - const query: any = { + const query: Sequelize.FindOrInitializeOptions = { where: author, - defaults: author + defaults: author, + transaction } - if (transaction !== null) query.transaction = transaction - - Author.findOrCreate(query).asCallback(function (err, result) { - if (err) return callback(err) - - // [ instance, wasCreated ] - return callback(null, result[0]) - }) + return Author.findOrCreate(query).then(([ authorInstance ]) => authorInstance) } diff --git a/server/models/video/tag-interface.ts b/server/models/video/tag-interface.ts index e045e7ca5..08e5c3246 100644 --- a/server/models/video/tag-interface.ts +++ b/server/models/video/tag-interface.ts @@ -1,8 +1,8 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' export namespace TagMethods { - export type FindOrCreateTagsCallback = (err: Error, tagInstances: TagInstance[]) => void - export type FindOrCreateTags = (tags: string[], transaction: Sequelize.Transaction, callback: FindOrCreateTagsCallback) => void + export type FindOrCreateTags = (tags: string[], transaction: Sequelize.Transaction) => Promise } export interface TagClass { diff --git a/server/models/video/tag.ts b/server/models/video/tag.ts index 3c657d751..d0d8353d7 100644 --- a/server/models/video/tag.ts +++ b/server/models/video/tag.ts @@ -1,9 +1,8 @@ -import { each } from 'async' import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { addMethodsToModel } from '../utils' import { - TagClass, TagInstance, TagAttributes, @@ -52,10 +51,9 @@ function associate (models) { }) } -findOrCreateTags = function (tags: string[], transaction: Sequelize.Transaction, callback: TagMethods.FindOrCreateTagsCallback) { - const tagInstances = [] - - each(tags, function (tag, callbackEach) { +findOrCreateTags = function (tags: string[], transaction: Sequelize.Transaction) { + const tasks: Promise[] = [] + tags.forEach(tag => { const query: any = { where: { name: tag @@ -67,15 +65,9 @@ findOrCreateTags = function (tags: string[], transaction: Sequelize.Transaction, if (transaction) query.transaction = transaction - Tag.findOrCreate(query).asCallback(function (err, res) { - if (err) return callbackEach(err) - - // res = [ tag, isCreated ] - const tag = res[0] - tagInstances.push(tag) - return callbackEach() - }) - }, function (err) { - return callback(err, tagInstances) + const promise = Tag.findOrCreate(query).then(([ tagInstance ]) => tagInstance) + tasks.push(promise) }) + + return Promise.all(tasks) } diff --git a/server/models/video/video-abuse-interface.ts b/server/models/video/video-abuse-interface.ts index c85d09091..75647fe0e 100644 --- a/server/models/video/video-abuse-interface.ts +++ b/server/models/video/video-abuse-interface.ts @@ -1,6 +1,8 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { PodInstance } from '../pod' +import { ResultList } from '../../../shared' // Don't use barrel, import just what we need import { VideoAbuse as FormatedVideoAbuse } from '../../../shared/models/video-abuse.model' @@ -8,8 +10,7 @@ import { VideoAbuse as FormatedVideoAbuse } from '../../../shared/models/video-a export namespace VideoAbuseMethods { export type ToFormatedJSON = (this: VideoAbuseInstance) => FormatedVideoAbuse - export type ListForApiCallback = (err: Error, videoAbuseInstances?: VideoAbuseInstance[], total?: number) => void - export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList > } export interface VideoAbuseClass { diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index bc5f01e21..ab1a3ea7d 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts @@ -5,7 +5,6 @@ import { isVideoAbuseReporterUsernameValid, isVideoAbuseReasonValid } from '../. import { addMethodsToModel, getSort } from '../utils' import { - VideoAbuseClass, VideoAbuseInstance, VideoAbuseAttributes, @@ -109,7 +108,7 @@ function associate (models) { }) } -listForApi = function (start: number, count: number, sort: string, callback: VideoAbuseMethods.ListForApiCallback) { +listForApi = function (start: number, count: number, sort: string) { const query = { offset: start, limit: count, @@ -122,11 +121,7 @@ listForApi = function (start: number, count: number, sort: string, callback: Vid ] } - return VideoAbuse.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) + return VideoAbuse.findAndCountAll(query).then(({ rows, count }) => { + return { total: count, data: rows } }) } - - diff --git a/server/models/video/video-blacklist-interface.ts b/server/models/video/video-blacklist-interface.ts index d4d6528d1..5ca423801 100644 --- a/server/models/video/video-blacklist-interface.ts +++ b/server/models/video/video-blacklist-interface.ts @@ -1,4 +1,7 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' + +import { ResultList } from '../../../shared' // Don't use barrel, import just what we need import { BlacklistedVideo as FormatedBlacklistedVideo } from '../../../shared/models/video-blacklist.model' @@ -6,20 +9,15 @@ import { BlacklistedVideo as FormatedBlacklistedVideo } from '../../../shared/mo export namespace BlacklistedVideoMethods { export type ToFormatedJSON = (this: BlacklistedVideoInstance) => FormatedBlacklistedVideo - export type CountTotalCallback = (err: Error, total: number) => void - export type CountTotal = (callback: CountTotalCallback) => void + export type CountTotal = () => Promise - export type ListCallback = (err: Error, backlistedVideoInstances: BlacklistedVideoInstance[]) => void - export type List = (callback: ListCallback) => void + export type List = () => Promise - export type ListForApiCallback = (err: Error, blacklistedVIdeoInstances?: BlacklistedVideoInstance[], total?: number) => void - export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList > - export type LoadByIdCallback = (err: Error, blacklistedVideoInstance: BlacklistedVideoInstance) => void - export type LoadById = (id: number, callback: LoadByIdCallback) => void + export type LoadById = (id: number) => Promise - export type LoadByVideoIdCallback = (err: Error, blacklistedVideoInstance: BlacklistedVideoInstance) => void - export type LoadByVideoId = (id: string, callback: LoadByVideoIdCallback) => void + export type LoadByVideoId = (id: string) => Promise } export interface BlacklistedVideoClass { @@ -35,7 +33,8 @@ export interface BlacklistedVideoAttributes { videoId: string } -export interface BlacklistedVideoInstance extends BlacklistedVideoClass, BlacklistedVideoAttributes, Sequelize.Instance { +export interface BlacklistedVideoInstance + extends BlacklistedVideoClass, BlacklistedVideoAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date @@ -43,4 +42,5 @@ export interface BlacklistedVideoInstance extends BlacklistedVideoClass, Blackli toFormatedJSON: BlacklistedVideoMethods.ToFormatedJSON } -export interface BlacklistedVideoModel extends BlacklistedVideoClass, Sequelize.Model {} +export interface BlacklistedVideoModel + extends BlacklistedVideoClass, Sequelize.Model {} diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index 3576c96f6..8c42dbc21 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts @@ -2,7 +2,6 @@ import * as Sequelize from 'sequelize' import { addMethodsToModel, getSort } from '../utils' import { - BlacklistedVideoClass, BlacklistedVideoInstance, BlacklistedVideoAttributes, @@ -66,38 +65,39 @@ function associate (models) { }) } -countTotal = function (callback: BlacklistedVideoMethods.CountTotalCallback) { - return BlacklistedVideo.count().asCallback(callback) +countTotal = function () { + return BlacklistedVideo.count() } -list = function (callback: BlacklistedVideoMethods.ListCallback) { - return BlacklistedVideo.findAll().asCallback(callback) +list = function () { + return BlacklistedVideo.findAll() } -listForApi = function (start: number, count: number, sort: string, callback: BlacklistedVideoMethods.ListForApiCallback) { +listForApi = function (start: number, count: number, sort: string) { const query = { offset: start, limit: count, order: [ getSort(sort) ] } - return BlacklistedVideo.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) + return BlacklistedVideo.findAndCountAll(query).then(({ rows, count }) => { + return { + data: rows, + total: count + } }) } -loadById = function (id: number, callback: BlacklistedVideoMethods.LoadByIdCallback) { - return BlacklistedVideo.findById(id).asCallback(callback) +loadById = function (id: number) { + return BlacklistedVideo.findById(id) } -loadByVideoId = function (id: string, callback: BlacklistedVideoMethods.LoadByIdCallback) { +loadByVideoId = function (id: string) { const query = { where: { videoId: id } } - return BlacklistedVideo.find(query).asCallback(callback) + return BlacklistedVideo.findOne(query) } diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts index 4b591b9e7..c3e3365d5 100644 --- a/server/models/video/video-interface.ts +++ b/server/models/video/video-interface.ts @@ -1,10 +1,12 @@ import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { AuthorInstance } from './author-interface' -import { VideoTagInstance } from './video-tag-interface' +import { TagAttributes, TagInstance } from './tag-interface' // Don't use barrel, import just what we need import { Video as FormatedVideo } from '../../../shared/models/video.model' +import { ResultList } from '../../../shared/models/result-list.model' export type FormatedAddRemoteVideo = { name: string @@ -56,46 +58,32 @@ export namespace VideoMethods { export type IsOwned = (this: VideoInstance) => boolean export type ToFormatedJSON = (this: VideoInstance) => FormatedVideo - export type ToAddRemoteJSONCallback = (err: Error, videoFormated?: FormatedAddRemoteVideo) => void - export type ToAddRemoteJSON = (this: VideoInstance, callback: ToAddRemoteJSONCallback) => void - + export type ToAddRemoteJSON = (this: VideoInstance) => Promise export type ToUpdateRemoteJSON = (this: VideoInstance) => FormatedUpdateRemoteVideo - export type TranscodeVideofileCallback = (err: Error) => void - export type TranscodeVideofile = (this: VideoInstance, callback: TranscodeVideofileCallback) => void - - export type GenerateThumbnailFromDataCallback = (err: Error, thumbnailName?: string) => void - export type GenerateThumbnailFromData = (video: VideoInstance, thumbnailData: string, callback: GenerateThumbnailFromDataCallback) => void - - export type GetDurationFromFileCallback = (err: Error, duration?: number) => void - export type GetDurationFromFile = (videoPath, callback) => void - - export type ListCallback = (err: Error, videoInstances: VideoInstance[]) => void - export type List = (callback: ListCallback) => void - - export type ListForApiCallback = (err: Error, videoInstances?: VideoInstance[], total?: number) => void - export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void - - export type LoadByHostAndRemoteIdCallback = (err: Error, videoInstance: VideoInstance) => void - export type LoadByHostAndRemoteId = (fromHost: string, remoteId: string, callback: LoadByHostAndRemoteIdCallback) => void - - export type ListOwnedAndPopulateAuthorAndTagsCallback = (err: Error, videoInstances: VideoInstance[]) => void - export type ListOwnedAndPopulateAuthorAndTags = (callback: ListOwnedAndPopulateAuthorAndTagsCallback) => void - - export type ListOwnedByAuthorCallback = (err: Error, videoInstances: VideoInstance[]) => void - export type ListOwnedByAuthor = (author: string, callback: ListOwnedByAuthorCallback) => void - - export type LoadCallback = (err: Error, videoInstance: VideoInstance) => void - export type Load = (id: string, callback: LoadCallback) => void - - export type LoadAndPopulateAuthorCallback = (err: Error, videoInstance: VideoInstance) => void - export type LoadAndPopulateAuthor = (id: string, callback: LoadAndPopulateAuthorCallback) => void - - export type LoadAndPopulateAuthorAndPodAndTagsCallback = (err: Error, videoInstance: VideoInstance) => void - export type LoadAndPopulateAuthorAndPodAndTags = (id: string, callback: LoadAndPopulateAuthorAndPodAndTagsCallback) => void - - export type SearchAndPopulateAuthorAndPodAndTagsCallback = (err: Error, videoInstances?: VideoInstance[], total?: number) => void - export type SearchAndPopulateAuthorAndPodAndTags = (value: string, field: string, start: number, count: number, sort: string, callback: SearchAndPopulateAuthorAndPodAndTagsCallback) => void + export type TranscodeVideofile = (this: VideoInstance) => Promise + + // Return thumbnail name + export type GenerateThumbnailFromData = (video: VideoInstance, thumbnailData: string) => Promise + export type GetDurationFromFile = (videoPath: string) => Promise + + export type List = () => Promise + export type ListOwnedAndPopulateAuthorAndTags = () => Promise + export type ListOwnedByAuthor = (author: string) => Promise + + export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList > + export type SearchAndPopulateAuthorAndPodAndTags = ( + value: string, + field: string, + start: number, + count: number, + sort: string + ) => Promise< ResultList > + + export type Load = (id: string) => Promise + export type LoadByHostAndRemoteId = (fromHost: string, remoteId: string) => Promise + export type LoadAndPopulateAuthor = (id: string) => Promise + export type LoadAndPopulateAuthorAndPodAndTags = (id: string) => Promise } export interface VideoClass { @@ -139,7 +127,7 @@ export interface VideoAttributes { dislikes?: number Author?: AuthorInstance - Tags?: VideoTagInstance[] + Tags?: TagInstance[] } export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance { @@ -157,6 +145,8 @@ export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.In toAddRemoteJSON: VideoMethods.ToAddRemoteJSON toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON transcodeVideofile: VideoMethods.TranscodeVideofile + + setTags: Sequelize.HasManySetAssociationsMixin } export interface VideoModel extends VideoClass, Sequelize.Model {} diff --git a/server/models/video/video-tag.ts b/server/models/video/video-tag.ts index 71ca85332..ac45374f8 100644 --- a/server/models/video/video-tag.ts +++ b/server/models/video/video-tag.ts @@ -1,12 +1,8 @@ import * as Sequelize from 'sequelize' -import { addMethodsToModel } from '../utils' import { - VideoTagClass, VideoTagInstance, - VideoTagAttributes, - - VideoTagMethods + VideoTagAttributes } from './video-tag-interface' let VideoTag: Sequelize.Model diff --git a/server/models/video/video.ts b/server/models/video/video.ts index e66ebee2d..629051ae4 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -1,17 +1,15 @@ import * as safeBuffer from 'safe-buffer' const Buffer = safeBuffer.Buffer -import * as createTorrent from 'create-torrent' import * as ffmpeg from 'fluent-ffmpeg' -import * as fs from 'fs' import * as magnetUtil from 'magnet-uri' import { map, values } from 'lodash' -import { parallel, series } from 'async' import * as parseTorrent from 'parse-torrent' import { join } from 'path' import * as Sequelize from 'sequelize' +import * as Promise from 'bluebird' import { database as db } from '../../initializers/database' -import { VideoTagInstance } from './video-tag-interface' +import { TagInstance } from './tag-interface' import { logger, isVideoNameValid, @@ -21,7 +19,12 @@ import { isVideoNSFWValid, isVideoDescriptionValid, isVideoInfoHashValid, - isVideoDurationValid + isVideoDurationValid, + readFileBufferPromise, + unlinkPromise, + renamePromise, + writeFilePromise, + createTorrentPromise } from '../../helpers' import { CONSTRAINTS_FIELDS, @@ -37,7 +40,6 @@ import { JobScheduler, removeVideoToFriends } from '../../lib' import { addMethodsToModel, getSort } from '../utils' import { - VideoClass, VideoInstance, VideoAttributes, @@ -260,7 +262,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da toFormatedJSON, toAddRemoteJSON, toUpdateRemoteJSON, - transcodeVideofile, + transcodeVideofile ] addMethodsToModel(Video, classMethods, instanceMethods) @@ -276,91 +278,53 @@ function beforeValidate (video: VideoInstance) { } function beforeCreate (video: VideoInstance, options: { transaction: Sequelize.Transaction }) { - return new Promise(function (resolve, reject) { + if (video.isOwned()) { + const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) const tasks = [] - if (video.isOwned()) { - const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) - - tasks.push( - function createVideoTorrent (callback) { - createTorrentFromVideo(video, videoPath, callback) - }, - - function createVideoThumbnail (callback) { - createThumbnail(video, videoPath, callback) - }, - - function createVideoPreview (callback) { - createPreview(video, videoPath, callback) - } - ) - - if (CONFIG.TRANSCODING.ENABLED === true) { - tasks.push( - function createVideoTranscoderJob (callback) { - const dataInput = { - id: video.id - } + tasks.push( + createTorrentFromVideo(video, videoPath), + createThumbnail(video, videoPath), + createPreview(video, videoPath) + ) - JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) - } - ) + if (CONFIG.TRANSCODING.ENABLED === true) { + const dataInput = { + id: video.id } - return parallel(tasks, function (err) { - if (err) return reject(err) - - return resolve() - }) + tasks.push( + JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput) + ) } - return resolve() - }) + return Promise.all(tasks) + } + + return Promise.resolve() } function afterDestroy (video: VideoInstance) { - return new Promise(function (resolve, reject) { - const tasks = [] - - tasks.push( - function (callback) { - removeThumbnail(video, callback) - } - ) - - if (video.isOwned()) { - tasks.push( - function removeVideoFile (callback) { - removeFile(video, callback) - }, + const tasks = [] - function removeVideoTorrent (callback) { - removeTorrent(video, callback) - }, - - function removeVideoPreview (callback) { - removePreview(video, callback) - }, - - function notifyFriends (callback) { - const params = { - remoteId: video.id - } - - removeVideoToFriends(params) + tasks.push( + removeThumbnail(video) + ) - return callback() - } - ) + if (video.isOwned()) { + const removeVideoToFriendsParams = { + remoteId: video.id } - parallel(tasks, function (err) { - if (err) return reject(err) + tasks.push( + removeFile(video), + removeTorrent(video), + removePreview(video), + removeVideoToFriends(removeVideoToFriendsParams) + ) + } - return resolve() - }) - }) + return Promise.all(tasks) } // ------------------------------ METHODS ------------------------------ @@ -488,7 +452,7 @@ toFormatedJSON = function (this: VideoInstance) { views: this.views, likes: this.likes, dislikes: this.dislikes, - tags: map(this.Tags, 'name'), + tags: map(this.Tags, 'name'), thumbnailPath: join(STATIC_PATHS.THUMBNAILS, this.getThumbnailName()), createdAt: this.createdAt, updatedAt: this.updatedAt @@ -497,15 +461,11 @@ toFormatedJSON = function (this: VideoInstance) { return json } -toAddRemoteJSON = function (this: VideoInstance, callback: VideoMethods.ToAddRemoteJSONCallback) { +toAddRemoteJSON = function (this: VideoInstance) { // Get thumbnail data to send to the other pod const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) - fs.readFile(thumbnailPath, (err, thumbnailData) => { - if (err) { - logger.error('Cannot read the thumbnail of the video') - return callback(err) - } + return readFileBufferPromise(thumbnailPath).then(thumbnailData => { const remoteVideo = { name: this.name, category: this.category, @@ -518,7 +478,7 @@ toAddRemoteJSON = function (this: VideoInstance, callback: VideoMethods.ToAddRem author: this.Author.name, duration: this.duration, thumbnailData: thumbnailData.toString('binary'), - tags: map(this.Tags, 'name'), + tags: map(this.Tags, 'name'), createdAt: this.createdAt, updatedAt: this.updatedAt, extname: this.extname, @@ -527,7 +487,7 @@ toAddRemoteJSON = function (this: VideoInstance, callback: VideoMethods.ToAddRem dislikes: this.dislikes } - return callback(null, remoteVideo) + return remoteVideo }) } @@ -543,7 +503,7 @@ toUpdateRemoteJSON = function (this: VideoInstance) { remoteId: this.id, author: this.Author.name, duration: this.duration, - tags: map(this.Tags, 'name'), + tags: map(this.Tags, 'name'), createdAt: this.createdAt, updatedAt: this.updatedAt, extname: this.extname, @@ -555,7 +515,7 @@ toUpdateRemoteJSON = function (this: VideoInstance) { return json } -transcodeVideofile = function (this: VideoInstance, finalCallback: VideoMethods.TranscodeVideofileCallback) { +transcodeVideofile = function (this: VideoInstance) { const video = this const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR @@ -563,78 +523,73 @@ transcodeVideofile = function (this: VideoInstance, finalCallback: VideoMethods. const videoInputPath = join(videosDirectory, video.getVideoFilename()) const videoOutputPath = join(videosDirectory, video.id + '-transcoded' + newExtname) - ffmpeg(videoInputPath) - .output(videoOutputPath) - .videoCodec('libx264') - .outputOption('-threads ' + CONFIG.TRANSCODING.THREADS) - .outputOption('-movflags faststart') - .on('error', finalCallback) - .on('end', function () { - series([ - function removeOldFile (callback) { - fs.unlink(videoInputPath, callback) - }, - - function moveNewFile (callback) { - // Important to do this before getVideoFilename() to take in account the new file extension - video.set('extname', newExtname) - - const newVideoPath = join(videosDirectory, video.getVideoFilename()) - fs.rename(videoOutputPath, newVideoPath, callback) - }, - - function torrent (callback) { - const newVideoPath = join(videosDirectory, video.getVideoFilename()) - createTorrentFromVideo(video, newVideoPath, callback) - }, - - function videoExtension (callback) { - video.save().asCallback(callback) - } - - ], function (err: Error) { - if (err) { - // Autodesctruction... - video.destroy().asCallback(function (err) { - if (err) logger.error('Cannot destruct video after transcoding failure.', { error: err }) + return new Promise((res, rej) => { + ffmpeg(videoInputPath) + .output(videoOutputPath) + .videoCodec('libx264') + .outputOption('-threads ' + CONFIG.TRANSCODING.THREADS) + .outputOption('-movflags faststart') + .on('error', rej) + .on('end', () => { + + return unlinkPromise(videoInputPath) + .then(() => { + // Important to do this before getVideoFilename() to take in account the new file extension + video.set('extname', newExtname) + + const newVideoPath = join(videosDirectory, video.getVideoFilename()) + return renamePromise(videoOutputPath, newVideoPath) }) + .then(() => { + const newVideoPath = join(videosDirectory, video.getVideoFilename()) + return createTorrentFromVideo(video, newVideoPath) + }) + .then(() => { + return video.save() + }) + .then(() => { + return res() + }) + .catch(err => { + // Autodesctruction... + video.destroy().asCallback(function (err) { + if (err) logger.error('Cannot destruct video after transcoding failure.', { error: err }) + }) - return finalCallback(err) - } - - return finalCallback(null) + return rej(err) + }) }) - }) - .run() + .run() + }) } // ------------------------------ STATICS ------------------------------ -generateThumbnailFromData = function (video: VideoInstance, thumbnailData: string, callback: VideoMethods.GenerateThumbnailFromDataCallback) { +generateThumbnailFromData = function (video: VideoInstance, thumbnailData: string) { // Creating the thumbnail for a remote video const thumbnailName = video.getThumbnailName() const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, thumbnailName) - fs.writeFile(thumbnailPath, Buffer.from(thumbnailData, 'binary'), function (err) { - if (err) return callback(err) - - return callback(null, thumbnailName) + return writeFilePromise(thumbnailPath, Buffer.from(thumbnailData, 'binary')).then(() => { + return thumbnailName }) } -getDurationFromFile = function (videoPath: string, callback: VideoMethods.GetDurationFromFileCallback) { - ffmpeg.ffprobe(videoPath, function (err, metadata) { - if (err) return callback(err) +getDurationFromFile = function (videoPath: string) { + return new Promise((res, rej) => { + ffmpeg.ffprobe(videoPath, function (err, metadata) { + if (err) return rej(err) - return callback(null, Math.floor(metadata.format.duration)) + return res(Math.floor(metadata.format.duration)) + }) }) } -list = function (callback: VideoMethods.ListCallback) { - return Video.findAll().asCallback(callback) +list = function () { + return Video.findAll() } -listForApi = function (start: number, count: number, sort: string, callback: VideoMethods.ListForApiCallback) { +listForApi = function (start: number, count: number, sort: string) { // Exclude Blakclisted videos from the list const query = { distinct: true, @@ -652,14 +607,15 @@ listForApi = function (start: number, count: number, sort: string, callback: Vid where: createBaseVideosWhere() } - return Video.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) + return Video.findAndCountAll(query).then(({ rows, count }) => { + return { + data: rows, + total: count + } }) } -loadByHostAndRemoteId = function (fromHost: string, remoteId: string, callback: VideoMethods.LoadByHostAndRemoteIdCallback) { +loadByHostAndRemoteId = function (fromHost: string, remoteId: string) { const query = { where: { remoteId: remoteId @@ -680,10 +636,10 @@ loadByHostAndRemoteId = function (fromHost: string, remoteId: string, callback: ] } - return Video.findOne(query).asCallback(callback) + return Video.findOne(query) } -listOwnedAndPopulateAuthorAndTags = function (callback: VideoMethods.ListOwnedAndPopulateAuthorAndTagsCallback) { +listOwnedAndPopulateAuthorAndTags = function () { // If remoteId is null this is *our* video const query = { where: { @@ -692,10 +648,10 @@ listOwnedAndPopulateAuthorAndTags = function (callback: VideoMethods.ListOwnedAn include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ] } - return Video.findAll(query).asCallback(callback) + return Video.findAll(query) } -listOwnedByAuthor = function (author: string, callback: VideoMethods.ListOwnedByAuthorCallback) { +listOwnedByAuthor = function (author: string) { const query = { where: { remoteId: null @@ -710,22 +666,22 @@ listOwnedByAuthor = function (author: string, callback: VideoMethods.ListOwnedBy ] } - return Video.findAll(query).asCallback(callback) + return Video.findAll(query) } -load = function (id: string, callback: VideoMethods.LoadCallback) { - return Video.findById(id).asCallback(callback) +load = function (id: string) { + return Video.findById(id) } -loadAndPopulateAuthor = function (id: string, callback: VideoMethods.LoadAndPopulateAuthorCallback) { +loadAndPopulateAuthor = function (id: string) { const options = { include: [ Video['sequelize'].models.Author ] } - return Video.findById(id, options).asCallback(callback) + return Video.findById(id, options) } -loadAndPopulateAuthorAndPodAndTags = function (id: string, callback: VideoMethods.LoadAndPopulateAuthorAndPodAndTagsCallback) { +loadAndPopulateAuthorAndPodAndTags = function (id: string) { const options = { include: [ { @@ -736,17 +692,10 @@ loadAndPopulateAuthorAndPodAndTags = function (id: string, callback: VideoMethod ] } - return Video.findById(id, options).asCallback(callback) + return Video.findById(id, options) } -searchAndPopulateAuthorAndPodAndTags = function ( - value: string, - field: string, - start: number, - count: number, - sort: string, - callback: VideoMethods.SearchAndPopulateAuthorAndPodAndTagsCallback -) { +searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, start: number, count: number, sort: string) { const podInclude: any = { model: Video['sequelize'].models.Pod, required: false @@ -778,7 +727,11 @@ searchAndPopulateAuthorAndPodAndTags = function ( } else if (field === 'tags') { const escapedValue = Video['sequelize'].escape('%' + value + '%') query.where.id.$in = Video['sequelize'].literal( - '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')' + `(SELECT "VideoTags"."videoId" + FROM "Tags" + INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" + WHERE name LIKE ${escapedValue} + )` ) } else if (field === 'host') { // FIXME: Include our pod? (not stored in the database) @@ -810,10 +763,11 @@ searchAndPopulateAuthorAndPodAndTags = function ( // query.include.push([ Video['sequelize'].models.Tag ]) } - return Video.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) + return Video.findAndCountAll(query).then(({ rows, count }) => { + return { + data: rows, + total: count + } }) } @@ -829,27 +783,27 @@ function createBaseVideosWhere () { } } -function removeThumbnail (video: VideoInstance, callback: (err: Error) => void) { +function removeThumbnail (video: VideoInstance) { const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()) - fs.unlink(thumbnailPath, callback) + return unlinkPromise(thumbnailPath) } -function removeFile (video: VideoInstance, callback: (err: Error) => void) { +function removeFile (video: VideoInstance) { const filePath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) - fs.unlink(filePath, callback) + return unlinkPromise(filePath) } -function removeTorrent (video: VideoInstance, callback: (err: Error) => void) { +function removeTorrent (video: VideoInstance) { const torrenPath = join(CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName()) - fs.unlink(torrenPath, callback) + return unlinkPromise(torrenPath) } -function removePreview (video: VideoInstance, callback: (err: Error) => void) { +function removePreview (video: VideoInstance) { // Same name than video thumnail - fs.unlink(CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName(), callback) + return unlinkPromise(CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName()) } -function createTorrentFromVideo (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { +function createTorrentFromVideo (video: VideoInstance, videoPath: string) { const options = { announceList: [ [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ] @@ -859,30 +813,27 @@ function createTorrentFromVideo (video: VideoInstance, videoPath: string, callba ] } - createTorrent(videoPath, options, function (err, torrent) { - if (err) return callback(err) - - const filePath = join(CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName()) - fs.writeFile(filePath, torrent, function (err) { - if (err) return callback(err) - + return createTorrentPromise(videoPath, options) + .then(torrent => { + const filePath = join(CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName()) + return writeFilePromise(filePath, torrent).then(() => torrent) + }) + .then(torrent => { const parsedTorrent = parseTorrent(torrent) video.set('infoHash', parsedTorrent.infoHash) - video.validate().asCallback(callback) + return video.validate() }) - }) } -function createPreview (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { - generateImage(video, videoPath, CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), null, callback) +function createPreview (video: VideoInstance, videoPath: string) { + return generateImage(video, videoPath, CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), null) } -function createThumbnail (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { - generateImage(video, videoPath, CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName(), THUMBNAILS_SIZE, callback) +function createThumbnail (video: VideoInstance, videoPath: string) { + return generateImage(video, videoPath, CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName(), THUMBNAILS_SIZE) } -type GenerateImageCallback = (err: Error, imageName: string) => void -function generateImage (video: VideoInstance, videoPath: string, folder: string, imageName: string, size: string, callback?: GenerateImageCallback) { +function generateImage (video: VideoInstance, videoPath: string, folder: string, imageName: string, size: string) { const options: any = { filename: imageName, count: 1, @@ -893,29 +844,25 @@ function generateImage (video: VideoInstance, videoPath: string, folder: string, options.size = size } - ffmpeg(videoPath) - .on('error', callback) - .on('end', function () { - callback(null, imageName) - }) - .thumbnail(options) + return new Promise((res, rej) => { + ffmpeg(videoPath) + .on('error', rej) + .on('end', function () { + return res(imageName) + }) + .thumbnail(options) + }) } -function removeFromBlacklist (video: VideoInstance, callback: (err: Error) => void) { +function removeFromBlacklist (video: VideoInstance) { // Find the blacklisted video - db.BlacklistedVideo.loadByVideoId(video.id, function (err, video) { - // If an error occured, stop here - if (err) { - logger.error('Error when fetching video from blacklist.', { error: err }) - return callback(err) + return db.BlacklistedVideo.loadByVideoId(video.id).then(video => { + // Not found the video, skip + if (!video) { + return null } // If we found the video, remove it from the blacklist - if (video) { - video.destroy().asCallback(callback) - } else { - // If haven't found it, simply ignore it and do nothing - return callback(null) - } + return video.destroy() }) } -- cgit v1.2.3