Skip to content
Snippets Groups Projects
1698750314-add-full-quality-converted-object-to-storedobjects.js 3.71 KiB
Newer Older
/* eslint-disable import/no-unresolved */
const logger = require('@pubsweet/logger')
const mime = require('mime-types')
const fs = require('fs-extra')
const path = require('path')
const sharp = require('sharp')
const { useTransaction } = require('@coko/server')
const File = require('@coko/server/src/models/file/file.model')

const {
  connectToFileStorage,
} = require('@coko/server/src/services/fileStorage')

const {
  convertFileStreamIntoBuffer,
  getFileExtension,
  getImageFileMetadata,
} = require('@coko/server/src/helpers')

const imageSizeConversionMapper = {
  tiff: {
    full: 'png',
  },
  tif: {
    full: 'png',
  },
  svg: {
    full: 'svg',
  },
  png: {
    full: 'png',
  },
  default: {
    full: 'jpeg',
  },
}

const sharpConversionFullFilePath = async (
  buffer,
  tempDir,
  filenameWithoutExtension,
  format,
) => {
  await fs.ensureDir(tempDir)

  const tempFullFilePath = path.join(
    tempDir,
    `${filenameWithoutExtension}_full.${
      imageSizeConversionMapper[format]
        ? imageSizeConversionMapper[format].full
        : imageSizeConversionMapper.default.full
    }`,
  )

  await sharp(buffer).toFile(tempFullFilePath)

  return tempFullFilePath
}

exports.up = async knex => {
  try {
    return useTransaction(async trx => {
      await connectToFileStorage()
      const files = await File.query(trx)

      const tempDir = path.join(__dirname, '..', 'temp')

      await Promise.all(
        files.map(async file => {
          const mimetype = mime.lookup(file.name)

          if (mimetype.match(/^image\//)) {
            const originalStoredObject = file.storedObjects.find(
              storedObject => storedObject.type === 'original',
            )

            const filenameWithoutExtension = path.parse(
              originalStoredObject.key,
            ).name

            const tempPath = path.join(tempDir, originalStoredObject.key)
            await download(originalStoredObject.key, tempPath)

            const format = originalStoredObject.extension

            const buffer = fs.readFileSync(tempPath)

            const tempFullFilePath = await sharpConversionFullFilePath(
              buffer,
              tempDir,
              filenameWithoutExtension,
              format,
            )

            const fullImageStream = fs.createReadStream(tempFullFilePath)

            const full = await uploadFileHandler(
              fs.createReadStream(tempFullFilePath),
              path.basename(tempFullFilePath),
              mime.lookup(tempFullFilePath),
            )

            const fullFileBuffer = await convertFileStreamIntoBuffer(
              fullImageStream,
            )

            const {
              width: fWidth,
              height: fHeight,
              space: fSpace,
              density: fDensity,
              size: fSize,
            } = await getImageFileMetadata(fullFileBuffer)

            full.imageMetadata = {
              density: fDensity,
              height: fHeight,
              space: fSpace,
              width: fWidth,
            }
            full.size = fSize
            full.extension = `${getFileExtension(tempFullFilePath)}`
            full.type = 'full'
            full.mimetype = mime.lookup(tempFullFilePath)

            file.storedObjects.push(full)

            await File.query(trx).patchAndFetchById(file.id, {
              storedObjects: file.storedObjects,
            })

            fs.unlinkSync(tempFullFilePath)
          }
        }),
      )

      return true
    })
  } catch (e) {
    logger.error(
      'File: Add full conversion image quality to stored objects migration failed!',
    )
    throw new Error(e)
  }
}