getImage.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. 'use strict'
  2. import express from 'express'
  3. import path from 'path'
  4. import boom from '@hapi/boom'
  5. import { imagesPath, imageServedUrl } from '../../config'
  6. import { asyncMiddleware, checkSceneName, checkRequiredParameters, getSceneFilesData } from '../functions'
  7. const router = express.Router()
  8. /**
  9. * @api {get} /getImage?sceneName=:sceneName&imageQuality=:imageQuality Get an image from a scene
  10. * @apiVersion 0.1.0
  11. * @apiName GetImage
  12. * @apiGroup API
  13. *
  14. * @apiDescription Get an image from a scene with the required quality
  15. *
  16. * @apiParam {String} sceneName The selected scene
  17. * @apiParam {Number} imageQuality The required quality of the image
  18. *
  19. * @apiExample Usage example
  20. * curl -i -L -X GET "http://diran.univ-littoral.fr/api/getImage?sceneName=bathroom&imageQuality=200"
  21. *
  22. * @apiSuccess {String} data Path to the image
  23. * @apiSuccessExample {json} Success response example
  24. * HTTP/1.1 200 OK /api/getImage?sceneName=bathroom&imageQuality=200
  25. * {
  26. * "data": "/api/images/bathroom/bathroom_00200.png"
  27. * }
  28. *
  29. * @apiError (Error 4xx) 400_[1] Missing parameter(s)
  30. * @apiErrorExample {json} Missing parameter
  31. * HTTP/1.1 400 Bad Request
  32. * {
  33. * "message": "Missing parameter(s). Required parameters : sceneName, imageQuality."
  34. * }
  35. *
  36. * @apiError (Error 4xx) 400_[2] Invalid query parameter
  37. * @apiErrorExample {json} Invalid query parameter(s)
  38. * HTTP/1.1 400 Bad Request
  39. * {
  40. * "message": "Invalid query parameter(s).",
  41. * "data": [
  42. * "The requested scene name \".//../\" is not valid.",
  43. * "The specified quality is not an integer."
  44. * ]
  45. * }
  46. *
  47. * @apiError (Error 4xx) 404_[1] Quality not found
  48. * @apiErrorExample {json} Quality not found
  49. * HTTP/1.1 404 Not Found
  50. * {
  51. * "message": "The requested quality (9999) was not found for the requested scene (bathroom)."
  52. * }
  53. *
  54. * @apiError (Error 5xx) 500_[1] Can't access the `IMAGES_PATH` directory
  55. * @apiErrorExample {json} Images directory not accessible
  56. * HTTP/1.1 500 Internal Server Error
  57. * {
  58. * "message": "Can't access the \"images\" directory. Check it exists and you have read permission on it"
  59. * }
  60. *
  61. * @apiError (Error 5xx) 500_[2] Failed to parse a file's name
  62. * @apiErrorExample {json} Failed to parse a file's name
  63. * HTTP/1.1 500 Internal Server Error
  64. * {
  65. * "message": "Failed to parse file names in the \"bathroom\"'s scene directory.",
  66. * "data": [
  67. * "The file name does not match convention (scene_000150.ext - /^(.*)?_([0-9]{2,})\\.(.*)$/) : \"bathroom_adz00020.png\".",
  68. * "The file name does not match convention (scene_000150.ext - /^(.*)?_([0-9]{2,})\\.(.*)$/) : \"bathroom_adz00020.png\"."
  69. * ]
  70. * }
  71. *
  72. */
  73. /**
  74. * @typedef {Object} Image
  75. * @property {string} link the link (URL) to an image on the app
  76. * @property {string} path the path to the image in the file system
  77. * @property {string} fileName the name of the image
  78. * @property {string} sceneName the scene of the image
  79. * @property {number} quality the quality of the image
  80. * @property {string} ext the extension of the image
  81. */
  82. /**
  83. * Get the link and path to an image
  84. * @param {string} sceneName the scene to get the image from
  85. * @param {number} qualityInt the requested quality
  86. * @returns {Promise<Image>} the link and path to the image
  87. */
  88. export const getImage = async (sceneName, qualityInt) => {
  89. const sceneData = await getSceneFilesData(sceneName)
  90. // Search an image with the requested quality in the scene
  91. for (const [imageName, imageData] of sceneData.entries())
  92. if (qualityInt === imageData.quality)
  93. return {
  94. link: `${imageServedUrl}/${sceneName}/${imageName}`,
  95. path: path.resolve(imagesPath, sceneName, imageName),
  96. fileName: imageName,
  97. sceneName,
  98. quality: imageData.quality,
  99. ext: imageData.ext
  100. }
  101. // Image not found
  102. throw boom.notFound(`The requested quality (${qualityInt}) was not found for the requested scene (${sceneName}).`)
  103. }
  104. router.get('/', asyncMiddleware(async (req, res) => {
  105. // Check the request contains all the required parameters
  106. checkRequiredParameters(['sceneName', 'imageQuality'], req.query)
  107. const { sceneName, imageQuality } = req.query
  108. let errorList = []
  109. // Check the scene name is valid
  110. try {
  111. checkSceneName(sceneName)
  112. }
  113. catch (err) {
  114. errorList.push(err.message)
  115. }
  116. // Check `imageQuality` is an integer
  117. const qualityInt = parseInt(imageQuality, 10)
  118. if (isNaN(qualityInt)) errorList.push('The specified quality is not an integer.')
  119. // Check there is no errors with parameters
  120. if (errorList.length > 0)
  121. throw boom.badRequest('Invalid query parameter(s).', errorList)
  122. const { link } = await getImage(sceneName, qualityInt)
  123. res.json({ data: link })
  124. }))
  125. export default router