kopia lustrzana https://github.com/manuelkasper/sotlas-api
Porównaj commity
2 Commity
641b472cf9
...
8d7bbb4986
Autor | SHA1 | Data |
---|---|---|
Manuel Kasper | 8d7bbb4986 | |
Manuel Kasper | 1e757e4667 |
13
config.js
13
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'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
57
photos.js
57
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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -247,13 +247,14 @@ app.get('/activators/search', (req, res) => {
|
|||
if (req.query.q !== undefined && req.query.q !== '') {
|
||||
query = {callsign: {'$regex': req.query.q, '$options': 'i'}};
|
||||
}
|
||||
let cursor = db.getDb().collection('activators').find(query, {projection: {'_id': false}}).sort(sort);
|
||||
cursor.count((err, count) => {
|
||||
|
||||
db.getDb().collection('activators').countDocuments(query, (err, count) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.status(500).end();
|
||||
return;
|
||||
}
|
||||
let cursor = db.getDb().collection('activators').find(query, {projection: {'_id': false}}).sort(sort);
|
||||
|
||||
cursor.skip(skip).limit(limit).toArray((err, activators) => {
|
||||
res.json({activators, total: count});
|
||||
|
|
Ładowanie…
Reference in New Issue