@bigfishtv/cockpit
Version:
156 lines (141 loc) • 5.66 kB
JavaScript
/**
* File Utilities
* @module Utilities/fileUtils
*/
import pluploadSettings from '../config/pluploadSettings'
import filesizeParser from 'filesize-parser'
import filesize from 'file-size'
import { notifyFailure } from '../actions/notifications'
let store = null
const maxSize = filesizeParser(pluploadSettings.max_file_size)
/**
* Makes a reference to redux store for notification dispatches
* @param {Object} store
*/
export function init(_store) {
store = _store
}
/**
* Filters an of files based on validation props provided
* @param {Array} files - Array of files
* @param {Object} props - Uploader props: multiple, maxFiles, files, subject
* @return {Array} - Returns filtered array of files depending on max files and filesize limits, or empty array. Will dispatch notifications via store
*/
export function validateFiles(files, props = {}) {
const maxFiles = props.multiple ? (props.maxFiles ? props.maxFiles : 9999) : 1
const currentFiles = props.files || []
const fileTypeStore = store && store.getState().fileTypes
const subject = props.subject
const extensions = subject && fileTypeStore && subject in fileTypeStore ? fileTypeStore[subject] : null
if (maxFiles && currentFiles.length + files.length > maxFiles) {
const remaining = maxFiles - currentFiles.length
if (store) store.dispatch(notifyFailure('Too many files! (' + maxFiles + ' allowed, ' + remaining + ' remaining)'))
return []
}
const maxBytes = (store && store.getState().maximumUploadSize) || maxSize
return files.filter(file => {
if (extensions && !isValidExtension(file, extensions)) {
const extension = getExtension(file.name)
if (store) store.dispatch(notifyFailure('".' + extension + '" is an invalid ' + (subject || 'file') + ' type!'))
} else if (file.size > maxBytes) {
const sizeReadable = filesize(file.size).human('si')
const maxSizeReadable = filesize(maxBytes).human('si')
if (store)
store.dispatch(
notifyFailure('"' + file.name + '" is too big (' + sizeReadable + '), limit is ' + maxSizeReadable)
)
} else {
return true
}
return false
})
}
/**
* Takes filename and returns file extension
* @param {String} filename - File name (can include path)
* @return {String} - Returns extension
*/
export function getExtension(filename) {
if (typeof filename !== 'string' || filename.indexOf('.') < 0) return false
return filename.substring(filename.lastIndexOf('.') + 1, filename.length).toLowerCase()
}
/**
* Is basically a glorified inArray function...
* @param {Object} file - File object containing 'name' key
* @param {Array} extensions - Array of valid file extensions
* @return {Boolean} - Returns true or false if file's extension is valid
*/
export function isValidExtension(file, extensions) {
if (typeof file !== 'object' || !file.name || !(extensions instanceof Array)) return false
const extension = getExtension(file.name)
return extension && extensions.indexOf(extension) >= 0
}
/**
* Cherry picks bits of data from native file object and returns new object
* @param {Object} file - Native file object, e.g. from drop zone
* @return {Object} - Returns object with data extracted from native file
*/
export function createFileObjectFromNative(file) {
return {
name: file.name,
type: file.type,
extension: getExtension(file.name),
lastModified: file.lastModified,
lastModifiedDate: file.lastModifiedDate,
size: file.size,
}
}
/**
* Takes a native file object and a callback. It loads the file via FileReader and once read sends data url back via callback
* @param {Object} file - Native file object
* @param {Function} callback - Callback function, called with 1 argument - the image's data url
*/
export function extractDataUrlFromNative(file, callback = () => false) {
const img = new FileReader()
img.onload = function(e) {
callback(this.result)
}
img.readAsDataURL(file)
}
/**
* Tank specific function for getting a generated image url based on size preset and extension
* @param {Object} file - Image object, containing keys: filename,
* @param {String} size - Image size preset - defined in tank, defaults to 'cockpit-small'
* @param {String} extension - Not required, used to specify extension, defaults to original file extension
* @param {Boolean} getOriginal - Whether or not to fetch pre-edited image
* @return {String} - Returns url string
*/
export function getImageUrl(file, size = 'cockpit-small', extension = null, getOriginal = false) {
if (typeof file != 'object' || file instanceof Array || !file.filename || typeof size != 'string') return false
const dot = file.filename.lastIndexOf('.')
if (!file.slug) file.slug = file.filename.substr(0, dot)
if (!file.extension) file.extension = file.filename.substr(dot + 1, file.filename.length)
if (file.extension === 'svg') return getAssetUrl(file)
if (file.extension === 'pdf' && !extension) extension = 'png'
const originalStr = getOriginal ? 'original/' : ''
const url =
'/generated/' +
originalStr +
size +
'/' +
file.slug +
'.' +
(extension ? extension : file.extension ? file.extension : 'jpg')
return url
}
/**
* Takes file object and returns original upload url
* @param {Object} file - File object, containing keys: filename
* @return {String} - Returns url to original upload
*/
export function getAssetUrl(file) {
if (
file instanceof Array ||
(typeof file != 'object' && typeof file != 'string') ||
(typeof file == 'object' && !file.filename)
)
return false
const filename = typeof file == 'string' ? file : file.filename
const url = '/uploads/' + filename
return url
}