1
0
Fork 0

Save rating data to another database field

This maintains the old behavior while also writing rating result to another
field in the database.
master
Mike Gerwitz 2019-10-29 15:24:54 -04:00
commit d2f9f5f18f
31 changed files with 1933 additions and 1015 deletions

View File

@ -341,14 +341,17 @@ If this is a concern,
in conjunction with ease.js'
@url{https://www.gnu.org/software/easejs/manual/easejs.html#Type-Checks-and-Polymorphism,@samp{Class.isA}}.
Interfaces do not exist at runtime in TypeScript,
but they do in easejs.
Consequently,
you can continue to export an ease.js interface while also exporting
a TypeScript interface.
Often times you will need to reference a class or interface as a
dependency before it has been migrated away from ease.js.
To do this,
continue to export using @samp{module.exports} rather than
TypeScript's @samp{export =}.
create a corresponding @code{.d.ts} file in the same directory
as the dependency.
For example,
if a class @code{Foo} is contained in @file{Foo.js},
create a sibling @file{Foo.d.ts} file.
For more information,
see @url{https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html,Declaration Files}
in the TypeScript handbook.
ease.js implements stackable Scala-like traits.
Traits are @emph{not} provided by TypeScript.
@ -446,7 +449,7 @@ This can be done using
@verbatim
type PositiveInteger = NominalType<number, 'PositiveInteger'>;
const isPositiveInteger = ( x: number ): n is PositiveInteger => n > 0;
const isPositiveInteger = ( n: number ): n is PositiveInteger => n > 0;
const lookupIndex<T>( arr: T[], i: PositiveInteger ): T => arr[ i ];

View File

@ -0,0 +1,39 @@
/**
* Representation of actions to be performed by the client
*
* Copyright (C) 2010-2019 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/>.
*/
/**
* Action to be performed by the client
*
* TODO: More specific types
*/
export interface ClientAction
{
/** Action to be performed */
action: string;
/** Action arguments */
[P: string]: any;
}
/** Set of actions */
export type ClientActions = ClientAction[];

43
src/numeric.ts 100644
View File

@ -0,0 +1,43 @@
/**
* Numeric types
*
* Copyright (C) 2010-2019 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/>.
*
* TypeScript's type system does not support algebraic numeric domains. A
* compromise is to provide nominal types that allow developers to assume
* that some constraint has been met, and then ensure that the type is only
* ever asserted when that constraint is explicitly validated at
* runtime. This allows us to have compile-time checks on numeric values
* under the assumption that the runtime will enforce them.
*
* For this to work, _it is important to always use type predicates_;
* if you explicit cast to one of these numeric types, it circumvents the
* safety provided by the system and may introduce nasty bugs, since users
* of these types assume the provided data has already been validated.
*/
/**
* Any number 0
*
* This is useful for array indexing.
*/
export type PositiveInteger = NominalType<number, 'PositiveInteger'>;
/** Whether the given number is suitable as a PositiveInteger */
export const isPositiveInteger = ( n: number ): n is PositiveInteger => n >= 0;

27
src/program/Program.d.ts vendored 100644
View File

@ -0,0 +1,27 @@
/**
* Contains Program base class
*
* Copyright (C) 2010-2019 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/>.
*/
export declare abstract class Program
{
readonly ineligibleLockCount: number;
getId(): string;
}

93
src/quote/BaseQuote.d.ts vendored 100644
View File

@ -0,0 +1,93 @@
/**
* Contains program Quote class
*
* Copyright (C) 2010-2019 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/>.
*
* @todo Use ``document'' terminology in place of ``quote''
*/
import { Program } from "../program/Program";
import { Quote, QuoteId } from "./Quote";
export declare class BaseQuote implements Quote
{
/**
* Retrieve Program associated with quote
*
* @return quote program
*/
getProgram(): Program;
/**
* Returns the program id associated with the quote
*
* @return program id
*/
getProgramId(): string;
/**
* Returns the quote id
*
* The quote id is immutable. A different quote id would represent a
* different quote, therefore a new object should be created with the
* desired quote id.
*
* @return quote id
*/
getId(): QuoteId;
/**
* Returns the id of the current step
*
* @return id of current step
*/
getCurrentStepId(): number;
/**
* Sets an explicit lock, providing a reason for doing so
*
* @param reason - lock reason
* @param step - step that user may not navigate prior
*
* @return self
*/
setExplicitLock( reason: string, step: number ): this;
/**
* Set the date that the premium was calculated as a Unix timestamp
*
* @param timestamp - Unix timestamp representing premium date
*
* @return self
*/
setLastPremiumDate( timestamp: UnixTimestamp ): this;
/**
* Retrieve the last time the premium was calculated
*
* @return last calculated time or 0
*/
getLastPremiumDate(): UnixTimestamp;
}

33
src/quote/Quote.d.ts vendored 100644
View File

@ -0,0 +1,33 @@
/**
* Generic interface to represent quotes
*
* Copyright (C) 2010-2019 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/>.
*
* @todo Use ``document'' terminology in place of ``quote''
*/
import { Program } from "../program/Program";
import { QuoteId } from "../document/Document";
export declare interface Quote
{
// TODO: the easejs interface is empty; is this actually needed?
}
export { QuoteId };

66
src/server/Server.d.ts vendored 100644
View File

@ -0,0 +1,66 @@
/**
* General server actions
*
* Copyright (C) 2010-2019 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/>.
*/
import { ClientActions } from "../client/action/ClientAction";
import { ServerSideQuote } from "./quote/ServerSideQuote";
import { UserRequest } from "./request/UserRequest";
/**
* General server actions
*/
export declare class Server
{
/**
* Send response to user
*
* @param request - request to respond to
* @param quote - quote associated with request
* @param data - data with which to reply
* @param actions - optional client actions
*
* @return self
*/
sendResponse(
request: UserRequest,
quote: ServerSideQuote,
data: Record<string, any>,
actions?: ClientActions,
): this;
/**
* Send response to user
*
* @param request - request to respond to
* @param message - message to display to user
* @param actions - optional client actions
* @param btn_caption - optional caption for acknowledgement button
*
* @return self
*/
sendError(
request: UserRequest,
message: string,
actions?: ClientActions,
btn_caption?: string,
): this;
}

View File

@ -28,6 +28,8 @@ const {
ReplSetServers: ReplSetServers,
} = require( 'mongodb/lib/mongodb' );
const easejs = require( 'easejs' );
const regex_base = /^\/quote\/([a-z0-9-]+)\/?(?:\/(\d+)\/?(?:\/(.*))?|\/(program.js))?$/;
const regex_step = /^step\/(\d+)\/?(?:\/(post|visit))?$/;
@ -83,9 +85,8 @@ const {
ExportService,
},
RatingService,
RatingService: { RatingService },
RatingServicePublish,
RatingServiceSubmitNotify,
TokenedService,
},
@ -137,7 +138,7 @@ exports.init = function( logger, enc_service, conf )
server.init( server_cache, exports.rater );
// TODO: temporary proof-of-concept
rating_service = RatingService.use(
rating_service = easejs( RatingService ).use(
RatingServicePublish( amqplib, exports.post_rate_publish, logger )
)(
logger, dao, server, exports.rater
@ -535,11 +536,9 @@ function doRoute( program, request, data, resolve, reject )
{
var response = UserResponse( request );
rating_service.request( request, response, quote, alias, function()
{
// we're done; free the lock
free();
} );
rating_service.request( request, response, quote, alias )
.catch( () => {} )
.then( () => free() );
} );
}, true );
}

145
src/server/db/MongoServerDao.d.ts vendored 100644
View File

@ -0,0 +1,145 @@
/**
* Mongo DB DAO for program server
*
* Copyright (C) 2010-2019 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/>.
*/
import { ServerDao, Callback } from "./ServerDao";
import { ClassificationData, WorksheetData } from "../rater/Rater";
import { PositiveInteger } from "../../numeric";
import { QuoteId } from "../../document/Document";
import { ServerSideQuote } from "../quote/ServerSideQuote";
/**
* MongoDB-backed data store
*/
export declare class MongoServerDao implements ServerDao
{
/**
* Saves a quote to the database
*
* A full save will include all metadata.
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
* @param save_data - quote data to save (optional)
*/
saveQuote(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
save_data: Record<string, any>,
): this;
/**
* Merges bucket data with the existing bucket (rather than overwriting the
* entire bucket)
*
* @param quote - quote to save
* @param data - bucket data
* @param success - successful callback
* @param failure - failure callback
*/
mergeBucket(
quote: ServerSideQuote,
data: Record<string, any>,
success: Callback,
failure: Callback,
): this;
/**
* Save quote classification data
*
* @param quote - quote to save
* @param classes - classification data
* @param success - successful callback
* @param failure - failure callback
*/
saveQuoteClasses(
quote: ServerSideQuote,
classes: ClassificationData,
success: Callback,
failure: Callback,
): this;
/**
* Saves the quote state to the database
*
* The quote state includes the current step, the top visited step and the
* explicit lock message.
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
*/
saveQuoteState(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
): this;
/**
* Saves the quote lock state to the database
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
*/
saveQuoteLockState(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
): this
/**
* Save worksheet data
*
* @param qid - quote identifier
* @param data - worksheet data
* @param callback - callback
*/
setWorksheets(
qid: QuoteId,
data: WorksheetData,
callback: NodeCallback<void>,
): this;
/**
* Retrieve worksheet data
*
* @param qid - quote identifier
* @param supplier - supplier id
* @param index - worksheet index
* @param callback - callback
*/
getWorksheet(
qid: QuoteId,
supplier: string,
index: PositiveInteger,
callback: ( data: WorksheetData | null ) => void,
): this;
}

149
src/server/db/ServerDao.d.ts vendored 100644
View File

@ -0,0 +1,149 @@
/**
* General server database operations
*
* Copyright (C) 2010-2019 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/>.
*
* This interface was created to satisfy MongoServerDao and may not be
* sufficiently general for other database abstractions.
*/
import { ClassificationData, WorksheetData } from "../rater/Rater";
import { PositiveInteger } from "../../numeric";
import { QuoteId } from "../../document/Document";
import { ServerSideQuote } from "../quote/ServerSideQuote";
/** Success or failure callback */
export type Callback = ( quote: ServerSideQuote ) => void;
/**
* Database abstraction
*/
export interface ServerDao
{
/**
* Saves a quote to the database
*
* A full save will include all metadata.
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
* @param save_data - quote data to save (optional)
*/
saveQuote(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
save_data: Record<string, any>,
): this;
/**
* Merges bucket data with the existing bucket (rather than overwriting the
* entire bucket)
*
* @param quote - quote to save
* @param data - bucket data
* @param success - successful callback
* @param failure - failure callback
*/
mergeBucket(
quote: ServerSideQuote,
data: Record<string, any>,
success: Callback,
failure: Callback,
): this;
/**
* Save quote classification data
*
* @param quote - quote to save
* @param classes - classification data
* @param success - successful callback
* @param failure - failure callback
*/
saveQuoteClasses(
quote: ServerSideQuote,
classes: ClassificationData,
success: Callback,
failure: Callback,
): this;
/**
* Saves the quote state to the database
*
* The quote state includes the current step, the top visited step and the
* explicit lock message.
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
*/
saveQuoteState(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
): this;
/**
* Saves the quote lock state to the database
*
* @param quote - the quote to save
* @param success - function to call on success
* @param failure - function to call if save fails
*/
saveQuoteLockState(
quote: ServerSideQuote,
success: Callback,
failure: Callback,
): this
/**
* Save worksheet data
*
* @param qid - quote identifier
* @param data - worksheet data
* @param callback - callback
*/
setWorksheets(
qid: QuoteId,
data: WorksheetData,
callback: NodeCallback<void>,
): this;
/**
* Retrieve worksheet data
*
* @param qid - quote identifier
* @param supplier - supplier id
* @param index - worksheet index
* @param callback - callback
*/
getWorksheet(
qid: QuoteId,
supplier: string,
index: PositiveInteger,
callback: ( data: WorksheetData | null ) => void,
): this;
}

45
src/server/log/PriorityLog.d.ts vendored 100644
View File

@ -0,0 +1,45 @@
/**
* Priority log typescript type definitions
*
* Copyright (C) 2010-2019 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/>.
*/
export declare interface PriorityLog
{
readonly PRIORITY_ERROR: number;
readonly PRIORITY_IMPORTANT: number;
readonly PRIORITY_DB: number;
readonly PRIORITY_INFO: number;
readonly PRIORITY_SOCKET: number;
/**
* Write to the log at the given priority
*
* If the priority is less than or equal to the set priority for this
* object, it will be logged. Otherwise, the message will be ignored.
*
* The first argument should be the priority. The remaining arguments should
* be provided in a sprintf()-style fashion
*
* @param priority - logging priority
* @param ...args - sprintf-style aruments
*
* @return self
*/
log( priority: number, ...args: Array<string|number> ): this;
}

View File

@ -0,0 +1,46 @@
/**
* Augments a quote with additional data for use by the quote server
*
* Copyright (C) 2010-2019 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/>.
*
* @todo Use ``document'' terminology in place of ``quote''
*/
import { Program } from "../../program/Program";
import { BaseQuote } from "../../quote/BaseQuote";
export declare class ServerSideQuote extends BaseQuote
{
/**
* Last rated date, if any
*
* @return last rated date
*/
getRatedDate(): UnixTimestamp;
/**
* Set the timestamp of the first time quote was rated
*
* @param timestamp - Unix timestamp representing first rated date
*
* @return self
*/
setRatedDate( timestamp: UnixTimestamp ): this;
}

View File

@ -20,7 +20,6 @@
*/
var Class = require( 'easejs' ).Class,
Rater = require( './Rater' ),
EventEmitter = require( 'events' ).EventEmitter,
DslRaterContext = require( './DslRaterContext' );

View File

@ -20,7 +20,6 @@
*/
var Class = require( 'easejs' ).Class,
Rater = require( './Rater' ),
EventEmitter = require( 'events' ).EventEmitter,
Quote = require( '../../quote/Quote' );

View File

@ -22,18 +22,14 @@
* "HttpRater"
*/
var Class = require( 'easejs' ).Class,
Rater = require( './Rater' ),
querystring = require( 'querystring' )
;
var Class = require( 'easejs' ).Class;
var querystring = require( 'querystring' );
/**
* Rates using one of the PHP raters
*/
module.exports = Class( 'HttpRater' )
.implement( Rater )
.extend(
{
/**

View File

@ -0,0 +1,35 @@
/**
* Rating process manager
*
* Copyright (C) 2010-2019 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/>.
*/
import { Rater } from "./Rater";
export declare class ProcessManager
{
/**
* Returns the rater associated with the given id
*
* @param id - rater id
*
* @return requested rater
*/
byId( id: string ): Rater;
}

View File

@ -69,6 +69,9 @@ const _signum = {
*
* Handles formatting and sending requests to the rating process; and
* processing replies.
*
* TODO: Rename this class and provide a more generic interface. The caller
* does not care that this sends data to another process for rating.
*/
module.exports = Class( 'ProcessManager',
{

121
src/server/rater/Rater.d.ts vendored 100644
View File

@ -0,0 +1,121 @@
/**
* Contains Rater interface
*
* Copyright (C) 2010-2019 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/>.
*/
import { ClientActions } from "../../client/action/ClientAction";
import { ServerSideQuote } from "../quote/ServerSideQuote";
import { UserSession } from "../request/UserSession";
/** Result of rating */
export interface RateResult
{
/** Whether all suppliers were not able to provide rates */
_unavailable_all: '0' | '1';
/** Result data */
[P: string]: any;
}
/**
* Result of rating with an individual supplier
*
* This gets combined into a single RateResult prefixed with each supplier
* id and an underscore.
*/
export interface SupplierRateResult
{
/** Rating worksheet data */
__worksheet?: WorksheetData,
/** Classification system results */
__classes?: ClassificationData,
/** Basic profiling data */
__perf: PerformanceData,
/** Ineligible message, if any */
ineligible: string,
/** Submit message, if any */
submit: string,
/** Final premium */
premium: number,
/** Rating data */
[P: string]: any;
}
/** Basic profiling data */
export interface PerformanceData
{
/** Timestamp of beginning of rating */
start: UnixTimestampMillis;
/** Timestamp of end of rating */
end: UnixTimestampMillis;
/** Total rating time */
total: Milliseconds;
}
/**
* Worksheet data from rater
*
* These data come from the compiled raters.
*
* TODO: Fill in a schema here
*/
export type WorksheetData = Record<string, any>;
/** Classification results */
export type ClassificationData = Record<string, boolean>;
/**
* Represents a rater that will generate a quote from a given set of values
*/
export interface Rater
{
/**
* Asynchronously performs rating
*
* @param quote - quote to perform rating on
* @param session - user session
* @param indv - individual supplier to rate (otherwise empty)
* @param success - continuation when rating is successful
* @param failure - continuation when rating fails
*
* @return self
*/
rate(
quote: ServerSideQuote,
session: UserSession,
indv: string,
success: ( rate_data: RateResult, actions: ClientActions ) => void,
failure: ( message: string ) => void,
): this;
}

View File

@ -1,5 +1,5 @@
/**
* Contains Rater interface
* User request abstraction
*
* Copyright (C) 2010-2019 R-T Specialty, LLC.
*
@ -19,22 +19,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Interface = require( 'easejs' ).Interface;
import { UserSession } from "./UserSession";
/**
* Represents a rater that will generate a quote from a given set of values
* Representation of request from user
*/
module.exports = Interface( 'Rater',
export declare class UserRequest
{
/**
* Asynchronously performs rating using the data from the given bucket
* Retrieve the current session
*
* @param {Quote} quote to rate
* @param {function()} callback function to call when complete
*
* @return {Rater} self
* @return current session
*/
'public rate': [ 'quote', 'args', 'callback' ],
} );
getSession(): UserSession;
}

View File

@ -0,0 +1,28 @@
/**
* UserResponse class
*
* Copyright (C) 2010-2019 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/>.
*/
/**
* Manipulates response to user request
*/
export declare class UserResponse
{
}

View File

@ -0,0 +1,34 @@
/**
* UserSession class
*
* Copyright (C) 2010-2019 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/>.
*/
/**
* Session management
*/
export declare class UserSession
{
/**
* Whether the user is logged in as an internal user
*
* @return true if internal user, otherwise false
*/
isInternal(): boolean;
}

View File

@ -1,420 +0,0 @@
/**
* Rating service
*
* Copyright (C) 2010-2019 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/>.
*/
var Class = require( 'easejs' ).Class;
/**
* XXX: Half-assed, quick refactoring to extract from Server class; this is not
* yet complete!
*
* TODO: Logging should be implemented by observers
*/
module.exports = Class( 'RatingService',
{
logger: null,
dao: null,
_server: null,
_raters: null,
__construct: function( logger, dao, server, raters )
{
this._logger = logger;
this._dao = dao;
this._server = server;
this._raters = raters;
},
/**
* Sends rates to the client
*
* Note that the continuation will be called after all data saving is
* complete; the request will be sent back to the client before then.
*
* @param {UserRequest} request user request to satisfy
* @param {UserResponse} response pending response
* @param {Quote} quote quote to export
* @param {string} cmd applicable of command request
* @param {Function} callback continuation after saving is complete
*
* @return Server self to allow for method chaining
*/
'public request': function( request, response, quote, cmd, callback )
{
// cmd represents a request for a single rater
if ( !cmd && this._isQuoteValid( quote ) )
{
// send an empty reply (keeps what is currently in the bucket)
this._server.sendResponse( request, quote, {
data: {},
}, [] );
callback();
return this;
}
var program = quote.getProgram();
try
{
this._performRating( request, program, quote, cmd, callback );
}
catch ( err )
{
this._sendRatingError( request, quote, program, err );
callback();
}
return this;
},
_getProgramRater: function( program, quote )
{
var rater = this._raters.byId( program.getId() );
// if a rater could not be found, we can't do any rating
if ( rater === null )
{
this._logger.log( this._logger.PRIORITY_ERROR,
"Rating for quote %d (program %s) failed; missing module",
quote.getId(),
program.getId()
);
}
return rater;
},
_isQuoteValid: function( quote )
{
// quotes are valid for 30 days
var re_date = Math.round( ( ( new Date() ).getTime() / 1000 ) -
( 60 * 60 * 24 * 30 )
);
if ( quote.getLastPremiumDate() > re_date )
{
this._logger.log( this._logger.PRIORITY_INFO,
"Skipping '%s' rating for quote #%s; quote is still valid",
quote.getProgramId(),
quote.getId()
);
return true;
}
return false;
},
_performRating: function( request, program, quote, indv, c )
{
var _self = this;
var rater = this._getProgramRater( program );
if ( !rater )
{
this._server.sendError( request, 'Unable to perform rating.' );
c();
}
this._logger.log( this._logger.PRIORITY_INFO,
"Performing '%s' rating for quote #%s",
quote.getProgramId(),
quote.getId()
);
rater.rate( quote, request.getSession(), indv,
function( rate_data, actions )
{
actions = actions || [];
_self.postProcessRaterData(
request, rate_data, actions, program, quote
);
const class_dest = {};
const cleaned = _self._cleanRateData(
rate_data,
class_dest
);
// TODO: move me during refactoring
_self._dao.saveQuoteClasses( quote, class_dest );
// save all data server-side (important: do after
// post-processing); async
_self._saveRatingData( quote, rate_data, indv, function()
{
// we're done
c();
} );
// no need to wait for the save; send the response
_self._server.sendResponse( request, quote, {
data: cleaned,
initialRatedDate: quote.getRatedDate(),
lastRatedDate: quote.getLastPremiumDate()
}, actions );
},
function( message )
{
_self._sendRatingError( request, quote, program,
Error( message )
);
c();
}
);
},
/**
* Saves rating data
*
* Data will be merged with existing bucket data and saved. The idea behind
* this is to allow us to reference the data (e.g. for reporting) even if
* the client does not save it.
*
* @param {Quote} quote quote to save data to
* @param {Object} data rating data
*
* @return {undefined}
*/
_saveRatingData: function( quote, data, indv, c )
{
// only update the last premium calc date on the initial request
if ( !indv )
{
var cur_date = Math.round(
( new Date() ).getTime() / 1000
);
quote.setLastPremiumDate( cur_date );
quote.setRatedDate( cur_date );
function done()
{
c();
}
// save the last prem status (we pass an empty object as the save
// data argument to ensure that we do not save the actual bucket
// data, which may cause a race condition with the below merge call)
this._dao.saveQuote( quote, done, done, {} );
}
else
{
c();
}
// we're not going to worry about whether or not this fails; if it does,
// an error will be automatically logged, but we still want to give the
// user a rate (if this save fails, it's likely we have bigger problems
// anyway); this can also be done concurrently with the above request
// since it only modifies a portion of the bucket
this._dao.mergeBucket( quote, data );
},
/**
* Process rater data returned from a rater
*
* @param {UserRequest} request user request to satisfy
* @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}
*/
'virtual protected postProcessRaterData': function(
request, data, actions, program, quote
)
{
var meta = data._cmpdata || {};
// the metadata will not be provided to the client
delete data._cmpdata;
// rating worksheets are returned as metadata
this._processWorksheetData( quote.getId(), data );
if ( ( program.ineligibleLockCount > 0 )
&& ( +meta.count_ineligible >= program.ineligibleLockCount )
)
{
// lock the quote client-side (we don't send them the reason; they
// don't need it) to the current step
actions.push( { action: 'lock' } );
var lock_reason = 'Supplier ineligibility restriction';
var lock_step = quote.getCurrentStepId();
// the next step is the step that displays the rating results
quote.setExplicitLock( lock_reason, ( lock_step + 1 ) );
// important: only save the lock state, not the step states, as we
// have a race condition with async. rating (the /visit request may
// be made while we're rating, and when we come back we would then
// update the step id with a prior, incorrect step)
this._dao.saveQuoteLockState( quote );
}
// if any have been deferred, instruct the client to request them
// individually
if ( Array.isArray( meta.deferred ) && ( meta.deferred.length > 0 ) )
{
var torate = [];
meta.deferred.forEach( function( alias )
{
actions.push( { action: 'indvRate', id: alias } );
torate.push( alias );
} );
// we log that we're performing rating, so we should also log when
// it is deferred (otherwise the logs will be rather confusing)
this._logger.log( this._logger.PRIORITY_INFO,
"'%s' rating deferred for quote #%s; will rate: %s",
quote.getProgramId(),
quote.getId(),
torate.join( ',' )
);
}
},
_sendRatingError: function( request, quote, program, err )
{
// well that's no good
this._logger.log( this._logger.PRIORITY_ERROR,
"Rating for quote %d (program %s) failed: %s",
quote.getId(),
program.getId(),
err.message + '\n-!' + err.stack.replace( /\n/g, '\n-!' )
);
this._server.sendError( request,
'There was a problem during the rating process. Unable to ' +
'continue. Please contact our support team for assistance.' +
// show details for internal users
( ( request.getSession().isInternal() )
? '<br /><br />[Internal] ' + err.message + '<br /><br />' +
'<hr />' + err.stack.replace( /\n/g, '<br />' )
: ''
)
);
},
_processWorksheetData: function( qid, data )
{
// TODO: this should be done earlier on, so that this is not necessary
var wre = /^(.+)___worksheet$/,
worksheets = {};