New things for GCS Adapter
This commit is contained in:
@@ -1,35 +1,34 @@
|
|||||||
|
|
||||||
var FilesController = require('../src/Controllers/FilesController').FilesController;
|
var FilesController = require('../src/Controllers/FilesController').FilesController;
|
||||||
var Config = require("../src/Config");
|
var Config = require("../src/Config");
|
||||||
|
|
||||||
var testAdapter = function(name, adapter) {
|
var testAdapter = function(name, adapter) {
|
||||||
// Small additional tests to improve overall coverage
|
// Small additional tests to improve overall coverage
|
||||||
|
|
||||||
var config = new Config(Parse.applicationId);
|
var config = new Config(Parse.applicationId);
|
||||||
var filesController = new FilesController(adapter);
|
var filesController = new FilesController(adapter);
|
||||||
|
|
||||||
describe("FilesController with "+name,()=>{
|
describe("FilesController with "+name,()=>{
|
||||||
|
|
||||||
it("should properly expand objects", (done) => {
|
it("should properly expand objects", (done) => {
|
||||||
|
|
||||||
var result = filesController.expandFilesInObject(config, function(){});
|
var result = filesController.expandFilesInObject(config, function(){});
|
||||||
|
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
var fullFile = {
|
var fullFile = {
|
||||||
type: '__type',
|
type: '__type',
|
||||||
url: "http://an.url"
|
url: "http://an.url"
|
||||||
}
|
}
|
||||||
|
|
||||||
var anObject = {
|
var anObject = {
|
||||||
aFile: fullFile
|
aFile: fullFile
|
||||||
}
|
}
|
||||||
filesController.expandFilesInObject(config, anObject);
|
filesController.expandFilesInObject(config, anObject);
|
||||||
expect(anObject.aFile.url).toEqual("http://an.url");
|
expect(anObject.aFile.url).toEqual("http://an.url");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should properly create, read, delete files", (done) => {
|
it("should properly create, read, delete files", (done) => {
|
||||||
var filename;
|
var filename;
|
||||||
filesController.createFile(config, "file.txt", "hello world").then( (result) => {
|
filesController.createFile(config, "file.txt", "hello world").then( (result) => {
|
||||||
@@ -51,14 +50,14 @@ var testAdapter = function(name, adapter) {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
done();
|
done();
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
|
|
||||||
filesController.getFileData(config, filename).then((res) => {
|
filesController.getFileData(config, filename).then((res) => {
|
||||||
fail("the file should be deleted");
|
fail("the file should be deleted");
|
||||||
done();
|
done();
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
fail("The adapter should delete the file");
|
fail("The adapter should delete the file");
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export function loadAdapter(adapter, defaultAdapter, options) {
|
export function loadAdapter(adapter, defaultAdapter, options) {
|
||||||
|
if (!adapter)
|
||||||
if (!adapter)
|
|
||||||
{
|
{
|
||||||
if (!defaultAdapter) {
|
if (!defaultAdapter) {
|
||||||
return options;
|
return options;
|
||||||
@@ -20,7 +19,7 @@ export function loadAdapter(adapter, defaultAdapter, options) {
|
|||||||
if (adapter.default) {
|
if (adapter.default) {
|
||||||
adapter = adapter.default;
|
adapter = adapter.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadAdapter(adapter, undefined, options);
|
return loadAdapter(adapter, undefined, options);
|
||||||
} else if (adapter.module) {
|
} else if (adapter.module) {
|
||||||
return loadAdapter(adapter.module, undefined, adapter.options);
|
return loadAdapter(adapter.module, undefined, adapter.options);
|
||||||
@@ -30,7 +29,7 @@ export function loadAdapter(adapter, defaultAdapter, options) {
|
|||||||
return loadAdapter(adapter.adapter, undefined, adapter.options);
|
return loadAdapter(adapter.adapter, undefined, adapter.options);
|
||||||
}
|
}
|
||||||
// return the adapter as provided
|
// return the adapter as provided
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default loadAdapter;
|
export default loadAdapter;
|
||||||
|
|||||||
@@ -4,18 +4,33 @@ import { storage } from 'gcloud';
|
|||||||
import { FilesAdapter } from './FilesAdapter';
|
import { FilesAdapter } from './FilesAdapter';
|
||||||
import requiredParameter from '../../requiredParameter';
|
import requiredParameter from '../../requiredParameter';
|
||||||
|
|
||||||
|
function requiredOrFromEnvironment(env, name) {
|
||||||
|
let environmentVariable = process.env[env];
|
||||||
|
if (!environmentVariable) {
|
||||||
|
requiredParameter(`GCSAdapter requires an ${name}`);
|
||||||
|
}
|
||||||
|
return environmentVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromEnvironmentOrDefault(env, defaultValue) {
|
||||||
|
let environmentVariable = process.env[env];
|
||||||
|
if (environmentVariable) {
|
||||||
|
return environmentVariable;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
export class GCSAdapter extends FilesAdapter {
|
export class GCSAdapter extends FilesAdapter {
|
||||||
// GCS Project ID and the name of a corresponding Keyfile are required.
|
// GCS Project ID and the name of a corresponding Keyfile are required.
|
||||||
// Unlike the S3 adapter, you must create a new Cloud Storage bucket, as this is not created automatically.
|
// Unlike the S3 adapter, you must create a new Cloud Storage bucket, as this is not created automatically.
|
||||||
// See https://googlecloudplatform.github.io/gcloud-node/#/docs/master/guides/authentication
|
// See https://googlecloudplatform.github.io/gcloud-node/#/docs/master/guides/authentication
|
||||||
// for more details.
|
// for more details.
|
||||||
constructor(
|
constructor(
|
||||||
projectId = requiredParameter('GCSAdapter requires a GCP Project ID'),
|
projectId = requiredOrFromEnvironment('GCP_PROJECT_ID', 'projectId'),
|
||||||
keyFilename = requiredParameter('GCSAdapter requires a GCP keyfile'),
|
keyFilename = requiredOrFromEnvironment('GCP_KEYFILE_PATH', 'keyfile path'),
|
||||||
bucket = requiredParameter('GCSAdapter requires a GCS bucket name'),
|
bucket = requiredOrFromEnvironment('GCS_BUCKET_NAME', 'bucket name'),
|
||||||
{ bucketPrefix = '',
|
{ bucketPrefix = fromEnvironmentOrDefault('GCS_BUCKET_PREFIX', ''),
|
||||||
directAccess = false } = {}
|
directAccess = fromEnvironmentOrDefault('GCS_DIRECT_ACCESS', false) } = {}) {
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._bucket = bucket;
|
this._bucket = bucket;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
AdaptableController.js
|
AdaptableController.js
|
||||||
|
|
||||||
AdaptableController is the base class for all controllers
|
AdaptableController is the base class for all controllers
|
||||||
that support adapter,
|
that support adapter,
|
||||||
The super class takes care of creating the right instance for the adapter
|
The super class takes care of creating the right instance for the adapter
|
||||||
based on the parameters passed
|
based on the parameters passed
|
||||||
|
|
||||||
@@ -28,30 +28,30 @@ export class AdaptableController {
|
|||||||
this.validateAdapter(adapter);
|
this.validateAdapter(adapter);
|
||||||
this[_adapter] = adapter;
|
this[_adapter] = adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
get adapter() {
|
get adapter() {
|
||||||
return this[_adapter];
|
return this[_adapter];
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config() {
|
||||||
return new Config(this.appId);
|
return new Config(this.appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedAdapterType() {
|
expectedAdapterType() {
|
||||||
throw new Error("Subclasses should implement expectedAdapterType()");
|
throw new Error("Subclasses should implement expectedAdapterType()");
|
||||||
}
|
}
|
||||||
|
|
||||||
validateAdapter(adapter) {
|
validateAdapter(adapter) {
|
||||||
if (!adapter) {
|
if (!adapter) {
|
||||||
throw new Error(this.constructor.name+" requires an adapter");
|
throw new Error(this.constructor.name+" requires an adapter");
|
||||||
}
|
}
|
||||||
|
|
||||||
let Type = this.expectedAdapterType();
|
let Type = this.expectedAdapterType();
|
||||||
// Allow skipping for testing
|
// Allow skipping for testing
|
||||||
if (!Type) {
|
if (!Type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Makes sure the prototype matches
|
// Makes sure the prototype matches
|
||||||
let mismatches = Object.getOwnPropertyNames(Type.prototype).reduce( (obj, key) => {
|
let mismatches = Object.getOwnPropertyNames(Type.prototype).reduce( (obj, key) => {
|
||||||
const adapterType = typeof adapter[key];
|
const adapterType = typeof adapter[key];
|
||||||
@@ -64,7 +64,7 @@ export class AdaptableController {
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
if (Object.keys(mismatches).length > 0) {
|
if (Object.keys(mismatches).length > 0) {
|
||||||
throw new Error("Adapter prototype don't match expected prototype", adapter, mismatches);
|
throw new Error("Adapter prototype don't match expected prototype", adapter, mismatches);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ export class FilesController extends AdaptableController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createFile(config, filename, data, contentType) {
|
createFile(config, filename, data, contentType) {
|
||||||
|
|
||||||
let extname = path.extname(filename);
|
let extname = path.extname(filename);
|
||||||
|
|
||||||
const hasExtension = extname.length > 0;
|
const hasExtension = extname.length > 0;
|
||||||
|
|
||||||
if (!hasExtension && contentType && mime.extension(contentType)) {
|
if (!hasExtension && contentType && mime.extension(contentType)) {
|
||||||
filename = filename + '.' + mime.extension(contentType);
|
filename = filename + '.' + mime.extension(contentType);
|
||||||
} else if (hasExtension && !contentType) {
|
} else if (hasExtension && !contentType) {
|
||||||
@@ -27,6 +27,8 @@ export class FilesController extends AdaptableController {
|
|||||||
filename = randomHexString(32) + '_' + filename;
|
filename = randomHexString(32) + '_' + filename;
|
||||||
|
|
||||||
var location = this.adapter.getFileLocation(config, filename);
|
var location = this.adapter.getFileLocation(config, filename);
|
||||||
|
console.log(this.adapter);
|
||||||
|
console.log(location);
|
||||||
return this.adapter.createFile(config, filename, data, contentType).then(() => {
|
return this.adapter.createFile(config, filename, data, contentType).then(() => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
url: location,
|
url: location,
|
||||||
|
|||||||
Reference in New Issue
Block a user