Notification support given no rating results
commit
f38d0bf96c
|
@ -49,7 +49,8 @@
|
||||||
"remote": {
|
"remote": {
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"domain": ""
|
"domain": ""
|
||||||
}
|
},
|
||||||
|
"noResultsUrl": ""
|
||||||
},
|
},
|
||||||
"c1export": {
|
"c1export": {
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
|
|
|
@ -61,7 +61,7 @@ module.exports = Class( 'QuoteDataApi' )
|
||||||
if ( !( Class.isA( DataApi, dapi ) ) )
|
if ( !( Class.isA( DataApi, dapi ) ) )
|
||||||
{
|
{
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
'Expected object of type DataApi; given: ' + data_api
|
'Expected object of type DataApi; given: ' + dapi
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,14 +139,33 @@ module.exports = Class( 'HttpDataApi' )
|
||||||
|
|
||||||
this._validateDataType( data );
|
this._validateDataType( data );
|
||||||
|
|
||||||
this._impl.requestData(
|
this.requestData( this._url, this._method, data, callback );
|
||||||
this._url,
|
|
||||||
this._method,
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request data from underlying HttpImpl
|
||||||
|
*
|
||||||
|
* Subtypes may override this method to alter any aspect of the request
|
||||||
|
* before sending.
|
||||||
|
*
|
||||||
|
* @param {string} url destination URL
|
||||||
|
* @param {string} method RFC-2616-compliant HTTP method
|
||||||
|
* @param {Object|string} data request params
|
||||||
|
* @param {function(?Error, ?string)} callback server response callback
|
||||||
|
*
|
||||||
|
* @return {HttpDataApi} self
|
||||||
|
*/
|
||||||
|
'virtual protected requestData'( url, method, data, callback )
|
||||||
|
{
|
||||||
|
return this._impl.requestData(
|
||||||
|
url,
|
||||||
|
method,
|
||||||
this.encodeData( data ),
|
this.encodeData( data ),
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/**
|
||||||
|
* Provide data as part of URL
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework
|
||||||
|
*
|
||||||
|
* Liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Trait } = require( 'easejs' );
|
||||||
|
const HttpDataApi = require( './HttpDataApi' );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place fields from given data in the URL
|
||||||
|
*
|
||||||
|
* All remaining fields are passed to the underlying supertype.
|
||||||
|
*/
|
||||||
|
module.exports = Trait( 'HttpDataApiUrlData' )
|
||||||
|
.extend( HttpDataApi,
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fields to take from data and place in URL
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
'private _fields': [],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize with URL field list
|
||||||
|
*
|
||||||
|
* @param {Array<string>} fields list of fields to include in URL
|
||||||
|
*/
|
||||||
|
__mixin( fields )
|
||||||
|
{
|
||||||
|
this._fields = fields;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenate chosen fields with URL
|
||||||
|
*
|
||||||
|
* The previously specified fields will have their values delimited by '/'
|
||||||
|
* and will be concatenated with the URL. All used fields in DATA will be
|
||||||
|
* removed before being passed to the supertype. METHOD and CALLBACK are
|
||||||
|
* proxied as-is.
|
||||||
|
*
|
||||||
|
* @param {string} url destination URL
|
||||||
|
* @param {string} method RFC-2616-compliant HTTP method
|
||||||
|
* @param {Object|string} data request params
|
||||||
|
* @param {function(Error, Object)} callback server response callback
|
||||||
|
*
|
||||||
|
* @return {HttpImpl} self
|
||||||
|
*/
|
||||||
|
'override public requestData'( url, method, data, callback )
|
||||||
|
{
|
||||||
|
const [ values, filtered_data ] = this._getFieldValues( data );
|
||||||
|
|
||||||
|
const params = values.map( ( [ , value ] ) => value );
|
||||||
|
const missing = values.filter( ( [ , value ] ) => value === undefined );
|
||||||
|
|
||||||
|
if ( missing.length > 0 )
|
||||||
|
{
|
||||||
|
callback(
|
||||||
|
Error(
|
||||||
|
"Missing URL parameters: " +
|
||||||
|
missing.map( ( [ field ] ) => field ).join( ", " )
|
||||||
|
),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const built_url = ( params.length > 0 )
|
||||||
|
? url + '/' + params.join( '/' )
|
||||||
|
: url;
|
||||||
|
|
||||||
|
return this.__super( built_url, method, filtered_data, callback );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associate fields with their respective values from DATA
|
||||||
|
*
|
||||||
|
* The returned values are of the form `[ [ field, value ], ... ]`.
|
||||||
|
* The returned data object is a copy of the original and is stripped
|
||||||
|
* of the respective fields.
|
||||||
|
*
|
||||||
|
* @param {Object} data source data
|
||||||
|
*
|
||||||
|
* @return {Array} values and copy of data stripped of those fields
|
||||||
|
*/
|
||||||
|
'private _getFieldValues'( data )
|
||||||
|
{
|
||||||
|
const fieldset = new Set( this._fields );
|
||||||
|
const values = this._fields.map( field => [ field, data[ field ] ] );
|
||||||
|
|
||||||
|
// copy of data with fields stripped
|
||||||
|
const new_data = Object.keys( data ).reduce( ( dest, key ) =>
|
||||||
|
{
|
||||||
|
if ( fieldset.has( key ) )
|
||||||
|
{
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[ key ] = data[ key ];
|
||||||
|
return dest;
|
||||||
|
}, {} );
|
||||||
|
|
||||||
|
return [ values, new_data ];
|
||||||
|
},
|
||||||
|
} );
|
|
@ -87,7 +87,7 @@ module.exports = Class( 'NodeHttpImpl' )
|
||||||
*
|
*
|
||||||
* @return {HttpImpl} self
|
* @return {HttpImpl} self
|
||||||
*/
|
*/
|
||||||
'public requestData'( url, method, data, callback )
|
'virtual public requestData'( url, method, data, callback )
|
||||||
{
|
{
|
||||||
const options = this._parseUrl( url );
|
const options = this._parseUrl( url );
|
||||||
const protocol = options.protocol.replace( /:$/, '' );
|
const protocol = options.protocol.replace( /:$/, '' );
|
||||||
|
|
|
@ -37,7 +37,7 @@ module.exports = Trait( 'SpoofedNodeHttpImpl' )
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Session to spoof
|
* Session to spoof
|
||||||
* @type {UserSession}
|
* @type {UserRequest}
|
||||||
*/
|
*/
|
||||||
'private _request': null,
|
'private _request': null,
|
||||||
|
|
||||||
|
@ -45,11 +45,11 @@ module.exports = Trait( 'SpoofedNodeHttpImpl' )
|
||||||
/**
|
/**
|
||||||
* Use session for spoofing requests
|
* Use session for spoofing requests
|
||||||
*
|
*
|
||||||
* @param {UserSession} session session to spoof
|
* @param {UserRequest} request session to spoof
|
||||||
*/
|
*/
|
||||||
__mixin( session )
|
__mixin( request )
|
||||||
{
|
{
|
||||||
this._request = session;
|
this._request = request;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ module.exports = Class( 'XhrHttpImpl' )
|
||||||
*
|
*
|
||||||
* @return {HttpImpl} self
|
* @return {HttpImpl} self
|
||||||
*/
|
*/
|
||||||
'public requestData': function( url, method, data, callback )
|
'virtual public requestData': function( url, method, data, callback )
|
||||||
{
|
{
|
||||||
if ( typeof data !== 'string' )
|
if ( typeof data !== 'string' )
|
||||||
{
|
{
|
||||||
|
|
|
@ -113,7 +113,8 @@ module.exports = AbstractClass( 'Daemon',
|
||||||
this._createDebugLog(),
|
this._createDebugLog(),
|
||||||
this._createAccessLog(),
|
this._createAccessLog(),
|
||||||
this._conf.get( 'skey' ),
|
this._conf.get( 'skey' ),
|
||||||
] ).then( ([ debug_log, access_log, skey ]) =>
|
this._conf.get( 'services.rating.noResultsUrl' ),
|
||||||
|
] ).then( ([ debug_log, access_log, skey, no_results_url ]) =>
|
||||||
{
|
{
|
||||||
this._debugLog = debug_log;
|
this._debugLog = debug_log;
|
||||||
this._accessLog = access_log;
|
this._accessLog = access_log;
|
||||||
|
@ -122,7 +123,7 @@ module.exports = AbstractClass( 'Daemon',
|
||||||
this._rater = liza.server.rater.ProcessManager();
|
this._rater = liza.server.rater.ProcessManager();
|
||||||
this._encService = this.getEncryptionService();
|
this._encService = this.getEncryptionService();
|
||||||
this._memcache = this.getMemcacheClient();
|
this._memcache = this.getMemcacheClient();
|
||||||
this._routers = this.getRouters( skey );
|
this._routers = this.getRouters( skey, no_results_url );
|
||||||
} )
|
} )
|
||||||
.then( () => this._startDaemon() );
|
.then( () => this._startDaemon() );
|
||||||
},
|
},
|
||||||
|
@ -182,10 +183,12 @@ module.exports = AbstractClass( 'Daemon',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
'protected getProgramController': function( skey )
|
'protected getProgramController': function( skey, no_results_url )
|
||||||
{
|
{
|
||||||
var controller = require( './controller' );
|
var controller = require( './controller' );
|
||||||
|
|
||||||
controller.rater = this._rater;
|
controller.rater = this._rater;
|
||||||
|
controller.no_results_url = no_results_url || "";
|
||||||
|
|
||||||
if ( skey )
|
if ( skey )
|
||||||
{
|
{
|
||||||
|
@ -276,10 +279,10 @@ module.exports = AbstractClass( 'Daemon',
|
||||||
'abstract protected getEncryptionService': [],
|
'abstract protected getEncryptionService': [],
|
||||||
|
|
||||||
|
|
||||||
'protected getRouters': function( skey )
|
'protected getRouters': function( skey, no_results_url )
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
this.getProgramController( skey ),
|
this.getProgramController( skey, no_results_url ),
|
||||||
this.getScriptsController(),
|
this.getScriptsController(),
|
||||||
this.getClientErrorController(),
|
this.getClientErrorController(),
|
||||||
];
|
];
|
||||||
|
|
|
@ -43,6 +43,12 @@ const {
|
||||||
},
|
},
|
||||||
|
|
||||||
dapi: {
|
dapi: {
|
||||||
|
http: {
|
||||||
|
HttpDataApi,
|
||||||
|
HttpDataApiUrlData,
|
||||||
|
NodeHttpImpl,
|
||||||
|
SpoofedNodeHttpImpl,
|
||||||
|
},
|
||||||
DataApiFactory,
|
DataApiFactory,
|
||||||
DataApiManager,
|
DataApiManager,
|
||||||
},
|
},
|
||||||
|
@ -69,6 +75,7 @@ const {
|
||||||
},
|
},
|
||||||
|
|
||||||
RatingService,
|
RatingService,
|
||||||
|
RatingServiceSubmitNotify,
|
||||||
TokenedService,
|
TokenedService,
|
||||||
TokenDao,
|
TokenDao,
|
||||||
},
|
},
|
||||||
|
@ -95,6 +102,7 @@ var sflag = {};
|
||||||
// TODO: kluge to get liza somewhat decoupled from lovullo (rating module)
|
// TODO: kluge to get liza somewhat decoupled from lovullo (rating module)
|
||||||
exports.rater = {};
|
exports.rater = {};
|
||||||
exports.skey = "";
|
exports.skey = "";
|
||||||
|
exports.no_results_url = "";
|
||||||
|
|
||||||
|
|
||||||
exports.init = function( logger, enc_service, conf )
|
exports.init = function( logger, enc_service, conf )
|
||||||
|
@ -118,7 +126,31 @@ exports.init = function( logger, enc_service, conf )
|
||||||
server_cache = _createCache( server );
|
server_cache = _createCache( server );
|
||||||
server.init( server_cache, exports.rater );
|
server.init( server_cache, exports.rater );
|
||||||
|
|
||||||
rating_service = RatingService( logger, dao, server, exports.rater );
|
// TODO: do none of this if no_results_url is provided
|
||||||
|
const createSubmitDapi = request => HttpDataApi
|
||||||
|
.use( HttpDataApiUrlData( [ 'quote_id' ] ) )
|
||||||
|
(
|
||||||
|
exports.no_results_url,
|
||||||
|
'PUT',
|
||||||
|
|
||||||
|
NodeHttpImpl
|
||||||
|
.use( SpoofedNodeHttpImpl( request ) )
|
||||||
|
(
|
||||||
|
{
|
||||||
|
http: require( 'http' ),
|
||||||
|
https: require( 'https' ),
|
||||||
|
},
|
||||||
|
require( 'url' ),
|
||||||
|
this._origin
|
||||||
|
),
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
rating_service = RatingService
|
||||||
|
.use( RatingServiceSubmitNotify( createSubmitDapi, dao ) )
|
||||||
|
(
|
||||||
|
logger, dao, server, exports.rater
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: exports.init needs to support callbacks; this will work, but
|
// TODO: exports.init needs to support callbacks; this will work, but
|
||||||
// only because it's unlikely that we'll get a request within
|
// only because it's unlikely that we'll get a request within
|
||||||
|
|
|
@ -783,5 +783,70 @@ module.exports = Class( 'MongoServerDao' )
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
} );
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set arbitrary data on a document
|
||||||
|
*
|
||||||
|
* @param {number} qid quote/document id
|
||||||
|
* @param {string} key field key
|
||||||
|
* @param {*} value field value
|
||||||
|
* @param {function(?Error)} callback completion callback
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'public setDocumentField'( qid, key, value, callback )
|
||||||
|
{
|
||||||
|
this._collection.update(
|
||||||
|
{ id: qid },
|
||||||
|
{ '$set': { [key]: value } },
|
||||||
|
|
||||||
|
// create record if it does not yet exist
|
||||||
|
{ upsert: true },
|
||||||
|
|
||||||
|
// on complete
|
||||||
|
function( err )
|
||||||
|
{
|
||||||
|
callback && callback( err );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve arbitrary data on a document
|
||||||
|
*
|
||||||
|
* @param {number} qid quote/document id
|
||||||
|
* @param {string} key field key
|
||||||
|
* @param {function(?Error)} callback completion callback
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'public getDocumentField'( qid, key, callback )
|
||||||
|
{
|
||||||
|
this._collection.find(
|
||||||
|
{ id: qid },
|
||||||
|
{ limit: 1 },
|
||||||
|
function( err, cursor )
|
||||||
|
{
|
||||||
|
if ( err !== null )
|
||||||
|
{
|
||||||
|
callback( err, null );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.toArray( function( err, data )
|
||||||
|
{
|
||||||
|
if ( err !== null )
|
||||||
|
{
|
||||||
|
callback( err, null );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback( null, data[ key ] );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
|
|
@ -154,8 +154,8 @@ module.exports = Class( 'RatingService',
|
||||||
{
|
{
|
||||||
actions = actions || [];
|
actions = actions || [];
|
||||||
|
|
||||||
_self._postProcessRaterData(
|
_self.postProcessRaterData(
|
||||||
rate_data, actions, program, quote
|
request, rate_data, actions, program, quote
|
||||||
);
|
);
|
||||||
|
|
||||||
const class_dest = {};
|
const class_dest = {};
|
||||||
|
@ -244,6 +244,7 @@ module.exports = Class( 'RatingService',
|
||||||
/**
|
/**
|
||||||
* Process rater data returned from a rater
|
* Process rater data returned from a rater
|
||||||
*
|
*
|
||||||
|
* @param {UserRequest} request user request to satisfy
|
||||||
* @param {Object} data rating data returned
|
* @param {Object} data rating data returned
|
||||||
* @param {Array} actions actions to send to client
|
* @param {Array} actions actions to send to client
|
||||||
* @param {Program} program program used to perform rating
|
* @param {Program} program program used to perform rating
|
||||||
|
@ -251,7 +252,9 @@ module.exports = Class( 'RatingService',
|
||||||
*
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
_postProcessRaterData: function( data, actions, program, quote )
|
'virtual protected postProcessRaterData': function(
|
||||||
|
request, data, actions, program, quote
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var meta = data._cmpdata || {};
|
var meta = data._cmpdata || {};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* Notification on all submit
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of liza.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Trait } = require( 'easejs' );
|
||||||
|
const DslRaterContext = require( '../rater/DslRaterContext' )
|
||||||
|
const RatingService = require( './RatingService' );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers DataApi when no results are available
|
||||||
|
*
|
||||||
|
* This information is currently stored in `__prem_avail_count`. In the
|
||||||
|
* future, it may be worth accepting a parameter to configure this at
|
||||||
|
* runtime.
|
||||||
|
*
|
||||||
|
* Notification status will persist using the provided DAO. The next time
|
||||||
|
* such a notification is requested, it will only occur if the flag is not
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
module.exports = Trait( 'RatingServiceSubmitNotify' )
|
||||||
|
.extend( RatingService,
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Function returning DataApi to trigger
|
||||||
|
* @type {Function(UserSession):DataApi}
|
||||||
|
*/
|
||||||
|
'private _dapif': null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data store for notification flag
|
||||||
|
* @type {ServerDao}
|
||||||
|
*/
|
||||||
|
'private _notifyDao': null,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize mixin with DataApi to trigger
|
||||||
|
*
|
||||||
|
* @param {Function(UserSession):DataApi} dapif Function producing DataApi
|
||||||
|
* @param {ServerDao} dao store for notification flag
|
||||||
|
*/
|
||||||
|
__mixin( dapif, dao )
|
||||||
|
{
|
||||||
|
this._dapif = dapif;
|
||||||
|
this._notifyDao = dao;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger previously provided DataApi when no results are available
|
||||||
|
*
|
||||||
|
* Result count is determined by DATA.__prem_avail_count.
|
||||||
|
*
|
||||||
|
* @param {UserRequest} request user request
|
||||||
|
* @param {Object} data rating data returned
|
||||||
|
* @param {Array} actions actions to send to client
|
||||||
|
* @param {Program} program program used to perform rating
|
||||||
|
* @param {Quote} quote quote used for rating
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'override protected postProcessRaterData'(
|
||||||
|
request, data, actions, program, quote
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const quote_id = quote.getId();
|
||||||
|
const avail = ( data.__prem_avail_count || [ 0 ] )[ 0 ];
|
||||||
|
|
||||||
|
if ( avail === 0 )
|
||||||
|
{
|
||||||
|
this._getNotifyState( quote_id, notified =>
|
||||||
|
{
|
||||||
|
if ( notified === true )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dapif( request )
|
||||||
|
.request( { quote_id: quote_id }, () => {} );
|
||||||
|
|
||||||
|
this._setNotified( quote_id );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__super( request, data, actions, program, quote );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of notification flag
|
||||||
|
*
|
||||||
|
* @param {number} quote_id id of quote
|
||||||
|
* @param {function(boolean)} callback callback to call when complete
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'private _getNotifyState'( quote_id, callback )
|
||||||
|
{
|
||||||
|
this._notifyDao.getDocumentField(
|
||||||
|
quote_id,
|
||||||
|
'submitNotified',
|
||||||
|
( err, value ) => callback( value )
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set notification flag
|
||||||
|
*
|
||||||
|
* @param {number} quote_id id of quote
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'private _setNotified'( quote_id )
|
||||||
|
{
|
||||||
|
this._notifyDao.setDocumentField(
|
||||||
|
quote_id, 'submitNotified', true
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} );
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* Tests RatingService
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
|
||||||
|
exports.getStubs = function()
|
||||||
|
{
|
||||||
|
const program_id = 'foo';
|
||||||
|
const program = {
|
||||||
|
getId: () => program_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
// rate reply
|
||||||
|
const stub_rate_data = {};
|
||||||
|
|
||||||
|
const rater = {
|
||||||
|
rate: ( quote, session, indv, callback ) => callback( stub_rate_data ),
|
||||||
|
};
|
||||||
|
|
||||||
|
const raters = {
|
||||||
|
byId: () => rater,
|
||||||
|
};
|
||||||
|
|
||||||
|
const logger = {
|
||||||
|
log: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const server = {
|
||||||
|
sendResponse: () => {},
|
||||||
|
sendError: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const dao = {
|
||||||
|
mergeBucket: () => {},
|
||||||
|
saveQuoteClasses: () => {},
|
||||||
|
setWorksheets: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const session = {
|
||||||
|
isInternal: () => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
getSession: () => session,
|
||||||
|
getSessionIdName: () => {},
|
||||||
|
};
|
||||||
|
const response = {};
|
||||||
|
|
||||||
|
const quote = {
|
||||||
|
getProgramId: () => program_id,
|
||||||
|
getProgram: () => program,
|
||||||
|
getId: () => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
program: program,
|
||||||
|
stub_rate_data: stub_rate_data,
|
||||||
|
rater: rater,
|
||||||
|
raters: raters,
|
||||||
|
logger: logger,
|
||||||
|
server: server,
|
||||||
|
dao: dao,
|
||||||
|
session: session,
|
||||||
|
request: request,
|
||||||
|
response: response,
|
||||||
|
quote: quote,
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* Tests HttpDataApiUrlData
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Class } = require( 'easejs' );
|
||||||
|
const { expect } = require( 'chai' );
|
||||||
|
|
||||||
|
const {
|
||||||
|
dapi: {
|
||||||
|
http: {
|
||||||
|
HttpDataApi,
|
||||||
|
HttpImpl,
|
||||||
|
HttpDataApiUrlData: Sut,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = require( '../../../' );
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'HttpDataApiUrlData', () =>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
{
|
||||||
|
fields: [],
|
||||||
|
data: {
|
||||||
|
foo: "foodata",
|
||||||
|
bar: "bardata",
|
||||||
|
},
|
||||||
|
base_url: "base",
|
||||||
|
after_data: "foo=foodata&bar=bardata",
|
||||||
|
expected: "base",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fields: [ 'foo', 'bar' ],
|
||||||
|
data: {
|
||||||
|
foo: "foodata",
|
||||||
|
bar: "bardata",
|
||||||
|
baz: "shouldnotuse",
|
||||||
|
},
|
||||||
|
base_url: "base2",
|
||||||
|
after_data: "baz=shouldnotuse",
|
||||||
|
expected: "base2/foodata/bardata",
|
||||||
|
},
|
||||||
|
].forEach( ( { fields, data, base_url, after_data, expected }, i ) =>
|
||||||
|
it( `can include portion of data in url (#${i})`, done =>
|
||||||
|
{
|
||||||
|
const expected_method = 'PUT';
|
||||||
|
|
||||||
|
const impl = Class.implement( HttpImpl ).extend(
|
||||||
|
{
|
||||||
|
'virtual requestData'( url, method, given_data, callback )
|
||||||
|
{
|
||||||
|
expect( url ).to.equal( expected );
|
||||||
|
expect( method ).to.equal( expected_method );
|
||||||
|
expect( given_data ).to.deep.equal( after_data );
|
||||||
|
|
||||||
|
// should not have mutated the original object
|
||||||
|
// (they shouldn't be the same object)
|
||||||
|
expect( data ).to.not.equal( given_data );
|
||||||
|
|
||||||
|
// should be done
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
setOptions: () => {},
|
||||||
|
} )();
|
||||||
|
|
||||||
|
const sut = HttpDataApi.use( Sut( fields ) )(
|
||||||
|
base_url, expected_method, impl
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = sut.request( data, done );
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
it( "throws error if param is missing from data", done =>
|
||||||
|
{
|
||||||
|
const impl = Class.implement( HttpImpl ).extend(
|
||||||
|
{
|
||||||
|
'virtual requestData': ( url, method, data, callback ) => {},
|
||||||
|
setOptions: () => {},
|
||||||
|
} )();
|
||||||
|
|
||||||
|
const sut = HttpDataApi.use( Sut( [ 'foo' ] ) )(
|
||||||
|
'', 'PUT', impl
|
||||||
|
);
|
||||||
|
|
||||||
|
// missing `foo` in data
|
||||||
|
sut.request( { unused: "missing foo" }, ( err, data ) =>
|
||||||
|
{
|
||||||
|
expect( err ).to.be.instanceof( Error );
|
||||||
|
expect( err.message ).to.match( /\bfoo\b/ );
|
||||||
|
|
||||||
|
expect( data ).to.equal( null );
|
||||||
|
|
||||||
|
done();
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* Tests RatingServiceSubmitNotify
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { Class } = require( 'easejs' );
|
||||||
|
const { expect } = require( 'chai' );
|
||||||
|
|
||||||
|
|
||||||
|
const {
|
||||||
|
dapi: {
|
||||||
|
DataApi,
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
service: {
|
||||||
|
RatingServiceSubmitNotify: Sut,
|
||||||
|
RatingService,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
server: {
|
||||||
|
service: {
|
||||||
|
RatingServiceStub,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = require( '../../../' );
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'RatingServiceSubmitNotify', () =>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
{
|
||||||
|
prem_avail_count: [ 0 ],
|
||||||
|
prev_called: false,
|
||||||
|
expected_request: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prem_avail_count: [ 2 ],
|
||||||
|
prev_called: false,
|
||||||
|
expected_request: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// this shouldn't happen; ignore all but first index
|
||||||
|
prem_avail_count: [ 2, 2 ],
|
||||||
|
prev_called: false,
|
||||||
|
expected_request: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// save as above, but already saved
|
||||||
|
{
|
||||||
|
prem_avail_count: [ 0 ],
|
||||||
|
prev_called: true,
|
||||||
|
expected_request: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prem_avail_count: [ 2 ],
|
||||||
|
prev_called: true,
|
||||||
|
expected_request: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// this shouldn't happen; ignore all but first index
|
||||||
|
prem_avail_count: [ 2, 2 ],
|
||||||
|
prev_called: true,
|
||||||
|
expected_request: false,
|
||||||
|
},
|
||||||
|
].forEach( ( { prem_avail_count, expected_request, prev_called }, i ) =>
|
||||||
|
it( `sends request on post process if no premiums (#${i})`, done =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
dao,
|
||||||
|
logger,
|
||||||
|
quote,
|
||||||
|
raters,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
server,
|
||||||
|
stub_rate_data,
|
||||||
|
} = RatingServiceStub.getStubs();
|
||||||
|
|
||||||
|
const quote_id = 1234;
|
||||||
|
let requested = false;
|
||||||
|
|
||||||
|
const dapif = given_request =>
|
||||||
|
Class.implement( DataApi ).extend(
|
||||||
|
{
|
||||||
|
// warning: if an expectation fails, because of how
|
||||||
|
// RatingService handles errors, it will cause the test to
|
||||||
|
// _hang_ rather than throw the assertion error
|
||||||
|
request( data, callback )
|
||||||
|
{
|
||||||
|
expect( given_request ).to.equal( request );
|
||||||
|
expect( data ).to.deep.equal( { quote_id: quote_id } );
|
||||||
|
|
||||||
|
requested = true;
|
||||||
|
},
|
||||||
|
} )();
|
||||||
|
|
||||||
|
const sut = RatingService.use( Sut( dapif, dao ) )(
|
||||||
|
logger, dao, server, raters
|
||||||
|
);
|
||||||
|
|
||||||
|
quote.getId = () => quote_id;
|
||||||
|
|
||||||
|
// one of the methods that is called by the supertype
|
||||||
|
let save_called = false;
|
||||||
|
dao.setWorksheets = () => save_called = true;
|
||||||
|
|
||||||
|
// whether the notify flag is actually set
|
||||||
|
let notify_saved = false;
|
||||||
|
|
||||||
|
// request for notification status
|
||||||
|
dao.getDocumentField = ( qid, key, callback ) =>
|
||||||
|
{
|
||||||
|
expect( qid ).to.equal( quote_id );
|
||||||
|
expect( key ).to.equal( 'submitNotified' );
|
||||||
|
|
||||||
|
callback( null, prev_called );
|
||||||
|
};
|
||||||
|
|
||||||
|
dao.setDocumentField = ( qid, key, value, callback ) =>
|
||||||
|
{
|
||||||
|
expect( qid ).to.equal( quote_id );
|
||||||
|
expect( key ).to.equal( 'submitNotified' );
|
||||||
|
expect( value ).to.equal( true );
|
||||||
|
|
||||||
|
notify_saved = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
stub_rate_data.__prem_avail_count = prem_avail_count;
|
||||||
|
|
||||||
|
sut.request( request, response, quote, 'something', () =>
|
||||||
|
{
|
||||||
|
expect( requested ).to.equal( expected_request );
|
||||||
|
expect( save_called ).to.be.true;
|
||||||
|
|
||||||
|
// only save notification status if we're notifying
|
||||||
|
expect( notify_saved ).to.equal(
|
||||||
|
!prev_called && expected_request
|
||||||
|
);
|
||||||
|
|
||||||
|
done();
|
||||||
|
} );
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
} );
|
|
@ -0,0 +1,65 @@
|
||||||
|
/**
|
||||||
|
* Tests RatingService
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { expect } = require( 'chai' );
|
||||||
|
const Sut = require( '../../../' ).server.service.RatingService;
|
||||||
|
const RatingServiceStub = require( '../../../' ).test.server.service.RatingServiceStub;
|
||||||
|
|
||||||
|
describe( 'RatingService', () =>
|
||||||
|
{
|
||||||
|
describe( "protected API", () =>
|
||||||
|
{
|
||||||
|
it( "calls #postProcessRaterData after rating before save", done =>
|
||||||
|
{
|
||||||
|
let processed = false;
|
||||||
|
|
||||||
|
const {
|
||||||
|
logger,
|
||||||
|
server,
|
||||||
|
raters,
|
||||||
|
dao,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
quote,
|
||||||
|
} = RatingServiceStub.getStubs();
|
||||||
|
|
||||||
|
dao.mergeBucket = () =>
|
||||||
|
{
|
||||||
|
expect( processed ).to.equal( true );
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
const sut = Sut.extend(
|
||||||
|
{
|
||||||
|
'override postProcessRaterData'(
|
||||||
|
request, data, actions, program, quote
|
||||||
|
)
|
||||||
|
{
|
||||||
|
processed = true;
|
||||||
|
}
|
||||||
|
} )( logger, dao, server, raters );
|
||||||
|
|
||||||
|
sut.request( request, response, quote, 'something', () => {} );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
} );
|
Loading…
Reference in New Issue