// page.js // Copyright (C) 2022 DTP Technologies, LLC // License: Apache-2.0 'use strict'; const fs = require('fs'); const express = require('express'); const mongoose = require('mongoose'); const multer = require('multer'); const { SiteController/*, SiteError*/ } = require('../../lib/site-lib'); class ImageController extends SiteController { constructor (dtp) { super(dtp, module.exports); } async start ( ) { const { dtp } = this; const { limiter: limiterService } = dtp.services; const router = express.Router(); dtp.app.use('/image', router); const imageUpload = multer({ dest: `/tmp/${this.dtp.config.site.domainKey}/uploads/${this.component.slug}`, limits: { fileSize: 1024 * 1000 * 12, }, }); router.use(async (req, res, next) => { res.locals.currentView = 'image'; return next(); }); router.param('imageId', this.populateImage.bind(this)); router.post('/tinymce', imageUpload.single('file'), this.postTinyMceImage.bind(this), ); router.post('/', limiterService.createMiddleware(limiterService.config.image.postCreateImage), imageUpload.single('file'), this.postCreateImage.bind(this), ); router.get('/:imageId', limiterService.createMiddleware(limiterService.config.image.getImage), this.getHostCacheImage.bind(this), // this.getImage.bind(this), ); } async populateImage (req, res, next, imageId) { try { res.locals.imageId = mongoose.Types.ObjectId(imageId); res.locals.image = await this.dtp.services.image.getImageById(res.locals.imageId); return next(); } catch (error) { this.log.error('failed to populate image', { error }); return next(error); } } async postTinyMceImage (req, res, next) { const { image: imageService } = this.dtp.services; try { res.locals.image = await imageService.create(req.user, req.body, req.file); res.status(200).json({ location: `/image/${res.locals.image._id}` }); } catch (error) { this.log.error('failed to create image', { error }); return next(error); } } async postCreateImage (req, res, next) { const { image: imageService } = this.dtp.services; try { res.locals.image = await imageService.create(req.user, req.body, req.file); res.status(200).json({ success: true, imageId: res.locals.image._id.toString(), }); } catch (error) { this.log.error('failed to create image', { error }); return next(error); } } async getHostCacheImage (req, res) { const { hostCache: hostCacheService } = this.dtp.services; const { image } = res.locals; try { const fileInfo = await hostCacheService.getFile(image.file.bucket, image.file.key); const stream = fs.createReadStream(fileInfo.file.path); res.header('Content-Type', image.type); res.header('Content-Length', fileInfo.file.stats.size); res.status(200); stream.pipe(res); } catch (error) { this.log.error('failed to fetch image', { image, error }); return res.status(error.statusCode || 500).json({ success: false, message: error.message, }); } } async getImage (req, res) { const { minio: minioService } = this.dtp.services; try { const stream = await minioService.openDownloadStream({ bucket: res.locals.image.file.bucket, key: res.locals.image.file.key }); res.header('Content-Type', res.locals.image.type); res.header('Content-Length', res.locals.image.size); res.status(200); stream.pipe(res); } catch (error) { return res.status(error.statusCode || 500).json({ success: false, message: error.message, }); } } } module.exports = { slug: 'image', name: 'image', create: async (dtp) => { return new ImageController(dtp); }, };