mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-10 20:09:57 +00:00
MWS: fix editing attachment tiddlers (#8455)
* fix breaking bug in image tiddler attachment * fix comments * fix code format * refactor processIncomingTiddler flow * remove whitespaces after if statements * refactor attachment_blob persistence flow * refactor process tiddler to support different attachments * add tests for attachment * add more attachement test cases * working on adding instanbul for test coverage report * code coverage report generation * remove unnecessary packages * fix comments
This commit is contained in:
parent
eac8a2c3d8
commit
3287dce40c
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ store/
|
|||||||
/playwright-report/
|
/playwright-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
$__StoryList.tid
|
$__StoryList.tid
|
||||||
|
/editions/test/test-store/*
|
1
editions/multiwikiserver/tiddlers/$__StoryList_1.tid
Normal file
1
editions/multiwikiserver/tiddlers/$__StoryList_1.tid
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -32,7 +32,9 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./tiddlywiki.js ./editions/multiwikiserver --mws-load-plugin-bags --build load-mws-demo-data --mws-listen",
|
"start": "node ./tiddlywiki.js ./editions/multiwikiserver --mws-load-plugin-bags --build load-mws-demo-data --mws-listen",
|
||||||
"test": "node ./tiddlywiki.js ./editions/test --verbose --version --build index && node ./tiddlywiki ./editions/multiwikiserver/ --build load-mws-demo-data --mws-listen --mws-test-server http://127.0.0.1:8080/ --quit",
|
"build:test-edition": "node ./tiddlywiki.js ./editions/test --verbose --version --build index",
|
||||||
|
"test:multiwikiserver-edition": "node ./tiddlywiki.js ./editions/multiwikiserver/ --build load-mws-demo-data --mws-listen --mws-test-server http://127.0.0.1:8080/ --quit",
|
||||||
|
"test": "npm run build:test-edition && npm run test:multiwikiserver-edition",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"lint": "eslint ."
|
"lint": "eslint ."
|
||||||
},
|
},
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
title: $:/config/MultiWikiServer/EnableAttachments
|
title: $:/config/MultiWikiServer/EnableAttachments
|
||||||
text: no
|
text: yes
|
||||||
|
@ -53,6 +53,7 @@ Saves an attachment to a file. Options include:
|
|||||||
text: text content (may be binary)
|
text: text content (may be binary)
|
||||||
type: MIME type of content
|
type: MIME type of content
|
||||||
reference: reference to use for debugging
|
reference: reference to use for debugging
|
||||||
|
_canonical_uri: canonical uri of the content
|
||||||
*/
|
*/
|
||||||
AttachmentStore.prototype.saveAttachment = function(options) {
|
AttachmentStore.prototype.saveAttachment = function(options) {
|
||||||
const path = require("path"),
|
const path = require("path"),
|
||||||
@ -69,6 +70,7 @@ AttachmentStore.prototype.saveAttachment = function(options) {
|
|||||||
fs.writeFileSync(path.resolve(attachmentPath,dataFilename),options.text,contentTypeInfo.encoding);
|
fs.writeFileSync(path.resolve(attachmentPath,dataFilename),options.text,contentTypeInfo.encoding);
|
||||||
// Save the meta.json file
|
// Save the meta.json file
|
||||||
fs.writeFileSync(path.resolve(attachmentPath,"meta.json"),JSON.stringify({
|
fs.writeFileSync(path.resolve(attachmentPath,"meta.json"),JSON.stringify({
|
||||||
|
_canonical_uri: options._canonical_uri,
|
||||||
created: $tw.utils.stringifyDate(new Date()),
|
created: $tw.utils.stringifyDate(new Date()),
|
||||||
modified: $tw.utils.stringifyDate(new Date()),
|
modified: $tw.utils.stringifyDate(new Date()),
|
||||||
contentHash: contentHash,
|
contentHash: contentHash,
|
||||||
@ -81,7 +83,7 @@ AttachmentStore.prototype.saveAttachment = function(options) {
|
|||||||
/*
|
/*
|
||||||
Adopts an attachment file into the store
|
Adopts an attachment file into the store
|
||||||
*/
|
*/
|
||||||
AttachmentStore.prototype.adoptAttachment = function(incomingFilepath,type,hash) {
|
AttachmentStore.prototype.adoptAttachment = function(incomingFilepath,type,hash,_canonical_uri) {
|
||||||
const path = require("path"),
|
const path = require("path"),
|
||||||
fs = require("fs");
|
fs = require("fs");
|
||||||
// Choose the best file extension for the attachment given its type
|
// Choose the best file extension for the attachment given its type
|
||||||
@ -95,6 +97,7 @@ AttachmentStore.prototype.adoptAttachment = function(incomingFilepath,type,hash)
|
|||||||
fs.renameSync(incomingFilepath,dataFilepath);
|
fs.renameSync(incomingFilepath,dataFilepath);
|
||||||
// Save the meta.json file
|
// Save the meta.json file
|
||||||
fs.writeFileSync(path.resolve(attachmentPath,"meta.json"),JSON.stringify({
|
fs.writeFileSync(path.resolve(attachmentPath,"meta.json"),JSON.stringify({
|
||||||
|
_canonical_uri: _canonical_uri,
|
||||||
created: $tw.utils.stringifyDate(new Date()),
|
created: $tw.utils.stringifyDate(new Date()),
|
||||||
modified: $tw.utils.stringifyDate(new Date()),
|
modified: $tw.utils.stringifyDate(new Date()),
|
||||||
contentHash: hash,
|
contentHash: hash,
|
||||||
@ -137,6 +140,42 @@ AttachmentStore.prototype.getAttachmentStream = function(attachment_name) {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the size of an attachment file given the contentHash.
|
||||||
|
Returns the size in bytes, or null if the file doesn't exist.
|
||||||
|
*/
|
||||||
|
AttachmentStore.prototype.getAttachmentFileSize = function(contentHash) {
|
||||||
|
const path = require("path"),
|
||||||
|
fs = require("fs");
|
||||||
|
// Construct the path to the attachment directory
|
||||||
|
const attachmentPath = path.resolve(this.storePath, "files", contentHash);
|
||||||
|
// Read the meta.json file
|
||||||
|
const metaJsonPath = path.resolve(attachmentPath, "meta.json");
|
||||||
|
if(fs.existsSync(metaJsonPath) && fs.statSync(metaJsonPath).isFile()) {
|
||||||
|
const meta = $tw.utils.parseJSONSafe(fs.readFileSync(metaJsonPath, "utf8"), function() { return null; });
|
||||||
|
if(meta) {
|
||||||
|
const dataFilepath = path.resolve(attachmentPath, meta.filename);
|
||||||
|
// Check if the data file exists and return its size
|
||||||
|
if(fs.existsSync(dataFilepath) && fs.statSync(dataFilepath).isFile()) {
|
||||||
|
return fs.statSync(dataFilepath).size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return null if the file doesn't exist or there was an error
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentStore.prototype.getAttachmentMetadata = function(attachmentBlob) {
|
||||||
|
const path = require("path"),
|
||||||
|
fs = require("fs");
|
||||||
|
const attachmentPath = path.resolve(this.storePath, "files", attachmentBlob);
|
||||||
|
const metaJsonPath = path.resolve(attachmentPath, "meta.json");
|
||||||
|
if(fs.existsSync(metaJsonPath)) {
|
||||||
|
const metadata = JSON.parse(fs.readFileSync(metaJsonPath, "utf8"));
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
exports.AttachmentStore = AttachmentStore;
|
exports.AttachmentStore = AttachmentStore;
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -539,6 +539,42 @@ SqlTiddlerDatabase.prototype.getRecipeBags = function(recipe_name) {
|
|||||||
return rows.map(value => value.bag_name);
|
return rows.map(value => value.bag_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the attachment value of a bag, if any exist
|
||||||
|
*/
|
||||||
|
SqlTiddlerDatabase.prototype.getBagTiddlerAttachmentBlob = function(title,bag_name) {
|
||||||
|
const row = this.engine.runStatementGet(`
|
||||||
|
SELECT t.attachment_blob
|
||||||
|
FROM bags AS b
|
||||||
|
INNER JOIN tiddlers AS t ON b.bag_id = t.bag_id
|
||||||
|
WHERE t.title = $title AND b.bag_name = $bag_name AND t.is_deleted = FALSE
|
||||||
|
`, {
|
||||||
|
$title: title,
|
||||||
|
$bag_name: bag_name
|
||||||
|
});
|
||||||
|
return row ? row.attachment_blob : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the attachment value of a recipe, if any exist
|
||||||
|
*/
|
||||||
|
SqlTiddlerDatabase.prototype.getRecipeTiddlerAttachmentBlob = function(title,recipe_name) {
|
||||||
|
const row = this.engine.runStatementGet(`
|
||||||
|
SELECT t.attachment_blob
|
||||||
|
FROM bags AS b
|
||||||
|
INNER JOIN recipe_bags AS rb ON b.bag_id = rb.bag_id
|
||||||
|
INNER JOIN recipes AS r ON rb.recipe_id = r.recipe_id
|
||||||
|
INNER JOIN tiddlers AS t ON b.bag_id = t.bag_id
|
||||||
|
WHERE r.recipe_name = $recipe_name AND t.title = $title AND t.is_deleted = FALSE
|
||||||
|
ORDER BY rb.position DESC
|
||||||
|
LIMIT 1
|
||||||
|
`, {
|
||||||
|
$title: title,
|
||||||
|
$recipe_name: recipe_name
|
||||||
|
});
|
||||||
|
return row ? row.attachment_blob : null;
|
||||||
|
};
|
||||||
|
|
||||||
exports.SqlTiddlerDatabase = SqlTiddlerDatabase;
|
exports.SqlTiddlerDatabase = SqlTiddlerDatabase;
|
||||||
|
|
||||||
})();
|
})();
|
@ -143,28 +143,49 @@ SqlTiddlerStore.prototype.processOutgoingTiddler = function(tiddlerFields,tiddle
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
SqlTiddlerStore.prototype.processIncomingTiddler = function(tiddlerFields) {
|
SqlTiddlerStore.prototype.processIncomingTiddler = function(tiddlerFields, existing_attachment_blob, existing_canonical_uri) {
|
||||||
let attachmentSizeLimit = $tw.utils.parseNumber(this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/AttachmentSizeLimit"));
|
let attachmentSizeLimit = $tw.utils.parseNumber(this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/AttachmentSizeLimit"));
|
||||||
if(attachmentSizeLimit < 100 * 1024) {
|
if(attachmentSizeLimit < 100 * 1024) {
|
||||||
attachmentSizeLimit = 100 * 1024;
|
attachmentSizeLimit = 100 * 1024;
|
||||||
}
|
}
|
||||||
const attachmentsEnabled = this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/EnableAttachments","yes") === "yes";
|
const attachmentsEnabled = this.adminWiki.getTiddlerText("$:/config/MultiWikiServer/EnableAttachments", "yes") === "yes";
|
||||||
const contentTypeInfo = $tw.config.contentTypeInfo[tiddlerFields.type || "text/vnd.tiddlywiki"],
|
const contentTypeInfo = $tw.config.contentTypeInfo[tiddlerFields.type || "text/vnd.tiddlywiki"];
|
||||||
isBinary = !!contentTypeInfo && contentTypeInfo.encoding === "base64";
|
const isBinary = !!contentTypeInfo && contentTypeInfo.encoding === "base64";
|
||||||
if(attachmentsEnabled && isBinary && tiddlerFields.text && tiddlerFields.text.length > attachmentSizeLimit) {
|
|
||||||
const attachment_blob = this.attachmentStore.saveAttachment({
|
let shouldProcessAttachment = tiddlerFields.text && tiddlerFields.text.length <= attachmentSizeLimit;
|
||||||
|
|
||||||
|
if(existing_attachment_blob) {
|
||||||
|
const fileSize = this.attachmentStore.getAttachmentFileSize(existing_attachment_blob);
|
||||||
|
if(fileSize <= attachmentSizeLimit) {
|
||||||
|
const existingAttachmentMeta = this.attachmentStore.getAttachmentMetadata(existing_attachment_blob);
|
||||||
|
const hasCanonicalField = !!tiddlerFields._canonical_uri;
|
||||||
|
const skipAttachment = hasCanonicalField && (tiddlerFields._canonical_uri === (existingAttachmentMeta?._canonical_uri || existing_canonical_uri));
|
||||||
|
shouldProcessAttachment = !skipAttachment;
|
||||||
|
} else {
|
||||||
|
shouldProcessAttachment = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attachmentsEnabled && isBinary && shouldProcessAttachment) {
|
||||||
|
const attachment_blob = existing_attachment_blob || this.attachmentStore.saveAttachment({
|
||||||
text: tiddlerFields.text,
|
text: tiddlerFields.text,
|
||||||
type: tiddlerFields.type,
|
type: tiddlerFields.type,
|
||||||
reference: tiddlerFields.title
|
reference: tiddlerFields.title,
|
||||||
|
_canonical_uri: tiddlerFields._canonical_uri
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(tiddlerFields?._canonical_uri) {
|
||||||
|
delete tiddlerFields._canonical_uri;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tiddlerFields: Object.assign({},tiddlerFields,{text: undefined}),
|
tiddlerFields: Object.assign({}, tiddlerFields, { text: undefined }),
|
||||||
attachment_blob: attachment_blob
|
attachment_blob: attachment_blob
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
tiddlerFields: tiddlerFields,
|
tiddlerFields: tiddlerFields,
|
||||||
attachment_blob: null
|
attachment_blob: existing_attachment_blob
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -244,7 +265,12 @@ SqlTiddlerStore.prototype.createRecipe = function(recipe_name,bag_names,descript
|
|||||||
Returns {tiddler_id:}
|
Returns {tiddler_id:}
|
||||||
*/
|
*/
|
||||||
SqlTiddlerStore.prototype.saveBagTiddler = function(incomingTiddlerFields,bag_name) {
|
SqlTiddlerStore.prototype.saveBagTiddler = function(incomingTiddlerFields,bag_name) {
|
||||||
const {tiddlerFields, attachment_blob} = this.processIncomingTiddler(incomingTiddlerFields);
|
let _canonical_uri;
|
||||||
|
const existing_attachment_blob = this.sqlTiddlerDatabase.getBagTiddlerAttachmentBlob(incomingTiddlerFields.title,bag_name)
|
||||||
|
if(existing_attachment_blob) {
|
||||||
|
_canonical_uri = `/bags/${$tw.utils.encodeURIComponentExtended(bag_name)}/tiddlers/${$tw.utils.encodeURIComponentExtended(incomingTiddlerFields.title)}/blob`
|
||||||
|
}
|
||||||
|
const {tiddlerFields, attachment_blob} = this.processIncomingTiddler(incomingTiddlerFields,existing_attachment_blob,_canonical_uri);
|
||||||
const result = this.sqlTiddlerDatabase.saveBagTiddler(tiddlerFields,bag_name,attachment_blob);
|
const result = this.sqlTiddlerDatabase.saveBagTiddler(tiddlerFields,bag_name,attachment_blob);
|
||||||
this.dispatchEvent("change");
|
this.dispatchEvent("change");
|
||||||
return result;
|
return result;
|
||||||
@ -261,7 +287,7 @@ type - content type of file as uploaded
|
|||||||
Returns {tiddler_id:}
|
Returns {tiddler_id:}
|
||||||
*/
|
*/
|
||||||
SqlTiddlerStore.prototype.saveBagTiddlerWithAttachment = function(incomingTiddlerFields,bag_name,options) {
|
SqlTiddlerStore.prototype.saveBagTiddlerWithAttachment = function(incomingTiddlerFields,bag_name,options) {
|
||||||
const attachment_blob = this.attachmentStore.adoptAttachment(options.filepath,options.type,options.hash);
|
const attachment_blob = this.attachmentStore.adoptAttachment(options.filepath,options.type,options.hash,options._canonical_uri);
|
||||||
if(attachment_blob) {
|
if(attachment_blob) {
|
||||||
const result = this.sqlTiddlerDatabase.saveBagTiddler(incomingTiddlerFields,bag_name,attachment_blob);
|
const result = this.sqlTiddlerDatabase.saveBagTiddler(incomingTiddlerFields,bag_name,attachment_blob);
|
||||||
this.dispatchEvent("change");
|
this.dispatchEvent("change");
|
||||||
@ -275,7 +301,8 @@ SqlTiddlerStore.prototype.saveBagTiddlerWithAttachment = function(incomingTiddle
|
|||||||
Returns {tiddler_id:,bag_name:}
|
Returns {tiddler_id:,bag_name:}
|
||||||
*/
|
*/
|
||||||
SqlTiddlerStore.prototype.saveRecipeTiddler = function(incomingTiddlerFields,recipe_name) {
|
SqlTiddlerStore.prototype.saveRecipeTiddler = function(incomingTiddlerFields,recipe_name) {
|
||||||
const {tiddlerFields, attachment_blob} = this.processIncomingTiddler(incomingTiddlerFields);
|
const existing_attachment_blob = this.sqlTiddlerDatabase.getRecipeTiddlerAttachmentBlob(incomingTiddlerFields.title,recipe_name)
|
||||||
|
const {tiddlerFields, attachment_blob} = this.processIncomingTiddler(incomingTiddlerFields,existing_attachment_blob,incomingTiddlerFields._canonical_uri);
|
||||||
const result = this.sqlTiddlerDatabase.saveRecipeTiddler(tiddlerFields,recipe_name,attachment_blob);
|
const result = this.sqlTiddlerDatabase.saveRecipeTiddler(tiddlerFields,recipe_name,attachment_blob);
|
||||||
this.dispatchEvent("change");
|
this.dispatchEvent("change");
|
||||||
return result;
|
return result;
|
||||||
|
175
plugins/tiddlywiki/multiwikiserver/modules/test-attachment.js
Normal file
175
plugins/tiddlywiki/multiwikiserver/modules/test-attachment.js
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/plugins/tiddlywiki/multiwikiserver/modules/test-attachment.js
|
||||||
|
type: application/javascript
|
||||||
|
tags: [[$:/tags/test-spec]]
|
||||||
|
|
||||||
|
Tests attachments.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var assert = require('assert');
|
||||||
|
var AttachmentStore = require('$:/plugins/tiddlywiki/multiwikiserver/store/attachments.js').AttachmentStore;
|
||||||
|
const {Buffer} = require('buffer');
|
||||||
|
|
||||||
|
function generateFileWithSize(filePath, sizeInBytes) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var buffer = Buffer.alloc(sizeInBytes);
|
||||||
|
for(var i = 0; i < sizeInBytes; i++) {
|
||||||
|
buffer[i] = Math.floor(Math.random() * 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(filePath, buffer, (err) => {
|
||||||
|
if(err) {
|
||||||
|
console.error('Error writing file:', err);
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
console.log('File '+filePath+' generated with size '+sizeInBytes+' bytes');
|
||||||
|
fs.readFile(filePath, (err, data) => {
|
||||||
|
if(err) {
|
||||||
|
console.error('Error reading file:', err);
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
if($tw.node) {
|
||||||
|
describe('AttachmentStore', function() {
|
||||||
|
var storePath = './editions/test/test-store';
|
||||||
|
var attachmentStore = new AttachmentStore({ storePath: storePath });
|
||||||
|
var originalTimeout;
|
||||||
|
|
||||||
|
beforeAll(function() {
|
||||||
|
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(function() {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
fs.readdirSync(storePath).forEach(function(file) {
|
||||||
|
var filePath = path.join(storePath, file);
|
||||||
|
if(fs.lstatSync(filePath).isFile()) {
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
} else if(fs.lstatSync(filePath).isDirectory()) {
|
||||||
|
fs.rmdirSync(filePath, { recursive: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isValidAttachmentName', function() {
|
||||||
|
expect(attachmentStore.isValidAttachmentName('abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890')).toBe(true);
|
||||||
|
expect(attachmentStore.isValidAttachmentName('invalid-name')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saveAttachment', function() {
|
||||||
|
var options = {
|
||||||
|
text: 'Hello, World!',
|
||||||
|
type: 'text/plain',
|
||||||
|
reference: 'test-reference',
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
assert.strictEqual(contentHash.length, 64);
|
||||||
|
assert.strictEqual(fs.existsSync(path.resolve(storePath, 'files', contentHash)), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adoptAttachment', function() {
|
||||||
|
var incomingFilepath = path.resolve(storePath, 'incoming-file.txt');
|
||||||
|
fs.writeFileSync(incomingFilepath, 'Hello, World!');
|
||||||
|
var type = 'text/plain';
|
||||||
|
var hash = 'abcdef0123456789abcdef0123456789';
|
||||||
|
var _canonical_uri = 'test-canonical-uri';
|
||||||
|
attachmentStore.adoptAttachment(incomingFilepath, type, hash, _canonical_uri);
|
||||||
|
expect(fs.existsSync(path.resolve(storePath, 'files', hash))).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAttachmentStream', function() {
|
||||||
|
var options = {
|
||||||
|
text: 'Hello, World!',
|
||||||
|
type: 'text/plain',
|
||||||
|
filename: 'data.txt',
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
var stream = attachmentStore.getAttachmentStream(contentHash);
|
||||||
|
expect(stream).not.toBeNull();
|
||||||
|
expect(stream.type).toBe('text/plain');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAttachmentFileSize', function() {
|
||||||
|
var options = {
|
||||||
|
text: 'Hello, World!',
|
||||||
|
type: 'text/plain',
|
||||||
|
reference: 'test-reference',
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
var fileSize = attachmentStore.getAttachmentFileSize(contentHash);
|
||||||
|
expect(fileSize).toBe(13);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAttachmentMetadata', function() {
|
||||||
|
var options = {
|
||||||
|
text: 'Hello, World!',
|
||||||
|
type: 'text/plain',
|
||||||
|
filename: 'data.txt',
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
var metadata = attachmentStore.getAttachmentMetadata(contentHash);
|
||||||
|
expect(metadata).not.toBeNull();
|
||||||
|
expect(metadata.type).toBe('text/plain');
|
||||||
|
expect(metadata.filename).toBe('data.txt');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saveAttachment large file', async function() {
|
||||||
|
var sizeInMB = 10
|
||||||
|
const file = await generateFileWithSize('./editions/test/test-store/large-file.txt', 1024 * 1024 * sizeInMB)
|
||||||
|
var options = {
|
||||||
|
text: file,
|
||||||
|
type: 'application/octet-stream',
|
||||||
|
reference: 'test-reference',
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
assert.strictEqual(contentHash.length, 64);
|
||||||
|
assert.strictEqual(fs.existsSync(path.resolve(storePath, 'files', contentHash)), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saveAttachment multiple large files', async function() {
|
||||||
|
var sizeInMB = 10;
|
||||||
|
var numFiles = 5;
|
||||||
|
for (var i = 0; i < numFiles; i++) {
|
||||||
|
const file = await generateFileWithSize(`./editions/test/test-store/large-file-${i}.txt`, 1024 * 1024 * sizeInMB);
|
||||||
|
var options = {
|
||||||
|
text: file,
|
||||||
|
type: 'application/octet-stream',
|
||||||
|
reference: `test-reference-${i}`,
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
assert.strictEqual(contentHash.length, 64);
|
||||||
|
assert.strictEqual(fs.existsSync(path.resolve(storePath, 'files', contentHash)), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getAttachmentStream multiple large files', async function() {
|
||||||
|
var sizeInMB = 10;
|
||||||
|
var numFiles = 5;
|
||||||
|
for (var i = 0; i < numFiles; i++) {
|
||||||
|
const file = await generateFileWithSize(`./editions/test/test-store/large-file-${i}.txt`, 1024 * 1024 * sizeInMB);
|
||||||
|
var options = {
|
||||||
|
text: file,
|
||||||
|
type: 'application/octet-stream',
|
||||||
|
reference: `test-reference-${i}`,
|
||||||
|
};
|
||||||
|
var contentHash = attachmentStore.saveAttachment(options);
|
||||||
|
var stream = attachmentStore.getAttachmentStream(contentHash);
|
||||||
|
assert.notStrictEqual(stream, null);
|
||||||
|
assert.strictEqual(stream.type, 'application/octet-stream');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user