sotlas-api/photos_router.js

217 wiersze
6.0 KiB
JavaScript

const express = require('express')
const multer = require('multer')
const config = require('./config')
const photos = require('./photos')
const jwt = require('express-jwt')
const jwksRsa = require('jwks-rsa')
const nodemailer = require('nodemailer')
const db = require('./db')
let upload = multer({dest: config.photos.uploadPath})
let router = express.Router()
module.exports = router
let jwtCallback = jwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: config.sso.jwksUri
})
})
router.post('/summits/:association/:code/upload', jwtCallback, upload.array('photo'), async (req, res) => {
try {
res.cacheControl = {
noCache: true
}
if (!req.user.callsign) {
res.status(401).send('Missing callsign in SSO token').end()
return
}
let summitCode = req.params.association + '/' + req.params.code
let summit = await db.getDb().collection('summits').findOne({code: summitCode})
if (!summit) {
res.status(404).end()
return
}
if (req.files) {
let dbPhotos = []
for (let file of req.files) {
let photo = await photos.importPhoto(file.path, req.user.callsign)
dbPhotos.push(photo)
}
// Check for duplicates
if (summit.photos) {
dbPhotos = dbPhotos.filter(photo => !summit.photos.some(summitPhoto => summitPhoto.filename === photo.filename ))
}
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)
} else {
res.status(400).end()
}
} catch (err) {
console.error(err)
res.status(500).end()
}
})
router.delete('/summits/:association/:code/:filename', jwtCallback, async (req, res) => {
res.cacheControl = {
noCache: true
}
if (!req.user.callsign) {
res.status(401).send('Missing callsign in SSO token').end()
return
}
let summitCode = req.params.association + '/' + req.params.code
let summit = await db.getDb().collection('summits').findOne({code: summitCode})
let photo = summit.photos.find(photo => photo.filename === req.params.filename)
if (!photo) {
res.status(404).end()
return
}
// Check that uploader is currently logged in user
if (photo.author !== req.user.callsign) {
res.status(401).send('Cannot delete another user\'s photos').end()
return
}
await db.getDb().collection('summits').updateOne({code: summitCode}, { $pull: { photos: { filename: req.params.filename } } })
res.status(204).end()
})
router.post('/summits/:association/:code/reorder', jwtCallback, async (req, res) => {
res.cacheControl = {
noCache: true
}
if (!req.user.callsign) {
res.status(401).send('Missing callsign in SSO token').end()
return
}
let summitCode = req.params.association + '/' + req.params.code
// Assign new sortOrder index to photos of this user, in the order given by req.body.filenames
let updates = req.body.filenames.map((filename, index) => {
return db.getDb().collection('summits').updateOne(
{ code: summitCode, 'photos.author': req.user.callsign, 'photos.filename': filename },
{ $set: { 'photos.$.sortOrder': index + 1 } }
)
})
await Promise.all(updates)
res.status(204).end()
})
router.post('/summits/:association/:code/:filename', jwtCallback, async (req, res) => {
res.cacheControl = {
noCache: true
}
if (!req.user.callsign) {
res.status(401).send('Missing callsign in SSO token').end()
return
}
let summitCode = req.params.association + '/' + req.params.code
let summit = await db.getDb().collection('summits').findOne({code: summitCode})
let photo = summit.photos.find(photo => photo.filename === req.params.filename)
if (!photo) {
res.status(404).end()
return
}
// Check that editor is the currently logged in user
if (photo.author !== req.user.callsign) {
res.status(401).send('Cannot delete another user\'s photos').end()
return
}
let update = {
$set: {},
$unset: {}
}
if (req.body.title) {
update.$set['photos.$.title'] = req.body.title
} else {
update.$unset['photos.$.title'] = ''
}
if (req.body.date) {
update.$set['photos.$.date'] = new Date(req.body.date)
} else {
update.$unset['photos.$.date'] = ''
}
if (req.body.coordinates) {
update.$set['photos.$.coordinates'] = req.body.coordinates
update.$set['photos.$.positioningError'] = req.body.positioningError
} else {
update.$unset['photos.$.coordinates'] = ''
update.$unset['photos.$.positioningError'] = ''
}
if (req.body.direction !== null && req.body.direction !== undefined && req.body.direction !== '') {
update.$set['photos.$.direction'] = req.body.direction
} else {
update.$unset['photos.$.direction'] = ''
}
if (req.body.isCover) {
update.$set['photos.$.isCover'] = true
// Only one photo can be the cover photo, so unmark all others first
await db.getDb().collection('summits').updateOne(
{ code: summitCode },
{ $unset: { 'photos.$[].isCover': '' } }
)
} else {
update.$unset['photos.$.isCover'] = ''
}
if (Object.keys(update.$set).length === 0) {
delete update.$set
}
if (Object.keys(update.$unset).length === 0) {
delete update.$unset
}
await db.getDb().collection('summits').updateOne(
{ code: summitCode, 'photos.filename': req.params.filename },
update
)
res.status(204).end()
})