Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' into defect-1816
Browse files Browse the repository at this point in the history
  • Loading branch information
cazfletch authored Oct 27, 2017
2 parents 743babc + bb65aee commit 1e962ae
Show file tree
Hide file tree
Showing 73 changed files with 2,024 additions and 688 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"packages": [
"packages/*"
],
"version": "0.14.2",
"version": "0.14.3",
"hoist": true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"name": "composer",
"description": "You must install [Lerna](https://lernajs.io) to build this multi-package repository.",
"version": "0.14.2",
"version": "0.14.3",
"main": "index.js",
"private": true,
"scripts": {
Expand Down
6 changes: 3 additions & 3 deletions packages/composer-admin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "composer-admin",
"version": "0.14.2",
"version": "0.14.3",
"description": "Hyperledger Composer Admin, code that manages business networks deployed to Hyperledger Fabric",
"engines": {
"node": ">=6",
Expand Down Expand Up @@ -41,8 +41,8 @@
"sinon": "2.3.8"
},
"dependencies": {
"composer-common": "0.14.2",
"composer-connector-hlfv1": "0.14.2"
"composer-common": "0.14.3",
"composer-connector-hlfv1": "0.14.3"
},
"license-check-config": {
"src": [
Expand Down
10 changes: 5 additions & 5 deletions packages/composer-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "composer-cli",
"version": "0.14.2",
"version": "0.14.3",
"description": "Hyperledger Composer command line interfaces (CLIs)",
"engines": {
"node": ">=6",
Expand Down Expand Up @@ -41,10 +41,10 @@
"dependencies": {
"chalk": "1.1.3",
"cli-table": "0.3.1",
"composer-admin": "0.14.2",
"composer-client": "0.14.2",
"composer-common": "0.14.2",
"composer-rest-server": "0.14.2",
"composer-admin": "0.14.3",
"composer-client": "0.14.3",
"composer-common": "0.14.3",
"composer-rest-server": "0.14.3",
"homedir": "0.6.0",
"mkdirp": "0.5.1",
"npm-paths": "0.1.3",
Expand Down
10 changes: 7 additions & 3 deletions packages/composer-client/lib/businessnetworkconnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,13 @@ class BusinessNetworkConnection extends EventEmitter {
let card;

return this.cardStore.get(cardName)
.then((card_)=>{
card = card_;
return this.connectionProfileManager.connectWithData(card.getConnectionProfile(),card.getBusinessNetworkName(), additionalConnectOptions);
.then((retrievedCard)=>{
card = retrievedCard;
if (!additionalConnectOptions) {
additionalConnectOptions = {};
}
additionalConnectOptions.cardName = cardName;
return this.connectionProfileManager.connectWithData(card.getConnectionProfile(), card.getBusinessNetworkName(), additionalConnectOptions);
})
.then((connection) => {
LOG.exit(method);
Expand Down
6 changes: 3 additions & 3 deletions packages/composer-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "composer-client",
"version": "0.14.2",
"version": "0.14.3",
"description": "The node.js client library for Hyperledger Composer, a development framework for Hyperledger Fabric",
"engines": {
"node": ">=6",
Expand Down Expand Up @@ -44,8 +44,8 @@
"logError": true
},
"dependencies": {
"composer-common": "0.14.2",
"composer-connector-hlfv1": "0.14.2",
"composer-common": "0.14.3",
"composer-connector-hlfv1": "0.14.3",
"uuid": "3.0.1"
},
"devDependencies": {
Expand Down
42 changes: 35 additions & 7 deletions packages/composer-client/test/businessnetworkconnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,18 @@ describe('BusinessNetworkConnection', () => {
});

describe('#connectWithCard',()=>{
const userName = 'FredBloggs';
const enrollmentSecret = 'password';
const keyValStore = '/conga/conga/conga';

it('Correct with with existing card name',()=>{
beforeEach(() => {
sandbox.stub(businessNetworkConnection.connectionProfileManager, 'connectWithData').resolves(mockConnection);
let mockCardStore = sinon.createStubInstance(CardStore);
let mockIdCard = sinon.createStubInstance(IdCard);
mockCardStore.get.resolves(mockIdCard);
mockIdCard.getEnrollmentCredentials.returns({secret:'password'});
mockIdCard.getUserName.returns('FredBloggs');
mockIdCard.getEnrollmentCredentials.returns({secret: enrollmentSecret});
mockIdCard.getUserName.returns(userName);
mockIdCard.getConnectionProfile.returns({ keyValStore: keyValStore });
businessNetworkConnection.cardStore = mockCardStore;

mockConnection.login.resolves(mockSecurityContext);
Expand All @@ -254,18 +258,42 @@ describe('BusinessNetworkConnection', () => {
{ $class: 'org.acme.sample.SampleEvent', eventId: 'event1' },
{ $class: 'org.acme.sample.SampleEvent', eventId: 'event2' }
]);
});

afterEach(() => {
sandbox.reset();
});

it('Connect with existing card name',()=>{
return businessNetworkConnection.connectWithCard('cardName')
.then((result)=>{
sinon.assert.calledOnce(mockCardStore.get);
sinon.assert.calledWith(mockCardStore.get,'cardName');
sinon.assert.calledWith(mockConnection.login,'FredBloggs','password');
sinon.assert.calledWith(mockConnection.login, userName, enrollmentSecret);
});
});

});
it('should add card name to connection profile additional options when additional options not specified', () => {
const cardName = 'CARD_NAME';
return businessNetworkConnection.connectWithCard(cardName)
.then(result => {
sinon.assert.calledWith(businessNetworkConnection.connectionProfileManager.connectWithData,
sinon.match.any,
sinon.match.any,
sinon.match.has('cardName', cardName));
});
});

it('should override cardName property specified in additional options', () => {
const cardName = 'CARD_NAME';
return businessNetworkConnection.connectWithCard(cardName, { cardName: 'WRONG' })
.then(result => {
sinon.assert.calledWith(businessNetworkConnection.connectionProfileManager.connectWithData,
sinon.match.any,
sinon.match.any,
sinon.match.has('cardName', cardName));
});
});

});

describe('#disconnect', () => {

Expand Down
18 changes: 3 additions & 15 deletions packages/composer-common/lib/cardstore/filesystemcardstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

'use strict';

const composerUtil = require('../util');
const nodeFs = require('fs');
const os = require('os');
const path = require('path');
const rimraf = require('rimraf');
const thenifyAll = require('thenify-all');
const IdCard = require('../idcard');
const BusinessNetworkCardStore = require('./businessnetworkcardstore');
const IdCard = require('../idcard');

const thenifyRimraf = thenifyAll(rimraf);

Expand Down Expand Up @@ -50,19 +50,7 @@ class FileSystemCardStore extends BusinessNetworkCardStore {
this.thenifyFs = thenifyAll(this.fs);
this.rimrafOptions = Object.assign({}, this.fs);
this.rimrafOptions.disableGlob = true;
this.storePath = options.storePath || FileSystemCardStore._defaultStorePath(os.homedir);
}

/**
* Get the default store path based on the user's home directory, or based on the filesystem root
* directory if the supplied function does not exist or returns a falsy value.
* @private
* @param {Function} homedirFunction Function to obtain the user's home directory
* @returns {String} Absolute path
*/
static _defaultStorePath(homedirFunction) {
const homeDirectory = (homedirFunction && homedirFunction()) || path.sep;
return path.join(homeDirectory, '.composer', 'cards');
this.storePath = options.storePath || path.join(composerUtil.homeDirectory(), '.composer', 'cards');
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/composer-common/lib/idcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class IdCard {
* @return {Object} connection profile.
*/
getConnectionProfile() {
return this.connectionProfile;
return Object.assign({}, this.connectionProfile);
}

/**
Expand Down
10 changes: 9 additions & 1 deletion packages/composer-common/lib/query/parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,14 @@ LogicalORExpressionNoIn
LogicalOROperator
= "OR"

ContainsExpression
= first:LogicalORExpression
rest:(__ ContainsOperator __ LogicalORExpression)*
{ return buildBinaryExpression(first, rest); }

ContainsOperator
= "CONTAINS"

ConditionalExpression
= test:LogicalORExpression __
"?" __ consequent:AssignmentExpression __
Expand All @@ -836,7 +844,7 @@ ConditionalExpression
alternate: alternate
};
}
/ LogicalORExpression
/ ContainsExpression

ConditionalExpressionNoIn
= test:LogicalORExpressionNoIn __
Expand Down
95 changes: 91 additions & 4 deletions packages/composer-common/lib/query/queryanalyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ class QueryAnalyzer {
result = this.visitIdentifier(thing, parameters);
} else if (thing.type === 'Literal') {
result = this.visitLiteral(thing, parameters);
} else if (thing.type === 'ArrayExpression') {
result = this.visitArrayExpression(thing, parameters);
} else if (thing.type === 'MemberExpression') {
result = this.visitMemberExpression(thing, parameters);
} else {
Expand Down Expand Up @@ -251,6 +253,8 @@ class QueryAnalyzer {
let result;
if (arrayCombinationOperators.indexOf(ast.operator) !== -1) {
result = this.visitArrayCombinationOperator(ast, parameters);
} else if (ast.operator === 'CONTAINS') {
result = this.visitContainsOperator(ast, parameters);
} else {
result = this.visitConditionOperator(ast, parameters);
}
Expand Down Expand Up @@ -279,6 +283,56 @@ class QueryAnalyzer {
return result;
}

/**
* Visitor design pattern; handle an contains operator.
* @param {Object} ast The abstract syntax tree being visited.
* @param {Object} parameters The parameters.
* @return {Object} The result of visiting, or null.
* @private
*/
visitContainsOperator(ast, parameters) {
const method = 'visitContainsOperator';
LOG.entry(method, ast, parameters);

// Check we haven't already entered a scope - let's keep it simple!
if (parameters.validationDisabled) {
throw new Error('A CONTAINS expression cannot be nested within another CONTAINS expression');
}

// Disable validation.
parameters.validationDisabled = true;

// Resolve both the left and right sides of the expression.
let left = this.visit(ast.left, parameters);
let right = this.visit(ast.right, parameters);

// Enable validation again.
parameters.validationDisabled = false;

// Initialize the scopes array.
parameters.scopes = parameters.scopes || [];

// Look for a scope name.
if (typeof left === 'string' && !left.startsWith('_$')) {
parameters.scopes.push(left);
} else if (typeof right === 'string' && !right.startsWith('_$')) {
parameters.scopes.push(right);
} else {
throw new Error('A property name is required on one side of a CONTAINS expression');
}

// Re-resolve both the left and right sides of the expression.
left = this.visit(ast.left, parameters);
right = this.visit(ast.right, parameters);

// Pop the scope name off again.
parameters.scopes.pop();

const result = [left, right];
LOG.exit(method, result);
return result;
}

/**
* Visitor design pattern; handle a condition operator.
* Condition operators are operators that compare two pieces of data, such
Expand All @@ -298,19 +352,27 @@ class QueryAnalyzer {
const rhs = this.visit(ast.right, parameters);
const lhs = this.visit(ast.left, parameters);

// Bypass the following validation if required. This will be set during
// the first pass of a CONTAINS when we are trying to figure out the name
// of the current scope so we can correctly validate model references.
if (parameters.validationDisabled) {
LOG.exit(method, result);
return result;
}

// if the rhs is a string, it is the name of a property
// and we infer the type of the lhs from the model
// if the lhs is a parameter
if (typeof rhs === 'string' && (lhs instanceof Array && lhs.length > 0)) {
lhs[0].type = this.getParameterType(rhs);
lhs[0].type = this.getParameterType(rhs, parameters);
result = result.concat(lhs);
}

// if the lhs is a string, it is the name of a property
// and we infer the type of the rhs from the model
// if the rhs is a parameter
if (typeof lhs === 'string' && (rhs instanceof Array && rhs.length > 0)) {
rhs[0].type = this.getParameterType(lhs);
rhs[0].type = this.getParameterType(lhs, parameters);
result = result.concat(rhs);
}

Expand Down Expand Up @@ -368,6 +430,23 @@ class QueryAnalyzer {
return result;
}

/**
* Visitor design pattern; handle an array expression.
* @param {Object} ast The abstract syntax tree being visited.
* @param {Object} parameters The parameters.
* @return {Object} The result of visiting, or null.
* @private
*/
visitArrayExpression(ast, parameters) {
const method = 'visitArrayExpression';
LOG.entry(method, ast, parameters);
const result = ast.elements.map((element) => {
return this.visit(element, parameters);
});
LOG.exit(method, result);
return result;
}

/**
* Visitor design pattern; handle a member expression.
* @param {Object} ast The abstract syntax tree being visited.
Expand All @@ -388,16 +467,24 @@ class QueryAnalyzer {
/**
* Get the parameter type for a property path on a resource
* @param {string} parameterName The parameter name or name with nested structure e.g A.B.C
* @param {object} parameters The parameters
* @return {string} The type to use for the parameter
* @throws {Error} if the property does not exist or is of an unsupported type
* @private
*/
getParameterType(parameterName) {
getParameterType(parameterName, parameters) {
const method = 'getParameterType';
LOG.entry(method, parameterName);

// If we have entered a scope, for example a CONTAINS, then we need
// to prepend the current scope to the property name.
let actualParameterName = parameterName;
if (parameters.scopes && parameters.scopes.length) {
actualParameterName = parameters.scopes.concat(parameterName).join('.');
}

const classDeclaration = this.query.getSelect().getResourceClassDeclaration();
const property = classDeclaration.getNestedProperty(parameterName);
const property = classDeclaration.getNestedProperty(actualParameterName);

let result = null;

Expand Down
Loading

0 comments on commit 1e962ae

Please sign in to comment.