if (obj[key] === undefined) continue
+ if (Array.isArray(obj[key]) && obj[key].length === 0) {
+ fd.append(key, null)
+ continue
+ }
+
if (obj[key] !== null && typeof obj[ key ] === 'object' && !(obj[ key ] instanceof File)) {
objectToFormData(obj[ key ], fd, key)
} else {
this.form.addControl('licence', new FormControl('', VIDEO_LICENCE.VALIDATORS))
this.form.addControl('language', new FormControl('', VIDEO_LANGUAGE.VALIDATORS))
this.form.addControl('description', new FormControl('', VIDEO_DESCRIPTION.VALIDATORS))
- this.form.addControl('tags', new FormControl(''))
+ this.form.addControl('tags', new FormControl([]))
this.form.addControl('thumbnailfile', new FormControl(''))
this.form.addControl('previewfile', new FormControl(''))
this.form.addControl('support', new FormControl('', VIDEO_SUPPORT.VALIDATORS))
this.cleanerInterval = null
}
+ if (this.db) {
+ await this.db.close()
+
+ await this.dropDatabase(this.databaseName)
+ }
+
if (this.expirationDB) {
await this.expirationDB.close()
this.expirationDB = null
}
- if (this.db) {
- console.log('Destroying IndexDB database %s.', this.databaseName)
- await this.db.close()
- await this.db.delete()
- }
-
return cb()
} catch (err) {
console.error('Cannot destroy peertube chunk store.', err)
}, PeertubeChunkStore.CLEANER_INTERVAL_MS)
}
- private checkExpiration () {
- this.expirationDB.transaction('rw', this.expirationDB.databases, async () => {
- // Update our database expiration since we are alive
- await this.expirationDB.databases.put({
- name: this.databaseName,
- expiration: new Date().getTime() + PeertubeChunkStore.CLEANER_EXPIRATION_MS
- })
+ private async checkExpiration () {
+ let databasesToDeleteInfo: { name: string }[] = []
- const now = new Date().getTime()
- const databasesToDeleteInfo = await this.expirationDB.databases.where('expiration').below(now).toArray()
+ try {
+ await this.expirationDB.transaction('rw', this.expirationDB.databases, async () => {
+ // Update our database expiration since we are alive
+ await this.expirationDB.databases.put({
+ name: this.databaseName,
+ expiration: new Date().getTime() + PeertubeChunkStore.CLEANER_EXPIRATION_MS
+ })
- for (const databaseToDeleteInfo of databasesToDeleteInfo) {
- await this.dropDatabase(databaseToDeleteInfo.name)
+ const now = new Date().getTime()
+ databasesToDeleteInfo = await this.expirationDB.databases.where('expiration').below(now).toArray()
+ })
+ } catch (err) {
+ console.error('Cannot update expiration of fetch expired databases.', err)
+ }
- await this.expirationDB.databases.where({ name: databaseToDeleteInfo.name }).delete()
- }
- }).catch(err => console.error('Cannot check expiration.', err))
+ for (const databaseToDeleteInfo of databasesToDeleteInfo) {
+ await this.dropDatabase(databaseToDeleteInfo.name)
+ }
}
- private dropDatabase (databaseName: string) {
+ private async dropDatabase (databaseName: string) {
const dbToDelete = new ChunkDatabase(databaseName)
+ console.log('Destroying IndexDB database %s.', databaseName)
- console.log('Deleting %s.', databaseName)
- return dbToDelete.delete()
- .catch(err => console.error('Cannot delete %s.', databaseName))
+ try {
+ await dbToDelete.delete()
+
+ await this.expirationDB.transaction('rw', this.expirationDB.databases, () => {
+ return this.expirationDB.databases.where({ name: databaseName }).delete()
+ })
+ } catch (err) {
+ console.error('Cannot delete %s.', databaseName, err)
+ }
}
private nextTick (cb, err, val?) {
video.VideoFiles = [ videoFile ]
- if (videoInfo.tags) {
+ if (videoInfo.tags !== undefined) {
const tagInstances = await TagModel.findOrCreateTags(videoInfo.tags, t)
await video.$set('Tags', tagInstances, sequelizeOptions)
const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
// Video tags update?
- if (videoInfoToUpdate.tags) {
+ if (videoInfoToUpdate.tags !== undefined) {
const tagInstances = await TagModel.findOrCreateTags(videoInfoToUpdate.tags, t)
await videoInstanceUpdated.$set('Tags', tagInstances, sequelizeOptions)
return validator.toInt(value)
}
-function toStringOrNull (value: string) {
+function toValueOrNull (value: string) {
if (value === 'null') return null
return value
isUUIDValid,
isIdOrUUIDValid,
isDateValid,
- toStringOrNull,
+ toValueOrNull,
isBooleanValid,
toIntOrNull,
isFileValid
}
function isVideoTagsValid (tags: string[]) {
- return isArray(tags) &&
- validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
- tags.every(tag => isVideoTagValid(tag))
+ return tags === null || (
+ isArray(tags) &&
+ validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
+ tags.every(tag => isVideoTagValid(tag))
+ )
}
function isVideoAbuseReasonValid (value: string) {
import 'express-validator'
import { body, param, query } from 'express-validator/check'
import { UserRight, VideoPrivacy } from '../../../shared'
-import { isBooleanValid, isIdOrUUIDValid, isIdValid, isUUIDValid, toIntOrNull, toStringOrNull } from '../../helpers/custom-validators/misc'
+import { isBooleanValid, isIdOrUUIDValid, isIdValid, isUUIDValid, toIntOrNull, toValueOrNull } from '../../helpers/custom-validators/misc'
import {
isVideoAbuseReasonValid,
isVideoCategoryValid,
.custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
body('language')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoLanguageValid).withMessage('Should have a valid language'),
body('nsfw')
.toBoolean()
.custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
body('description')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
body('support')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoSupportValid).withMessage('Should have a valid support text'),
body('tags')
.optional()
+ .customSanitizer(toValueOrNull)
.custom(isVideoTagsValid).withMessage('Should have correct tags'),
body('commentsEnabled')
.toBoolean()
.custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
body('language')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoLanguageValid).withMessage('Should have a valid language'),
body('nsfw')
.optional()
.custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
body('description')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
body('support')
.optional()
- .customSanitizer(toStringOrNull)
+ .customSanitizer(toValueOrNull)
.custom(isVideoSupportValid).withMessage('Should have a valid support text'),
body('tags')
.optional()
+ .customSanitizer(toValueOrNull)
.custom(isVideoTagsValid).withMessage('Should have correct tags'),
body('commentsEnabled')
.optional()
Videos: VideoModel[]
static findOrCreateTags (tags: string[], transaction: Transaction) {
+ if (tags === null) return []
+
const tasks: Bluebird<TagModel>[] = []
tags.forEach(tag => {
const query = {