define('application/datasources/kpn', [
'rofl/datasources/abstract',
'rofl/datasources/adapter/rest',
'antie/application',
'rofl/models/api/abstract',
'rofl/lib/promise',
'rofl/lib/utils',
'rofl/logger',
'application/managers/session'
], function (
Abstract,
RESTAdapter,
Application,
ModelInterface,
Promise,
Utils,
Logger,
SessionManager
) {
'use strict';
var app = Application.getCurrentApplication(),
device = app.getDevice(),
sessionManager = SessionManager.getInstance(),
excludedModels = [
'session',
'parental'
],
ErrorCodes = {
USER_HAS_NO_RIGHTS: '403-10100'
},
isExcluded;
isExcluded = function (modelReference) {
if (excludedModels.indexOf(modelReference) >= 0) {
return true;
}
return false;
};
return Abstract.extend({
init: function (config) {
this.setModelPath(config.modelPath);
this.setApiEndpoint(config.endpoint.url);
this.setAdapter(new RESTAdapter());
},
/**
* Returns a Promise with an instance of the Model being requested.
*
* @throws {Error} When the fetched model module isn't an instance of ModelInterface.
* @param {string|ModelInterface} modelReference - Reference to the model or instance.
* @param {Object} opts - Options object.
* @param {Object} opts.params - Parameters object which is used in the resolveEndpoint method of the requested Model.
* @param {Object} [opts.data={}] - Data to send as payload.
* @param {*} [retryFulFilled] - Resolve function for repeating request after failure.
* @param {*} [retryRejected] - Reject function for repeating request after failure.
* @returns {Promise} Returns a Promise.
*/
create: function (modelReference, opts, retryFulFilled, retryRejected) {
var self = this;
return new Promise(function (onFulFilled, onRejected) {
self.fetchModel(modelReference).then(function (model) {
var url;
if (!(model instanceof ModelInterface)) {
throw new Error('Model should be an instance of ModelInterface');
}
url = self.getApiEndpoint() + model.resolveCreateEndpoint(opts.params);
model.transformToCreate(opts.data).then(function (data) {
opts.data = data;
return self._adapter.create(url, opts);
}).then(function (response) {
if (model.validateCreateResponse(response)) {
if (retryFulFilled) {
return retryFulFilled(model.transformFromCreate(response));
}
return onFulFilled(model.transformFromCreate(response));
}
if (!retryFulFilled && !isExcluded(modelReference)) {
Logger.onApiError(url, 'POST', '200', response.message);
if (response.errorDescription === ErrorCodes.USER_HAS_NO_RIGHTS) {
return sessionManager.refreshToken()
.then(function () {
return self.create(modelReference, opts, onFulFilled, onRejected);
});
}
// do retry once
return self.create(modelReference, opts, onFulFilled, onRejected);
}
if (retryRejected) {
return retryRejected(response || 'Invalid response from API');
}
return onRejected(response || 'Invalid response from API');
});
});
});
},
/**
* Returns a Promise with an instance of the Model being requested.
*
* @throws {Error} When the fetched model module isn't an instance of
* ModelInterface.
* @param {string|ModelInterface} modelReference - Reference to the model or instance.
* @param {Object} [opts={}] - Options object.
* @param {Object} [opts.params={}] - Parameters object which is used
* for the cache key and in the
* resolveEndpoint method of the
* requested Model.
* @param {Object} [opts.headers={}] - Headers object which is used for
* the cache key.
* @param {boolean} [opts.notFromCache] - Whether it should get the
* model from cache if possible.
* @param {*} [retryFulFilled] - Resolve function for repeating request after failure.
* @param {*} [retryRejected] - Reject function for repeating request after failure.
* @returns {Promise} Returns a Promise.
*/
read: function (modelReference, opts, retryFulFilled, retryRejected) {
var self = this,
cache,
cacheKey;
opts = opts || {};
// Only check for cache if we got a textual reference
if (Utils.isString(modelReference)) {
// Check for session cache
cacheKey = modelReference + device.encodeJson(opts.params || {}) + device.encodeJson(opts.headers || {});
cache = self.getCache(cacheKey);
if (opts.notFromCache !== true && cache) {
return Promise.resolve(cache);
}
}
// Try loading model response
return new Promise(function (onFulFilled, onRejected) {
self.fetchModel(modelReference).then(function (model) {
var responsePromise,
url,
transformedResponse;
if (!(model instanceof ModelInterface)) {
throw new Error('Model should be an instance of ModelInterface');
}
if (model.hasLocalData(opts)) {
// Wrap the local data in a Promise
responsePromise = Promise.resolve(model.getLocalData(opts));
} else {
// Load the response from a remote
url = self.getApiEndpoint() + model.resolveReadEndpoint(opts.params);
responsePromise = self._adapter.read(url, opts);
}
// Chain on either the local data or remote response
responsePromise.then(function (response) {
if (model.validateReadResponse(response)) {
transformedResponse = model.transformFromRead(response);
if (retryFulFilled) {
retryFulFilled(transformedResponse);
} else {
onFulFilled(transformedResponse);
}
return transformedResponse;
}
if (!retryFulFilled && !isExcluded(modelReference) && (!Utils.isFunction(model.shouldRetry) || (Utils.isFunction(model.shouldRetry) && model.shouldRetry(response)))) {
Logger.onApiError(url, 'GET', '200', response.message);
if (response.errorDescription === ErrorCodes.USER_HAS_NO_RIGHTS) {
return sessionManager.refreshToken()
.then(function () {
return self.read(modelReference, opts, onFulFilled, onRejected);
});
}
// do retry once
return self.read(modelReference, opts, onFulFilled, onRejected);
}
if (retryRejected) {
retryRejected(response || 'Invalid response from API');
} else {
onRejected(response || 'Invalid response from API');
}
return Promise.reject();
}).then(function (transformedData) {
if (model.isCacheable() && cacheKey) {
self.setCache(cacheKey, transformedData);
}
return transformedData;
});
});
});
},
/**
* Returns a Promise with an instance of the Model being requested.
*
* @throws {Error} When the fetched model module isn't an instance of ModelInterface.
* @param {string|ModelInterface} modelReference - Reference to the model or instance.
* @param {Object} opts - Options object.
* @param {Object} opts.params - Parameters object which is used in the
* resolveEndpoint method of the requested Model.
* @param {Object} [opts.data={}] - Data to send as payload.
* @param {*} [retryFulFilled] - Resolve function for repeating request after failure.
* @param {*} [retryRejected] - Reject function for repeating request after failure.
* @returns {Promise} Returns a Promise.
*/
update: function (modelReference, opts, retryFulFilled, retryRejected) {
var self = this;
return new Promise(function (onFulFilled, onRejected) {
self.fetchModel(modelReference).then(function (model) {
var url,
transformedResponse;
if (!(model instanceof ModelInterface)) {
throw new Error('Model should be an instance of ModelInterface');
}
url = self.getApiEndpoint() + model.resolveUpdateEndpoint(opts.params);
model.transformToUpdate(opts.data).then(function (data) {
opts.data = data;
return self._adapter.update(url, opts);
}).then(function (response) {
if (model.validateUpdateResponse(response)) {
transformedResponse = model.transformFromUpdate(response);
if (retryFulFilled) {
retryFulFilled(transformedResponse);
} else {
onFulFilled(transformedResponse);
}
return transformedResponse;
}
if (!retryFulFilled && !isExcluded(modelReference)) {
Logger.onApiError(url, 'PUT', '200', response.message);
if (response.errorDescription === ErrorCodes.USER_HAS_NO_RIGHTS) {
return sessionManager.refreshToken()
.then(function () {
return self.update(modelReference, opts, onFulFilled, onRejected);
});
}
// do retry once
return self.update(modelReference, opts, onFulFilled, onRejected);
}
if (retryRejected) {
return retryRejected(response || 'Invalid response from API');
}
onRejected(response || 'Invalid response from API');
});
});
});
},
/**
* Returns a Promise with an instance of the Model being requested.
*
* @throws {Error} When the fetched model module isn't an instance of ModelInterface.
* @param {string|ModelInterface} modelReference - Reference to the model or instance.
* @param {Object} opts - Options object.
* @param {Object} opts.params - Parameters object which is used in the
* resolveEndpoint method of the requested Model.
* @param {*} [retryFulFilled] - Resolve function for repeating request after failure.
* @param {*} [retryRejected] - Reject function for repeating request after failure.
* @returns {Promise} Returns a Promise.
*/
destroy: function (modelReference, opts, retryFulFilled, retryRejected) {
var self = this,
transformedResponse;
return new Promise(function (onFulFilled, onRejected) {
self.fetchModel(modelReference).then(function (model) {
var url;
if (!(model instanceof ModelInterface)) {
throw new Error('Model should be an instance of ModelInterface');
}
url = self.getApiEndpoint() + model.resolveDestroyEndpoint(opts.params);
self._adapter.destroy(url, opts).then(function (response) {
if (model.validateDestroyResponse(response)) {
transformedResponse = model.transformFromDestroy(response);
if (retryFulFilled) {
retryFulFilled(transformedResponse);
} else {
onFulFilled(transformedResponse);
}
return transformedResponse;
}
if (!retryFulFilled && !isExcluded(modelReference)) {
Logger.onApiError(url, 'DELETE', '200', response.message);
if (response.errorDescription === ErrorCodes.USER_HAS_NO_RIGHTS) {
return sessionManager.refreshToken()
.then(function () {
return self.destroy(modelReference, opts, onFulFilled, onRejected);
});
}
// do retry once
return self.destroy(modelReference, opts, onFulFilled, onRejected);
}
if (retryRejected) {
return retryRejected(response || 'Invalid response from API');
}
return onRejected(response || 'Invalid response from API');
});
});
});
}
});
});