Skip to content

Commit

Permalink
controllers: addition of chained actions
Browse files Browse the repository at this point in the history
Signed-off-by: Harris Tzovanakis <me@drjova.com>
  • Loading branch information
drjova committed Sep 2, 2016
1 parent e09b695 commit c0bc895
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 94 deletions.
148 changes: 75 additions & 73 deletions src/invenio-records-js/controllers/InvenioRecordsCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,78 +155,83 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,
}

/**
* Records actions
* Do a data massage before sending with request
* @memberof InvenioRecordsCtrl
* @function invenioRecordsActions
* @param {Object} evt - The event object.
* @param {String} type - The invenio action type.
* @param {String} method - The invenio request method.
* @param {Object} successCallback - Call function after success.
* @param {Object} errorCallback - Call function after error..
* @function cleanData
*/
function invenioRecordsActions(evt, type, method, successCallback, errorCallback) {
function cleanData() {
var _data = angular.merge({}, {metdata: vm.invenioRecordsModel});
var unwatend = [[null], [{}], '', [undefined]];
angular.forEach(_data, function(value, key) {
angular.forEach(unwatend, function(_value) {
if (angular.equals(_value, value)) {
delete _data[key];
}
});
});
return _data;
}

// Get the endpoints and do the request
getEndpoints().then(
function success() {
var _data = angular.merge({}, vm.invenioRecordsModel);

var unwatend = [[null], [{}], '', [undefined]];
angular.forEach(_data, function(value, key) {
angular.forEach(unwatend, function(_value) {
if (angular.equals(_value, value)) {
delete _data[key];
}
});
});
/**
* Make the API request with the _data payload
* @memberof InvenioRecordsCtrl
* @function makeActionRequest
* @param {String} type - The action type (any existing key from ``links``).
* @param {String} method - The method (POST, PUT, DELETE).
*/
function makeActionRequest(type, method) {
var _data = cleanData();
return InvenioRecordsAPI.request({
url: vm.invenioRecordsEndpoints[type],
method: (method || 'PUT').toUpperCase(),
data: _data,
headers: vm.invenioRecordsArgs.headers || {}
});
}

if (!angular.isUndefined(vm.invenioRecordsEndpoints[type])) {
InvenioRecordsAPI.request({
url: vm.invenioRecordsEndpoints[type],
method: (method || 'PUT').toUpperCase(),
data: {
metadata: _data
},
headers: vm.invenioRecordsArgs.headers || {}
}).then(
successCallback,
errorCallback
);
} else {
errorCallback({
type: 'danger',
data: {
message: 'The action type is not supported.'
}
});
}
},
errorCallback);
/**
* Handle the redirection after a success action if needed
* @memberof InvenioRecordsCtrl
* @function handleActionRedirection
* @param {String} redirect_path - The url to redirect on success.
*/
function handleActionRedirection(redirect_path) {
// Redirect if defined
if (!angular.isUndefined(redirect_path) && redirect_path !== '') {
// Redirect to new location
var _url = redirect_path;
if (redirect_path.substr(0, 1) !== '/' && redirect_path.substr(0, 4) !== 'http') {
// Find the url
_url = vm.invenioRecordsEndpoints[redirect_path];
}
$window.location.href = _url;
}
}

/**
* Action handler
* @memberof InvenioRecordsCtrl
* @function invenioRecordsHandler
* @param {string} type - The action key from ``links`` object.
* @param {string} method - The request method type i.e. GET, POST, PUT.
* @param {string} redirect_path - The url to redirect on success.
* @param {Array} actions - Actions array [[type, method]].
* @param {String} redirect_path - The url to redirect on success.
*/
function invenioRecordsHandler(type, method, redirect_path) {
function invenioRecordsHandler(actions, redirect_path) {

var _actions = (typeof(actions[0]) === 'string') ? [actions] : actions;
/**
* After a successful request
* @memberof invenioRecordsHandler
* @function actionSuccessful
* @param {Object} response - The action request response.
* @param {Object} responses - The promise action request responses.
*/
function actionSuccessful(response) {
function actionSuccessful(responses) {
// NOTE: We keep only the response of the last action!!
var response = responses[responses.length - 1] || {};

$rootScope.$broadcast('invenio.records.alert', {
type: 'success',
data: response.data,
action: type,
});

// Update the endpoints
if (!angular.isUndefined(response.data.links)){
$rootScope.$broadcast(
Expand All @@ -235,19 +240,13 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,
}

// Trigger successful event for action
$rootScope.$broadcast('invenio.records.action.success', type);
$rootScope.$broadcast('invenio.records.action.success', _actions);

// Stop loadig idicator
$rootScope.$broadcast('invenio.records.loading.stop');
if (!angular.isUndefined(redirect_path) && redirect_path !== '') {
// Redirect to new location
var _url = redirect_path;
if (redirect_path.substr(0, 1) !== '/' && redirect_path.substr(0, 4) !== 'http') {
// Find the url
_url = vm.invenioRecordsEndpoints[redirect_path];
}
$window.location.href = _url;
}

// Redirect if defined
handleActionRedirection(redirect_path || undefined);
}
/**
* After an errored request
Expand All @@ -259,7 +258,6 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,
$rootScope.$broadcast('invenio.records.alert', {
type: 'danger',
data: response.data,
action: type
});

if (response.data.status === 400 && response.data.errors) {
Expand Down Expand Up @@ -295,12 +293,20 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,
// Start loading
$rootScope.$broadcast('invenio.records.loading.start');

// Request submission
$scope.$broadcast(
'invenio.records.action',
type,
method,
actionSuccessful,
// Get the endpoints and do the request
getEndpoints().then(
function() {
var promises = [];
angular.forEach(_actions, function(action, index) {
this.push(
makeActionRequest(action[0], action[1])
);
}, promises);
$q.all(promises).then(
actionSuccessful,
actionErrored
);
},
actionErrored
);
}
Expand Down Expand Up @@ -378,7 +384,6 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,
$scope.depositionForm.$setSubmitted();
}
}
// Set the form to $invalid if it's deleted/discarded
}

/**
Expand Down Expand Up @@ -432,9 +437,6 @@ function InvenioRecordsCtrl($scope, $rootScope, $q, $window, $location,

// Local

// When invenio.records action requested
$scope.$on('invenio.records.action', invenioRecordsActions);

// When the module initialized
$scope.$on('invenio.records.init', invenioRecordsInit);

Expand Down Expand Up @@ -476,4 +478,4 @@ InvenioRecordsCtrl.$inject = [
];

angular.module('invenioRecords.controllers')
.controller('InvenioRecordsCtrl', InvenioRecordsCtrl);
.controller('InvenioRecordsCtrl', InvenioRecordsCtrl);
10 changes: 5 additions & 5 deletions src/invenio-records-js/templates/actions.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<div ng-hide="recordsVM.invenioRecordsAlert.type == 'success' && recordsVM.invenioRecordsArgs.templateParams.responseParams[recordsVM.invenioRecordsAlert.action].hide">
<div ng-show="recordsVM.invenioRecordsEndpoints.self">
<ul class="list-inline text-right">
<li><button ng-disabled="depositionForm.$invalid || depositionForm.$prestine || recordsVM.invenioRecordsLoading" class="btn btn-default" ng-click="recordsVM.actionHandler('self', 'PUT')">Save</button></li>
<li><button ng-disabled="depositionForm.$invalid || depositionForm.$dirty || recordsVM.invenioRecordsLoading" class="btn btn-success" ng-click="recordsVM.actionHandler('publish', 'POST')">Publish</button></li>
<li><button ng-disabled="recordsVM.invenioRecordsLoading" ng-hide="!recordsVM.invenioRecordsEndpoints.discard" class="btn btn-danger" ng-click="recordsVM.actionHandler('discard', 'PUT')">Discard</button></li>
<li><button ng-disabled="depositionForm.$invalid || depositionForm.$prestine || recordsVM.invenioRecordsLoading" class="btn btn-default" ng-click="recordsVM.actionHandler(['self', 'PUT'])">Save</button></li>
<li><button ng-disabled="depositionForm.$invalid || depositionForm.$dirty || recordsVM.invenioRecordsLoading" class="btn btn-success" ng-click="recordsVM.actionHandler(['publish', 'POST'])">Publish</button></li>
<li><button ng-disabled="recordsVM.invenioRecordsLoading" ng-hide="!recordsVM.invenioRecordsEndpoints.discard" class="btn btn-danger" ng-click="recordsVM.actionHandler(['discard', 'PUT'])">Discard</button></li>
</ul>
</div>

<div ng-show="!recordsVM.invenioRecordsEndpoints.self">
<ul class="list-inline text-right">
<li><button ng-disabled="depositionForm.$invalid || recordsVM.invenioRecordsLoading" class="btn btn-default" ng-click="recordsVM.actionHandler('self', 'PUT')">Save</button></li>
<li><button ng-disabled="recordsVM.invenioRecordsLoading" ng-hide="!recordsVM.invenioRecordsEndpoints.initialization" class="btn btn-danger" ng-click="recordsVM.actionHandler('self', 'DELETE')">Delete</button></li>
<li><button ng-disabled="depositionForm.$invalid || recordsVM.invenioRecordsLoading" class="btn btn-default" ng-click="recordsVM.actionHandler(['self', 'PUT'])">Save</button></li>
<li><button ng-disabled="recordsVM.invenioRecordsLoading" ng-hide="!recordsVM.invenioRecordsEndpoints.initialization" class="btn btn-danger" ng-click="recordsVM.actionHandler(['self', 'DELETE'])">Delete</button></li>
</ul>
</div>
</div>
119 changes: 103 additions & 16 deletions test/e2e/invenio-records-js/invenioRecordsActionsSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,6 @@ describe('testing directive invenio-records-actions', function() {

//Should trigger init
expect(spy.calledWith('invenio.records.init')).to.be.true;
//Should trigger action
expect(spy.calledWith('invenio.records.action')).to.be.true;
//Should trigger endpoints updated
expect(spy.calledWith('invenio.records.endpoints.updated')).to.be.true;
// Should trigger action success
Expand All @@ -214,20 +212,6 @@ describe('testing directive invenio-records-actions', function() {
// Flash responses to trigger the events
$httpBackend.flush();

scope.recordsVM.actionHandler('The Punisher Action');

// Digest
scope.$digest();

// Expect error
var error = 'The action type is not supported.';

// Flush timeout
$timeout.flush();

// Expect the message to be
expect(scope.recordsVM.invenioRecordsAlert.data.message).to.be.equal(error);

// Check the validation
scope.recordsVM.removeValidationMessage(
angular.noop, {
Expand Down Expand Up @@ -257,6 +241,7 @@ describe('testing directive invenio-records-actions', function() {
expect(spy.calledWith('schemaForm.error.hello')).to.be.false;
});


it('should trigger action event for delete', function() {
// Spy the broadcast
var spy = sinon.spy($rootScope, '$broadcast');
Expand Down Expand Up @@ -412,4 +397,106 @@ describe('testing directive invenio-records-actions', function() {
// Should trigger an event
spy.should.have.been.called.twice;
});

it('should trigger successful chained actions', function() {
// Spy the broadcast
var spy = sinon.spy($rootScope, '$broadcast');
var links = {
links: {
harley: '/harley/quinn/wins',
jessica: '/jessica/jones/wins',
kilgrave: '/kilgrave/wins',
jocker: '/jocker/wins',
}
}
var batman_link = {
links: {
batman: '/bruce/wayne'
}
}
// Request expected
$httpBackend.whenPOST('jessica jones://herley/quinn').respond(200, links);
$httpBackend.whenPOST('/harley/quinn/wins').respond(200, {});
$httpBackend.whenPUT('/jessica/jones/wins').respond(200, batman_link);
// Complile&Digest here to catch the event
// The directive's template
template = '<invenio-records ' +
'initialization="jessica jones://herley/quinn" ' +
'form="/example/static/json/form.json" ' +
'record=\'{"a": "", "b": "c"}\' ' +
'schema="/example/static/json/schema.json"> ' +
'<invenio-records-actions ' +
'template="src/invenio-records-js/templates/actions.html"> '+
'</invenio-records-actions>'+
'</invenio-records>';
// Compile
template = $compile(template)(scope);
// Digest
scope.$digest();

// Flash responses to trigger the events
$httpBackend.flush();

// Do a chained action
scope.recordsVM.actionHandler([
['harley', 'POST'],
['jessica', 'PUT'],
]);

// Flash responses to trigger the events
$httpBackend.flush();
// Expected the new links to be added
expect(scope.recordsVM.invenioRecordsEndpoints.batman).to.be.equal('/bruce/wayne');
});

it('should trigger errrored chained actions', function() {
// Spy the broadcast
var spy = sinon.spy($rootScope, '$broadcast');
var links = {
links: {
kilgrave: '/kilgrave/wins',
jocker: '/jocker/wins',
}
};
var message = {
message: 'Bring Bruce Wayne back!'
}
// Request expected
$httpBackend.whenPOST('jessica jones://herley/quinn').respond(200, links);
$httpBackend.whenPUT('/kilgrave/wins').respond(200, {});
$httpBackend.whenPOST('/jocker/wins').respond(400, message);
// Complile&Digest here to catch the event
// The directive's template
template = '<invenio-records ' +
'initialization="jessica jones://herley/quinn" ' +
'form="/example/static/json/form.json" ' +
'record=\'{"a": "", "b": "c"}\' ' +
'schema="/example/static/json/schema.json"> ' +
'<invenio-records-actions ' +
'template="src/invenio-records-js/templates/actions.html"> '+
'</invenio-records-actions>'+
'</invenio-records>';
// Compile
template = $compile(template)(scope);
// Digest
scope.$digest();

// Flash responses to trigger the events
$httpBackend.flush();

// Do a chained action
scope.recordsVM.actionHandler([
['kilgrave', 'PUT'],
['jocker', 'POST'],
]);

// Flash responses to trigger the events
$httpBackend.flush();
// Flash the timeout
$timeout.flush();
// Force digest
scope.$digest();
// Expected the new links to be added
expect(scope.recordsVM.invenioRecordsAlert.data.message).to.be.equal(message.message);
});
});

0 comments on commit c0bc895

Please sign in to comment.