Completed
Push — master ( f56d73...9b6507 )
by greg
02:03
created

image.js ➔ ... ➔ ???   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 55
rs 9.7692

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
import execPromise from 'child-process-promise'
2
import mkdirp from 'mkdirp'
3
import fse from 'fs-extra'
4
import limax from 'limax'
5
import Jimp from 'jimp'
6
import path from 'path'
7
import {Promise} from 'bluebird'
8
9
import {
10
  abeExtend,
11
  coreUtils,
12
  cmsData,
13
  config
14
} from '../../'
15
16
export function cropAndSaveFile(imageSize, file, newFile) {
17
  var p = new Promise((resolve) => {
18
    Jimp.read(file).then(function (lenna) {
19
      lenna.crop(0, 0, parseInt(imageSize[0]), parseInt(imageSize[1])).write(newFile)
20
    }).catch(function (err) {
21
      console.error(err)
22
    })
23
    resolve()
24
  })
25
  return p
26
}
27
28
export function smartCropAndSaveFile(imageSize, file, newFile) {
29
  var cmd = `node node_modules/smartcrop-cli/smartcrop-cli.js --width ${parseInt(imageSize[0])} --height ${parseInt(imageSize[1])} ${file} ${newFile}`
30
  var p = execPromise.exec(cmd)
31
  return p
32
}
33
34
export function cropAndSaveFiles(images, file, resp) {
35
  var length = images.length
36
  var cropedImage = 0
37
  resp.thumbs = []
38
  var p = new Promise((resolve) => {
39
    for (var i = 0; i < length; i++) {
40
      var image = images[i]
41
      var ext = path.extname(file)
42
      var newFile = file.replace(ext, `_${images[i]}${ext}`)
43
      resp.thumbs.push({
44
        name: newFile.replace(path.join(config.root, config.publish.url), ''),
45
        size: image
46
      })
47
      smartCropAndSaveFile(image.split('x'), file, newFile)
48
        .then(function (result) {
49
          if(result.stderr) {
50
            cropAndSaveFile(image.split('x'), file, newFile).then(function () {
0 ignored issues
show
Bug introduced by
The variable image is changed as part of the for loop for example by images.i on line 40. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
Bug introduced by
The variable newFile is changed as part of the for loop for example by file.replace(ext, `_${images.i}${ext}`) on line 42. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
51
              if(++cropedImage === length) {
52
                resolve(resp)
53
              }
54
            })
55
          }
56
          else if(++cropedImage === length) {
57
            resolve(resp)
58
          }
59
        })
60
        .catch(function (err) {
61
          console.log(err)
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
62
        })
63
    }
64
  })
65
66
  return p
67
}
68
69
export function generateThumbnail(file) {
70
  var ext = path.extname(file).toLowerCase()
71
  var thumbFileName = file.replace(ext, `_thumb${ext}`)
72
  var thumbFileNameRelative = thumbFileName.replace(path.join(config.root, config.publish.url), '')
73
  var p = new Promise((resolve) => {
74
    var cropThumb = smartCropAndSaveFile([250, 250], file, thumbFileName)
75
    cropThumb.then(function (result) {
76
      var stderr = result.stderr
77
      if(stderr) {
78
        cropAndSaveFile([250, 250], file, thumbFileName).then(function () {
79
          resolve({thumb: thumbFileNameRelative})
80
        })
81
      }
82
      else resolve({thumb: thumbFileNameRelative})
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
83
    })
84
  })
85
86
  return p
87
}
88
89
export function saveFile(req) {
90
  var p = new Promise((resolve) => {
91
    var resp = {success: 1}
92
    var filePath
93
    req.pipe(req.busboy)
94
    req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
95
      var ext = path.extname(filename).toLowerCase()
96
      var slug = createMediaSlug(filename, ext)
97
      var mediaType = getMediaType(ext)
98
99
      var folderFilePath = createMediaFolder(mediaType)
100
      var hasSentHeader = false
101
      
102
      filePath = path.join(folderFilePath, slug)
103
      resp['filePath'] = path.join('/' + mediaType, slug)
104
105
      file.on('limit', function() {
106
        hasSentHeader = true
107
        file.resume()
108
        resolve({error: 1, response: 'file is too big'})
109
        return
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
110
      })
111
112
      var isValid = isValidMedia(mimetype, ext)
113
      if(isValid.error){
114
        hasSentHeader = true
115
        file.resume()
116
        resolve({error: 1, response: isValid.error})
117
        return
118
      }
119
120
      var fstream = fse.createWriteStream(filePath)
121
      fstream.on('finish', function() {
122
        if(hasSentHeader) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
123
124
        resp = abeExtend.hooks.instance.trigger('afterSaveImage', resp, req)
125
126
        if(mediaType === 'image') {
127
          var thumbPromise = generateThumbnail(filePath)
128
          thumbPromise.then(function (thumbResp) {
129
            resp.thumbnail = thumbResp.thumb
130
            if(req.query.input.indexOf('data-size') > -1){
131
              var thumbsSizes = cmsData.regex.getAttr(req.query.input, 'data-size').split(',')
132
              cropAndSaveFiles(thumbsSizes, filePath, resp).then(function (resp) {
133
                resolve(resp)
134
              })
135
            }
136
            else resolve(resp)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
137
          })
138
        } else {
139
          resolve(resp)
140
        }
141
      })
142
      file.pipe(fstream)
143
    })
144
  })
145
146
  return p
147
}
148
149
export function isValidMedia(mimetype, ext) {
150
  var allowedExtensions = config.upload.extensions
151
  var allowedMimetypes = config.upload.mimetypes
152
153
  var error = false
154
  if (allowedMimetypes.indexOf(mimetype) < 0) error = 'unauthorized file'
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
155
  else if (allowedExtensions.indexOf(ext) < 0) error = 'not a valid asset'
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
156
157
  return {error: error}
158
}
159
160
export function getMediaType(ext) {
161
  let type = 'document'
162
163
  if(/\.(jpg|jpeg|png|gif|svg)/.test(ext)){
164
    type = 'image'
165
  } else if(/\.(mov|avi|mp4)/.test(ext)) {
166
    type = 'video'
167
  } else if(/\.(mp3|wav)/.test(ext)){
168
    type = 'sound'
169
  }
170
171
  return type
172
}
173
174
export function createMediaSlug(filename, ext) {
175
  var filenameNoExt = path.basename(filename, ext)
176
  return limax(filenameNoExt, {separateNumbers: false}) + '-' + coreUtils.random.generateUniqueIdentifier(2) + ext
177
}
178
179
export function createMediaFolder(mediaType) {
180
  var folderWebPath = '/' + mediaType
181
  folderWebPath = abeExtend.hooks.instance.trigger('beforeSaveImage', folderWebPath)
182
  var folderFilePath = path.join(config.root, config.publish.url, folderWebPath)
183
  mkdirp.sync(folderFilePath)
184
185
  return folderFilePath
186
}
187
188
export function getThumbsList() {
189
  var thumbsList = []
190
  var pathToThumbs = path.join(config.root, config.publish.url, config.upload.image)
191
  var files = coreUtils.file.getFilesSync(pathToThumbs, true)
192
  Array.prototype.forEach.call(files, (pathFile) => {
193
    pathFile = pathFile.replace(path.join(config.root, config.publish.url), '')
194
    if(pathFile.indexOf('_thumb.') > -1){
195
      thumbsList.push({
196
        originalFile: pathFile.replace('_thumb.', '.'),
197
        thumbFile: pathFile
198
      })
199
    }
200
  })
201
202
  return thumbsList
203
}
204
205
export function getAssociatedImageFileFromThumb(name) {
206
  var rexMatchImageName = /_(thumb|\d+x\d+)\./
207
  name = path.join(path.sep, name)
208
  var originalName = path.join(path.sep, name.replace(rexMatchImageName, '.'))
209
  var imageList = {
210
    thumbFile: name,
211
    originalFile: originalName,
212
    thumbs: []
213
  }
214
  var pathThumb = name.split('/')
215
  pathThumb.pop()
216
  pathThumb = path.join(config.root, config.publish.url, pathThumb.join('/'))
217
218
  var files = coreUtils.file.getFilesSync(pathThumb, true)
219
  Array.prototype.forEach.call(files, (pathFile) => {
220
    pathFile = pathFile.replace(path.join(config.root, config.publish.url), '')
221
    if(pathFile !== originalName && pathFile !== name && pathFile.replace(rexMatchImageName, '.') === originalName){
222
      imageList.thumbs.push(pathFile)
223
    }
224
  })
225
226
  return imageList
227
}
228