media: Add route that can resize existing uploaded image
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
This commit is contained in:
parent
f1871fe41f
commit
f4afd8bfae
6 changed files with 468 additions and 9 deletions
|
@ -107,9 +107,7 @@ export default class MediaRoutes {
|
||||||
return this.upload(ctx, true)
|
return this.upload(ctx, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async resize(ctx) {
|
async resizeFile(ctx, sourceFile) {
|
||||||
await this.upload(ctx)
|
|
||||||
|
|
||||||
this.security.verifyBody(ctx)
|
this.security.verifyBody(ctx)
|
||||||
|
|
||||||
let keys = Object.keys(ctx.req.body)
|
let keys = Object.keys(ctx.req.body)
|
||||||
|
@ -126,7 +124,7 @@ export default class MediaRoutes {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
let item = ctx.req.body[key]
|
let item = ctx.req.body[key]
|
||||||
let sharp = this.sharp(`./public/${ctx.state.site}/${ctx.body.filename}`)
|
let sharp = this.sharp(`./public/${ctx.state.site}/${sourceFile}`)
|
||||||
.rotate()
|
.rotate()
|
||||||
|
|
||||||
for (let operation of allowedOperations) {
|
for (let operation of allowedOperations) {
|
||||||
|
@ -136,7 +134,7 @@ export default class MediaRoutes {
|
||||||
}
|
}
|
||||||
sharp = sharp[item.format](item[item.format])
|
sharp = sharp[item.format](item[item.format])
|
||||||
|
|
||||||
let target = ctx.body.filename
|
let target = sourceFile
|
||||||
if (path.extname(target).length > 0) {
|
if (path.extname(target).length > 0) {
|
||||||
target = target.slice(0, -path.extname(target).length)
|
target = target.slice(0, -path.extname(target).length)
|
||||||
}
|
}
|
||||||
|
@ -167,6 +165,20 @@ export default class MediaRoutes {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async resizeExisting(ctx) {
|
||||||
|
let site = await this.security.verifyToken(ctx)
|
||||||
|
ctx.state.site = site
|
||||||
|
|
||||||
|
ctx.body = {}
|
||||||
|
await this.resizeFile(ctx, ctx.params.filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
async resize(ctx) {
|
||||||
|
await this.upload(ctx)
|
||||||
|
|
||||||
|
await this.resizeFile(ctx, ctx.body.filename)
|
||||||
|
}
|
||||||
|
|
||||||
async remove(ctx) {
|
async remove(ctx) {
|
||||||
let site = await this.security.verifyToken(ctx)
|
let site = await this.security.verifyToken(ctx)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { performance } from 'perf_hooks'
|
import { performance } from 'perf_hooks'
|
||||||
import { Flaska, QueryHandler } from 'flaska'
|
import { Flaska, QueryHandler, JsonHandler } from 'flaska'
|
||||||
|
|
||||||
import TestRoutes from './test/routes.mjs'
|
import TestRoutes from './test/routes.mjs'
|
||||||
import MediaRoutes from './media/routes.mjs'
|
import MediaRoutes from './media/routes.mjs'
|
||||||
|
@ -57,6 +57,7 @@ app.get('/media/:site', media.listPublicFiles.bind(media))
|
||||||
app.post('/media', [QueryHandler()], media.upload.bind(media))
|
app.post('/media', [QueryHandler()], media.upload.bind(media))
|
||||||
app.post('/media/noprefix', [QueryHandler()], media.uploadNoPrefix.bind(media))
|
app.post('/media/noprefix', [QueryHandler()], media.uploadNoPrefix.bind(media))
|
||||||
app.post('/media/resize', [QueryHandler()], media.resize.bind(media))
|
app.post('/media/resize', [QueryHandler()], media.resize.bind(media))
|
||||||
|
app.post('/media/resize/:filename', [QueryHandler(), JsonHandler()], media.resizeExisting.bind(media))
|
||||||
app.delete('/media/:filename', [QueryHandler()], media.remove.bind(media))
|
app.delete('/media/:filename', [QueryHandler()], media.remove.bind(media))
|
||||||
|
|
||||||
app.listen(config.get('server:port'), function(a,b) {
|
app.listen(config.get('server:port'), function(a,b) {
|
||||||
|
|
17
package.json
17
package.json
|
@ -1,13 +1,24 @@
|
||||||
{
|
{
|
||||||
"name": "storage-upload",
|
"name": "storage-upload",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node api/server.mjs",
|
"start": "node api/server.mjs",
|
||||||
"start:bunyan": "node api/server.mjs | bunyan",
|
"start:bunyan": "node api/server.mjs | bunyan",
|
||||||
"test": "set NODE_ENV=test&& eltro test/**/*.test.mjs -r dot",
|
"test": "set NODE_ENV=test&& eltro test/**/*.test.mjs -r dot",
|
||||||
"test:linux": "NODE_ENV=test eltro 'test/**/*.test.mjs' -r dot"
|
"test:linux": "NODE_ENV=test eltro 'test/**/*.test.mjs' -r dot",
|
||||||
|
"test:watch": "npm-watch test"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"test": {
|
||||||
|
"patterns": [
|
||||||
|
"{api,test}/*"
|
||||||
|
],
|
||||||
|
"extensions": "js,mjs",
|
||||||
|
"quiet": true,
|
||||||
|
"inherit": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -21,7 +32,7 @@
|
||||||
"homepage": "https://github.com/nfp-projects/storage-upload#readme",
|
"homepage": "https://github.com/nfp-projects/storage-upload#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bunyan-lite": "^1.1.1",
|
"bunyan-lite": "^1.1.1",
|
||||||
"flaska": "^0.9.8",
|
"flaska": "^1.2.3",
|
||||||
"formidable": "^1.2.2",
|
"formidable": "^1.2.2",
|
||||||
"nconf-lite": "^2.0.0",
|
"nconf-lite": "^2.0.0",
|
||||||
"sharp-lite": "^1.29.6"
|
"sharp-lite": "^1.29.6"
|
||||||
|
|
|
@ -67,6 +67,16 @@ Client.prototype.get = function(url = '/') {
|
||||||
return this.customRequest('GET', url, null)
|
return this.customRequest('GET', url, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client.prototype.post = function(url = '/', body = {}) {
|
||||||
|
let parsed = JSON.stringify(body)
|
||||||
|
return this.customRequest('POST', url, parsed, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': parsed.length,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Client.prototype.del = function(url = '/', body = {}) {
|
Client.prototype.del = function(url = '/', body = {}) {
|
||||||
return this.customRequest('DELETE', url, JSON.stringify(body))
|
return this.customRequest('DELETE', url, JSON.stringify(body))
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,170 @@ t.describe('Media (API)', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.timeout(10000).describe('POST /media/resize/:filename', function temp() {
|
||||||
|
let sourceFilename
|
||||||
|
let sourcePath
|
||||||
|
|
||||||
|
t.before(async function() {
|
||||||
|
let token = encode(null, { iss: 'development' }, secret)
|
||||||
|
|
||||||
|
let data = await assert.isFulfilled(
|
||||||
|
client.upload(
|
||||||
|
`/media/resize?token=${token}`,
|
||||||
|
resolve('test.png'),
|
||||||
|
'POST',
|
||||||
|
{ }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
testFiles.push(data.path)
|
||||||
|
|
||||||
|
assert.ok(data)
|
||||||
|
assert.ok(data.filename)
|
||||||
|
assert.ok(data.filename.startsWith(currYear))
|
||||||
|
assert.ok(data.path)
|
||||||
|
|
||||||
|
sourceFilename = data.filename
|
||||||
|
sourcePath = data.path
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should require authentication', async () => {
|
||||||
|
resetLog()
|
||||||
|
assert.strictEqual(server.log.error.callCount, 0)
|
||||||
|
assert.strictEqual(server.log.warn.callCount, 0)
|
||||||
|
let err = await assert.isRejected(
|
||||||
|
client.post(`/media/resize/${sourceFilename}`, {})
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.strictEqual(err.status, 422)
|
||||||
|
assert.match(err.message, /[Tt]oken/)
|
||||||
|
assert.match(err.message, /[Mm]issing/)
|
||||||
|
|
||||||
|
assert.strictEqual(server.log.error.callCount, 0)
|
||||||
|
assert.strictEqual(server.log.warn.callCount, 2)
|
||||||
|
assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string')
|
||||||
|
assert.match(server.log.warn.firstCall[0], /[Tt]oken/)
|
||||||
|
assert.match(server.log.warn.firstCall[0], /[Mm]issing/)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should verify token correctly', async () => {
|
||||||
|
const assertToken = 'asdf.asdf.asdf'
|
||||||
|
resetLog()
|
||||||
|
assert.strictEqual(server.log.error.callCount, 0)
|
||||||
|
assert.strictEqual(server.log.warn.callCount, 0)
|
||||||
|
assert.strictEqual(server.log.info.callCount, 0)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(
|
||||||
|
client.post(`/media/resize/${sourceFilename}?token=${assertToken}`, {})
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.strictEqual(err.status, 422)
|
||||||
|
assert.match(err.message, /[Tt]oken/)
|
||||||
|
assert.match(err.message, /[Ii]nvalid/)
|
||||||
|
|
||||||
|
assert.strictEqual(server.log.error.callCount, 1)
|
||||||
|
assert.strictEqual(server.log.warn.callCount, 2)
|
||||||
|
assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string')
|
||||||
|
assert.match(server.log.warn.firstCall[0], /[Tt]oken/)
|
||||||
|
assert.match(server.log.warn.firstCall[0], /[Ii]nvalid/)
|
||||||
|
assert.ok(server.log.error.lastCall[0] instanceof Error)
|
||||||
|
assert.match(server.log.error.lastCall[1], new RegExp(assertToken))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should create multiple sizes for existing file', async () => {
|
||||||
|
let token = encode(null, { iss: 'development' }, secret)
|
||||||
|
|
||||||
|
let data = await assert.isFulfilled(
|
||||||
|
client.post(
|
||||||
|
`/media/resize/${sourceFilename}?token=${token}`,
|
||||||
|
{
|
||||||
|
test1: {
|
||||||
|
format: 'jpeg',
|
||||||
|
resize: {
|
||||||
|
width: 300,
|
||||||
|
},
|
||||||
|
blur: 0.5,
|
||||||
|
flatten: {r:0,g:0,b:0},
|
||||||
|
trim: 1,
|
||||||
|
extend: { top: 10, left: 10, bottom: 10, right: 10, background: {r:0,g:0,b:0} },
|
||||||
|
jpeg: {
|
||||||
|
quality: 80,
|
||||||
|
mozjpeg: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
test2: {
|
||||||
|
format: 'png',
|
||||||
|
resize: {
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
png: {
|
||||||
|
compressionLevel: 9,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
testFiles.push(data.test1.path)
|
||||||
|
testFiles.push(data.test2.path)
|
||||||
|
|
||||||
|
assert.ok(data.test1.filename)
|
||||||
|
assert.ok(data.test1.filename.startsWith(currYear))
|
||||||
|
assert.ok(data.test1.path)
|
||||||
|
assert.ok(data.test2.filename)
|
||||||
|
assert.ok(data.test2.filename.startsWith(currYear))
|
||||||
|
assert.ok(data.test2.path)
|
||||||
|
|
||||||
|
let img = await sharp(resolve(`../../public/${sourcePath}`)).metadata()
|
||||||
|
assert.strictEqual(img.width, 600)
|
||||||
|
assert.strictEqual(img.height, 700)
|
||||||
|
assert.strictEqual(img.format, 'png')
|
||||||
|
|
||||||
|
img = await sharp(resolve(`../../public/${data.test1.path}`)).metadata()
|
||||||
|
assert.strictEqual(img.width, 320)
|
||||||
|
assert.strictEqual(img.height, 413)
|
||||||
|
assert.strictEqual(img.format, 'jpeg')
|
||||||
|
|
||||||
|
img = await sharp(resolve(`../../public/${data.test2.path}`)).metadata()
|
||||||
|
assert.strictEqual(img.width, 150)
|
||||||
|
assert.strictEqual(img.height, 175)
|
||||||
|
assert.strictEqual(img.format, 'png')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should base64 output of existing file', async () => {
|
||||||
|
let token = encode(null, { iss: 'development' }, secret)
|
||||||
|
|
||||||
|
let data = await assert.isFulfilled(
|
||||||
|
client.post(
|
||||||
|
`/media/resize/${sourceFilename}?token=${token}`,
|
||||||
|
{
|
||||||
|
outtest: {
|
||||||
|
out: 'base64',
|
||||||
|
format: 'jpeg',
|
||||||
|
resize: {
|
||||||
|
width: 10,
|
||||||
|
},
|
||||||
|
jpeg: {
|
||||||
|
quality: 80,
|
||||||
|
mozjpeg: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.ok(data)
|
||||||
|
assert.ok(data.outtest.base64)
|
||||||
|
|
||||||
|
let bufferBase64 = Buffer.from(data.outtest.base64.slice(data.outtest.base64.indexOf(',')), 'base64')
|
||||||
|
|
||||||
|
let img = await sharp(bufferBase64).metadata()
|
||||||
|
assert.strictEqual(img.width, 10)
|
||||||
|
assert.strictEqual(img.height, 12)
|
||||||
|
assert.strictEqual(img.format, 'jpeg')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.timeout(10000).describe('DELETE /media/:filename', function temp() {
|
t.timeout(10000).describe('DELETE /media/:filename', function temp() {
|
||||||
t.test('should require authentication', async () => {
|
t.test('should require authentication', async () => {
|
||||||
resetLog()
|
resetLog()
|
||||||
|
|
|
@ -279,6 +279,267 @@ t.describe('#uploadNoPrefix', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.describe('#resizeExisting', function() {
|
||||||
|
const stubVerifyToken = stub()
|
||||||
|
const stubVerifyBody = stub()
|
||||||
|
const stubSharp = stub()
|
||||||
|
const stubSharpResize = stub()
|
||||||
|
const stubSharpBlur = stub()
|
||||||
|
const stubSharpTrim = stub()
|
||||||
|
const stubSharpExtend = stub()
|
||||||
|
const stubSharpFlatten = stub()
|
||||||
|
const stubSharpRotate = stub()
|
||||||
|
const stubSharpToFile = stub()
|
||||||
|
const stubSharpJpeg = stub()
|
||||||
|
const stubSharpPng = stub()
|
||||||
|
const stubSharpToBuffer = stub()
|
||||||
|
const stubStat = stub()
|
||||||
|
|
||||||
|
const routes = new MediaRoutes({
|
||||||
|
security: {
|
||||||
|
verifyToken: stubVerifyToken,
|
||||||
|
verifyBody: stubVerifyBody,
|
||||||
|
},
|
||||||
|
fs: { stat: stubStat },
|
||||||
|
sharp: stubSharp,
|
||||||
|
})
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
stubVerifyToken.reset()
|
||||||
|
stubVerifyBody.reset()
|
||||||
|
let def = {
|
||||||
|
toFile: stubSharpToFile,
|
||||||
|
jpeg: stubSharpJpeg,
|
||||||
|
png: stubSharpPng,
|
||||||
|
resize: stubSharpResize,
|
||||||
|
trim: stubSharpTrim,
|
||||||
|
extend: stubSharpExtend,
|
||||||
|
flatten: stubSharpFlatten,
|
||||||
|
blur: stubSharpBlur,
|
||||||
|
rotate: stubSharpRotate,
|
||||||
|
toBuffer: stubSharpToBuffer,
|
||||||
|
}
|
||||||
|
stubStat.reset()
|
||||||
|
stubStat.resolves({ size: 0 })
|
||||||
|
stubSharp.reset()
|
||||||
|
stubSharp.returns(def)
|
||||||
|
for (let key in def) {
|
||||||
|
def[key].reset()
|
||||||
|
def[key].returns(def)
|
||||||
|
}
|
||||||
|
stubSharpToFile.resolves()
|
||||||
|
stubSharpToBuffer.resolves()
|
||||||
|
routes.siteCache.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.test('should call security verifyToken correctly', async function() {
|
||||||
|
reset()
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: { } } })
|
||||||
|
const assertError = new Error('temp')
|
||||||
|
stubVerifyToken.rejects(assertError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(routes.resizeExisting(ctx))
|
||||||
|
|
||||||
|
assert.ok(stubVerifyToken.called)
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.strictEqual(stubVerifyToken.firstCall[0], ctx)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call security verifyBody correctly', async function() {
|
||||||
|
reset()
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: { }}})
|
||||||
|
const assertError = new Error('temp')
|
||||||
|
stubVerifyBody.throws(assertError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(routes.resizeExisting(ctx))
|
||||||
|
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.ok(stubVerifyBody.called)
|
||||||
|
assert.strictEqual(stubVerifyBody.firstCall[0], ctx)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call sharp correctly if items are specified', async function() {
|
||||||
|
reset()
|
||||||
|
const assertKey = 'asdf'
|
||||||
|
const assertJpeg = { a: 1 }
|
||||||
|
const assertFilename = 'asdfsafd'
|
||||||
|
const assertSite = 'mario'
|
||||||
|
stubVerifyToken.resolves(assertSite)
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: {
|
||||||
|
[assertKey]: {
|
||||||
|
format: 'jpeg',
|
||||||
|
}
|
||||||
|
}}})
|
||||||
|
ctx.params.filename = assertFilename + '.png'
|
||||||
|
ctx.req.body[assertKey].jpeg = assertJpeg
|
||||||
|
|
||||||
|
await routes.resizeExisting(ctx)
|
||||||
|
|
||||||
|
assert.ok(stubSharp.called)
|
||||||
|
assert.match(stubSharp.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}\.png`))
|
||||||
|
assert.ok(stubSharpRotate.called)
|
||||||
|
assert.ok(stubSharpJpeg.called)
|
||||||
|
assert.strictEqual(stubSharpJpeg.firstCall[0], assertJpeg)
|
||||||
|
assert.ok(stubSharpToFile.called)
|
||||||
|
assert.match(stubSharpToFile.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}_${assertKey}\.jpg`))
|
||||||
|
assert.notOk(stubSharpPng.called)
|
||||||
|
assert.notOk(stubSharpResize.called)
|
||||||
|
assert.notOk(ctx.body.filename)
|
||||||
|
assert.notOk(ctx.body.path)
|
||||||
|
assert.strictEqual(ctx.body[assertKey].filename, `${assertFilename}_${assertKey}\.jpg`)
|
||||||
|
assert.strictEqual(ctx.body[assertKey].path, `/${assertSite}/${assertFilename}_${assertKey}.jpg`)
|
||||||
|
})
|
||||||
|
|
||||||
|
let validOperations = [
|
||||||
|
'resize',
|
||||||
|
'blur',
|
||||||
|
'trim',
|
||||||
|
'extend',
|
||||||
|
'flatten',
|
||||||
|
]
|
||||||
|
|
||||||
|
let operationStubMap = {
|
||||||
|
resize: stubSharpResize,
|
||||||
|
blur: stubSharpBlur,
|
||||||
|
trim: stubSharpTrim,
|
||||||
|
extend: stubSharpExtend,
|
||||||
|
flatten: stubSharpFlatten,
|
||||||
|
}
|
||||||
|
|
||||||
|
validOperations.forEach(function(operation) {
|
||||||
|
t.test(`should call sharp correctly if items and ${operation} are specified`, async function() {
|
||||||
|
reset()
|
||||||
|
const assertKey = 'herpderp'
|
||||||
|
const assertPng = { a: 1 }
|
||||||
|
const assertPayload = { a: 1 }
|
||||||
|
const assertFilename = 'asdfsafd'
|
||||||
|
const assertSite = 'mario'
|
||||||
|
stubVerifyToken.resolves(assertSite)
|
||||||
|
|
||||||
|
let called = 0
|
||||||
|
stubStat.returnWith(function() {
|
||||||
|
called += 10
|
||||||
|
return { size: called }
|
||||||
|
})
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: {
|
||||||
|
[assertKey]: {
|
||||||
|
format: 'png',
|
||||||
|
}
|
||||||
|
}}})
|
||||||
|
ctx.params.filename = assertFilename + '.png'
|
||||||
|
ctx.req.body[assertKey].png = assertPng
|
||||||
|
ctx.req.body[assertKey][operation] = assertPayload
|
||||||
|
|
||||||
|
await routes.resizeExisting(ctx)
|
||||||
|
|
||||||
|
assert.ok(stubSharp.called)
|
||||||
|
assert.match(stubSharp.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}\.png`))
|
||||||
|
assert.ok(stubSharpRotate.called)
|
||||||
|
assert.ok(stubSharpPng.called)
|
||||||
|
assert.strictEqual(stubSharpPng.firstCall[0], assertPng)
|
||||||
|
assert.ok(stubSharpToFile.called)
|
||||||
|
assert.match(stubSharpToFile.firstCall[0], new RegExp(`\/${assertSite}\/${assertFilename}_${assertKey}\.png`))
|
||||||
|
assert.notOk(stubSharpJpeg.called)
|
||||||
|
|
||||||
|
assert.ok(operationStubMap[operation].called)
|
||||||
|
assert.strictEqual(operationStubMap[operation].firstCall[0], assertPayload)
|
||||||
|
|
||||||
|
assert.notOk(ctx.body.filename)
|
||||||
|
assert.notOk(ctx.body.path)
|
||||||
|
assert.strictEqual(ctx.body[assertKey].filename, `${assertFilename}_${assertKey}\.png`)
|
||||||
|
assert.strictEqual(ctx.body[assertKey].path, `/${assertSite}/${assertFilename}_${assertKey}.png`)
|
||||||
|
|
||||||
|
let filesFromCache = routes.filesCacheGet(assertSite)
|
||||||
|
assert.strictEqual(filesFromCache.length, 1)
|
||||||
|
assert.strictEqual(filesFromCache[0].filename, `${assertFilename}_${assertKey}\.png`)
|
||||||
|
assert.strictEqual(filesFromCache[0].size, 10)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should notify which item failed if one fails', async function() {
|
||||||
|
reset()
|
||||||
|
const assertValidKey1 = 'herp'
|
||||||
|
const assertValidKey2 = 'derp'
|
||||||
|
const assertErrorKey = 'throwmyerr'
|
||||||
|
const assertErrorMessage = 'some message here'
|
||||||
|
stubVerifyToken.resolves('asdf')
|
||||||
|
|
||||||
|
let called = 0
|
||||||
|
stubStat.returnWith(function() {
|
||||||
|
called += 10
|
||||||
|
return { size: called }
|
||||||
|
})
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: {
|
||||||
|
[assertValidKey1]: {
|
||||||
|
format: 'png',
|
||||||
|
png: { a: 1 },
|
||||||
|
},
|
||||||
|
[assertValidKey2]: {
|
||||||
|
format: 'png',
|
||||||
|
png: { a: 1 },
|
||||||
|
},
|
||||||
|
[assertErrorKey]: {
|
||||||
|
format: 'png',
|
||||||
|
png: { a: 1 },
|
||||||
|
},
|
||||||
|
}}})
|
||||||
|
ctx.params.filename = 'file.png'
|
||||||
|
|
||||||
|
stubSharpToFile.returnWith(function(file) {
|
||||||
|
if (file.match(new RegExp(assertErrorKey))) {
|
||||||
|
throw new Error(assertErrorMessage)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let err = await assert.isRejected(routes.resizeExisting(ctx))
|
||||||
|
|
||||||
|
assert.ok(err instanceof HttpError)
|
||||||
|
assert.ok(err instanceof Error)
|
||||||
|
assert.strictEqual(err.status, 422)
|
||||||
|
assert.match(err.message, new RegExp(assertErrorKey))
|
||||||
|
assert.match(err.message, new RegExp(assertErrorMessage))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call sharp correctly and return base64 format if out is base64', async function() {
|
||||||
|
reset()
|
||||||
|
const assertKey = 'outtest'
|
||||||
|
const assertFilename = 'asdfsafd.png'
|
||||||
|
const assertSite = 'mario'
|
||||||
|
const assertBase64Data = 'asdf1234'
|
||||||
|
stubVerifyToken.resolves(assertSite)
|
||||||
|
|
||||||
|
let ctx = createContext({ req: { body: {
|
||||||
|
[assertKey]: {
|
||||||
|
format: 'png',
|
||||||
|
png: { a: 1 },
|
||||||
|
out: 'base64',
|
||||||
|
}
|
||||||
|
}}})
|
||||||
|
ctx.params.filename = assertFilename
|
||||||
|
|
||||||
|
stubSharpToBuffer.resolves(Buffer.from(assertBase64Data))
|
||||||
|
|
||||||
|
await routes.resizeExisting(ctx)
|
||||||
|
|
||||||
|
assert.ok(stubSharp.called)
|
||||||
|
assert.notOk(stubSharpToFile.called)
|
||||||
|
assert.ok(stubSharpToBuffer.called)
|
||||||
|
assert.ok(ctx.body[assertKey].base64)
|
||||||
|
assert.ok(ctx.body[assertKey].base64.startsWith(`data:image/png;base64,`))
|
||||||
|
let base64 = ctx.body[assertKey].base64
|
||||||
|
let bufferBase64 = Buffer.from(base64.slice(base64.indexOf(',')), 'base64')
|
||||||
|
assert.strictEqual(bufferBase64.toString(), assertBase64Data)
|
||||||
|
|
||||||
|
let filesFromCache = routes.filesCacheGet(assertSite)
|
||||||
|
assert.strictEqual(filesFromCache.length, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.describe('#resize', function() {
|
t.describe('#resize', function() {
|
||||||
const stubVerifyToken = stub()
|
const stubVerifyToken = stub()
|
||||||
const stubVerifyBody = stub()
|
const stubVerifyBody = stub()
|
||||||
|
|
Loading…
Reference in a new issue