DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

170 lines
4.9 KiB

// page.js
// Copyright (C) 2022,2023 DTP Technologies, LLC
// All Rights Reserved
'use strict';
import fs from 'node:fs';
import { SiteController, SiteError } from '../../lib/site-lib.js';
import {
populateImageId,
} from './lib/populators.js';
export default class ImageController extends SiteController {
static get name ( ) { return 'ImageController'; }
static get slug ( ) { return 'image'; }
constructor (dtp) {
super(dtp, ImageController);
}
async start ( ) {
const { dtp } = this;
const { limiter: limiterService } = dtp.services;
const limiterConfig = limiterService.config.image;
const router = this.createRouter('/image');
const imageUpload = this.createMulter(ImageController.slug, {
limits: {
fileSize: 1024 * 1000 * 5,
},
});
router.use(async (req, res, next) => {
res.locals.currentView = 'image';
return next();
});
router.param('imageId', populateImageId(this));
router.post('/',
limiterService.create(limiterConfig.postCreateImage),
imageUpload.single('file'),
this.postCreateImage.bind(this),
);
router.get('/proxy',
limiterService.create(limiterConfig.getProxyImage),
this.getProxyImage.bind(this),
);
router.get('/:imageId',
limiterService.create(limiterConfig.getImage),
this.getHostCacheImage.bind(this),
// this.getImage.bind(this),
);
router.delete('/:imageId',
limiterService.create(limiterConfig.deleteImage),
this.deleteImage.bind(this),
);
}
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 getProxyImage (req, res) {
const { hostCache: hostCacheService } = this.dtp.services;
try {
if (!req.query || !req.query.url) {
throw new SiteError(400, 'Missing url parameter');
}
const fileInfo = await hostCacheService.fetchUrl(req.query.url);
const stream = fs.createReadStream(fileInfo.file.path);
res.setHeader('Cache-Control', 'public, maxage=86400, s-maxage=86400, immutable');
res.setHeader('Content-Type', fileInfo.file.meta.contentType);
res.setHeader('Content-Length', fileInfo.file.stats.size);
res.status(200);
stream.pipe(res);
} catch (error) {
this.log.error('failed to fetch web resource', { url: req.query.url, error });
return res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
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.setHeader('Cache-Control', 'public, maxage=86400, s-maxage=86400, immutable');
res.setHeader('Content-Type', image.type);
res.setHeader('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.setHeader('Cache-Control', 'public, maxage=86400, s-maxage=86400, immutable');
res.setHeader('Content-Type', res.locals.image.type);
res.setHeader('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,
});
}
}
async deleteImage (req, res) {
const { image: imageService } = this.dtp.services;
try {
if (!req.user) {
throw new SiteError(403, 'Must be logged in to delete images you own');
}
if (!req.user._id.equals(res.locals.image.owner._id)) {
throw new SiteError(403, 'You are not the owner of the requested image');
}
this.log.debug('deleting image', { imageId: res.locals.image._id });
await imageService.deleteImage(res.locals.image);
res.status(200).json({ success: true });
} catch (error) {
this.log.error('failed to delete image', { error });
res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
}