diff --git a/config.js b/config.js index c1e98ea..418e357 100644 --- a/config.js +++ b/config.js @@ -40,10 +40,6 @@ config.summitListUrl = 'https://www.sotadata.org.uk/summitslist.csv'; config.sotatrailsUrl = 'https://sotatrails.ch/api.php'; config.photos = { - paths: { - thumb: '/data/images/photos/thumb', - large: '/data/images/photos/large' - }, sizes: { large: { width: 1600, @@ -58,7 +54,14 @@ config.photos = { originalStorage: { endPoint: 's3.eu-central-003.backblazeb2.com', accessKey: process.env.B2_ACCESS_KEY, - secretKey: process.env.B2_SECRET_KEY + secretKey: process.env.B2_SECRET_KEY, + bucketName: 'sotlas-photos' + }, + storage: { + endPoint: 'fra1.digitaloceanspaces.com', + accessKey: process.env.SPACES_ACCESS_KEY, + secretKey: process.env.SPACES_SECRET_KEY, + bucketName: 'sotlas-photos' } }; diff --git a/photos.js b/photos.js index f1f3d9a..82da02e 100644 --- a/photos.js +++ b/photos.js @@ -22,20 +22,10 @@ module.exports = { } // Upload original photo to Backblaze (don't wait for completion) - let minioClient = new minio.Client(config.photos.originalStorage) - minioClient.fPutObject('sotlas-photos', 'original/' + hashFilename, filename, {'Content-Type': 'image/jpeg'}, (err, etag) => { - if (err) { - console.error(err) - - let transporter = nodemailer.createTransport(config.mail) - transporter.sendMail({ - from: 'api@sotl.as', - to: 'mk@neon1.net', - subject: 'Backblaze upload failed', - text: `The file ${filename} could not be uploaded:\n${err}` - }) - } - }) + fsPromises.readFile(filename) + .then(buffer => { + uploadToCloud(config.photos.originalStorage, 'original/' + hashFilename, buffer) + }) let photo = { filename: hashFilename, @@ -93,16 +83,17 @@ module.exports = { } } - let mkdirTasks = [] - let resizeTasks = [] + let tasks = [] Object.keys(config.photos.sizes).forEach(sizeDescr => { - let outPath = config.photos.paths[sizeDescr] + '/' + hashFilename.substr(0, 2) + '/' + hashFilename - mkdirTasks.push(fsPromises.mkdir(path.dirname(outPath), {recursive: true})) - resizeTasks.push(makeResized(filename, outPath, config.photos.sizes[sizeDescr].width, config.photos.sizes[sizeDescr].height)) + tasks.push( + makeResized(filename, config.photos.sizes[sizeDescr].width, config.photos.sizes[sizeDescr].height) + .then(buffer => { + return uploadToCloud(config.photos.storage, sizeDescr + '/' + hashFilename, buffer) + }) + ) }) - await Promise.all(mkdirTasks) - await Promise.all(resizeTasks) + await Promise.all(tasks) db.getDb().collection('uploads').insertOne({ uploadDate: new Date(), @@ -115,10 +106,30 @@ module.exports = { } } +function uploadToCloud(storageConfig, targetPath, buffer) { + let minioClient = new minio.Client(storageConfig) + let metadata = { + 'Content-Type': 'image/jpeg', + 'x-amz-acl': 'public-read' + } + return minioClient.putObject(storageConfig.bucketName, targetPath, buffer, metadata) + .catch(err => { + console.error(err) + + let transporter = nodemailer.createTransport(config.mail) + transporter.sendMail({ + from: 'api@sotl.as', + to: 'mk@neon1.net', + subject: 'Cloud photo upload failed', + text: `The file ${filename} could not be uploaded to ${storageConfig.endpoint} at path ${targetPath}:\n${err}` + }) + }) +} + function getMetadata(src) { return sharp(src).metadata() } -function makeResized(src, dst, maxWidth, maxHeight) { - return sharp(src).rotate().resize({ height: maxHeight, width: maxWidth, fit: 'inside' }).toFile(dst) +function makeResized(src, maxWidth, maxHeight) { + return sharp(src).rotate().resize({ height: maxHeight, width: maxWidth, fit: 'inside' }).toBuffer() } diff --git a/photos_router.js b/photos_router.js index 347909b..f75098d 100644 --- a/photos_router.js +++ b/photos_router.js @@ -53,20 +53,6 @@ router.post('/summits/:association/:code/upload', jwtCallback, upload.array('pho if (dbPhotos.length > 0) { await db.getDb().collection('summits').updateOne({code: summitCode}, { $push: { photos: { $each: dbPhotos } } }) - - let transporter = nodemailer.createTransport(config.mail) - transporter.sendMail({ - from: 'api@sotl.as', - to: 'mk@neon1.net', - subject: 'New photos added to summit ' + summitCode + ' by ' + req.user.callsign, - text: `${dbPhotos.length} new photos have been added. https://sotl.as/summits/${summitCode}\n`, - attachments: dbPhotos.map(photo => { - return { - filename: photo.filename, - path: config.photos.paths.thumb + '/' + photo.filename.substr(0, 2) + '/' + photo.filename - } - }) - }) } res.json(dbPhotos)