1
0
Fork 0

Update sequelize

This commit is contained in:
Chocobozzz 2019-04-18 11:28:17 +02:00
parent e8bafea35b
commit 1735c82572
No known key found for this signature in database
GPG key ID: 583A612D890159BE
46 changed files with 389 additions and 421 deletions

View file

@ -142,8 +142,8 @@
"reflect-metadata": "^0.1.12", "reflect-metadata": "^0.1.12",
"request": "^2.81.0", "request": "^2.81.0",
"scripty": "^1.5.0", "scripty": "^1.5.0",
"sequelize": "4.42.0", "sequelize": "5.6.1",
"sequelize-typescript": "0.6.7", "sequelize-typescript": "^1.0.0-beta.1",
"sharp": "^0.22.0", "sharp": "^0.22.0",
"sitemap": "^2.1.0", "sitemap": "^2.1.0",
"socket.io": "^2.2.0", "socket.io": "^2.2.0",

View file

@ -15,7 +15,6 @@ import { VideoImportModel } from '../../../models/video/video-import'
import { JobQueue } from '../../../lib/job-queue/job-queue' import { JobQueue } from '../../../lib/job-queue/job-queue'
import { join } from 'path' import { join } from 'path'
import { isArray } from '../../../helpers/custom-validators/misc' import { isArray } from '../../../helpers/custom-validators/misc'
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
import { VideoChannelModel } from '../../../models/video/video-channel' import { VideoChannelModel } from '../../../models/video/video-channel'
import * as Bluebird from 'bluebird' import * as Bluebird from 'bluebird'
import * as parseTorrent from 'parse-torrent' import * as parseTorrent from 'parse-torrent'
@ -228,7 +227,7 @@ function insertIntoDB (parameters: {
previewModel: ThumbnailModel, previewModel: ThumbnailModel,
videoChannel: VideoChannelModel, videoChannel: VideoChannelModel,
tags: string[], tags: string[],
videoImportAttributes: FilteredModelAttributes<VideoImportModel> videoImportAttributes: Partial<VideoImportModel>
}): Bluebird<VideoImportModel> { }): Bluebird<VideoImportModel> {
let { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes } = parameters let { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes } = parameters

View file

@ -332,15 +332,15 @@ async function updateVideo (req: express.Request, res: express.Response) {
if (videoInfoToUpdate.downloadEnabled !== undefined) videoInstance.set('downloadEnabled', videoInfoToUpdate.downloadEnabled) if (videoInfoToUpdate.downloadEnabled !== undefined) videoInstance.set('downloadEnabled', videoInfoToUpdate.downloadEnabled)
if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) { if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) {
videoInstance.set('originallyPublishedAt', videoInfoToUpdate.originallyPublishedAt) videoInstance.originallyPublishedAt = new Date(videoInfoToUpdate.originallyPublishedAt)
} }
if (videoInfoToUpdate.privacy !== undefined) { if (videoInfoToUpdate.privacy !== undefined) {
const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10)
videoInstance.set('privacy', newPrivacy) videoInstance.privacy = newPrivacy
if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) { if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) {
videoInstance.set('publishedAt', new Date()) videoInstance.publishedAt = new Date()
} }
} }

View file

@ -62,14 +62,13 @@ function updateInstanceWithAnother <T extends Model<T>> (instanceToUpdate: Model
const obj = baseInstance.toJSON() const obj = baseInstance.toJSON()
for (const key of Object.keys(obj)) { for (const key of Object.keys(obj)) {
instanceToUpdate.set(key, obj[key]) instanceToUpdate[key] = obj[key]
} }
} }
function resetSequelizeInstance (instance: Model<any>, savedFields: object) { function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
Object.keys(savedFields).forEach(key => { Object.keys(savedFields).forEach(key => {
const value = savedFields[key] instance[key] = savedFields[key]
instance.set(key, value)
}) })
} }

View file

@ -37,6 +37,7 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla
import { VideoPlaylistModel } from '../models/video/video-playlist' import { VideoPlaylistModel } from '../models/video/video-playlist'
import { VideoPlaylistElementModel } from '../models/video/video-playlist-element' import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
import { ThumbnailModel } from '../models/video/thumbnail' import { ThumbnailModel } from '../models/video/thumbnail'
import { QueryTypes, Transaction } from 'sequelize'
require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
@ -58,8 +59,7 @@ const sequelizeTypescript = new SequelizeTypescript({
max: poolMax max: poolMax
}, },
benchmark: isTestInstance(), benchmark: isTestInstance(),
isolationLevel: SequelizeTypescript.Transaction.ISOLATION_LEVELS.SERIALIZABLE, isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
operatorsAliases: false,
logging: (message: string, benchmark: number) => { logging: (message: string, benchmark: number) => {
if (process.env.NODE_DB_LOG === 'false') return if (process.env.NODE_DB_LOG === 'false') return
@ -141,10 +141,15 @@ async function checkPostgresExtensions () {
async function checkPostgresExtension (extension: string) { async function checkPostgresExtension (extension: string) {
const query = `SELECT true AS enabled FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;` const query = `SELECT true AS enabled FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;`
const [ res ] = await sequelizeTypescript.query(query, { raw: true }) const options = {
type: QueryTypes.SELECT as QueryTypes.SELECT,
raw: true
}
const res = await sequelizeTypescript.query<{ enabled: boolean }>(query, options)
if (!res || res.length === 0 || res[ 0 ][ 'enabled' ] !== true) { if (!res || res.length === 0 || res[ 0 ][ 'enabled' ] !== true) {
// Try to create the extension ourself // Try to create the extension ourselves
try { try {
await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true }) await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true })

View file

@ -69,7 +69,7 @@ async function up (utils: {
const options = { const options = {
type: Sequelize.QueryTypes.SELECT type: Sequelize.QueryTypes.SELECT
} }
const rawVideos = await utils.sequelize.query(query, options) const rawVideos = await utils.sequelize.query(query, options) as any
for (const rawVideo of rawVideos) { for (const rawVideo of rawVideos) {
const videoChannel = await utils.db.VideoChannel.findOne({ where: { authorId: rawVideo.authorId } }) const videoChannel = await utils.db.VideoChannel.findOne({ where: { authorId: rawVideo.authorId } })

View file

@ -21,7 +21,7 @@ async function up (utils: {
const options = { const options = {
type: Sequelize.QueryTypes.SELECT type: Sequelize.QueryTypes.SELECT
} }
const res = await utils.sequelize.query(query, options) const res = await utils.sequelize.query(query, options) as any
if (!res[0] || res[0].total !== 0) { if (!res[0] || res[0].total !== 0) {
throw new Error('You need to quit friends.') throw new Error('You need to quit friends.')
@ -68,8 +68,8 @@ async function up (utils: {
const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACTOR_NAME, null, applicationInstance.id, undefined) const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACTOR_NAME, null, applicationInstance.id, undefined)
const { publicKey, privateKey } = await createPrivateAndPublicKeys() const { publicKey, privateKey } = await createPrivateAndPublicKeys()
accountCreated.set('publicKey', publicKey) accountCreated.Actor.publicKey = publicKey
accountCreated.set('privateKey', privateKey) accountCreated.Actor.privateKey = privateKey
await accountCreated.save() await accountCreated.save()
} }
@ -86,8 +86,8 @@ async function up (utils: {
const account = await createLocalAccountWithoutKeys(user.username, user.id, null, undefined) const account = await createLocalAccountWithoutKeys(user.username, user.id, null, undefined)
const { publicKey, privateKey } = await createPrivateAndPublicKeys() const { publicKey, privateKey } = await createPrivateAndPublicKeys()
account.set('publicKey', publicKey) account.Actor.publicKey = publicKey
account.set('privateKey', privateKey) account.Actor.privateKey = privateKey
await account.save() await account.save()
} }

View file

@ -239,7 +239,8 @@ async function up (utils: {
{ {
const query = 'SELECT * FROM "actor" WHERE "serverId" IS NULL AND "publicKey" IS NULL' const query = 'SELECT * FROM "actor" WHERE "serverId" IS NULL AND "publicKey" IS NULL'
const [ res ] = await utils.sequelize.query(query) const options = { type: Sequelize.QueryTypes.SELECT as Sequelize.QueryTypes.SELECT }
const [ res ] = await utils.sequelize.query(query, options)
for (const actor of res) { for (const actor of res) {
const { privateKey, publicKey } = await createPrivateAndPublicKeys() const { privateKey, publicKey } = await createPrivateAndPublicKeys()

View file

@ -51,7 +51,9 @@ CREATE TABLE IF NOT EXISTS "videoPlaylistElement"
{ {
const userQuery = 'SELECT "username" FROM "user";' const userQuery = 'SELECT "username" FROM "user";'
const userResult = await utils.sequelize.query(userQuery, { transaction, type: Sequelize.QueryTypes.SELECT })
const options = { transaction, type: Sequelize.QueryTypes.SELECT as Sequelize.QueryTypes.SELECT }
const userResult = await utils.sequelize.query<{ username: string }>(userQuery, options)
const usernames = userResult.map(r => r.username) const usernames = userResult.map(r => r.username)
for (const username of usernames) { for (const username of usernames) {

View file

@ -3,6 +3,7 @@ import { logger } from '../helpers/logger'
import { LAST_MIGRATION_VERSION } from './constants' import { LAST_MIGRATION_VERSION } from './constants'
import { sequelizeTypescript } from './database' import { sequelizeTypescript } from './database'
import { readdir } from 'fs-extra' import { readdir } from 'fs-extra'
import { QueryTypes } from 'sequelize'
async function migrate () { async function migrate () {
const tables = await sequelizeTypescript.getQueryInterface().showAllTables() const tables = await sequelizeTypescript.getQueryInterface().showAllTables()
@ -13,7 +14,12 @@ async function migrate () {
let actualVersion: number | null = null let actualVersion: number | null = null
const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"') const query = 'SELECT "migrationVersion" FROM "application"'
const options = {
type: QueryTypes.SELECT as QueryTypes.SELECT
}
const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options)
if (rows && rows[0] && rows[0].migrationVersion) { if (rows && rows[0] && rows[0].migrationVersion) {
actualVersion = rows[0].migrationVersion actualVersion = rows[0].migrationVersion
} }

View file

@ -68,8 +68,8 @@ function updateCacheFile (
const attributes = cacheFileActivityObjectToDBAttributes(cacheFileObject, video, byActor) const attributes = cacheFileActivityObjectToDBAttributes(cacheFileObject, video, byActor)
redundancyModel.set('expires', attributes.expiresOn) redundancyModel.expiresOn = attributes.expiresOn
redundancyModel.set('fileUrl', attributes.fileUrl) redundancyModel.fileUrl = attributes.fileUrl
return redundancyModel.save({ transaction: t }) return redundancyModel.save({ transaction: t })
} }

View file

@ -14,7 +14,6 @@ import { getOrCreateVideoAndAccountAndChannel } from './videos'
import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist' import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist'
import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element' import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
import { VideoModel } from '../../models/video/video' import { VideoModel } from '../../models/video/video'
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
import { sequelizeTypescript } from '../../initializers/database' import { sequelizeTypescript } from '../../initializers/database'
import { createPlaylistThumbnailFromUrl } from '../thumbnail' import { createPlaylistThumbnailFromUrl } from '../thumbnail'
@ -87,7 +86,8 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc
} }
} }
const [ playlist ] = await VideoPlaylistModel.upsert<VideoPlaylistModel>(playlistAttributes, { returning: true }) // FIXME: sequelize typings
const [ playlist ] = (await VideoPlaylistModel.upsert<VideoPlaylistModel>(playlistAttributes, { returning: true }) as any)
let accItems: string[] = [] let accItems: string[] = []
await crawlCollectionPage<string>(playlistObject.id, items => { await crawlCollectionPage<string>(playlistObject.id, items => {
@ -156,7 +156,7 @@ export {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
async function resetVideoPlaylistElements (elementUrls: string[], playlist: VideoPlaylistModel) { async function resetVideoPlaylistElements (elementUrls: string[], playlist: VideoPlaylistModel) {
const elementsToCreate: FilteredModelAttributes<VideoPlaylistElementModel>[] = [] const elementsToCreate: object[] = [] // FIXME: sequelize typings
await Bluebird.map(elementUrls, async elementUrl => { await Bluebird.map(elementUrls, async elementUrl => {
try { try {

View file

@ -37,7 +37,9 @@ async function processFollow (actor: ActorModel, targetActorURL: string) {
if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) {
logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) logger.info('Rejecting %s because instance followers are disabled.', targetActor.url)
return sendReject(actor, targetActor) await sendReject(actor, targetActor)
return { actorFollow: undefined }
} }
const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({

View file

@ -120,9 +120,11 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate)
await actor.save({ transaction: t }) await actor.save({ transaction: t })
accountOrChannelInstance.set('name', actorAttributesToUpdate.name || actorAttributesToUpdate.preferredUsername) accountOrChannelInstance.name = actorAttributesToUpdate.name || actorAttributesToUpdate.preferredUsername
accountOrChannelInstance.set('description', actorAttributesToUpdate.summary) accountOrChannelInstance.description = actorAttributesToUpdate.summary
accountOrChannelInstance.set('support', actorAttributesToUpdate.support)
if (accountOrChannelInstance instanceof VideoChannelModel) accountOrChannelInstance.support = actorAttributesToUpdate.support
await accountOrChannelInstance.save({ transaction: t }) await accountOrChannelInstance.save({ transaction: t })
}) })

View file

@ -73,7 +73,8 @@ async function addVideoComment (videoInstance: VideoModel, commentUrl: string) {
const entry = await videoCommentActivityObjectToDBAttributes(videoInstance, actor, body) const entry = await videoCommentActivityObjectToDBAttributes(videoInstance, actor, body)
if (!entry) return { created: false } if (!entry) return { created: false }
const [ comment, created ] = await VideoCommentModel.upsert<VideoCommentModel>(entry, { returning: true }) // FIXME: sequelize typings
const [ comment, created ] = (await VideoCommentModel.upsert<VideoCommentModel>(entry, { returning: true }) as any)
comment.Account = actor.Account comment.Account = actor.Account
comment.Video = videoInstance comment.Video = videoInstance

View file

@ -56,7 +56,10 @@ async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRa
logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid)
// This is "likes" and "dislikes" // This is "likes" and "dislikes"
if (rateCounts !== 0) await video.increment(rate + 's', { by: rateCounts }) if (rateCounts !== 0) {
const field = rate === 'like' ? 'likes' : 'dislikes'
await video.increment(field, { by: rateCounts })
}
return return
} }

View file

@ -6,7 +6,7 @@ import {
ActivityPlaylistSegmentHashesObject, ActivityPlaylistSegmentHashesObject,
ActivityPlaylistUrlObject, ActivityPlaylistUrlObject,
ActivityUrlObject, ActivityUrlObject,
ActivityVideoUrlObject, VideoCreate, ActivityVideoUrlObject,
VideoState VideoState
} from '../../../shared/index' } from '../../../shared/index'
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
@ -45,7 +45,6 @@ import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
import { Notifier } from '../notifier' import { Notifier } from '../notifier'
import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist'
import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
import { AccountVideoRateModel } from '../../models/account/account-video-rate' import { AccountVideoRateModel } from '../../models/account/account-video-rate'
import { VideoShareModel } from '../../models/video/video-share' import { VideoShareModel } from '../../models/video/video-share'
import { VideoCommentModel } from '../../models/video/video-comment' import { VideoCommentModel } from '../../models/video/video-comment'
@ -312,7 +311,7 @@ async function updateVideoFromAP (options: {
// Update or add other one // Update or add other one
const upsertTasks = videoFileAttributes.map(a => { const upsertTasks = videoFileAttributes.map(a => {
return VideoFileModel.upsert<VideoFileModel>(a, { returning: true, transaction: t }) return (VideoFileModel.upsert<VideoFileModel>(a, { returning: true, transaction: t }) as any) // FIXME: sequelize typings
.then(([ file ]) => file) .then(([ file ]) => file)
}) })
@ -335,7 +334,8 @@ async function updateVideoFromAP (options: {
// Update or add other one // Update or add other one
const upsertTasks = streamingPlaylistAttributes.map(a => { const upsertTasks = streamingPlaylistAttributes.map(a => {
return VideoStreamingPlaylistModel.upsert<VideoStreamingPlaylistModel>(a, { returning: true, transaction: t }) // FIXME: sequelize typings
return (VideoStreamingPlaylistModel.upsert<VideoStreamingPlaylistModel>(a, { returning: true, transaction: t }) as any)
.then(([ streamingPlaylist ]) => streamingPlaylist) .then(([ streamingPlaylist ]) => streamingPlaylist)
}) })
@ -594,7 +594,7 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid
throw new Error('Cannot find video files for ' + video.url) throw new Error('Cannot find video files for ' + video.url)
} }
const attributes: FilteredModelAttributes<VideoFileModel>[] = [] const attributes: object[] = [] // FIXME: add typings
for (const fileUrl of fileUrls) { for (const fileUrl of fileUrls) {
// Fetch associated magnet uri // Fetch associated magnet uri
const magnet = videoObject.url.find(u => { const magnet = videoObject.url.find(u => {
@ -629,7 +629,7 @@ function streamingPlaylistActivityUrlToDBAttributes (video: VideoModel, videoObj
const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[] const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[]
if (playlistUrls.length === 0) return [] if (playlistUrls.length === 0) return []
const attributes: FilteredModelAttributes<VideoStreamingPlaylistModel>[] = [] const attributes: object[] = [] // FIXME: add typings
for (const playlistUrlObject of playlistUrls) { for (const playlistUrlObject of playlistUrls) {
const segmentsSha256UrlObject = playlistUrlObject.tag const segmentsSha256UrlObject = playlistUrlObject.tag
.find(t => { .find(t => {

View file

@ -7,7 +7,6 @@ import { UserModel } from '../models/account/user'
import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub'
import { createVideoChannel } from './video-channel' import { createVideoChannel } from './video-channel'
import { VideoChannelModel } from '../models/video/video-channel' import { VideoChannelModel } from '../models/video/video-channel'
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
import { ActorModel } from '../models/activitypub/actor' import { ActorModel } from '../models/activitypub/actor'
import { UserNotificationSettingModel } from '../models/account/user-notification-setting' import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users'
@ -73,7 +72,7 @@ async function createLocalAccountWithoutKeys (
userId, userId,
applicationId, applicationId,
actorId: actorInstanceCreated.id actorId: actorInstanceCreated.id
} as FilteredModelAttributes<AccountModel>) })
const accountInstanceCreated = await accountInstance.save({ transaction: t }) const accountInstanceCreated = await accountInstance.save({ transaction: t })
accountInstanceCreated.Actor = actorInstanceCreated accountInstanceCreated.Actor = actorInstanceCreated

View file

@ -28,7 +28,7 @@ async function createVideoComment (obj: {
videoId: obj.video.id, videoId: obj.video.id,
accountId: obj.account.id, accountId: obj.account.id,
url: 'fake url' url: 'fake url'
}, { transaction: t, validate: false }) }, { transaction: t, validate: false } as any) // FIXME: sequelize typings
comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment)) comment.set('url', getVideoCommentActivityPubUrl(obj.video, comment))

View file

@ -1,16 +1,15 @@
import { values } from 'lodash' import { values } from 'lodash'
import { Transaction, Op } from 'sequelize' import { FindOptions, Op, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions'
import { VideoRateType } from '../../../shared/models/videos' import { VideoRateType } from '../../../shared/models/videos'
import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants' import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants'
import { VideoModel } from '../video/video' import { VideoModel } from '../video/video'
import { AccountModel } from './account' import { AccountModel } from './account'
import { ActorModel } from '../activitypub/actor' import { ActorModel } from '../activitypub/actor'
import { throwIfNotValid, getSort } from '../utils' import { getSort, throwIfNotValid } from '../utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { AccountVideoRate } from '../../../shared' import { AccountVideoRate } from '../../../shared'
import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel' import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from '../video/video-channel'
/* /*
Account rates per video. Account rates per video.
@ -40,7 +39,7 @@ import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../vide
export class AccountVideoRateModel extends Model<AccountVideoRateModel> { export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(values(VIDEO_RATE_TYPES))) @Column(DataType.ENUM(...values(VIDEO_RATE_TYPES)))
type: VideoRateType type: VideoRateType
@AllowNull(false) @AllowNull(false)
@ -79,7 +78,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
Account: AccountModel Account: AccountModel
static load (accountId: number, videoId: number, transaction?: Transaction) { static load (accountId: number, videoId: number, transaction?: Transaction) {
const options: IFindOptions<AccountVideoRateModel> = { const options: FindOptions = {
where: { where: {
accountId, accountId,
videoId videoId
@ -97,7 +96,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
type?: string, type?: string,
accountId: number accountId: number
}) { }) {
const query: IFindOptions<AccountVideoRateModel> = { const query: FindOptions = {
offset: options.start, offset: options.start,
limit: options.count, limit: options.count,
order: getSort(options.sort), order: getSort(options.sort),
@ -123,7 +122,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
} }
static loadLocalAndPopulateVideo (rateType: VideoRateType, accountName: string, videoId: number, transaction?: Transaction) { static loadLocalAndPopulateVideo (rateType: VideoRateType, accountName: string, videoId: number, transaction?: Transaction) {
const options: IFindOptions<AccountVideoRateModel> = { const options: FindOptions = {
where: { where: {
videoId, videoId,
type: rateType type: rateType
@ -155,7 +154,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
} }
static loadByUrl (url: string, transaction: Transaction) { static loadByUrl (url: string, transaction: Transaction) {
const options: IFindOptions<AccountVideoRateModel> = { const options: FindOptions = {
where: { where: {
url url
} }

View file

@ -1,4 +1,3 @@
import * as Sequelize from 'sequelize'
import { import {
AllowNull, AllowNull,
BeforeDestroy, BeforeDestroy,
@ -28,6 +27,7 @@ import { UserModel } from './user'
import { AvatarModel } from '../avatar/avatar' import { AvatarModel } from '../avatar/avatar'
import { VideoPlaylistModel } from '../video/video-playlist' import { VideoPlaylistModel } from '../video/video-playlist'
import { WEBSERVER } from '../../initializers/constants' import { WEBSERVER } from '../../initializers/constants'
import { Op, Transaction, WhereOptions } from 'sequelize'
export enum ScopeNames { export enum ScopeNames {
SUMMARY = 'SUMMARY' SUMMARY = 'SUMMARY'
@ -42,7 +42,7 @@ export enum ScopeNames {
] ]
}) })
@Scopes({ @Scopes({
[ ScopeNames.SUMMARY ]: (whereActor?: Sequelize.WhereOptions<ActorModel>) => { [ ScopeNames.SUMMARY ]: (whereActor?: WhereOptions) => {
return { return {
attributes: [ 'id', 'name' ], attributes: [ 'id', 'name' ],
include: [ include: [
@ -90,7 +90,7 @@ export class AccountModel extends Model<AccountModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('AccountDescription', value => throwIfNotValid(value, isAccountDescriptionValid, 'description')) @Is('AccountDescription', value => throwIfNotValid(value, isAccountDescriptionValid, 'description', true))
@Column @Column
description: string description: string
@ -176,7 +176,7 @@ export class AccountModel extends Model<AccountModel> {
return undefined return undefined
} }
static load (id: number, transaction?: Sequelize.Transaction) { static load (id: number, transaction?: Transaction) {
return AccountModel.findByPk(id, { transaction }) return AccountModel.findByPk(id, { transaction })
} }
@ -207,15 +207,15 @@ export class AccountModel extends Model<AccountModel> {
static loadLocalByName (name: string) { static loadLocalByName (name: string) {
const query = { const query = {
where: { where: {
[ Sequelize.Op.or ]: [ [ Op.or ]: [
{ {
userId: { userId: {
[ Sequelize.Op.ne ]: null [ Op.ne ]: null
} }
}, },
{ {
applicationId: { applicationId: {
[ Sequelize.Op.ne ]: null [ Op.ne ]: null
} }
} }
] ]
@ -259,7 +259,7 @@ export class AccountModel extends Model<AccountModel> {
return AccountModel.findOne(query) return AccountModel.findOne(query)
} }
static loadByUrl (url: string, transaction?: Sequelize.Transaction) { static loadByUrl (url: string, transaction?: Transaction) {
const query = { const query = {
include: [ include: [
{ {

View file

@ -1,17 +1,4 @@
import { import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
AllowNull,
BelongsTo,
Column,
CreatedAt,
Default,
ForeignKey,
IFindOptions,
Is,
Model,
Scopes,
Table,
UpdatedAt
} from 'sequelize-typescript'
import { UserNotification, UserNotificationType } from '../../../shared' import { UserNotification, UserNotificationType } from '../../../shared'
import { getSort, throwIfNotValid } from '../utils' import { getSort, throwIfNotValid } from '../utils'
import { isBooleanValid } from '../../helpers/custom-validators/misc' import { isBooleanValid } from '../../helpers/custom-validators/misc'
@ -19,7 +6,7 @@ import { isUserNotificationTypeValid } from '../../helpers/custom-validators/use
import { UserModel } from './user' import { UserModel } from './user'
import { VideoModel } from '../video/video' import { VideoModel } from '../video/video'
import { VideoCommentModel } from '../video/video-comment' import { VideoCommentModel } from '../video/video-comment'
import { Op } from 'sequelize' import { FindOptions, Op } from 'sequelize'
import { VideoChannelModel } from '../video/video-channel' import { VideoChannelModel } from '../video/video-channel'
import { AccountModel } from './account' import { AccountModel } from './account'
import { VideoAbuseModel } from '../video/video-abuse' import { VideoAbuseModel } from '../video/video-abuse'
@ -160,7 +147,7 @@ function buildAccountInclude (required: boolean, withActor = false) {
}, },
buildAccountInclude(false, true) buildAccountInclude(false, true)
] ] as any // FIXME: sequelize typings
} }
}) })
@Table({ @Table({
@ -225,7 +212,7 @@ function buildAccountInclude (required: boolean, withActor = false) {
} }
} }
} }
] ] as any // FIXME: sequelize typings
}) })
export class UserNotificationModel extends Model<UserNotificationModel> { export class UserNotificationModel extends Model<UserNotificationModel> {
@ -344,7 +331,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
ActorFollow: ActorFollowModel ActorFollow: ActorFollowModel
static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) {
const query: IFindOptions<UserNotificationModel> = { const query: FindOptions = {
offset: start, offset: start,
limit: count, limit: count,
order: getSort(sort), order: getSort(sort),

View file

@ -76,7 +76,7 @@ export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> {
} }
if (beforeDate) { if (beforeDate) {
query.where.updatedAt = { query.where['updatedAt'] = {
[Op.lt]: beforeDate [Op.lt]: beforeDate
} }
} }

View file

@ -80,7 +80,7 @@ enum ScopeNames {
model: () => UserNotificationSettingModel, model: () => UserNotificationSettingModel,
required: true required: true
} }
] ] as any // FIXME: sequelize typings
} }
}) })
@Table({ @Table({
@ -115,13 +115,13 @@ export class UserModel extends Model<UserModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean')) @Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean', true))
@Column @Column
emailVerified: boolean emailVerified: boolean
@AllowNull(false) @AllowNull(false)
@Is('UserNSFWPolicy', value => throwIfNotValid(value, isUserNSFWPolicyValid, 'NSFW policy')) @Is('UserNSFWPolicy', value => throwIfNotValid(value, isUserNSFWPolicyValid, 'NSFW policy'))
@Column(DataType.ENUM(values(NSFW_POLICY_TYPES))) @Column(DataType.ENUM(...values(NSFW_POLICY_TYPES)))
nsfwPolicy: NSFWPolicyType nsfwPolicy: NSFWPolicyType
@AllowNull(false) @AllowNull(false)
@ -156,7 +156,7 @@ export class UserModel extends Model<UserModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('UserBlockedReason', value => throwIfNotValid(value, isUserBlockedReasonValid, 'blocked reason')) @Is('UserBlockedReason', value => throwIfNotValid(value, isUserBlockedReasonValid, 'blocked reason', true))
@Column @Column
blockedReason: string blockedReason: string
@ -556,10 +556,10 @@ export class UserModel extends Model<UserModel> {
notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined, notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined,
videoChannels: [], videoChannels: [],
videoQuotaUsed: videoQuotaUsed !== undefined videoQuotaUsed: videoQuotaUsed !== undefined
? parseInt(videoQuotaUsed, 10) ? parseInt(videoQuotaUsed + '', 10)
: undefined, : undefined,
videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined
? parseInt(videoQuotaUsedDaily, 10) ? parseInt(videoQuotaUsedDaily + '', 10)
: undefined : undefined
} }
@ -619,14 +619,14 @@ export class UserModel extends Model<UserModel> {
private static getTotalRawQuery (query: string, userId: number) { private static getTotalRawQuery (query: string, userId: number) {
const options = { const options = {
bind: { userId }, bind: { userId },
type: Sequelize.QueryTypes.SELECT type: Sequelize.QueryTypes.SELECT as Sequelize.QueryTypes.SELECT
} }
return UserModel.sequelize.query(query, options) return UserModel.sequelize.query<{ total: number }>(query, options)
.then(([ { total } ]) => { .then(([ { total } ]) => {
if (total === null) return 0 if (total === null) return 0
return parseInt(total, 10) return parseInt(total + '', 10)
}) })
} }
} }

View file

@ -1,6 +1,5 @@
import * as Bluebird from 'bluebird' import * as Bluebird from 'bluebird'
import { values } from 'lodash' import { values } from 'lodash'
import * as Sequelize from 'sequelize'
import { import {
AfterCreate, AfterCreate,
AfterDestroy, AfterDestroy,
@ -27,8 +26,8 @@ import { ServerModel } from '../server/server'
import { getSort } from '../utils' import { getSort } from '../utils'
import { ActorModel, unusedActorAttributesForAPI } from './actor' import { ActorModel, unusedActorAttributesForAPI } from './actor'
import { VideoChannelModel } from '../video/video-channel' import { VideoChannelModel } from '../video/video-channel'
import { IIncludeOptions } from '../../../node_modules/sequelize-typescript/lib/interfaces/IIncludeOptions'
import { AccountModel } from '../account/account' import { AccountModel } from '../account/account'
import { IncludeOptions, Op, Transaction, QueryTypes } from 'sequelize'
@Table({ @Table({
tableName: 'actorFollow', tableName: 'actorFollow',
@ -51,7 +50,7 @@ import { AccountModel } from '../account/account'
export class ActorFollowModel extends Model<ActorFollowModel> { export class ActorFollowModel extends Model<ActorFollowModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(values(FOLLOW_STATES))) @Column(DataType.ENUM(...values(FOLLOW_STATES)))
state: FollowState state: FollowState
@AllowNull(false) @AllowNull(false)
@ -126,7 +125,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved) if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved)
} }
static loadByActorAndTarget (actorId: number, targetActorId: number, t?: Sequelize.Transaction) { static loadByActorAndTarget (actorId: number, targetActorId: number, t?: Transaction) {
const query = { const query = {
where: { where: {
actorId, actorId,
@ -150,8 +149,8 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
return ActorFollowModel.findOne(query) return ActorFollowModel.findOne(query)
} }
static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) { static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Transaction) {
const actorFollowingPartInclude: IIncludeOptions = { const actorFollowingPartInclude: IncludeOptions = {
model: ActorModel, model: ActorModel,
required: true, required: true,
as: 'ActorFollowing', as: 'ActorFollowing',
@ -208,7 +207,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
.map(t => { .map(t => {
if (t.host) { if (t.host) {
return { return {
[ Sequelize.Op.and ]: [ [ Op.and ]: [
{ {
'$preferredUsername$': t.name '$preferredUsername$': t.name
}, },
@ -220,7 +219,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
} }
return { return {
[ Sequelize.Op.and ]: [ [ Op.and ]: [
{ {
'$preferredUsername$': t.name '$preferredUsername$': t.name
}, },
@ -234,9 +233,9 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
const query = { const query = {
attributes: [], attributes: [],
where: { where: {
[ Sequelize.Op.and ]: [ [ Op.and ]: [
{ {
[ Sequelize.Op.or ]: whereTab [ Op.or ]: whereTab
}, },
{ {
actorId actorId
@ -288,7 +287,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
required: true, required: true,
where: search ? { where: search ? {
host: { host: {
[Sequelize.Op.iLike]: '%' + search + '%' [Op.iLike]: '%' + search + '%'
} }
} : undefined } : undefined
} }
@ -323,7 +322,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
required: true, required: true,
where: search ? { where: search ? {
host: { host: {
[ Sequelize.Op.iLike ]: '%' + search + '%' [ Op.iLike ]: '%' + search + '%'
} }
} : undefined } : undefined
} }
@ -406,11 +405,11 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
}) })
} }
static listAcceptedFollowerUrlsForAP (actorIds: number[], t: Sequelize.Transaction, start?: number, count?: number) { static listAcceptedFollowerUrlsForAP (actorIds: number[], t: Transaction, start?: number, count?: number) {
return ActorFollowModel.createListAcceptedFollowForApiQuery('followers', actorIds, t, start, count) return ActorFollowModel.createListAcceptedFollowForApiQuery('followers', actorIds, t, start, count)
} }
static listAcceptedFollowerSharedInboxUrls (actorIds: number[], t: Sequelize.Transaction) { static listAcceptedFollowerSharedInboxUrls (actorIds: number[], t: Transaction) {
return ActorFollowModel.createListAcceptedFollowForApiQuery( return ActorFollowModel.createListAcceptedFollowForApiQuery(
'followers', 'followers',
actorIds, actorIds,
@ -422,7 +421,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
) )
} }
static listAcceptedFollowingUrlsForApi (actorIds: number[], t: Sequelize.Transaction, start?: number, count?: number) { static listAcceptedFollowingUrlsForApi (actorIds: number[], t: Transaction, start?: number, count?: number) {
return ActorFollowModel.createListAcceptedFollowForApiQuery('following', actorIds, t, start, count) return ActorFollowModel.createListAcceptedFollowForApiQuery('following', actorIds, t, start, count)
} }
@ -447,7 +446,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
} }
} }
static updateFollowScore (inboxUrl: string, value: number, t?: Sequelize.Transaction) { static updateFollowScore (inboxUrl: string, value: number, t?: Transaction) {
const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` +
'WHERE id IN (' + 'WHERE id IN (' +
'SELECT "actorFollow"."id" FROM "actorFollow" ' + 'SELECT "actorFollow"."id" FROM "actorFollow" ' +
@ -456,7 +455,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
')' ')'
const options = { const options = {
type: Sequelize.QueryTypes.BULKUPDATE, type: QueryTypes.BULKUPDATE,
transaction: t transaction: t
} }
@ -466,7 +465,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
private static async createListAcceptedFollowForApiQuery ( private static async createListAcceptedFollowForApiQuery (
type: 'followers' | 'following', type: 'followers' | 'following',
actorIds: number[], actorIds: number[],
t: Sequelize.Transaction, t: Transaction,
start?: number, start?: number,
count?: number, count?: number,
columnUrl = 'url', columnUrl = 'url',
@ -502,7 +501,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
const options = { const options = {
bind: { actorIds }, bind: { actorIds },
type: Sequelize.QueryTypes.SELECT, type: QueryTypes.SELECT,
transaction: t transaction: t
} }
tasks.push(ActorFollowModel.sequelize.query(query, options)) tasks.push(ActorFollowModel.sequelize.query(query, options))
@ -521,7 +520,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
const query = { const query = {
where: { where: {
score: { score: {
[Sequelize.Op.lte]: 0 [Op.lte]: 0
} }
}, },
logging: false logging: false

View file

@ -93,7 +93,7 @@ export const unusedActorAttributesForAPI = [
model: () => AvatarModel, model: () => AvatarModel,
required: false required: false
} }
] ] as any // FIXME: sequelize typings
} }
}) })
@Table({ @Table({
@ -131,7 +131,7 @@ export const unusedActorAttributesForAPI = [
export class ActorModel extends Model<ActorModel> { export class ActorModel extends Model<ActorModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(values(ACTIVITY_PUB_ACTOR_TYPES))) @Column({ type: DataType.ENUM(...values(ACTIVITY_PUB_ACTOR_TYPES)) }) // FIXME: sequelize typings
type: ActivityPubActorType type: ActivityPubActorType
@AllowNull(false) @AllowNull(false)
@ -151,12 +151,12 @@ export class ActorModel extends Model<ActorModel> {
url: string url: string
@AllowNull(true) @AllowNull(true)
@Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key')) @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY.max))
publicKey: string publicKey: string
@AllowNull(true) @AllowNull(true)
@Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key')) @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY.max))
privateKey: string privateKey: string

View file

@ -1,24 +1,24 @@
import * as Sequelize from 'sequelize' import { ModelAttributeColumnOptions } from 'sequelize'
declare namespace Migration { declare namespace Migration {
interface Boolean extends Sequelize.DefineAttributeColumnOptions { interface Boolean extends ModelAttributeColumnOptions {
defaultValue: boolean | null defaultValue: boolean | null
} }
interface String extends Sequelize.DefineAttributeColumnOptions { interface String extends ModelAttributeColumnOptions {
defaultValue: string | null defaultValue: string | null
} }
interface Integer extends Sequelize.DefineAttributeColumnOptions { interface Integer extends ModelAttributeColumnOptions {
defaultValue: number | null defaultValue: number | null
} }
interface BigInteger extends Sequelize.DefineAttributeColumnOptions { interface BigInteger extends ModelAttributeColumnOptions {
defaultValue: Sequelize.DataTypeBigInt | number | null defaultValue: number | null
} }
interface UUID extends Sequelize.DefineAttributeColumnOptions { interface UUID extends ModelAttributeColumnOptions {
defaultValue: Sequelize.DataTypeUUIDv4 | null defaultValue: null
} }
} }

View file

@ -24,10 +24,10 @@ export class OAuthClientModel extends Model<OAuthClientModel> {
@Column @Column
clientSecret: string clientSecret: string
@Column(DataType.ARRAY(DataType.STRING)) @Column({ type: DataType.ARRAY(DataType.STRING) }) // FIXME: sequelize typings
grants: string[] grants: string[]
@Column(DataType.ARRAY(DataType.STRING)) @Column({ type: DataType.ARRAY(DataType.STRING) }) // FIXME: sequelize typings
redirectUris: string[] redirectUris: string[]
@CreatedAt @CreatedAt

View file

@ -55,7 +55,7 @@ enum ScopeNames {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
} }
}) })
@Table({ @Table({

View file

@ -58,7 +58,7 @@ export enum ScopeNames {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
} }
}) })

View file

@ -1,26 +1,29 @@
import { Sequelize } from 'sequelize-typescript' import { Sequelize } from 'sequelize-typescript'
import * as validator from 'validator' import * as validator from 'validator'
import { OrderItem } from 'sequelize'
import { Col } from 'sequelize/types/lib/utils'
type SortType = { sortModel: any, sortValue: string } type SortType = { sortModel: any, sortValue: string }
// Translate for example "-name" to [ [ 'name', 'DESC' ], [ 'id', 'ASC' ] ] // Translate for example "-name" to [ [ 'name', 'DESC' ], [ 'id', 'ASC' ] ]
function getSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) { function getSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
let { direction, field } = buildDirectionAndField(value) const { direction, field } = buildDirectionAndField(value)
let finalField: string | Col
if (field.toLowerCase() === 'match') { // Search if (field.toLowerCase() === 'match') { // Search
field = Sequelize.col('similarity') finalField = Sequelize.col('similarity')
} else {
finalField = field
} }
return [ [ field, direction ], lastSort ] return [ [ finalField, direction ], lastSort ]
} }
function getVideoSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) { function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
let { direction, field } = buildDirectionAndField(value) const { direction, field } = buildDirectionAndField(value)
// Alias if (field.toLowerCase() === 'trending') { // Sort by aggregation
if (field.toLowerCase() === 'match') { // Search
field = Sequelize.col('similarity')
} else if (field.toLowerCase() === 'trending') { // Sort by aggregation
return [ return [
[ Sequelize.fn('COALESCE', Sequelize.fn('SUM', Sequelize.col('VideoViews.views')), '0'), direction ], [ Sequelize.fn('COALESCE', Sequelize.fn('SUM', Sequelize.col('VideoViews.views')), '0'), direction ],
@ -30,15 +33,24 @@ function getVideoSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) {
] ]
} }
const firstSort = typeof field === 'string' ? let finalField: string | Col
field.split('.').concat([ direction ]) :
[ field, direction ] // Alias
if (field.toLowerCase() === 'match') { // Search
finalField = Sequelize.col('similarity')
} else {
finalField = field
}
const firstSort = typeof finalField === 'string'
? finalField.split('.').concat([ direction ]) as any // FIXME: sequelize typings
: [ finalField, direction ]
return [ firstSort, lastSort ] return [ firstSort, lastSort ]
} }
function getSortOnModel (model: any, value: string, lastSort: string[] = [ 'id', 'ASC' ]) { function getSortOnModel (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
let [ firstSort ] = getSort(value) const [ firstSort ] = getSort(value)
if (model) return [ [ model, firstSort[0], firstSort[1] ], lastSort ] if (model) return [ [ model, firstSort[0], firstSort[1] ], lastSort ]
return [ firstSort, lastSort ] return [ firstSort, lastSort ]
@ -52,7 +64,9 @@ function isOutdated (model: { createdAt: Date, updatedAt: Date }, refreshInterva
return (now - createdAtTime) > refreshInterval && (now - updatedAtTime) > refreshInterval return (now - createdAtTime) > refreshInterval && (now - updatedAtTime) > refreshInterval
} }
function throwIfNotValid (value: any, validator: (value: any) => boolean, fieldName = 'value') { function throwIfNotValid (value: any, validator: (value: any) => boolean, fieldName = 'value', nullable = false) {
if (nullable && (value === null || value === undefined)) return
if (validator(value) === false) { if (validator(value) === false) {
throw new Error(`"${value}" is not a valid ${fieldName}.`) throw new Error(`"${value}" is not a valid ${fieldName}.`)
} }
@ -131,7 +145,7 @@ function searchTrigramNormalizeCol (col: string) {
} }
function buildDirectionAndField (value: string) { function buildDirectionAndField (value: string) {
let field: any let field: string
let direction: 'ASC' | 'DESC' let direction: 'ASC' | 'DESC'
if (value.substring(0, 1) === '-') { if (value.substring(0, 1) === '-') {

View file

@ -1,7 +1,7 @@
import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Sequelize, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { ScopeNames as VideoScopeNames, VideoModel } from './video' import { ScopeNames as VideoScopeNames, VideoModel } from './video'
import { VideoPrivacy } from '../../../shared/models/videos' import { VideoPrivacy } from '../../../shared/models/videos'
import { Transaction } from 'sequelize' import { Op, Transaction } from 'sequelize'
@Table({ @Table({
tableName: 'scheduleVideoUpdate', tableName: 'scheduleVideoUpdate',
@ -51,7 +51,7 @@ export class ScheduleVideoUpdateModel extends Model<ScheduleVideoUpdateModel> {
attributes: [ 'id' ], attributes: [ 'id' ],
where: { where: {
updateAt: { updateAt: {
[Sequelize.Op.lte]: new Date() [Op.lte]: new Date()
} }
} }
} }
@ -64,7 +64,7 @@ export class ScheduleVideoUpdateModel extends Model<ScheduleVideoUpdateModel> {
const query = { const query = {
where: { where: {
updateAt: { updateAt: {
[Sequelize.Op.lte]: new Date() [Op.lte]: new Date()
} }
}, },
include: [ include: [

View file

@ -1,5 +1,5 @@
import * as Bluebird from 'bluebird' import * as Bluebird from 'bluebird'
import * as Sequelize from 'sequelize' import { QueryTypes, Transaction } from 'sequelize'
import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { isVideoTagValid } from '../../helpers/custom-validators/videos' import { isVideoTagValid } from '../../helpers/custom-validators/videos'
import { throwIfNotValid } from '../utils' import { throwIfNotValid } from '../utils'
@ -37,7 +37,7 @@ export class TagModel extends Model<TagModel> {
}) })
Videos: VideoModel[] Videos: VideoModel[]
static findOrCreateTags (tags: string[], transaction: Sequelize.Transaction) { static findOrCreateTags (tags: string[], transaction: Transaction) {
if (tags === null) return [] if (tags === null) return []
const tasks: Bluebird<TagModel>[] = [] const tasks: Bluebird<TagModel>[] = []
@ -72,10 +72,10 @@ export class TagModel extends Model<TagModel> {
const options = { const options = {
bind: { threshold, count, videoPrivacy: VideoPrivacy.PUBLIC, videoState: VideoState.PUBLISHED }, bind: { threshold, count, videoPrivacy: VideoPrivacy.PUBLIC, videoState: VideoState.PUBLISHED },
type: Sequelize.QueryTypes.SELECT type: QueryTypes.SELECT as QueryTypes.SELECT
} }
return TagModel.sequelize.query(query, options) return TagModel.sequelize.query<{ name }>(query, options)
.then(data => data.map(d => d.name)) .then(data => data.map(d => d.name))
} }
} }

View file

@ -39,7 +39,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isVideoAbuseModerationCommentValid, 'moderationComment')) @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isVideoAbuseModerationCommentValid, 'moderationComment', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max))
moderationComment: string moderationComment: string

View file

@ -1,22 +1,11 @@
import { import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
AllowNull,
BelongsTo,
Column,
CreatedAt,
DataType,
Default,
ForeignKey,
Is, Model,
Table,
UpdatedAt,
IFindOptions
} from 'sequelize-typescript'
import { getSortOnModel, SortType, throwIfNotValid } from '../utils' import { getSortOnModel, SortType, throwIfNotValid } from '../utils'
import { VideoModel } from './video' import { VideoModel } from './video'
import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from './video-channel' import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel'
import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist'
import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants' import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
import { FindOptions } from 'sequelize'
@Table({ @Table({
tableName: 'videoBlacklist', tableName: 'videoBlacklist',
@ -30,7 +19,7 @@ import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
export class VideoBlacklistModel extends Model<VideoBlacklistModel> { export class VideoBlacklistModel extends Model<VideoBlacklistModel> {
@AllowNull(true) @AllowNull(true)
@Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason')) @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_BLACKLIST.REASON.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_BLACKLIST.REASON.max))
reason: string reason: string
@ -63,7 +52,7 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> {
Video: VideoModel Video: VideoModel
static listForApi (start: number, count: number, sort: SortType, type?: VideoBlacklistType) { static listForApi (start: number, count: number, sort: SortType, type?: VideoBlacklistType) {
const query: IFindOptions<VideoBlacklistModel> = { const query: FindOptions = {
offset: start, offset: start,
limit: count, limit: count,
order: getSortOnModel(sort.sortModel, sort.sortValue), order: getSortOnModel(sort.sortModel, sort.sortValue),

View file

@ -1,4 +1,4 @@
import * as Sequelize from 'sequelize' import { OrderItem, Transaction } from 'sequelize'
import { import {
AllowNull, AllowNull,
BeforeDestroy, BeforeDestroy,
@ -115,19 +115,19 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> {
return VideoCaptionModel.findOne(query) return VideoCaptionModel.findOne(query)
} }
static insertOrReplaceLanguage (videoId: number, language: string, transaction: Sequelize.Transaction) { static insertOrReplaceLanguage (videoId: number, language: string, transaction: Transaction) {
const values = { const values = {
videoId, videoId,
language language
} }
return VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) return (VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) as any) // FIXME: typings
.then(([ caption ]) => caption) .then(([ caption ]) => caption)
} }
static listVideoCaptions (videoId: number) { static listVideoCaptions (videoId: number) {
const query = { const query = {
order: [ [ 'language', 'ASC' ] ], order: [ [ 'language', 'ASC' ] ] as OrderItem[],
where: { where: {
videoId videoId
} }
@ -140,7 +140,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> {
return VIDEO_LANGUAGES[language] || 'Unknown' return VIDEO_LANGUAGES[language] || 'Unknown'
} }
static deleteAllCaptionsOfRemoteVideo (videoId: number, transaction: Sequelize.Transaction) { static deleteAllCaptionsOfRemoteVideo (videoId: number, transaction: Transaction) {
const query = { const query = {
where: { where: {
videoId videoId

View file

@ -43,7 +43,7 @@ enum ScopeNames {
{ model: () => VideoFileModel } { model: () => VideoFileModel }
] ]
} }
] ] as any // FIXME: sequelize typings
} }
}) })
export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> { export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> {

View file

@ -9,7 +9,6 @@ import {
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
HasMany, HasMany,
IFindOptions,
Is, Is,
Model, Model,
Scopes, Scopes,
@ -31,12 +30,12 @@ import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttr
import { VideoModel } from './video' import { VideoModel } from './video'
import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
import { ServerModel } from '../server/server' import { ServerModel } from '../server/server'
import { DefineIndexesOptions } from 'sequelize' import { FindOptions, ModelIndexesOptions, Op } from 'sequelize'
import { AvatarModel } from '../avatar/avatar' import { AvatarModel } from '../avatar/avatar'
import { VideoPlaylistModel } from './video-playlist' import { VideoPlaylistModel } from './video-playlist'
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
const indexes: DefineIndexesOptions[] = [ const indexes: ModelIndexesOptions[] = [
buildTrigramSearchIndex('video_channel_name_trigram', 'name'), buildTrigramSearchIndex('video_channel_name_trigram', 'name'),
{ {
@ -69,7 +68,7 @@ type AvailableForListOptions = {
}) })
@Scopes({ @Scopes({
[ScopeNames.SUMMARY]: (withAccount = false) => { [ScopeNames.SUMMARY]: (withAccount = false) => {
const base: IFindOptions<VideoChannelModel> = { const base: FindOptions = {
attributes: [ 'name', 'description', 'id', 'actorId' ], attributes: [ 'name', 'description', 'id', 'actorId' ],
include: [ include: [
{ {
@ -112,13 +111,13 @@ type AvailableForListOptions = {
}, },
model: ActorModel, model: ActorModel,
where: { where: {
[Sequelize.Op.or]: [ [Op.or]: [
{ {
serverId: null serverId: null
}, },
{ {
serverId: { serverId: {
[ Sequelize.Op.in ]: Sequelize.literal(inQueryInstanceFollow) [ Op.in ]: Sequelize.literal(inQueryInstanceFollow)
} }
} }
] ]
@ -172,13 +171,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description')) @Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.DESCRIPTION.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.DESCRIPTION.max))
description: string description: string
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoChannelSupport', value => throwIfNotValid(value, isVideoChannelSupportValid, 'support')) @Is('VideoChannelSupport', value => throwIfNotValid(value, isVideoChannelSupportValid, 'support', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.SUPPORT.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.SUPPORT.max))
support: string support: string
@ -313,7 +312,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
limit: options.count, limit: options.count,
order: getSort(options.sort), order: getSort(options.sort),
where: { where: {
[Sequelize.Op.or]: [ [Op.or]: [
Sequelize.literal( Sequelize.literal(
'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))' 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))'
), ),

View file

@ -1,4 +1,3 @@
import * as Sequelize from 'sequelize'
import { import {
AllowNull, AllowNull,
BeforeDestroy, BeforeDestroy,
@ -7,7 +6,6 @@ import {
CreatedAt, CreatedAt,
DataType, DataType,
ForeignKey, ForeignKey,
IFindOptions,
Is, Is,
Model, Model,
Scopes, Scopes,
@ -32,6 +30,7 @@ import { UserModel } from '../account/user'
import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor'
import { regexpCapture } from '../../helpers/regexp' import { regexpCapture } from '../../helpers/regexp'
import { uniq } from 'lodash' import { uniq } from 'lodash'
import { FindOptions, Op, Order, Sequelize, Transaction } from 'sequelize'
enum ScopeNames { enum ScopeNames {
WITH_ACCOUNT = 'WITH_ACCOUNT', WITH_ACCOUNT = 'WITH_ACCOUNT',
@ -86,7 +85,7 @@ enum ScopeNames {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
}, },
[ScopeNames.WITH_IN_REPLY_TO]: { [ScopeNames.WITH_IN_REPLY_TO]: {
include: [ include: [
@ -120,7 +119,7 @@ enum ScopeNames {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
} }
}) })
@Table({ @Table({
@ -244,8 +243,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
} }
} }
static loadById (id: number, t?: Sequelize.Transaction) { static loadById (id: number, t?: Transaction) {
const query: IFindOptions<VideoCommentModel> = { const query: FindOptions = {
where: { where: {
id id
} }
@ -256,8 +255,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
return VideoCommentModel.findOne(query) return VideoCommentModel.findOne(query)
} }
static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Sequelize.Transaction) { static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction) {
const query: IFindOptions<VideoCommentModel> = { const query: FindOptions = {
where: { where: {
id id
} }
@ -270,8 +269,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
.findOne(query) .findOne(query)
} }
static loadByUrlAndPopulateAccount (url: string, t?: Sequelize.Transaction) { static loadByUrlAndPopulateAccount (url: string, t?: Transaction) {
const query: IFindOptions<VideoCommentModel> = { const query: FindOptions = {
where: { where: {
url url
} }
@ -282,8 +281,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT ]).findOne(query) return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT ]).findOne(query)
} }
static loadByUrlAndPopulateReplyAndVideo (url: string, t?: Sequelize.Transaction) { static loadByUrlAndPopulateReplyAndVideo (url: string, t?: Transaction) {
const query: IFindOptions<VideoCommentModel> = { const query: FindOptions = {
where: { where: {
url url
} }
@ -307,7 +306,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
videoId, videoId,
inReplyToCommentId: null, inReplyToCommentId: null,
accountId: { accountId: {
[Sequelize.Op.notIn]: Sequelize.literal( [Op.notIn]: Sequelize.literal(
'(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')'
) )
} }
@ -336,15 +335,15 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
const userAccountId = user ? user.Account.id : undefined const userAccountId = user ? user.Account.id : undefined
const query = { const query = {
order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ], order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order,
where: { where: {
videoId, videoId,
[ Sequelize.Op.or ]: [ [ Op.or ]: [
{ id: threadId }, { id: threadId },
{ originCommentId: threadId } { originCommentId: threadId }
], ],
accountId: { accountId: {
[Sequelize.Op.notIn]: Sequelize.literal( [Op.notIn]: Sequelize.literal(
'(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')'
) )
} }
@ -366,12 +365,12 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
}) })
} }
static listThreadParentComments (comment: VideoCommentModel, t: Sequelize.Transaction, order: 'ASC' | 'DESC' = 'ASC') { static listThreadParentComments (comment: VideoCommentModel, t: Transaction, order: 'ASC' | 'DESC' = 'ASC') {
const query = { const query = {
order: [ [ 'createdAt', order ] ], order: [ [ 'createdAt', order ] ] as Order,
where: { where: {
id: { id: {
[ Sequelize.Op.in ]: Sequelize.literal('(' + [ Op.in ]: Sequelize.literal('(' +
'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' +
`SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` +
'UNION ' + 'UNION ' +
@ -380,7 +379,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
') ' + ') ' +
'SELECT id FROM children' + 'SELECT id FROM children' +
')'), ')'),
[ Sequelize.Op.ne ]: comment.id [ Op.ne ]: comment.id
} }
}, },
transaction: t transaction: t
@ -391,9 +390,9 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
.findAll(query) .findAll(query)
} }
static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Sequelize.Transaction, order: 'ASC' | 'DESC' = 'ASC') { static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Transaction, order: 'ASC' | 'DESC' = 'ASC') {
const query = { const query = {
order: [ [ 'createdAt', order ] ], order: [ [ 'createdAt', order ] ] as Order,
offset: start, offset: start,
limit: count, limit: count,
where: { where: {
@ -407,7 +406,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
static listForFeed (start: number, count: number, videoId?: number) { static listForFeed (start: number, count: number, videoId?: number) {
const query = { const query = {
order: [ [ 'createdAt', 'DESC' ] ], order: [ [ 'createdAt', 'DESC' ] ] as Order,
offset: start, offset: start,
limit: count, limit: count,
where: {}, where: {},
@ -457,7 +456,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
const query = { const query = {
where: { where: {
updatedAt: { updatedAt: {
[Sequelize.Op.lt]: beforeUpdatedAt [Op.lt]: beforeUpdatedAt
}, },
videoId videoId
} }

View file

@ -55,13 +55,13 @@ export class VideoImportModel extends Model<VideoImportModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl')) @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max))
targetUrl: string targetUrl: string
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri')) @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs
magnetUri: string magnetUri: string

View file

@ -15,12 +15,12 @@ import {
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { VideoModel } from './video' import { VideoModel } from './video'
import { VideoPlaylistModel } from './video-playlist' import { VideoPlaylistModel } from './video-playlist'
import * as Sequelize from 'sequelize'
import { getSort, throwIfNotValid } from '../utils' import { getSort, throwIfNotValid } from '../utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants' import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object'
import * as validator from 'validator' import * as validator from 'validator'
import { AggregateOptions, Op, Sequelize, Transaction } from 'sequelize'
@Table({ @Table({
tableName: 'videoPlaylistElement', tableName: 'videoPlaylistElement',
@ -96,7 +96,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
}) })
Video: VideoModel Video: VideoModel
static deleteAllOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { static deleteAllOf (videoPlaylistId: number, transaction?: Transaction) {
const query = { const query = {
where: { where: {
videoPlaylistId videoPlaylistId
@ -140,7 +140,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
return VideoPlaylistElementModel.findOne(query) return VideoPlaylistElementModel.findOne(query)
} }
static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Sequelize.Transaction) { static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Transaction) {
const query = { const query = {
attributes: [ 'url' ], attributes: [ 'url' ],
offset: start, offset: start,
@ -159,8 +159,8 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
}) })
} }
static getNextPositionOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { static getNextPositionOf (videoPlaylistId: number, transaction?: Transaction) {
const query = { const query: AggregateOptions<number> = {
where: { where: {
videoPlaylistId videoPlaylistId
}, },
@ -176,14 +176,14 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
firstPosition: number, firstPosition: number,
endPosition: number, endPosition: number,
newPosition: number, newPosition: number,
transaction?: Sequelize.Transaction transaction?: Transaction
) { ) {
const query = { const query = {
where: { where: {
videoPlaylistId, videoPlaylistId,
position: { position: {
[Sequelize.Op.gte]: firstPosition, [Op.gte]: firstPosition,
[Sequelize.Op.lte]: endPosition [Op.lte]: endPosition
} }
}, },
transaction, transaction,
@ -198,13 +198,13 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
fromPosition: number, fromPosition: number,
toPosition?: number, toPosition?: number,
by = 1, by = 1,
transaction?: Sequelize.Transaction transaction?: Transaction
) { ) {
const query = { const query = {
where: { where: {
videoPlaylistId, videoPlaylistId,
position: { position: {
[Sequelize.Op.gte]: fromPosition [Op.gte]: fromPosition
} }
}, },
transaction transaction

View file

@ -15,7 +15,6 @@ import {
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import * as Sequelize from 'sequelize'
import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getSort, isOutdated, throwIfNotValid } from '../utils' import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getSort, isOutdated, throwIfNotValid } from '../utils'
import { import {
@ -43,6 +42,7 @@ import { activityPubCollectionPagination } from '../../helpers/activitypub'
import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model' import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model'
import { ThumbnailModel } from './thumbnail' import { ThumbnailModel } from './thumbnail'
import { ActivityIconObject } from '../../../shared/models/activitypub/objects' import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
import { fn, literal, Op, Transaction } from 'sequelize'
enum ScopeNames { enum ScopeNames {
AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
@ -74,7 +74,11 @@ type AvailableForListOptions = {
attributes: { attributes: {
include: [ include: [
[ [
Sequelize.literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'), fn('COUNT', 'toto'),
'coucou'
],
[
literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'),
'videosLength' 'videosLength'
] ]
] ]
@ -116,13 +120,13 @@ type AvailableForListOptions = {
// Only list local playlists OR playlists that are on an instance followed by actorId // Only list local playlists OR playlists that are on an instance followed by actorId
const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId)
const actorWhere = { const actorWhere = {
[ Sequelize.Op.or ]: [ [ Op.or ]: [
{ {
serverId: null serverId: null
}, },
{ {
serverId: { serverId: {
[ Sequelize.Op.in ]: Sequelize.literal(inQueryInstanceFollow) [ Op.in ]: literal(inQueryInstanceFollow)
} }
} }
] ]
@ -155,7 +159,7 @@ type AvailableForListOptions = {
} }
const where = { const where = {
[Sequelize.Op.and]: whereAnd [Op.and]: whereAnd
} }
const accountScope = { const accountScope = {
@ -206,7 +210,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
name: string name: string
@AllowNull(true) @AllowNull(true)
@Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description')) @Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description', true))
@Column @Column
description: string description: string
@ -344,7 +348,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
model: VideoPlaylistElementModel.unscoped(), model: VideoPlaylistElementModel.unscoped(),
where: { where: {
videoId: { videoId: {
[Sequelize.Op.any]: videoIds [Op.any]: videoIds
} }
}, },
required: true required: true
@ -368,7 +372,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
.then(e => !!e) .then(e => !!e)
} }
static loadWithAccountAndChannelSummary (id: number | string, transaction: Sequelize.Transaction) { static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const query = { const query = {
@ -381,7 +385,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
.findOne(query) .findOne(query)
} }
static loadWithAccountAndChannel (id: number | string, transaction: Sequelize.Transaction) { static loadWithAccountAndChannel (id: number | string, transaction: Transaction) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const query = { const query = {
@ -412,7 +416,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
return VIDEO_PLAYLIST_TYPES[type] || 'Unknown' return VIDEO_PLAYLIST_TYPES[type] || 'Unknown'
} }
static resetPlaylistsOfChannel (videoChannelId: number, transaction: Sequelize.Transaction) { static resetPlaylistsOfChannel (videoChannelId: number, transaction: Transaction) {
const query = { const query = {
where: { where: {
videoChannelId videoChannelId
@ -489,7 +493,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
label: VideoPlaylistModel.getTypeLabel(this.type) label: VideoPlaylistModel.getTypeLabel(this.type)
}, },
videosLength: this.get('videosLength'), videosLength: this.get('videosLength') as number,
createdAt: this.createdAt, createdAt: this.createdAt,
updatedAt: this.updatedAt, updatedAt: this.updatedAt,
@ -499,7 +503,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
} }
} }
toActivityPubObject (page: number, t: Sequelize.Transaction): Promise<PlaylistObject> { toActivityPubObject (page: number, t: Transaction): Promise<PlaylistObject> {
const handler = (start: number, count: number) => { const handler = (start: number, count: number) => {
return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t)
} }

View file

@ -1,8 +1,7 @@
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, HasMany, Is, Model, Table, UpdatedAt, DataType } from 'sequelize-typescript'
import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
import { throwIfNotValid } from '../utils' import { throwIfNotValid } from '../utils'
import { VideoModel } from './video' import { VideoModel } from './video'
import * as Sequelize from 'sequelize'
import { VideoRedundancyModel } from '../redundancy/video-redundancy' import { VideoRedundancyModel } from '../redundancy/video-redundancy'
import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
@ -11,6 +10,7 @@ import { VideoFileModel } from './video-file'
import { join } from 'path' import { join } from 'path'
import { sha1 } from '../../helpers/core-utils' import { sha1 } from '../../helpers/core-utils'
import { isArrayOf } from '../../helpers/custom-validators/misc' import { isArrayOf } from '../../helpers/custom-validators/misc'
import { QueryTypes, Op } from 'sequelize'
@Table({ @Table({
tableName: 'videoStreamingPlaylist', tableName: 'videoStreamingPlaylist',
@ -26,7 +26,7 @@ import { isArrayOf } from '../../helpers/custom-validators/misc'
fields: [ 'p2pMediaLoaderInfohashes' ], fields: [ 'p2pMediaLoaderInfohashes' ],
using: 'gin' using: 'gin'
} }
] ] as any // FIXME: sequelize typings
}) })
export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistModel> { export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistModel> {
@CreatedAt @CreatedAt
@ -46,7 +46,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod
@AllowNull(false) @AllowNull(false)
@Is('VideoStreamingPlaylistInfoHashes', value => throwIfNotValid(value, v => isArrayOf(v, isVideoFileInfoHashValid), 'info hashes')) @Is('VideoStreamingPlaylistInfoHashes', value => throwIfNotValid(value, v => isArrayOf(v, isVideoFileInfoHashValid), 'info hashes'))
@Column(DataType.ARRAY(DataType.STRING)) @Column({ type: DataType.ARRAY(DataType.STRING) }) // FIXME: typings
p2pMediaLoaderInfohashes: string[] p2pMediaLoaderInfohashes: string[]
@AllowNull(false) @AllowNull(false)
@ -82,15 +82,13 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod
static doesInfohashExist (infoHash: string) { static doesInfohashExist (infoHash: string) {
const query = 'SELECT 1 FROM "videoStreamingPlaylist" WHERE $infoHash = ANY("p2pMediaLoaderInfohashes") LIMIT 1' const query = 'SELECT 1 FROM "videoStreamingPlaylist" WHERE $infoHash = ANY("p2pMediaLoaderInfohashes") LIMIT 1'
const options = { const options = {
type: Sequelize.QueryTypes.SELECT, type: QueryTypes.SELECT as QueryTypes.SELECT,
bind: { infoHash }, bind: { infoHash },
raw: true raw: true
} }
return VideoModel.sequelize.query(query, options) return VideoModel.sequelize.query<any>(query, options)
.then(results => { .then(results => results.length === 1)
return results.length === 1
})
} }
static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: VideoFileModel[]) { static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: VideoFileModel[]) {
@ -108,7 +106,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod
const query = { const query = {
where: { where: {
p2pMediaLoaderPeerVersion: { p2pMediaLoaderPeerVersion: {
[Sequelize.Op.ne]: P2P_MEDIA_LOADER_PEER_VERSION [Op.ne]: P2P_MEDIA_LOADER_PEER_VERSION
} }
} }
} }

View file

@ -3,7 +3,18 @@ import { maxBy } from 'lodash'
import * as magnetUtil from 'magnet-uri' import * as magnetUtil from 'magnet-uri'
import * as parseTorrent from 'parse-torrent' import * as parseTorrent from 'parse-torrent'
import { join } from 'path' import { join } from 'path'
import * as Sequelize from 'sequelize' import {
CountOptions,
FindOptions,
IncludeOptions,
ModelIndexesOptions,
Op,
QueryTypes,
ScopeOptions,
Sequelize,
Transaction,
WhereOptions
} from 'sequelize'
import { import {
AllowNull, AllowNull,
BeforeDestroy, BeforeDestroy,
@ -16,8 +27,6 @@ import {
ForeignKey, ForeignKey,
HasMany, HasMany,
HasOne, HasOne,
IFindOptions,
IIncludeOptions,
Is, Is,
IsInt, IsInt,
IsUUID, IsUUID,
@ -45,7 +54,7 @@ import {
isVideoStateValid, isVideoStateValid,
isVideoSupportValid isVideoSupportValid
} from '../../helpers/custom-validators/videos' } from '../../helpers/custom-validators/videos'
import { generateImageFromVideoFile, getVideoFileResolution } from '../../helpers/ffmpeg-utils' import { getVideoFileResolution } from '../../helpers/ffmpeg-utils'
import { logger } from '../../helpers/logger' import { logger } from '../../helpers/logger'
import { getServerActor } from '../../helpers/utils' import { getServerActor } from '../../helpers/utils'
import { import {
@ -54,11 +63,9 @@ import {
CONSTRAINTS_FIELDS, CONSTRAINTS_FIELDS,
HLS_REDUNDANCY_DIRECTORY, HLS_REDUNDANCY_DIRECTORY,
HLS_STREAMING_PLAYLIST_DIRECTORY, HLS_STREAMING_PLAYLIST_DIRECTORY,
PREVIEWS_SIZE,
REMOTE_SCHEME, REMOTE_SCHEME,
STATIC_DOWNLOAD_PATHS, STATIC_DOWNLOAD_PATHS,
STATIC_PATHS, STATIC_PATHS,
THUMBNAILS_SIZE,
VIDEO_CATEGORIES, VIDEO_CATEGORIES,
VIDEO_LANGUAGES, VIDEO_LANGUAGES,
VIDEO_LICENCES, VIDEO_LICENCES,
@ -111,7 +118,7 @@ import { ThumbnailModel } from './thumbnail'
import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
const indexes: Sequelize.DefineIndexesOptions[] = [ const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [
buildTrigramSearchIndex('video_name_trigram', 'name'), buildTrigramSearchIndex('video_name_trigram', 'name'),
{ fields: [ 'createdAt' ] }, { fields: [ 'createdAt' ] },
@ -123,7 +130,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [
fields: [ 'originallyPublishedAt' ], fields: [ 'originallyPublishedAt' ],
where: { where: {
originallyPublishedAt: { originallyPublishedAt: {
[Sequelize.Op.ne]: null [Op.ne]: null
} }
} }
}, },
@ -131,7 +138,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [
fields: [ 'category' ], // We don't care videos with an unknown category fields: [ 'category' ], // We don't care videos with an unknown category
where: { where: {
category: { category: {
[Sequelize.Op.ne]: null [Op.ne]: null
} }
} }
}, },
@ -139,7 +146,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [
fields: [ 'licence' ], // We don't care videos with an unknown licence fields: [ 'licence' ], // We don't care videos with an unknown licence
where: { where: {
licence: { licence: {
[Sequelize.Op.ne]: null [Op.ne]: null
} }
} }
}, },
@ -147,7 +154,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [
fields: [ 'language' ], // We don't care videos with an unknown language fields: [ 'language' ], // We don't care videos with an unknown language
where: { where: {
language: { language: {
[Sequelize.Op.ne]: null [Op.ne]: null
} }
} }
}, },
@ -222,10 +229,10 @@ type AvailableForListIDsOptions = {
@Scopes({ @Scopes({
[ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
where: { where: {
id: { id: {
[ Sequelize.Op.any ]: options.ids [ Op.in ]: options.ids // FIXME: sequelize any seems broken
} }
}, },
include: [ include: [
@ -256,21 +263,21 @@ type AvailableForListIDsOptions = {
return query return query
}, },
[ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => {
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
raw: true, raw: true,
attributes: [ 'id' ], attributes: [ 'id' ],
where: { where: {
id: { id: {
[ Sequelize.Op.and ]: [ [ Op.and ]: [
{ {
[ Sequelize.Op.notIn ]: Sequelize.literal( [ Op.notIn ]: Sequelize.literal(
'(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
) )
} }
] ]
}, },
channelId: { channelId: {
[ Sequelize.Op.notIn ]: Sequelize.literal( [ Op.notIn ]: Sequelize.literal(
'(' + '(' +
'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' +
buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) +
@ -288,12 +295,12 @@ type AvailableForListIDsOptions = {
// Always list public videos // Always list public videos
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
// Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding
[ Sequelize.Op.or ]: [ [ Op.or ]: [
{ {
state: VideoState.PUBLISHED state: VideoState.PUBLISHED
}, },
{ {
[ Sequelize.Op.and ]: { [ Op.and ]: {
state: VideoState.TO_TRANSCODE, state: VideoState.TO_TRANSCODE,
waitTranscoding: false waitTranscoding: false
} }
@ -318,7 +325,7 @@ type AvailableForListIDsOptions = {
} }
if (options.filter || options.accountId || options.videoChannelId) { if (options.filter || options.accountId || options.videoChannelId) {
const videoChannelInclude: IIncludeOptions = { const videoChannelInclude: IncludeOptions = {
attributes: [], attributes: [],
model: VideoChannelModel.unscoped(), model: VideoChannelModel.unscoped(),
required: true required: true
@ -331,7 +338,7 @@ type AvailableForListIDsOptions = {
} }
if (options.filter || options.accountId) { if (options.filter || options.accountId) {
const accountInclude: IIncludeOptions = { const accountInclude: IncludeOptions = {
attributes: [], attributes: [],
model: AccountModel.unscoped(), model: AccountModel.unscoped(),
required: true required: true
@ -371,8 +378,8 @@ type AvailableForListIDsOptions = {
// Force actorId to be a number to avoid SQL injections // Force actorId to be a number to avoid SQL injections
const actorIdNumber = parseInt(options.followerActorId.toString(), 10) const actorIdNumber = parseInt(options.followerActorId.toString(), 10)
query.where[ 'id' ][ Sequelize.Op.and ].push({ query.where[ 'id' ][ Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal( [ Op.in ]: Sequelize.literal(
'(' + '(' +
'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
@ -391,8 +398,8 @@ type AvailableForListIDsOptions = {
} }
if (options.withFiles === true) { if (options.withFiles === true) {
query.where[ 'id' ][ Sequelize.Op.and ].push({ query.where[ 'id' ][ Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal( [ Op.in ]: Sequelize.literal(
'(SELECT "videoId" FROM "videoFile")' '(SELECT "videoId" FROM "videoFile")'
) )
}) })
@ -406,8 +413,8 @@ type AvailableForListIDsOptions = {
} }
if (options.tagsOneOf) { if (options.tagsOneOf) {
query.where[ 'id' ][ Sequelize.Op.and ].push({ query.where[ 'id' ][ Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal( [ Op.in ]: Sequelize.literal(
'(' + '(' +
'SELECT "videoId" FROM "videoTag" ' + 'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
@ -418,8 +425,8 @@ type AvailableForListIDsOptions = {
} }
if (options.tagsAllOf) { if (options.tagsAllOf) {
query.where[ 'id' ][ Sequelize.Op.and ].push({ query.where[ 'id' ][ Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal( [ Op.in ]: Sequelize.literal(
'(' + '(' +
'SELECT "videoId" FROM "videoTag" ' + 'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
@ -437,19 +444,19 @@ type AvailableForListIDsOptions = {
if (options.categoryOneOf) { if (options.categoryOneOf) {
query.where[ 'category' ] = { query.where[ 'category' ] = {
[ Sequelize.Op.or ]: options.categoryOneOf [ Op.or ]: options.categoryOneOf
} }
} }
if (options.licenceOneOf) { if (options.licenceOneOf) {
query.where[ 'licence' ] = { query.where[ 'licence' ] = {
[ Sequelize.Op.or ]: options.licenceOneOf [ Op.or ]: options.licenceOneOf
} }
} }
if (options.languageOneOf) { if (options.languageOneOf) {
query.where[ 'language' ] = { query.where[ 'language' ] = {
[ Sequelize.Op.or ]: options.languageOneOf [ Op.or ]: options.languageOneOf
} }
} }
@ -498,7 +505,7 @@ type AvailableForListIDsOptions = {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
}, },
[ ScopeNames.WITH_ACCOUNT_DETAILS ]: { [ ScopeNames.WITH_ACCOUNT_DETAILS ]: {
include: [ include: [
@ -550,7 +557,7 @@ type AvailableForListIDsOptions = {
} }
] ]
} }
] ] as any // FIXME: sequelize typings
}, },
[ ScopeNames.WITH_TAGS ]: { [ ScopeNames.WITH_TAGS ]: {
include: [ () => TagModel ] include: [ () => TagModel ]
@ -656,19 +663,19 @@ export class VideoModel extends Model<VideoModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoCategory', value => throwIfNotValid(value, isVideoCategoryValid, 'category')) @Is('VideoCategory', value => throwIfNotValid(value, isVideoCategoryValid, 'category', true))
@Column @Column
category: number category: number
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoLicence', value => throwIfNotValid(value, isVideoLicenceValid, 'licence')) @Is('VideoLicence', value => throwIfNotValid(value, isVideoLicenceValid, 'licence', true))
@Column @Column
licence: number licence: number
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoLanguage', value => throwIfNotValid(value, isVideoLanguageValid, 'language')) @Is('VideoLanguage', value => throwIfNotValid(value, isVideoLanguageValid, 'language', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.LANGUAGE.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.LANGUAGE.max))
language: string language: string
@ -684,13 +691,13 @@ export class VideoModel extends Model<VideoModel> {
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoDescription', value => throwIfNotValid(value, isVideoDescriptionValid, 'description')) @Is('VideoDescription', value => throwIfNotValid(value, isVideoDescriptionValid, 'description', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max))
description: string description: string
@AllowNull(true) @AllowNull(true)
@Default(null) @Default(null)
@Is('VideoSupport', value => throwIfNotValid(value, isVideoSupportValid, 'support')) @Is('VideoSupport', value => throwIfNotValid(value, isVideoSupportValid, 'support', true))
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max)) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max))
support: string support: string
@ -754,7 +761,7 @@ export class VideoModel extends Model<VideoModel> {
updatedAt: Date updatedAt: Date
@AllowNull(false) @AllowNull(false)
@Default(Sequelize.NOW) @Default(DataType.NOW)
@Column @Column
publishedAt: Date publishedAt: Date
@ -999,12 +1006,12 @@ export class VideoModel extends Model<VideoModel> {
distinct: true, distinct: true,
offset: start, offset: start,
limit: count, limit: count,
order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ]), order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings
where: { where: {
id: { id: {
[ Sequelize.Op.in ]: Sequelize.literal('(' + rawQuery + ')') [ Op.in ]: Sequelize.literal('(' + rawQuery + ')')
}, },
[ Sequelize.Op.or ]: [ [ Op.or ]: [
{ privacy: VideoPrivacy.PUBLIC }, { privacy: VideoPrivacy.PUBLIC },
{ privacy: VideoPrivacy.UNLISTED } { privacy: VideoPrivacy.UNLISTED }
] ]
@ -1021,10 +1028,10 @@ export class VideoModel extends Model<VideoModel> {
required: false, required: false,
// We only want videos shared by this actor // We only want videos shared by this actor
where: { where: {
[ Sequelize.Op.and ]: [ [ Op.and ]: [
{ {
id: { id: {
[ Sequelize.Op.not ]: null [ Op.not ]: null
} }
}, },
{ {
@ -1070,13 +1077,13 @@ export class VideoModel extends Model<VideoModel> {
return Bluebird.all([ return Bluebird.all([
// FIXME: typing issue // FIXME: typing issue
VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findAll(query as any), VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findAll(query as any),
VideoModel.sequelize.query(rawCountQuery, { type: Sequelize.QueryTypes.SELECT }) VideoModel.sequelize.query<{ total: number }>(rawCountQuery, { type: QueryTypes.SELECT })
]).then(([ rows, totals ]) => { ]).then(([ rows, totals ]) => {
// totals: totalVideos + totalVideoShares // totals: totalVideos + totalVideoShares
let totalVideos = 0 let totalVideos = 0
let totalVideoShares = 0 let totalVideoShares = 0
if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10) if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total + '', 10)
if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10) if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total + '', 10)
const total = totalVideos + totalVideoShares const total = totalVideos + totalVideoShares
return { return {
@ -1087,7 +1094,7 @@ export class VideoModel extends Model<VideoModel> {
} }
static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) {
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
offset: start, offset: start,
limit: count, limit: count,
order: getVideoSort(sort), order: getVideoSort(sort),
@ -1158,7 +1165,7 @@ export class VideoModel extends Model<VideoModel> {
throw new Error('Try to filter all-local but no user has not the see all videos right') throw new Error('Try to filter all-local but no user has not the see all videos right')
} }
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
offset: options.start, offset: options.start,
limit: options.count, limit: options.count,
order: getVideoSort(options.sort) order: getVideoSort(options.sort)
@ -1225,8 +1232,8 @@ export class VideoModel extends Model<VideoModel> {
if (options.startDate || options.endDate) { if (options.startDate || options.endDate) {
const publishedAtRange = {} const publishedAtRange = {}
if (options.startDate) publishedAtRange[ Sequelize.Op.gte ] = options.startDate if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate
if (options.endDate) publishedAtRange[ Sequelize.Op.lte ] = options.endDate if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate
whereAnd.push({ publishedAt: publishedAtRange }) whereAnd.push({ publishedAt: publishedAtRange })
} }
@ -1234,8 +1241,8 @@ export class VideoModel extends Model<VideoModel> {
if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) {
const originallyPublishedAtRange = {} const originallyPublishedAtRange = {}
if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Sequelize.Op.gte ] = options.originallyPublishedStartDate if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate
if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Sequelize.Op.lte ] = options.originallyPublishedEndDate if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate
whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange })
} }
@ -1243,8 +1250,8 @@ export class VideoModel extends Model<VideoModel> {
if (options.durationMin || options.durationMax) { if (options.durationMin || options.durationMax) {
const durationRange = {} const durationRange = {}
if (options.durationMin) durationRange[ Sequelize.Op.gte ] = options.durationMin if (options.durationMin) durationRange[ Op.gte ] = options.durationMin
if (options.durationMax) durationRange[ Sequelize.Op.lte ] = options.durationMax if (options.durationMax) durationRange[ Op.lte ] = options.durationMax
whereAnd.push({ duration: durationRange }) whereAnd.push({ duration: durationRange })
} }
@ -1256,7 +1263,7 @@ export class VideoModel extends Model<VideoModel> {
whereAnd.push( whereAnd.push(
{ {
id: { id: {
[ Sequelize.Op.in ]: Sequelize.literal( [ Op.in ]: Sequelize.literal(
'(' + '(' +
'SELECT "video"."id" FROM "video" ' + 'SELECT "video"."id" FROM "video" ' +
'WHERE ' + 'WHERE ' +
@ -1282,7 +1289,7 @@ export class VideoModel extends Model<VideoModel> {
) )
} }
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
attributes: { attributes: {
include: attributesInclude include: attributesInclude
}, },
@ -1290,7 +1297,7 @@ export class VideoModel extends Model<VideoModel> {
limit: options.count, limit: options.count,
order: getVideoSort(options.sort), order: getVideoSort(options.sort),
where: { where: {
[ Sequelize.Op.and ]: whereAnd [ Op.and ]: whereAnd
} }
} }
@ -1312,7 +1319,7 @@ export class VideoModel extends Model<VideoModel> {
return VideoModel.getAvailableForApi(query, queryOptions) return VideoModel.getAvailableForApi(query, queryOptions)
} }
static load (id: number | string, t?: Sequelize.Transaction) { static load (id: number | string, t?: Transaction) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const options = { const options = {
where, where,
@ -1322,7 +1329,7 @@ export class VideoModel extends Model<VideoModel> {
return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
} }
static loadWithRights (id: number | string, t?: Sequelize.Transaction) { static loadWithRights (id: number | string, t?: Transaction) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const options = { const options = {
where, where,
@ -1336,7 +1343,7 @@ export class VideoModel extends Model<VideoModel> {
]).findOne(options) ]).findOne(options)
} }
static loadOnlyId (id: number | string, t?: Sequelize.Transaction) { static loadOnlyId (id: number | string, t?: Transaction) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const options = { const options = {
@ -1348,7 +1355,7 @@ export class VideoModel extends Model<VideoModel> {
return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
} }
static loadWithFiles (id: number, t?: Sequelize.Transaction, logging?: boolean) { static loadWithFiles (id: number, t?: Transaction, logging?: boolean) {
return VideoModel.scope([ return VideoModel.scope([
ScopeNames.WITH_FILES, ScopeNames.WITH_FILES,
ScopeNames.WITH_STREAMING_PLAYLISTS, ScopeNames.WITH_STREAMING_PLAYLISTS,
@ -1366,8 +1373,8 @@ export class VideoModel extends Model<VideoModel> {
return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
} }
static loadByUrl (url: string, transaction?: Sequelize.Transaction) { static loadByUrl (url: string, transaction?: Transaction) {
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
where: { where: {
url url
}, },
@ -1377,8 +1384,8 @@ export class VideoModel extends Model<VideoModel> {
return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query)
} }
static loadByUrlAndPopulateAccount (url: string, transaction?: Sequelize.Transaction) { static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction) {
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
where: { where: {
url url
}, },
@ -1393,11 +1400,11 @@ export class VideoModel extends Model<VideoModel> {
]).findOne(query) ]).findOne(query)
} }
static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) { static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const options = { const options = {
order: [ [ 'Tags', 'name', 'ASC' ] ], order: [ [ 'Tags', 'name', 'ASC' ] ] as any, // FIXME: sequelize typings
where, where,
transaction: t transaction: t
} }
@ -1421,11 +1428,11 @@ export class VideoModel extends Model<VideoModel> {
.findOne(options) .findOne(options)
} }
static loadForGetAPI (id: number | string, t?: Sequelize.Transaction, userId?: number) { static loadForGetAPI (id: number | string, t?: Transaction, userId?: number) {
const where = buildWhereIdOrUUID(id) const where = buildWhereIdOrUUID(id)
const options = { const options = {
order: [ [ 'Tags', 'name', 'ASC' ] ], order: [ [ 'Tags', 'name', 'ASC' ] ] as any, // FIXME: sequelize typings
where, where,
transaction: t transaction: t
} }
@ -1489,7 +1496,7 @@ export class VideoModel extends Model<VideoModel> {
'LIMIT 1' 'LIMIT 1'
const options = { const options = {
type: Sequelize.QueryTypes.SELECT, type: QueryTypes.SELECT,
bind: { followerActorId, videoId }, bind: { followerActorId, videoId },
raw: true raw: true
} }
@ -1509,14 +1516,14 @@ export class VideoModel extends Model<VideoModel> {
includeLocalVideos: true includeLocalVideos: true
} }
const query: IFindOptions<VideoModel> = { const query: FindOptions = {
attributes: [ field ], attributes: [ field ],
limit: count, limit: count,
group: field, group: field,
having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), { having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), {
[ Sequelize.Op.gte ]: threshold [ Op.gte ]: threshold
}) as any, // FIXME: typings }) as any, // FIXME: typings
order: [ this.sequelize.random() ] order: [ (this.sequelize as any).random() ]
} }
return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] })
@ -1532,7 +1539,7 @@ export class VideoModel extends Model<VideoModel> {
required: false, required: false,
where: { where: {
startDate: { startDate: {
[ Sequelize.Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
} }
} }
} }
@ -1549,11 +1556,11 @@ export class VideoModel extends Model<VideoModel> {
} }
private static async getAvailableForApi ( private static async getAvailableForApi (
query: IFindOptions<VideoModel>, query: FindOptions,
options: AvailableForListIDsOptions, options: AvailableForListIDsOptions,
countVideos = true countVideos = true
) { ) {
const idsScope = { const idsScope: ScopeOptions = {
method: [ method: [
ScopeNames.AVAILABLE_FOR_LIST_IDS, options ScopeNames.AVAILABLE_FOR_LIST_IDS, options
] ]
@ -1561,8 +1568,8 @@ export class VideoModel extends Model<VideoModel> {
// Remove trending sort on count, because it uses a group by // Remove trending sort on count, because it uses a group by
const countOptions = Object.assign({}, options, { trendingDays: undefined }) const countOptions = Object.assign({}, options, { trendingDays: undefined })
const countQuery = Object.assign({}, query, { attributes: undefined, group: undefined }) const countQuery: CountOptions = Object.assign({}, query, { attributes: undefined, group: undefined })
const countScope = { const countScope: ScopeOptions = {
method: [ method: [
ScopeNames.AVAILABLE_FOR_LIST_IDS, countOptions ScopeNames.AVAILABLE_FOR_LIST_IDS, countOptions
] ]
@ -1576,7 +1583,7 @@ export class VideoModel extends Model<VideoModel> {
if (ids.length === 0) return { data: [], total: count } if (ids.length === 0) return { data: [], total: count }
const secondQuery: IFindOptions<VideoModel> = { const secondQuery: FindOptions = {
offset: 0, offset: 0,
limit: query.limit, limit: query.limit,
attributes: query.attributes, attributes: query.attributes,

View file

@ -1,6 +1,6 @@
import * as Sequelize from 'sequelize' import { QueryTypes, Sequelize } from 'sequelize'
let sequelizes: { [ id: number ]: Sequelize.Sequelize } = {} let sequelizes: { [ id: number ]: Sequelize } = {}
function getSequelize (serverNumber: number) { function getSequelize (serverNumber: number) {
if (sequelizes[serverNumber]) return sequelizes[serverNumber] if (sequelizes[serverNumber]) return sequelizes[serverNumber]
@ -27,7 +27,7 @@ function getSequelize (serverNumber: number) {
function setActorField (serverNumber: number, to: string, field: string, value: string) { function setActorField (serverNumber: number, to: string, field: string, value: string) {
const seq = getSequelize(serverNumber) const seq = getSequelize(serverNumber)
const options = { type: Sequelize.QueryTypes.UPDATE } const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
} }
@ -35,7 +35,7 @@ function setActorField (serverNumber: number, to: string, field: string, value:
function setVideoField (serverNumber: number, uuid: string, field: string, value: string) { function setVideoField (serverNumber: number, uuid: string, field: string, value: string) {
const seq = getSequelize(serverNumber) const seq = getSequelize(serverNumber)
const options = { type: Sequelize.QueryTypes.UPDATE } const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
} }
@ -43,7 +43,7 @@ function setVideoField (serverNumber: number, uuid: string, field: string, value
function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) { function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) {
const seq = getSequelize(serverNumber) const seq = getSequelize(serverNumber)
const options = { type: Sequelize.QueryTypes.UPDATE } const options = { type: QueryTypes.UPDATE }
return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
} }
@ -54,12 +54,13 @@ async function countVideoViewsOf (serverNumber: number, uuid: string) {
// tslint:disable // tslint:disable
const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
const options = { type: Sequelize.QueryTypes.SELECT } const options = { type: QueryTypes.SELECT as QueryTypes.SELECT }
const [ { total } ] = await seq.query(query, options) const [ { total } ] = await seq.query<{ total: number }>(query, options)
if (!total) return 0 if (!total) return 0
return parseInt(total, 10) // FIXME: check if we really need parseInt
return parseInt(total + '', 10)
} }
async function closeAllSequelize (servers: any[]) { async function closeAllSequelize (servers: any[]) {

139
yarn.lock
View file

@ -38,7 +38,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/bluebird@*", "@types/bluebird@3.5.18", "@types/bluebird@3.5.21": "@types/bluebird@*", "@types/bluebird@3.5.21":
version "3.5.21" version "3.5.21"
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.21.tgz#567615589cc913e84a28ecf9edb031732bdf2634" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.21.tgz#567615589cc913e84a28ecf9edb031732bdf2634"
integrity sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ== integrity sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ==
@ -100,13 +100,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/continuation-local-storage@*":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@types/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#a33e0df9dce9b424d1c98fc4fdebd8578dceec7e"
integrity sha1-oz4N+dzptCTRyY/E/evYV43O7H4=
dependencies:
"@types/node" "*"
"@types/cookiejar@*": "@types/cookiejar@*":
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80"
@ -162,11 +155,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/geojson@^1.0.0":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.6.tgz#3e02972728c69248c2af08d60a48cbb8680fffdf"
integrity sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==
"@types/ioredis@*": "@types/ioredis@*":
version "4.0.10" version "4.0.10"
resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.10.tgz#ca8bd95ca7d5fee32cbc5a0bf92fc29264bee237" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.10.tgz#ca8bd95ca7d5fee32cbc5a0bf92fc29264bee237"
@ -181,7 +169,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/lodash@*", "@types/lodash@^4.14.64": "@types/lodash@^4.14.64":
version "4.14.123" version "4.14.123"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d"
integrity sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q== integrity sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==
@ -241,11 +229,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1"
integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng== integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==
"@types/node@6.0.41":
version "6.0.41"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.41.tgz#578cf53aaec65887bcaf16792f8722932e8ff8ea"
integrity sha1-V4z1Oq7GWIe8rxZ5L4ciky6P+Oo=
"@types/node@^10.0.8": "@types/node@^10.0.8":
version "10.14.4" version "10.14.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5"
@ -310,16 +293,6 @@
"@types/node" "*" "@types/node" "*"
"@types/tough-cookie" "*" "@types/tough-cookie" "*"
"@types/sequelize@4.27.24":
version "4.27.24"
resolved "https://registry.yarnpkg.com/@types/sequelize/-/sequelize-4.27.24.tgz#7d593c062c368f570c68b0217f5c1d4c892ead48"
integrity sha512-5uMFsMa/0hU/7/8znyfBKSJy2Mbd57uRpYk5X1+Phz9dN0MRZLbTbj1JMeB3CJ4R9b1coNQGfp2kXh4OjI9UyA==
dependencies:
"@types/bluebird" "*"
"@types/continuation-local-storage" "*"
"@types/lodash" "*"
"@types/validator" "*"
"@types/serve-static@*": "@types/serve-static@*":
version "1.13.2" version "1.13.2"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"
@ -374,7 +347,7 @@
resolved "https://registry.yarnpkg.com/@types/tv4/-/tv4-1.2.29.tgz#4c6d2222b03245dd2104f4fd67f54d1658985911" resolved "https://registry.yarnpkg.com/@types/tv4/-/tv4-1.2.29.tgz#4c6d2222b03245dd2104f4fd67f54d1658985911"
integrity sha512-NtJmi+XbYocrLb5Au4Q64srX4FlCPDvrSF/OnK3H0QJwrw40tIUoQPDoUHnZ5wpAB2KThtVyeS+kOEQyZabORg== integrity sha512-NtJmi+XbYocrLb5Au4Q64srX4FlCPDvrSF/OnK3H0QJwrw40tIUoQPDoUHnZ5wpAB2KThtVyeS+kOEQyZabORg==
"@types/validator@*", "@types/validator@^10.9.0": "@types/validator@^10.9.0":
version "10.11.0" version "10.11.0"
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-10.11.0.tgz#aae9009ce28cc4f878e32c34d3900a81193c98d5" resolved "https://registry.yarnpkg.com/@types/validator/-/validator-10.11.0.tgz#aae9009ce28cc4f878e32c34d3900a81193c98d5"
integrity sha512-i1aY7RKb6HmQIEnK0cBmUZUp1URx0riIHw/GYNoZ46Su0GWfLiDmMI8zMRmaauMnOTg2bQag0qfwcyUFC9Tn+A== integrity sha512-i1aY7RKb6HmQIEnK0cBmUZUp1URx0riIHw/GYNoZ46Su0GWfLiDmMI8zMRmaauMnOTg2bQag0qfwcyUFC9Tn+A==
@ -562,6 +535,11 @@ any-observable@^0.3.0:
resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==
any-promise@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
anymatch@^2.0.0: anymatch@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@ -1033,7 +1011,7 @@ bluebird@^2.10.0:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
bluebird@^3.0.5, bluebird@^3.4.6, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3: bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3:
version "3.5.3" version "3.5.3"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
@ -1992,7 +1970,7 @@ debug@2.3.3:
dependencies: dependencies:
ms "0.7.2" ms "0.7.2"
debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -2013,7 +1991,7 @@ debug@3.2.6, debug@^3.1.0:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debug@^4.0.1, debug@^4.1.0, debug@~4.1.0: debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
@ -2154,7 +2132,7 @@ depd@2.0.0:
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@^1.1.0, depd@~1.1.0, depd@~1.1.2: depd@~1.1.0, depd@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
@ -2548,11 +2526,6 @@ es6-set@~0.1.5:
es6-symbol "3.1.1" es6-symbol "3.1.1"
event-emitter "~0.3.5" event-emitter "~0.3.5"
es6-shim@0.35.3:
version "0.35.3"
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26"
integrity sha1-m/tzY/7//4emzbbNk+QF7DxLbyY=
es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
@ -3295,11 +3268,6 @@ generate-object-property@^1.1.0:
dependencies: dependencies:
is-property "^1.0.0" is-property "^1.0.0"
generic-pool@^3.4.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.7.1.tgz#36fe5bb83e7e0e032e5d32cd05dc00f5ff119aa8"
integrity sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==
genfun@^5.0.0: genfun@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
@ -4955,7 +4923,7 @@ lodash@=3.10.1:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
lodash@^4.0.0, lodash@^4.17.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.3.0, lodash@~4.17.10: lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.3.0, lodash@~4.17.10:
version "4.17.11" version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
@ -5376,14 +5344,14 @@ mocha@^6.0.0:
yargs-parser "11.1.1" yargs-parser "11.1.1"
yargs-unparser "1.5.0" yargs-unparser "1.5.0"
moment-timezone@^0.5.14, moment-timezone@^0.5.23: moment-timezone@^0.5.21, moment-timezone@^0.5.23:
version "0.5.23" version "0.5.23"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463"
integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w== integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==
dependencies: dependencies:
moment ">= 2.9.0" moment ">= 2.9.0"
"moment@>= 2.9.0", moment@^2.20.0: "moment@>= 2.9.0", moment@^2.24.0:
version "2.24.0" version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
@ -7272,13 +7240,12 @@ ret@~0.1.10:
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
retry-as-promised@^2.3.2: retry-as-promised@^3.1.0:
version "2.3.2" version "3.2.0"
resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-2.3.2.tgz#cd974ee4fd9b5fe03cbf31871ee48221c07737b7" resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543"
integrity sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c= integrity sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==
dependencies: dependencies:
bluebird "^3.4.6" any-promise "^1.3.0"
debug "^2.6.9"
retry@^0.10.0: retry@^0.10.0:
version "0.10.1" version "0.10.1"
@ -7487,39 +7454,40 @@ send@0.16.2:
range-parser "~1.2.0" range-parser "~1.2.0"
statuses "~1.4.0" statuses "~1.4.0"
sequelize-typescript@0.6.7: sequelize-pool@^1.0.2:
version "0.6.7" version "1.0.2"
resolved "https://registry.yarnpkg.com/sequelize-typescript/-/sequelize-typescript-0.6.7.tgz#372be979cbae060c554fdbaf2c2d8c93a0283303" resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-1.0.2.tgz#89c767882bbdb8a41dac66922ed9820939a5401e"
integrity sha512-ae21Gq9VOVXlIjnh2vLdL42Kev6r4LC82xOQ2fXo0lHzQvjFeH8/GaWUlpvYv57AOgc+ZnElbYFbSLKdT9ue0w== integrity sha512-VMKl/gCCdIvB1gFZ7p+oqLFEyZEz3oMMYjkKvfEC7GoO9bBcxmfOOU9RdkoltfXGgBZFigSChihRly2gKtsh2w==
dependencies:
bluebird "^3.5.3"
sequelize-typescript@^1.0.0-beta.1:
version "1.0.0-beta.1"
resolved "https://registry.yarnpkg.com/sequelize-typescript/-/sequelize-typescript-1.0.0-beta.1.tgz#402279fec52669cbd78ecbf50e189638483a7360"
integrity sha512-xD28kqa1rIKujlmgA4hWQgtwFfRM6tLv1/mnZOrOFEZxvSWazUbTzqGB7OZydZDNj3iJnyrV1l6i6HOfvrpvEw==
dependencies: dependencies:
"@types/bluebird" "3.5.18"
"@types/node" "6.0.41"
"@types/sequelize" "4.27.24"
es6-shim "0.35.3"
glob "7.1.2" glob "7.1.2"
sequelize@4.42.0: sequelize@5.6.1:
version "4.42.0" version "5.6.1"
resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.42.0.tgz#439467ba7bfe7d5afcc56d62b3e091860fbf18f3" resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.6.1.tgz#fc22306109fb2504a6573edfb3c469ec86fae873"
integrity sha512-qxAYnX4rcv7PbNtEidb56REpxNJCdbN0qyk1jb3+e6sE7OrmS0nYMU+MFVbNTJtZfSpOEEL1TX0TkMw+wzZBxg== integrity sha512-QsXUDar6ow0HrF9BtnHRaNumu6qRYb97dfwvez/Z5guH3i6w6k8+bp6gP3VCiDC+2qX+jQIyrYohKg9evy8GFg==
dependencies: dependencies:
bluebird "^3.5.0" bluebird "^3.5.0"
cls-bluebird "^2.1.0" cls-bluebird "^2.1.0"
debug "^3.1.0" debug "^4.1.1"
depd "^1.1.0"
dottie "^2.0.0" dottie "^2.0.0"
generic-pool "^3.4.0"
inflection "1.12.0" inflection "1.12.0"
lodash "^4.17.1" lodash "^4.17.11"
moment "^2.20.0" moment "^2.24.0"
moment-timezone "^0.5.14" moment-timezone "^0.5.21"
retry-as-promised "^2.3.2" retry-as-promised "^3.1.0"
semver "^5.5.0" semver "^5.6.0"
terraformer-wkt-parser "^1.1.2" sequelize-pool "^1.0.2"
toposort-class "^1.0.1" toposort-class "^1.0.1"
uuid "^3.2.1" uuid "^3.2.1"
validator "^10.4.0" validator "^10.11.0"
wkx "^0.4.1" wkx "^0.4.6"
serve-static@1.13.2: serve-static@1.13.2:
version "1.13.2" version "1.13.2"
@ -8398,21 +8366,6 @@ term-size@^1.2.0:
dependencies: dependencies:
execa "^0.7.0" execa "^0.7.0"
terraformer-wkt-parser@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/terraformer-wkt-parser/-/terraformer-wkt-parser-1.2.0.tgz#c9d6ac3dff25f4c0bd344e961f42694961834c34"
integrity sha512-QU3iA54St5lF8Za1jg1oj4NYc8sn5tCZ08aNSWDeGzrsaV48eZk1iAVWasxhNspYBoCqdHuoot1pUTUrE1AJ4w==
dependencies:
"@types/geojson" "^1.0.0"
terraformer "~1.0.5"
terraformer@~1.0.5:
version "1.0.9"
resolved "https://registry.yarnpkg.com/terraformer/-/terraformer-1.0.9.tgz#77851fef4a49c90b345dc53cf26809fdf29dcda6"
integrity sha512-YlmQ1fsMWTkKGDGibCRWgmLzrpDRUr63Q025LJ/taYQ6j1Yb8q9McKF7NBi6ACAyUXO6F/bl9w6v4MY307y5Ag==
optionalDependencies:
"@types/geojson" "^1.0.0"
text-hex@1.0.x: text-hex@1.0.x:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
@ -9002,7 +8955,7 @@ validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0:
dependencies: dependencies:
builtins "^1.0.3" builtins "^1.0.3"
validator@^10.0.0, validator@^10.2.0, validator@^10.4.0: validator@^10.0.0, validator@^10.11.0, validator@^10.2.0, validator@^10.4.0:
version "10.11.0" version "10.11.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
@ -9172,7 +9125,7 @@ winston@3.2.1:
triple-beam "^1.3.0" triple-beam "^1.3.0"
winston-transport "^4.3.0" winston-transport "^4.3.0"
wkx@^0.4.1: wkx@^0.4.6:
version "0.4.6" version "0.4.6"
resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.6.tgz#228ab592e6457382ea6fb79fc825058d07fce523" resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.4.6.tgz#228ab592e6457382ea6fb79fc825058d07fce523"
integrity sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A== integrity sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==