mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-23 10:16:32 -05:00
rewrote ImageRouter
- introduced UploadProvider interface - rewrote all current UploadProviders Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
parent
ab5a654068
commit
982bbe9728
14 changed files with 312 additions and 256 deletions
|
@ -1,35 +0,0 @@
|
|||
'use strict'
|
||||
const path = require('path')
|
||||
|
||||
const config = require('../../config')
|
||||
const logger = require('../../logger')
|
||||
|
||||
const azure = require('azure-storage')
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
var azureBlobService = azure.createBlobService(config.azure.connectionString)
|
||||
|
||||
azureBlobService.createContainerIfNotExists(config.azure.container, { publicAccessLevel: 'blob' }, function (err, result, response) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), null)
|
||||
} else {
|
||||
azureBlobService.createBlockBlobFromLocalFile(config.azure.container, path.basename(imagePath), imagePath, function (err, result, response) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), null)
|
||||
} else {
|
||||
callback(null, azureBlobService.getUrl(config.azure.container, result.name))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
38
lib/web/imageRouter/azure.ts
Normal file
38
lib/web/imageRouter/azure.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import azure from 'azure-storage'
|
||||
import path from 'path'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const AzureUploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
const azureBlobService = azure.createBlobService(config.azure.connectionString)
|
||||
|
||||
azureBlobService.createContainerIfNotExists(config.azure.container, { publicAccessLevel: 'blob' }, function (err, _, __) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
} else {
|
||||
azureBlobService.createBlockBlobFromLocalFile(config.azure.container, path.basename(imagePath), imagePath, function (err, result, _) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
} else {
|
||||
callback(undefined, azureBlobService.getUrl(config.azure.container, result.name))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { AzureUploadProvider }
|
|
@ -1,20 +0,0 @@
|
|||
'use strict'
|
||||
const URL = require('url').URL
|
||||
const path = require('path')
|
||||
|
||||
const config = require('../../config')
|
||||
const logger = require('../../logger')
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
callback(null, (new URL(path.basename(imagePath), config.serverURL + '/uploads/')).href)
|
||||
}
|
24
lib/web/imageRouter/filesystem.ts
Normal file
24
lib/web/imageRouter/filesystem.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import path from 'path'
|
||||
import { URL } from 'url'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const FilesystemUploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
callback(null, (new URL(path.basename(imagePath), config.serverURL + '/uploads/')).href)
|
||||
}
|
||||
}
|
||||
|
||||
export { FilesystemUploadProvider }
|
|
@ -1,26 +0,0 @@
|
|||
'use strict'
|
||||
const config = require('../../config')
|
||||
const logger = require('../../logger')
|
||||
|
||||
const imgur = require('imgur')
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
imgur.setClientId(config.imgur.clientID)
|
||||
imgur.uploadFile(imagePath)
|
||||
.then(function (json) {
|
||||
logger.debug(`SERVER uploadimage success: ${JSON.stringify(json)}`)
|
||||
callback(null, json.data.link.replace(/^http:\/\//i, 'https://'))
|
||||
}).catch(function (err) {
|
||||
callback(new Error(err), null)
|
||||
})
|
||||
}
|
30
lib/web/imageRouter/imgur.ts
Normal file
30
lib/web/imageRouter/imgur.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import imgur from 'imgur'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const ImgurUploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
imgur.setClientId(config.imgur.clientID)
|
||||
imgur.uploadFile(imagePath)
|
||||
.then(function (json) {
|
||||
logger.debug(`SERVER uploadimage success: ${JSON.stringify(json)}`)
|
||||
callback(null, json.data.link.replace(/^http:\/\//i, 'https://'))
|
||||
}).catch(function (err) {
|
||||
callback(new Error(err), undefined)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { ImgurUploadProvider }
|
|
@ -1,43 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const Router = require('express').Router
|
||||
const formidable = require('formidable')
|
||||
|
||||
const config = require('../../config')
|
||||
const logger = require('../../logger')
|
||||
const errors = require('../../errors')
|
||||
|
||||
const imageRouter = module.exports = Router()
|
||||
|
||||
// upload image
|
||||
imageRouter.post('/uploadimage', function (req, res) {
|
||||
var form = new formidable.IncomingForm()
|
||||
|
||||
form.keepExtensions = true
|
||||
|
||||
if (config.imageUploadType === 'filesystem') {
|
||||
form.uploadDir = config.uploadsPath
|
||||
}
|
||||
|
||||
form.parse(req, function (err, fields, files) {
|
||||
if (err || !files.image || !files.image.path) {
|
||||
logger.error(`formidable error: ${err}`)
|
||||
errors.errorForbidden(res)
|
||||
} else {
|
||||
logger.debug(`SERVER received uploadimage: ${JSON.stringify(files.image)}`)
|
||||
|
||||
const uploadProvider = require('./' + config.imageUploadType)
|
||||
logger.debug(`imageRouter: Uploading ${files.image.path} using ${config.imageUploadType}`)
|
||||
uploadProvider.uploadImage(files.image.path, function (err, url) {
|
||||
if (err !== null) {
|
||||
logger.error(err)
|
||||
return res.status(500).end('upload image error')
|
||||
}
|
||||
logger.debug(`SERVER sending ${url} to client`)
|
||||
res.send({
|
||||
link: url
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
75
lib/web/imageRouter/index.ts
Normal file
75
lib/web/imageRouter/index.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { Router } from 'express'
|
||||
import formidable from 'formidable'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { logger } from '../../logger'
|
||||
import { errors } from '../../errors'
|
||||
import { AzureUploadProvider } from './azure'
|
||||
import { FilesystemUploadProvider } from './filesystem'
|
||||
import { ImgurUploadProvider } from './imgur'
|
||||
import { LutimUploadProvider } from './lutim'
|
||||
import { MinioUploadProvider } from './minio'
|
||||
import { S3UploadProvider } from './s3'
|
||||
|
||||
interface UploadProvider {
|
||||
uploadImage: (imagePath: string, callback: (err?: Error, url?: string) => void) => void;
|
||||
}
|
||||
|
||||
const ImageRouter = Router()
|
||||
|
||||
// upload image
|
||||
ImageRouter.post('/uploadimage', function (req, res) {
|
||||
const form = new formidable.IncomingForm()
|
||||
|
||||
form.keepExtensions = true
|
||||
|
||||
if (config.imageUploadType === 'filesystem') {
|
||||
form.uploadDir = config.uploadsPath
|
||||
}
|
||||
|
||||
form.parse(req, function (err, fields, files) {
|
||||
if (err || !files.image || !files.image.path) {
|
||||
logger.error(`formidable error: ${err}`)
|
||||
errors.errorForbidden(res)
|
||||
} else {
|
||||
logger.debug(`SERVER received uploadimage: ${JSON.stringify(files.image)}`)
|
||||
|
||||
let uploadProvider: UploadProvider
|
||||
switch (config.imageUploadType) {
|
||||
case 'azure':
|
||||
uploadProvider = AzureUploadProvider
|
||||
break
|
||||
case 'filesystem':
|
||||
default:
|
||||
uploadProvider = FilesystemUploadProvider
|
||||
break
|
||||
case 'imgur':
|
||||
uploadProvider = ImgurUploadProvider
|
||||
break
|
||||
case 'lutim':
|
||||
uploadProvider = LutimUploadProvider
|
||||
break
|
||||
case 'minio':
|
||||
uploadProvider = MinioUploadProvider
|
||||
break
|
||||
case 's3':
|
||||
uploadProvider = S3UploadProvider
|
||||
break
|
||||
}
|
||||
|
||||
logger.debug(`imageRouter: Uploading ${files.image.path} using ${config.imageUploadType}`)
|
||||
uploadProvider.uploadImage(files.image.path, function (err, url) {
|
||||
if (err !== undefined) {
|
||||
logger.error(err)
|
||||
return res.status(500).end('upload image error')
|
||||
}
|
||||
logger.debug(`SERVER sending ${url} to client`)
|
||||
res.send({
|
||||
link: url
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
export { ImageRouter, UploadProvider }
|
|
@ -1,30 +0,0 @@
|
|||
'use strict'
|
||||
const config = require('../../config')
|
||||
const logger = require('../../logger')
|
||||
|
||||
const lutim = require('lutim')
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
if (config.lutim && config.lutim.url) {
|
||||
lutim.setAPIUrl(config.lutim.url)
|
||||
logger.debug(`Set lutim URL to ${lutim.getAPIUrl()}`)
|
||||
}
|
||||
|
||||
lutim.uploadImage(imagePath)
|
||||
.then(function (json) {
|
||||
logger.debug(`SERVER uploadimage success: ${JSON.stringify(json)}`)
|
||||
callback(null, lutim.getAPIUrl() + json.msg.short)
|
||||
}).catch(function (err) {
|
||||
callback(new Error(err), null)
|
||||
})
|
||||
}
|
34
lib/web/imageRouter/lutim.ts
Normal file
34
lib/web/imageRouter/lutim.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import lutim from 'lutim'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const LutimUploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (config.lutim && config.lutim.url) {
|
||||
lutim.setAPIUrl(config.lutim.url)
|
||||
logger.debug(`Set lutim URL to ${lutim.getAPIUrl()}`)
|
||||
}
|
||||
|
||||
lutim.uploadImage(imagePath)
|
||||
.then(function (json) {
|
||||
logger.debug(`SERVER uploadimage success: ${JSON.stringify(json)}`)
|
||||
callback(undefined, lutim.getAPIUrl() + json.msg.short)
|
||||
}).catch(function (err) {
|
||||
callback(new Error(err), undefined)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { LutimUploadProvider }
|
|
@ -1,48 +0,0 @@
|
|||
'use strict'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const config = require('../../config')
|
||||
const { getImageMimeType } = require('../../utils')
|
||||
const logger = require('../../logger')
|
||||
|
||||
const Minio = require('minio')
|
||||
const minioClient = new Minio.Client({
|
||||
endPoint: config.minio.endPoint,
|
||||
port: config.minio.port,
|
||||
secure: config.minio.secure,
|
||||
accessKey: config.minio.accessKey,
|
||||
secretKey: config.minio.secretKey
|
||||
})
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
fs.readFile(imagePath, function (err, buffer) {
|
||||
if (err) {
|
||||
callback(new Error(err), null)
|
||||
return
|
||||
}
|
||||
|
||||
let key = path.join('uploads', path.basename(imagePath))
|
||||
let protocol = config.minio.secure ? 'https' : 'http'
|
||||
|
||||
minioClient.putObject(config.s3bucket, key, buffer, buffer.size, getImageMimeType(imagePath), function (err, data) {
|
||||
if (err) {
|
||||
callback(new Error(err), null)
|
||||
return
|
||||
}
|
||||
let hidePort = [80, 443].includes(config.minio.port)
|
||||
let urlPort = hidePort ? '' : `:${config.minio.port}`
|
||||
callback(null, `${protocol}://${config.minio.endPoint}${urlPort}/${config.s3bucket}/${key}`)
|
||||
})
|
||||
})
|
||||
}
|
52
lib/web/imageRouter/minio.ts
Normal file
52
lib/web/imageRouter/minio.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import Minio from 'minio'
|
||||
|
||||
import { config } from '../../config'
|
||||
import { getImageMimeType } from '../../utils'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const minioClient = new Minio.Client({
|
||||
endPoint: config.minio.endPoint,
|
||||
port: config.minio.port,
|
||||
useSSL: config.minio.secure,
|
||||
accessKey: config.minio.accessKey,
|
||||
secretKey: config.minio.secretKey
|
||||
})
|
||||
|
||||
const MinioUploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
fs.readFile(imagePath, function (err, buffer) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
const key = path.join('uploads', path.basename(imagePath))
|
||||
const protocol = config.minio.secure ? 'https' : 'http'
|
||||
|
||||
minioClient.putObject(config.s3bucket, key, buffer, buffer.length, getImageMimeType(imagePath), function (err, _) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
return
|
||||
}
|
||||
const hidePort = [80, 443].includes(config.minio.port)
|
||||
const urlPort = hidePort ? '' : `:${config.minio.port}`
|
||||
callback(undefined, `${protocol}://${config.minio.endPoint}${urlPort}/${config.s3bucket}/${key}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { MinioUploadProvider }
|
|
@ -1,54 +0,0 @@
|
|||
'use strict'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const config = require('../../config')
|
||||
const { getImageMimeType } = require('../../utils')
|
||||
const logger = require('../../logger')
|
||||
|
||||
const AWS = require('aws-sdk')
|
||||
const awsConfig = new AWS.Config(config.s3)
|
||||
const s3 = new AWS.S3(awsConfig)
|
||||
|
||||
exports.uploadImage = function (imagePath, callback) {
|
||||
if (!imagePath || typeof imagePath !== 'string') {
|
||||
callback(new Error('Image path is missing or wrong'), null)
|
||||
return
|
||||
}
|
||||
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
fs.readFile(imagePath, function (err, buffer) {
|
||||
if (err) {
|
||||
callback(new Error(err), null)
|
||||
return
|
||||
}
|
||||
let params = {
|
||||
Bucket: config.s3bucket,
|
||||
Key: path.join('uploads', path.basename(imagePath)),
|
||||
Body: buffer
|
||||
}
|
||||
|
||||
const mimeType = getImageMimeType(imagePath)
|
||||
if (mimeType) { params.ContentType = mimeType }
|
||||
|
||||
logger.debug(`S3 object parameters: ${JSON.stringify(params)}`)
|
||||
s3.putObject(params, function (err, data) {
|
||||
if (err) {
|
||||
callback(new Error(err), null)
|
||||
return
|
||||
}
|
||||
|
||||
let s3Endpoint = 's3.amazonaws.com'
|
||||
if (config.s3.endpoint) {
|
||||
s3Endpoint = config.s3.endpoint
|
||||
} else if (config.s3.region && config.s3.region !== 'us-east-1') {
|
||||
s3Endpoint = `s3-${config.s3.region}.amazonaws.com`
|
||||
}
|
||||
callback(null, `https://${s3Endpoint}/${config.s3bucket}/${params.Key}`)
|
||||
})
|
||||
})
|
||||
}
|
59
lib/web/imageRouter/s3.ts
Normal file
59
lib/web/imageRouter/s3.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import AWS from 'aws-sdk'
|
||||
|
||||
import { config } from '../../config'
|
||||
// import { getImageMimeType } from '../../utils'
|
||||
import { logger } from '../../logger'
|
||||
import { UploadProvider } from './index'
|
||||
|
||||
const awsConfig = new AWS.Config(config.s3)
|
||||
const s3 = new AWS.S3(awsConfig)
|
||||
|
||||
const S3UploadProvider: UploadProvider = {
|
||||
uploadImage: (imagePath, callback) => {
|
||||
if (!imagePath) {
|
||||
callback(new Error('Image path is missing or wrong'), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (!callback || typeof callback !== 'function') {
|
||||
logger.error('Callback has to be a function')
|
||||
return
|
||||
}
|
||||
|
||||
fs.readFile(imagePath, function (err, buffer) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
Bucket: config.s3bucket,
|
||||
Key: path.join('uploads', path.basename(imagePath)),
|
||||
Body: buffer
|
||||
}
|
||||
|
||||
// ToDo: This does not exist (anymore?)
|
||||
// const mimeType = getImageMimeType(imagePath)
|
||||
// if (mimeType) { params.ContentType = mimeType }
|
||||
|
||||
logger.debug(`S3 object parameters: ${JSON.stringify(params)}`)
|
||||
s3.putObject(params, function (err, _) {
|
||||
if (err) {
|
||||
callback(new Error(err.message), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
let s3Endpoint = 's3.amazonaws.com'
|
||||
if (config.s3.endpoint) {
|
||||
s3Endpoint = config.s3.endpoint
|
||||
} else if (config.s3.region && config.s3.region !== 'us-east-1') {
|
||||
s3Endpoint = `s3-${config.s3.region}.amazonaws.com`
|
||||
}
|
||||
callback(undefined, `https://${s3Endpoint}/${config.s3bucket}/${params.Key}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export { S3UploadProvider }
|
Loading…
Reference in a new issue