NINS_CODE/bahmniapps/home/home.min.387e1376.js
travelershot 70dda814aa codepush
2024-12-12 22:37:39 +06:00

4511 lines
183 KiB
JavaScript

angular.module('FredrikSandell.worker-pool', []).service('WorkerService', [
'$q',
function ($q) {
var that = {};
//this should be configured from the app in the future
var urlToAngular = 'http://localhost:9876/base/bower_components/angular/angular.js';
var serviceToUrlMap = {};
var storage = {};
var scriptsToLoad = [];
that.setAngularUrl = function (urlToAngularJs) {
urlToAngular = urlToAngularJs;
};
function createAngularWorkerTemplate() {
/*jshint laxcomma:true */
/*jshint quotmark: false */
var workerTemplate = [
'',
'//try {',
'var window = self;',
'self.history = {};',
'var Node = function() {};',
'var app',
'var localStorage = {storage: <STORAGE>, getItem: function(key) {return this.storage[key]}, setItem: function(key, value) {this.storage[key]=value}}',
'var document = {',
' readyState: \'complete\',',
' cookie: \'\',',
' querySelector: function () {},',
' createElement: function () {',
' return {',
' pathname: \'\',',
' setAttribute: function () {}',
' };',
' }',
'};',
'importScripts(\'<URL_TO_ANGULAR>\');',
'<CUSTOM_DEP_INCLUDES>',
'angular = window.angular;',
'var workerApp = angular.module(\'WorkerApp\', [<DEP_MODULES>]);',
'workerApp.run([\'$q\'<STRING_DEP_NAMES>, function ($q<DEP_NAMES>) {',
' self.addEventListener(\'message\', function(e) {',
' var input = e.data;',
' var output = $q.defer();',
' var promise = output.promise;',
' promise.then(function(success) {',
' self.postMessage({event:\'success\', data : success});',
' }, function(reason) {',
' self.postMessage({event:\'failure\', data : reason});',
' }, function(update) {',
' self.postMessage({event:\'update\', data : update});',
' });',
' <WORKER_FUNCTION>;',
' });',
' self.postMessage({event:\'initDone\'});',
'}]);',
'angular.bootstrap(null, [\'WorkerApp\']);',
'//} catch(e) {self.postMessage(JSON.stringify(e));}'
];
return workerTemplate.join('\n');
}
var workerTemplate = createAngularWorkerTemplate();
that.addDependency = function (serviceName, moduleName, url) {
serviceToUrlMap[serviceName] = {
url: url,
moduleName: moduleName
};
return that;
};
that.includeScripts = function(url) {
scriptsToLoad.push(url);
};
that.addToLocalStorage = function(key, value) {
storage[key] = value;
};
function createIncludeStatements(listOfServiceNames) {
var includeString = '';
angular.forEach(scriptsToLoad, function(script) {
includeString += 'importScripts(\'' + script + '\');';
});
angular.forEach(listOfServiceNames, function (serviceName) {
if (serviceToUrlMap[serviceName]) {
includeString += 'importScripts(\'' + serviceToUrlMap[serviceName].url + '\');';
}
});
return includeString;
}
function createModuleList(listOfServiceNames) {
var moduleNameList = [];
angular.forEach(listOfServiceNames, function (serviceName) {
if (serviceToUrlMap[serviceName]) {
moduleNameList.push('\'' + serviceToUrlMap[serviceName].moduleName + '\'');
}
});
return moduleNameList.join(',');
}
function createDependencyMetaData(dependencyList) {
var dependencyServiceNames = dependencyList.filter(function (dep) {
return dep !== 'input' && dep !== 'output' && dep !== '$q';
});
var depMetaData = {
dependencies: dependencyServiceNames,
moduleList: createModuleList(dependencyServiceNames),
angularDepsAsStrings: dependencyServiceNames.length > 0 ? ',' + dependencyServiceNames.map(function (dep) {
return '\'' + dep + '\'';
}).join(',') : '',
angularDepsAsParamList: dependencyServiceNames.length > 0 ? ',' + dependencyServiceNames.join(',') : '',
servicesIncludeStatements: createIncludeStatements(dependencyServiceNames)
};
depMetaData.workerFuncParamList = 'input,output' + depMetaData.angularDepsAsParamList;
return depMetaData;
}
function populateWorkerTemplate(workerFunc, dependencyMetaData) {
return workerTemplate
.replace('<URL_TO_ANGULAR>', urlToAngular)
.replace('<CUSTOM_DEP_INCLUDES>', dependencyMetaData.servicesIncludeStatements)
.replace('<DEP_MODULES>', dependencyMetaData.moduleList)
.replace('<STRING_DEP_NAMES>', dependencyMetaData.angularDepsAsStrings)
.replace('<DEP_NAMES>', dependencyMetaData.angularDepsAsParamList)
.replace('<STORAGE>', JSON.stringify(storage))
.replace('<WORKER_FUNCTION>', workerFunc.toString());
}
var buildAngularWorker = function (initializedWorker) {
var that = {};
that.worker = initializedWorker;
that.run = function (input) {
var deferred = $q.defer();
initializedWorker.addEventListener('message', function (e) {
var eventId = e.data.event;
//console.log(e.data);
if (eventId === 'initDone') {
throw 'Received worker initialization in run method. This should already have occurred!';
} else if (eventId === 'success') {
deferred.resolve(e.data.data);
} else if (eventId === 'failure') {
deferred.reject(e.data.data);
} else if (eventId === 'update') {
deferred.notify(e.data.data);
} else {
deferred.reject(e);
}
});
initializedWorker.postMessage(input);
return deferred.promise;
};
that.terminate = function () {
initializedWorker.terminate();
};
return that;
};
var extractDependencyList = function (depFuncList) {
return depFuncList.slice(0, depFuncList.length - 1);
};
var workerFunctionToString = function (func, paramList) {
return '(' + func.toString() + ')(' + paramList + ')';
};
/**
* example call:
* WorkerService.createAngularWorker(['input', 'output', '$http', function(input, output, $http)
* {body of function}]);
* Parameters "input" and "output" is required. Not defining them will cause a runtime error.
* Declaring services to be injected, as '$http' is above, requires the web worker to be able to resolve them.
* '$http' service is a part of the standard angular package which means it will resolve without additional information
* since angular source is always loaded in the web worker.
* But if a custom service was to be injected the WorkerService would need be be informed on how to resolve the.
* @param depFuncList
*/
that.createAngularWorker = function (depFuncList) {
//validate the input
if (!Array.isArray(depFuncList) || depFuncList.length < 3 || typeof depFuncList[depFuncList.length - 1] !== 'function') {
throw 'Input needs to be: [\'workerInput\',\'deferredOutput\'/*optional additional dependencies*/,\n' + ' function(workerInput, deferredOutput /*optional additional dependencies*/)\n' + ' {/*worker body*/}' + ']';
}
var deferred = $q.defer();
var dependencyMetaData = createDependencyMetaData(extractDependencyList(depFuncList));
var blobURL = (window.webkitURL ? webkitURL : URL).createObjectURL(new Blob([populateWorkerTemplate(workerFunctionToString(depFuncList[depFuncList.length - 1], dependencyMetaData.workerFuncParamList), dependencyMetaData)], { type: 'application/javascript' }));
var worker = new Worker(blobURL);
//wait for the worker to load resources
worker.addEventListener('message', function (e) {
var eventId = e.data.event;
console.log(e.data);
if (eventId === 'initDone') {
deferred.resolve(buildAngularWorker(worker));
} else {
deferred.reject(e);
}
});
return deferred.promise;
};
return that;
}
]);
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.Util = Bahmni.Common.Util || {};
angular.module('bahmni.common.util', [])
.provider('$bahmniCookieStore', [function () {
var self = this;
self.defaultOptions = {};
var fixedEncodeURIComponent = function (str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16);
});
};
self.setDefaultOptions = function (options) {
self.defaultOptions = options;
};
self.$get = function () {
return {
get: function (name) {
var jsonCookie = $.cookie(name);
if (jsonCookie) {
return angular.fromJson(decodeURIComponent(jsonCookie));
}
return null;
},
put: function (name, value, options) {
options = $.extend({}, self.defaultOptions, options);
$.cookie.raw = true;
$.cookie(name, fixedEncodeURIComponent(angular.toJson(value)), options);
},
remove: function (name, options) {
options = $.extend({}, self.defaultOptions, options);
$.removeCookie(name, options);
}
};
};
}])
;
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.Models = Bahmni.Common.Models || {};
angular.module('bahmni.common.models', []);
'use strict';
angular.module('bahmni.common.models')
.factory('age', [function () {
var dateUtil = Bahmni.Common.Util.DateUtil;
var fromBirthDate = function (birthDate) {
var today = dateUtil.now();
var period = dateUtil.diffInYearsMonthsDays(birthDate, today);
return create(period.years, period.months, period.days);
};
var create = function (years, months, days) {
var isEmpty = function () {
return !(this.years || this.months || this.days);
};
return {
years: years,
months: months,
days: days,
isEmpty: isEmpty
};
};
var calculateBirthDate = function (age) {
var birthDate = dateUtil.now();
birthDate = dateUtil.subtractYears(birthDate, age.years);
birthDate = dateUtil.subtractMonths(birthDate, age.months);
birthDate = dateUtil.subtractDays(birthDate, age.days);
return birthDate;
};
return {
fromBirthDate: fromBirthDate,
create: create,
calculateBirthDate: calculateBirthDate
};
}]
);
Bahmni.Common.AuditLogEventDetails = {
"USER_LOGIN_SUCCESS": {eventType: "USER_LOGIN_SUCCESS", message: "USER_LOGIN_SUCCESS_MESSAGE"},
"USER_LOGIN_FAILED": {eventType: "USER_LOGIN_FAILED", message: "USER_LOGIN_FAILED_MESSAGE"},
"USER_LOGOUT_SUCCESS": {eventType: "USER_LOGOUT_SUCCESS", message: "USER_LOGOUT_SUCCESS_MESSAGE"},
"OPEN_VISIT": {eventType: "OPEN_VISIT", message: "OPEN_VISIT_MESSAGE"},
"EDIT_VISIT": {eventType: "EDIT_VISIT", message: "EDIT_VISIT_MESSAGE"},
"CLOSE_VISIT": {eventType: "CLOSE_VISIT", message: "CLOSE_VISIT_MESSAGE"},
"CLOSE_VISIT_FAILED": {eventType: "CLOSE_VISIT_FAILED", message: "CLOSE_VISIT_FAILED_MESSAGE"},
"EDIT_ENCOUNTER": {eventType: "EDIT_ENCOUNTER", message: "EDIT_ENCOUNTER_MESSAGE"},
"VIEWED_REGISTRATION_PATIENT_SEARCH": {eventType: "VIEWED_REGISTRATION_PATIENT_SEARCH", message: "VIEWED_REGISTRATION_PATIENT_SEARCH_MESSAGE"},
"VIEWED_NEW_PATIENT_PAGE": {eventType: "VIEWED_NEW_PATIENT_PAGE", message: "VIEWED_NEW_PATIENT_PAGE_MESSAGE"},
"REGISTER_NEW_PATIENT": {eventType: "REGISTER_NEW_PATIENT", message: "REGISTER_NEW_PATIENT_MESSAGE"},
"EDIT_PATIENT_DETAILS": {eventType: "EDIT_PATIENT_DETAILS", message: "EDIT_PATIENT_DETAILS_MESSAGE"},
"ACCESSED_REGISTRATION_SECOND_PAGE": {eventType: "ACCESSED_REGISTRATION_SECOND_PAGE", message: "ACCESSED_REGISTRATION_SECOND_PAGE_MESSAGE"},
"VIEWED_PATIENT_DETAILS": {eventType: "VIEWED_PATIENT_DETAILS", message: "VIEWED_PATIENT_DETAILS_MESSAGE"},
"PRINT_PATIENT_STICKER": {eventType: "PRINT_PATIENT_STICKER", message: "PRINT_PATIENT_STICKER_MESSAGE"},
"VIEWED_CLINICAL_PATIENT_SEARCH": {eventType: "VIEWED_CLINICAL_PATIENT_SEARCH", message: "VIEWED_PATIENT_SEARCH_MESSAGE"},
"VIEWED_CLINICAL_DASHBOARD": {eventType: "VIEWED_CLINICAL_DASHBOARD", message: "VIEWED_CLINICAL_DASHBOARD_MESSAGE"},
"VIEWED_OBSERVATIONS_TAB": {eventType: "VIEWED_OBSERVATIONS_TAB", message: "VIEWED_OBSERVATIONS_TAB_MESSAGE"},
"VIEWED_DIAGNOSIS_TAB": {eventType: "VIEWED_DIAGNOSIS_TAB", message: "VIEWED_DIAGNOSIS_TAB_MESSAGE"},
"VIEWED_TREATMENT_TAB": {eventType: "VIEWED_TREATMENT_TAB", message: "VIEWED_TREATMENT_TAB_MESSAGE"},
"VIEWED_DISPOSITION_TAB": {eventType: "VIEWED_DISPOSITION_TAB", message: "VIEWED_DISPOSITION_TAB_MESSAGE"},
"VIEWED_DASHBOARD_SUMMARY": {eventType: "VIEWED_DASHBOARD_SUMMARY", message: "VIEWED_DASHBOARD_SUMMARY_MESSAGE"},
"VIEWED_ORDERS_TAB": {eventType: "VIEWED_ORDERS_TAB", message: "VIEWED_ORDERS_TAB_MESSAGE"},
"VIEWED_BACTERIOLOGY_TAB": {eventType: "VIEWED_BACTERIOLOGY_TAB", message: "VIEWED_BACTERIOLOGY_TAB_MESSAGE"},
"VIEWED_INVESTIGATION_TAB": {eventType: "VIEWED_INVESTIGATION_TAB", message: "VIEWED_INVESTIGATION_TAB_MESSAGE"},
"VIEWED_SUMMARY_PRINT": {eventType: "VIEWED_SUMMARY_PRINT", message: "VIEWED_SUMMARY_PRINT_MESSAGE"},
"VIEWED_VISIT_DASHBOARD": {eventType: "VIEWED_VISIT_DASHBOARD", message: "VIEWED_VISIT_DASHBOARD_MESSAGE"},
"VIEWED_VISIT_PRINT": {eventType: "VIEWED_VISIT_PRINT", message: "VIEWED_VISIT_PRINT_MESSAGE"},
"VIEWED_DASHBOARD_OBSERVATION": {eventType: "VIEWED_DASHBOARD_OBSERVATION", message: "VIEWED_DASHBOARD_OBSERVATION_MESSAGE"},
"VIEWED_PATIENTPROGRAM": {eventType: "VIEWED_PATIENTPROGRAM", message: "VIEWED_PATIENTPROGRAM_MESSAGE"},
"RUN_REPORT": {eventType: "RUN_REPORT", message: "RUN_REPORT_MESSAGE"}
};
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
(function () {
var hostUrl = localStorage.getItem('host') ? ("https://" + localStorage.getItem('host')) : "";
var rootDir = localStorage.getItem('rootDir') || "";
var RESTWS = hostUrl + "/openmrs/ws/rest";
var RESTWS_V1 = hostUrl + "/openmrs/ws/rest/v1";
var BAHMNI_CORE = RESTWS_V1 + "/bahmnicore";
var EMRAPI = RESTWS + "/emrapi";
var BACTERIOLOGY = RESTWS_V1;
var BASE_URL = hostUrl + "/bahmni_config/openmrs/apps/";
var CUSTOM_URL = hostUrl + "/implementation_config/openmrs/apps/";
var serverErrorMessages = [
{
serverMessage: "Cannot have more than one active order for the same orderable and care setting at same time",
clientMessage: "One or more drugs you are trying to order are already active. Please change the start date of the conflicting drug or remove them from the new prescription."
},
{
serverMessage: "[Order.cannot.have.more.than.one]",
clientMessage: "One or more drugs you are trying to order are already active. Please change the start date of the conflicting drug or remove them from the new prescription."
}
];
var representation = "custom:(uuid,name,names,conceptClass," +
"setMembers:(uuid,name,names,conceptClass," +
"setMembers:(uuid,name,names,conceptClass," +
"setMembers:(uuid,name,names,conceptClass))))";
var unAuthenticatedReferenceDataMap = {
"/openmrs/ws/rest/v1/location?tags=Login+Location&s=byTags&v=default": "LoginLocations",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=locale.allowed.list": "LocaleList"
};
var authenticatedReferenceDataMap = {
"/openmrs/ws/rest/v1/idgen/identifiertype": "IdentifierTypes",
"/openmrs/module/addresshierarchy/ajax/getOrderedAddressHierarchyLevels.form": "AddressHierarchyLevels",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=mrs.genders": "Genders",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=bahmni.encountersession.duration": "encounterSessionDuration",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=bahmni.relationshipTypeMap": "RelationshipTypeMap",
"/openmrs/ws/rest/v1/bahmnicore/config/bahmniencounter?callerContext=REGISTRATION_CONCEPTS": "RegistrationConcepts",
"/openmrs/ws/rest/v1/relationshiptype?v=custom:(aIsToB,bIsToA,uuid)": "RelationshipType",
"/openmrs/ws/rest/v1/personattributetype?v=custom:(uuid,name,sortWeight,description,format,concept)": "PersonAttributeType",
"/openmrs/ws/rest/v1/entitymapping?mappingType=loginlocation_visittype&s=byEntityAndMappingType": "LoginLocationToVisitTypeMapping",
"/openmrs/ws/rest/v1/bahmnicore/config/patient": "PatientConfig",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Consultation+Note&v=custom:(uuid,name,answers)": "ConsultationNote",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Lab+Order+Notes&v=custom:(uuid,name)": "LabOrderNotes",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Impression&v=custom:(uuid,name)": "RadiologyImpressionConfig",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=All_Tests_and_Panels&v=custom:(uuid,name:(uuid,name),setMembers:(uuid,name:(uuid,name)))": "AllTestsAndPanelsConcept",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Dosage+Frequency&v=custom:(uuid,name,answers)": "DosageFrequencyConfig",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Dosage+Instructions&v=custom:(uuid,name,answers)": "DosageInstructionConfig",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=bahmni.encounterType.default": "DefaultEncounterType",
"/openmrs/ws/rest/v1/concept?s=byFullySpecifiedName&name=Stopped+Order+Reason&v=custom:(uuid,name,answers)": "StoppedOrderReasonConfig",
"/openmrs/ws/rest/v1/ordertype": "OrderType",
"/openmrs/ws/rest/v1/bahmnicore/config/drugOrders": "DrugOrderConfig",
"/openmrs/ws/rest/v1/bahmnicore/sql/globalproperty?property=drugOrder.drugOther": "NonCodedDrugConcept"
};
authenticatedReferenceDataMap["/openmrs/ws/rest/v1/entitymapping?mappingType=location_encountertype&s=byEntityAndMappingType&entityUuid=" + (localStorage.getItem("LoginInformation") ? JSON.parse(localStorage.getItem("LoginInformation")).currentLocation.uuid : "")] = "LoginLocationToEncounterTypeMapping";
Bahmni.Common.Constants = {
hostURL: hostUrl,
dateFormat: "dd/mm/yyyy",
dateDisplayFormat: "DD-MMM-YYYY",
timeDisplayFormat: "hh:mm",
emrapiDiagnosisUrl: EMRAPI + "/diagnosis",
bahmniDiagnosisUrl: BAHMNI_CORE + "/diagnosis/search",
bahmniDeleteDiagnosisUrl: BAHMNI_CORE + "/diagnosis/delete",
diseaseTemplateUrl: BAHMNI_CORE + "/diseaseTemplates",
AllDiseaseTemplateUrl: BAHMNI_CORE + "/diseaseTemplate",
emrapiConceptUrl: EMRAPI + "/concept",
encounterConfigurationUrl: BAHMNI_CORE + "/config/bahmniencounter",
patientConfigurationUrl: BAHMNI_CORE + "/config/patient",
drugOrderConfigurationUrl: BAHMNI_CORE + "/config/drugOrders",
emrEncounterUrl: EMRAPI + "/encounter",
encounterUrl: RESTWS_V1 + "/encounter",
locationUrl: RESTWS_V1 + "/location",
bahmniVisitLocationUrl: BAHMNI_CORE + "/visitLocation",
bahmniOrderUrl: BAHMNI_CORE + "/orders",
bahmniDrugOrderUrl: BAHMNI_CORE + "/drugOrders",
bahmniDispositionByVisitUrl: BAHMNI_CORE + "/disposition/visit",
bahmniDispositionByPatientUrl: BAHMNI_CORE + "/disposition/patient",
bahmniSearchUrl: BAHMNI_CORE + "/search",
bahmniLabOrderResultsUrl: BAHMNI_CORE + "/labOrderResults",
bahmniEncounterUrl: BAHMNI_CORE + "/bahmniencounter",
conceptUrl: RESTWS_V1 + "/concept",
bahmniConceptAnswerUrl: RESTWS_V1 + "/bahmniconceptanswer",
conceptSearchByFullNameUrl: RESTWS_V1 + "/concept?s=byFullySpecifiedName",
visitUrl: RESTWS_V1 + "/visit",
endVisitUrl: BAHMNI_CORE + "/visit/endVisit",
endVisitAndCreateEncounterUrl: BAHMNI_CORE + "/visit/endVisitAndCreateEncounter",
visitTypeUrl: RESTWS_V1 + "/visittype",
patientImageUrlByPatientUuid: RESTWS_V1 + "/patientImage?patientUuid=",
labResultUploadedFileNameUrl: "/uploaded_results/",
visitSummaryUrl: BAHMNI_CORE + "/visit/summary",
encounterModifierUrl: BAHMNI_CORE + "/bahmniencountermodifier",
openmrsUrl: hostUrl + "/openmrs",
loggingUrl: hostUrl + "/log/",
idgenConfigurationURL: RESTWS_V1 + "/idgen/identifiertype",
bahmniRESTBaseURL: BAHMNI_CORE + "",
observationsUrl: BAHMNI_CORE + "/observations",
obsRelationshipUrl: BAHMNI_CORE + "/obsrelationships",
encounterImportUrl: BAHMNI_CORE + "/admin/upload/encounter",
programImportUrl: BAHMNI_CORE + "/admin/upload/program",
conceptImportUrl: BAHMNI_CORE + "/admin/upload/concept",
conceptSetImportUrl: BAHMNI_CORE + "/admin/upload/conceptset",
drugImportUrl: BAHMNI_CORE + "/admin/upload/drug",
labResultsImportUrl: BAHMNI_CORE + "/admin/upload/labResults",
referenceTermsImportUrl: BAHMNI_CORE + "/admin/upload/referenceterms",
relationshipImportUrl: BAHMNI_CORE + "/admin/upload/relationship",
conceptSetExportUrl: BAHMNI_CORE + "/admin/export/conceptset?conceptName=:conceptName",
patientImportUrl: BAHMNI_CORE + "/admin/upload/patient",
adminImportStatusUrl: BAHMNI_CORE + "/admin/upload/status",
programUrl: RESTWS_V1 + "/program",
programEnrollPatientUrl: RESTWS_V1 + "/bahmniprogramenrollment",
programStateDeletionUrl: RESTWS_V1 + "/programenrollment",
programEnrollmentDefaultInformation: "default",
programEnrollmentFullInformation: "full",
programAttributeTypes: RESTWS_V1 + "/programattributetype",
relationshipTypesUrl: RESTWS_V1 + "/relationshiptype",
personAttributeTypeUrl: RESTWS_V1 + "/personattributetype",
diseaseSummaryPivotUrl: BAHMNI_CORE + "/diseaseSummaryData",
allTestsAndPanelsConceptName: 'All_Tests_and_Panels',
dosageFrequencyConceptName: 'Dosage Frequency',
dosageInstructionConceptName: 'Dosage Instructions',
stoppedOrderReasonConceptName: 'Stopped Order Reason',
consultationNoteConceptName: 'Consultation Note',
diagnosisConceptSet: 'Diagnosis Concept Set',
radiologyOrderType: 'Radiology Order',
radiologyResultConceptName: "Radiology Result",
investigationEncounterType: "INVESTIGATION",
validationNotesEncounterType: "VALIDATION NOTES",
labOrderNotesConcept: "Lab Order Notes",
impressionConcept: "Impression",
qualifiedByRelationshipType: "qualified-by",
dispositionConcept: "Disposition",
dispositionGroupConcept: "Disposition Set",
dispositionNoteConcept: "Disposition Note",
ruledOutDiagnosisConceptName: 'Ruled Out Diagnosis',
emrapiConceptMappingSource: "org.openmrs.module.emrapi",
abbreviationConceptMappingSource: "Abbreviation",
includeAllObservations: false,
openmrsObsUrl: RESTWS_V1 + "/obs",
openmrsObsRepresentation: "custom:(uuid,obsDatetime,value:(uuid,name:(uuid,name)))",
admissionCode: 'ADMIT',
dischargeCode: 'DISCHARGE',
transferCode: 'TRANSFER',
undoDischargeCode: 'UNDO_DISCHARGE',
vitalsConceptName: "Vitals",
heightConceptName: "HEIGHT",
weightConceptName: "WEIGHT",
bmiConceptName: "BMI", // TODO : shruthi : revove this when this logic moved to server side
bmiStatusConceptName: "BMI STATUS", // TODO : shruthi : revove this when this logic moved to server side
abnormalObservationConceptName: "IS_ABNORMAL",
documentsPath: '/document_images',
documentsConceptName: 'Document',
miscConceptClassName: 'Misc',
abnormalConceptClassName: 'Abnormal',
unknownConceptClassName: 'Unknown',
durationConceptClassName: 'Duration',
conceptDetailsClassName: 'Concept Details',
admissionEncounterTypeName: 'ADMISSION',
dischargeEncounterTypeName: 'DISCHARGE',
imageClassName: 'Image',
videoClassName: 'Video',
locationCookieName: 'bahmni.user.location',
retrospectiveEntryEncounterDateCookieName: 'bahmni.clinical.retrospectiveEncounterDate',
JSESSIONID: "JSESSIONID",
rootScopeRetrospectiveEntry: 'retrospectiveEntry.encounterDate',
patientFileConceptName: 'Patient file',
serverErrorMessages: serverErrorMessages,
currentUser: 'bahmni.user',
retrospectivePrivilege: 'app:clinical:retrospective',
locationPickerPrivilege: 'app:clinical:locationpicker',
onBehalfOfPrivilege: 'app:clinical:onbehalf',
nutritionalConceptName: 'Nutritional Values',
messageForNoObservation: "NO_OBSERVATIONS_CAPTURED",
messageForNoDisposition: "NO_DISPOSTIONS_AVAILABLE_MESSAGE_KEY",
messageForNoFulfillment: "NO_FULFILMENT_MESSAGE",
reportsUrl: "/bahmnireports",
uploadReportTemplateUrl: "/bahmnireports/upload",
ruledOutdiagnosisStatus: "Ruled Out Diagnosis",
registartionConsultationPrivilege: 'app:common:registration_consultation_link',
manageIdentifierSequencePrivilege: "Manage Identifier Sequence",
closeVisitPrivilege: 'app:common:closeVisit',
deleteDiagnosisPrivilege: 'app:clinical:deleteDiagnosis',
viewPatientsPrivilege: 'View Patients',
editPatientsPrivilege: 'Edit Patients',
addVisitsPrivilege: 'Add Visits',
deleteVisitsPrivilege: 'Delete Visits',
grantProviderAccess: "app:clinical:grantProviderAccess",
grantProviderAccessDataCookieName: "app.clinical.grantProviderAccessData",
globalPropertyUrl: BAHMNI_CORE + "/sql/globalproperty",
passwordPolicyUrl: BAHMNI_CORE + "/globalProperty/passwordPolicyProperties",
fulfillmentConfiguration: "fulfillment",
fulfillmentFormSuffix: " Fulfillment Form",
noNavigationLinksMessage: "NO_NAVIGATION_LINKS_AVAILABLE_MESSAGE",
conceptSetRepresentationForOrderFulfillmentConfig: representation,
entityMappingUrl: RESTWS_V1 + "/entitymapping",
encounterTypeUrl: RESTWS_V1 + "/encountertype",
defaultExtensionName: "default",
orderSetMemberAttributeTypeUrl: RESTWS_V1 + "/ordersetmemberattributetype",
orderSetUrl: RESTWS_V1 + "/bahmniorderset",
primaryOrderSetMemberAttributeTypeName: "Primary",
bahmniBacteriologyResultsUrl: BACTERIOLOGY + "/specimen",
bedFromVisit: RESTWS_V1 + "/beds",
ordersUrl: RESTWS_V1 + "/order",
formDataUrl: RESTWS_V1 + "/obs",
providerUrl: RESTWS_V1 + "/provider",
drugUrl: RESTWS_V1 + "/drug",
orderTypeUrl: RESTWS_V1 + "/ordertype",
userUrl: RESTWS_V1 + "/user",
passwordUrl: RESTWS_V1 + "/password",
formUrl: RESTWS_V1 + "/form",
allFormsUrl: RESTWS_V1 + "/bahmniie/form/allForms",
latestPublishedForms: RESTWS_V1 + "/bahmniie/form/latestPublishedForms",
formTranslationsUrl: RESTWS_V1 + "/bahmniie/form/translations",
sqlUrl: BAHMNI_CORE + "/sql",
patientAttributeDateFieldFormat: "org.openmrs.util.AttributableDate",
platform: "user.platform",
RESTWS_V1: RESTWS_V1,
baseUrl: BASE_URL,
customUrl: CUSTOM_URL,
faviconUrl: hostUrl + "/bahmni/favicon.ico",
platformType: {
other: 'other'
},
numericDataType: "Numeric",
encryptionType: {
SHA3: 'SHA3'
},
LoginInformation: 'LoginInformation',
// orderSetSpecialUnits:["mg/kg","mg/m2"],
ServerDateTimeFormat: 'YYYY-MM-DDTHH:mm:ssZZ',
calculateDose: BAHMNI_CORE + "/calculateDose",
unAuthenticatedReferenceDataMap: unAuthenticatedReferenceDataMap,
authenticatedReferenceDataMap: authenticatedReferenceDataMap,
rootDir: rootDir,
dischargeUrl: BAHMNI_CORE + "/discharge",
uuidRegex: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
eventlogFilterUrl: hostUrl + "/openmrs/ws/rest/v1/eventlog/filter",
bahmniConnectMetaDataDb: "metaData",
serverDateTimeUrl: "/cgi-bin/systemdate",
loginText: "/bahmni_config/openmrs/apps/home/whiteLabel.json",
auditLogUrl: RESTWS_V1 + "/auditlog",
appointmentServiceUrl: RESTWS_V1 + "/appointmentService",
conditionUrl: EMRAPI + '/condition',
conditionHistoryUrl: EMRAPI + '/conditionhistory',
followUpConditionConcept: 'Follow-up Condition',
localeLangs: "/bahmni_config/openmrs/apps/home/locale_languages.json",
privilegeRequiredErrorMessage: "PRIVILEGE_REQUIRED",
defaultPossibleRelativeSearchLimit: 10
};
})();
'use strict';
angular.module('bahmni.common.routeErrorHandler', ['ui.router'])
.run(['$rootScope', function ($rootScope) {
$rootScope.$on('$stateChangeError', function (event) {
event.preventDefault();
});
}]);
'use strict';
angular.module('httpErrorInterceptor', [])
.config(['$httpProvider', function ($httpProvider) {
var interceptor = ['$rootScope', '$q', function ($rootScope, $q) {
var serverErrorMessages = Bahmni.Common.Constants.serverErrorMessages;
var showError = function (errorMessage) {
var result = _.find(serverErrorMessages, function (listItem) {
return listItem.serverMessage === errorMessage;
});
if (_.isEmpty(result)) {
$rootScope.$broadcast('event:serverError', errorMessage);
}
};
function stringAfter (value, searchString) {
var indexOfFirstColon = value.indexOf(searchString);
return value.substr(indexOfFirstColon + 1).trim();
}
function getServerError (message) {
return stringAfter(message, ':');
}
function success (response) {
return response;
}
function shouldRedirectToLogin (response) {
var errorMessage = response.data.error ? response.data.error.message : response.data;
if (errorMessage.search("HTTP Status 403 - Session timed out") > 0) {
return true;
}
}
function error (response) {
var data = response.data;
var unexpectedError = "There was an unexpected issue on the server. Please try again";
if (response.status === 500) {
var errorMessage = data.error && data.error.message ? getServerError(data.error.message) : unexpectedError;
showError(errorMessage);
} else if (response.status === 409) {
var errorMessage = data.error && data.error.message ? getServerError(data.error.message) : "Duplicate entry error";
showError(errorMessage);
} else if (response.status === 0) {
showError("Could not connect to the server. Please check your connection and try again");
} else if (response.status === 405) {
showError(unexpectedError);
} else if (response.status === 400) {
var errorMessage = data.error && data.error.message ? data.error.message : (data.localizedMessage || "Could not connect to the server. Please check your connection and try again");
showError(errorMessage);
} else if (response.status === 403) {
var errorMessage = data.error && data.error.message ? data.error.message : unexpectedError;
if (shouldRedirectToLogin(response)) {
$rootScope.$broadcast('event:auth-loginRequired');
} else {
showError(errorMessage);
}
} else if (response.status === 404) {
if (!_.includes(response.config.url, "implementation_config") && !_.includes(response.config.url, "locale_")
&& !_.includes(response.config.url, "offlineMetadata")) {
showError("The requested information does not exist");
}
}
return $q.reject(response);
}
return {
response: success,
responseError: error
};
}];
$httpProvider.interceptors.push(interceptor);
}]);
'use strict';
Bahmni.Common.Util.ArrayUtil = {
chunk: function (array, chunkSize) {
var chunks = [];
for (var i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
},
groupByPreservingOrder: function (records, groupingFunction, keyName, valueName) {
var groups = [];
records.forEach(function (record) {
var recordKey = groupingFunction(record);
var existingGroup = _.find(groups, function (group) { return group[keyName] === recordKey; });
if (existingGroup) {
existingGroup[valueName].push(record);
} else {
var newGroup = {};
newGroup[keyName] = recordKey;
newGroup[valueName] = [record];
groups.push(newGroup);
}
});
return groups;
}
};
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Auth = Bahmni.Auth || {};
angular.module('authentication', ['ui.router']);
'use strict';
Bahmni.Auth.User = function (user) {
angular.extend(this, user);
this.userProperties = user.userProperties || {};
this.favouriteObsTemplates = this.userProperties.favouriteObsTemplates ? this.userProperties.favouriteObsTemplates.split("###") : [];
this.favouriteWards = this.userProperties.favouriteWards ? this.userProperties.favouriteWards.split("###") : [];
this.recentlyViewedPatients = this.userProperties.recentlyViewedPatients ? JSON.parse(this.userProperties.recentlyViewedPatients) : [];
this.toContract = function () {
var user = angular.copy(this);
user.userProperties.favouriteObsTemplates = this.favouriteObsTemplates.join("###");
user.userProperties.favouriteWards = this.favouriteWards.join("###");
user.userProperties.recentlyViewedPatients = JSON.stringify(this.recentlyViewedPatients);
delete user.favouriteObsTemplates;
delete user.favouriteWards;
delete user.recentlyViewedPatients;
return user;
};
this.addDefaultLocale = function (locale) {
this.userProperties['defaultLocale'] = locale;
};
this.addToRecentlyViewed = function (patient, maxPatients) {
if (!_.some(this.recentlyViewedPatients, {'uuid': patient.uuid})) {
this.recentlyViewedPatients.unshift({
uuid: patient.uuid,
name: patient.name,
identifier: patient.identifier
});
if (_.size(this.recentlyViewedPatients) >= maxPatients) {
this.recentlyViewedPatients = _.take(this.recentlyViewedPatients, maxPatients);
}
}
};
this.isFavouriteObsTemplate = function (conceptName) {
return _.includes(this.favouriteObsTemplates, conceptName);
};
this.toggleFavoriteObsTemplate = function (conceptName) {
if (this.isFavouriteObsTemplate(conceptName)) {
this.favouriteObsTemplates = _.without(this.favouriteObsTemplates, conceptName);
} else {
this.favouriteObsTemplates.push(conceptName);
}
};
this.isFavouriteWard = function (wardName) {
return _.includes(this.favouriteWards, wardName);
};
this.toggleFavoriteWard = function (wardName) {
if (this.isFavouriteWard(wardName)) {
this.favouriteWards = _.without(this.favouriteWards, wardName);
} else {
this.favouriteWards.push(wardName);
}
};
};
'use strict';
angular.module('authentication')
.service('userService', ['$rootScope', '$http', '$q', function ($rootScope, $http, $q) {
var getUserFromServer = function (userName) {
return $http.get(Bahmni.Common.Constants.userUrl, {
method: "GET",
params: {
username: userName,
v: "custom:(username,uuid,person:(uuid,),privileges:(name,retired),userProperties)"
},
cache: false
});
};
this.getUser = function (userName) {
var deferrable = $q.defer();
getUserFromServer(userName).success(function (data) {
deferrable.resolve(data);
}).error(function () {
deferrable.reject('Unable to get user data');
});
return deferrable.promise;
};
this.savePreferences = function () {
var deferrable = $q.defer();
var user = $rootScope.currentUser.toContract();
$http.post(Bahmni.Common.Constants.userUrl + "/" + user.uuid, {"uuid": user.uuid, "userProperties": user.userProperties}, {
withCredentials: true
}).then(function (response) {
$rootScope.currentUser.userProperties = response.data.userProperties;
deferrable.resolve();
});
return deferrable.promise;
};
var getProviderFromServer = function (uuid) {
return $http.get(Bahmni.Common.Constants.providerUrl, {
method: "GET",
params: {
user: uuid
},
cache: false
});
};
this.getProviderForUser = function (uuid) {
var deferrable = $q.defer();
getProviderFromServer(uuid).success(function (data) {
if (data.results.length > 0) {
var providerName = data.results[0].display.split("-")[1];
data.results[0].name = providerName ? providerName.trim() : providerName;
deferrable.resolve(data);
} else {
deferrable.reject("UNABLE_TO_GET_PROVIDER_DATA");
}
}).error(function () {
deferrable.reject("UNABLE_TO_GET_PROVIDER_DATA");
});
return deferrable.promise;
};
this.getPasswordPolicies = function () {
return $http.get(Bahmni.Common.Constants.passwordPolicyUrl, {
method: "GET",
withCredentials: true
});
};
}]);
'use strict';
angular.module('authentication')
.config(['$httpProvider', function ($httpProvider) {
var interceptor = ['$rootScope', '$q', function ($rootScope, $q) {
function success (response) {
return response;
}
function error (response) {
if (response.status === 401) {
$rootScope.$broadcast('event:auth-loginRequired');
}
return $q.reject(response);
}
return {
response: success,
responseError: error
};
}];
$httpProvider.interceptors.push(interceptor);
}]).run(['$rootScope', '$window', '$timeout', function ($rootScope, $window, $timeout) {
$rootScope.$on('event:auth-loginRequired', function () {
$timeout(function () {
$window.location = "../home/index.html#/login";
});
});
}]).service('sessionService', ['$rootScope', '$http', '$q', '$bahmniCookieStore', 'userService', function ($rootScope, $http, $q, $bahmniCookieStore, userService) {
var sessionResourcePath = Bahmni.Common.Constants.RESTWS_V1 + '/session?v=custom:(uuid)';
var getAuthFromServer = function (username, password, otp) {
var btoa = otp ? username + ':' + password + ':' + otp : username + ':' + password;
return $http.get(sessionResourcePath, {
headers: {'Authorization': 'Basic ' + window.btoa(btoa)},
cache: false
});
};
this.resendOTP = function (username, password) {
var btoa = username + ':' + password;
return $http.get(sessionResourcePath + '&resendOTP=true', {
headers: {'Authorization': 'Basic ' + window.btoa(btoa)},
cache: false
});
};
var createSession = function (username, password, otp) {
var deferrable = $q.defer();
destroySessionFromServer().success(function () {
getAuthFromServer(username, password, otp).then(function (response) {
if (response.status == 204) {
deferrable.resolve({"firstFactAuthorization": true});
}
deferrable.resolve(response.data);
}, function (response) {
if (response.status == 401) {
deferrable.reject('LOGIN_LABEL_WRONG_OTP_MESSAGE_KEY');
} else if (response.status == 410) {
deferrable.reject('LOGIN_LABEL_OTP_EXPIRED');
} else if (response.status == 429) { // Too many requests
deferrable.reject('LOGIN_LABEL_MAX_FAILED_ATTEMPTS');
}
deferrable.reject('LOGIN_LABEL_LOGIN_ERROR_MESSAGE_KEY');
});
}).error(function () {
deferrable.reject('LOGIN_LABEL_LOGIN_ERROR_MESSAGE_KEY');
});
return deferrable.promise;
};
var hasAnyActiveProvider = function (providers) {
return _.filter(providers, function (provider) {
return (provider.retired == undefined || provider.retired == "false");
}).length > 0;
};
var self = this;
var destroySessionFromServer = function () {
return $http.delete(sessionResourcePath);
};
var sessionCleanup = function () {
delete $.cookie(Bahmni.Common.Constants.currentUser, null, {path: "/"});
delete $.cookie(Bahmni.Common.Constants.currentUser, null, {path: "/"});
delete $.cookie(Bahmni.Common.Constants.retrospectiveEntryEncounterDateCookieName, null, {path: "/"});
delete $.cookie(Bahmni.Common.Constants.grantProviderAccessDataCookieName, null, {path: "/"});
$rootScope.currentUser = undefined;
};
this.destroy = function () {
var deferrable = $q.defer();
destroySessionFromServer().then(function () {
sessionCleanup();
deferrable.resolve();
});
return deferrable.promise;
};
this.loginUser = function (username, password, location, otp) {
var deferrable = $q.defer();
createSession(username, password, otp).then(function (data) {
if (data.authenticated) {
$bahmniCookieStore.put(Bahmni.Common.Constants.currentUser, username, {path: '/', expires: 7});
if (location != undefined) {
$bahmniCookieStore.remove(Bahmni.Common.Constants.locationCookieName);
$bahmniCookieStore.put(Bahmni.Common.Constants.locationCookieName, {name: location.display, uuid: location.uuid}, {path: '/', expires: 7});
}
deferrable.resolve(data);
} else if (data.firstFactAuthorization) {
deferrable.resolve(data);
} else {
deferrable.reject('LOGIN_LABEL_LOGIN_ERROR_MESSAGE_KEY');
}
}, function (errorInfo) {
deferrable.reject(errorInfo);
});
return deferrable.promise;
};
this.get = function () {
return $http.get(sessionResourcePath, { cache: false });
};
this.loadCredentials = function () {
var deferrable = $q.defer();
var currentUser = $bahmniCookieStore.get(Bahmni.Common.Constants.currentUser);
if (!currentUser) {
this.destroy().finally(function () {
$rootScope.$broadcast('event:auth-loginRequired');
deferrable.reject("No User in session. Please login again.");
});
return deferrable.promise;
}
userService.getUser(currentUser).then(function (data) {
userService.getProviderForUser(data.results[0].uuid).then(function (providers) {
if (!_.isEmpty(providers.results) && hasAnyActiveProvider(providers.results)) {
$rootScope.currentUser = new Bahmni.Auth.User(data.results[0]);
$rootScope.currentUser.currentLocation = $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName).name;
$rootScope.$broadcast('event:user-credentialsLoaded', data.results[0]);
deferrable.resolve(data.results[0]);
} else {
self.destroy();
deferrable.reject("YOU_HAVE_NOT_BEEN_SETUP_PROVIDER");
}
},
function () {
self.destroy();
deferrable.reject("COULD_NOT_GET_PROVIDER");
});
}, function () {
self.destroy();
deferrable.reject('Could not get roles for the current user.');
});
return deferrable.promise;
};
this.getLoginLocationUuid = function () {
return $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName) ? $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName).uuid : null;
};
this.changePassword = function (currentUserUuid, oldPassword, newPassword) {
return $http({
method: 'POST',
url: Bahmni.Common.Constants.passwordUrl,
data: {
"oldPassword": oldPassword,
"newPassword": newPassword
},
headers: {'Content-Type': 'application/json'}
});
};
this.loadProviders = function (userInfo) {
return $http.get(Bahmni.Common.Constants.providerUrl, {
method: "GET",
params: {
user: userInfo.uuid
},
cache: false
}).success(function (data) {
var providerUuid = (data.results.length > 0) ? data.results[0].uuid : undefined;
$rootScope.currentProvider = { uuid: providerUuid };
});
};
}]).factory('authenticator', ['$rootScope', '$q', '$window', 'sessionService', function ($rootScope, $q, $window, sessionService) {
var authenticateUser = function () {
var defer = $q.defer();
var sessionDetails = sessionService.get();
sessionDetails.then(function (response) {
if (response.data.authenticated) {
defer.resolve();
} else {
defer.reject('User not authenticated');
$rootScope.$broadcast('event:auth-loginRequired');
}
});
return defer.promise;
};
return {
authenticateUser: authenticateUser
};
}]).directive('logOut', ['sessionService', '$window', 'configurationService', 'auditLogService', function (sessionService, $window, configurationService, auditLogService) {
return {
link: function (scope, element) {
element.bind('click', function () {
scope.$apply(function () {
auditLogService.log(undefined, 'USER_LOGOUT_SUCCESS', undefined, 'MODULE_LABEL_LOGOUT_KEY').then(function () {
sessionService.destroy().then(
function () {
$window.location = "../home/index.html#/login";
});
});
});
});
}
};
}])
.directive('btnUserInfo', [function () {
return {
restrict: 'CA',
link: function (scope, elem) {
elem.bind('click', function (event) {
$(this).next().toggleClass('active');
event.stopPropagation();
});
$(document).find('body').bind('click', function () {
$(elem).next().removeClass('active');
});
}
};
}
]);
angular.module('bahmni.common.config', []);
'use strict';
angular.module('bahmni.common.config')
.service('configurations', ['configurationService', function (configurationService) {
this.configs = {};
this.load = function (configNames) {
var self = this;
return configurationService.getConfigurations(_.difference(configNames, Object.keys(this.configs))).then(function (configurations) {
angular.extend(self.configs, configurations);
});
};
this.dosageInstructionConfig = function () {
return this.configs.dosageInstructionConfig || [];
};
this.stoppedOrderReasonConfig = function () {
return this.configs.stoppedOrderReasonConfig || [];
};
this.dosageFrequencyConfig = function () {
return this.configs.dosageFrequencyConfig || [];
};
this.allTestsAndPanelsConcept = function () {
return this.configs.allTestsAndPanelsConcept.results[0] || [];
};
this.impressionConcept = function () {
return this.configs.radiologyImpressionConfig.results[0] || [];
};
this.labOrderNotesConcept = function () {
return this.configs.labOrderNotesConfig.results[0] || [];
};
this.consultationNoteConcept = function () {
return this.configs.consultationNoteConfig.results[0] || [];
};
this.patientConfig = function () {
return this.configs.patientConfig || {};
};
this.encounterConfig = function () {
return angular.extend(new EncounterConfig(), this.configs.encounterConfig || []);
};
this.patientAttributesConfig = function () {
return this.configs.patientAttributesConfig.results;
};
this.identifierTypesConfig = function () {
return this.configs.identifierTypesConfig;
};
this.genderMap = function () {
return this.configs.genderMap;
};
this.addressLevels = function () {
return this.configs.addressLevels;
};
this.relationshipTypes = function () {
return this.configs.relationshipTypeConfig.results || [];
};
this.relationshipTypeMap = function () {
return this.configs.relationshipTypeMap || {};
};
this.loginLocationToVisitTypeMapping = function () {
return this.configs.loginLocationToVisitTypeMapping || {};
};
this.defaultEncounterType = function () {
return this.configs.defaultEncounterType;
};
}]);
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.Domain = Bahmni.Common.Domain || {};
Bahmni.Common.Domain.Helper = Bahmni.Common.Domain.Helper || {};
angular.module('bahmni.common.domain', []);
'use strict';
(function () {
var nameFor = {
"Date": function (obs) {
return moment(obs.value).format('D-MMM-YYYY');
},
"Datetime": function (obs) {
var date = Bahmni.Common.Util.DateUtil.parseDatetime(obs.value);
return date != null ? Bahmni.Common.Util.DateUtil.formatDateWithTime(date) : "";
},
"Boolean": function (obs) {
return obs.value === true ? "Yes" : obs.value === false ? "No" : obs.value;
},
"Coded": function (obs) {
return obs.value.shortName || obs.value.name || obs.value;
},
"Object": function (obs) {
return nameFor.Coded(obs);
},
"MultiSelect": function (obs) {
return obs.getValues().join(", ");
},
"Default": function (obs) {
return obs.value;
}
};
Bahmni.Common.Domain.ObservationValueMapper = {
getNameFor: nameFor,
map: function (obs) {
var type = (obs.concept && obs.concept.dataType) || obs.type;
if (!(type in nameFor)) {
type = (typeof obs.value === "object" && "Object") || (obs.isMultiSelect && "MultiSelect") || "Default";
}
return (nameFor[type])(obs);
}
};
})();
angular.module('bahmni.common.appFramework', ['authentication']);
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.AppFramework = Bahmni.Common.AppFramework || {};
'use strict';
Bahmni.Common.AppFramework.AppDescriptor = function (context, inheritContext, retrieveUserCallback, mergeService) {
this.id = null;
this.instanceOf = null;
this.description = null;
this.contextModel = null;
this.baseExtensionPoints = [];
this.customExtensionPoints = [];
this.baseExtensions = {};
this.customExtensions = {};
this.customConfigs = {};
this.baseConfigs = {};
this.extensionPath = context;
this.contextPath = inheritContext ? context.split("/")[0] : context;
var self = this;
var setExtensionPointsFromExtensions = function (currentExtensions, currentExtensionPoints) {
_.values(currentExtensions).forEach(function (extn) {
if (extn) {
var existing = self[currentExtensionPoints].filter(function (ep) {
return ep.id === extn.extensionPointId;
});
if (existing.length === 0) {
self[currentExtensionPoints].push({
id: extn.extensionPointId,
description: extn.description
});
}
}
});
};
this.setExtensions = function (baseExtensions, customExtensions) {
if (customExtensions) {
setExtensionPointsFromExtensions(customExtensions, "customExtensionPoints");
self.customExtensions = customExtensions;
}
self.baseExtensions = baseExtensions;
setExtensionPointsFromExtensions(baseExtensions, "baseExtensionPoints");
};
this.setTemplate = function (template) {
self.instanceOf = template.id;
self.description = self.description || template.description;
self.contextModel = self.contextModel || template.contextModel;
if (template.configOptions) {
_.values(template.configOptions).forEach(function (opt) {
var existing = self.configs.filter(function (cfg) {
return cfg.name === opt.name;
});
if (existing.length > 0) {
existing[0].description = opt.description;
} else {
self.configs.push({
name: opt.name,
description: opt.description,
value: opt.defaultValue
});
}
});
}
};
var setConfig = function (instance, currentConfig) {
for (var configName in instance.config) {
var existingConfig = getConfig(self[currentConfig], configName);
if (existingConfig) {
existingConfig.value = instance.config[configName];
} else {
self[currentConfig][configName] = { name: configName, value: instance.config[configName] };
}
}
};
var setDefinitionExtensionPoints = function (extensionPoints, currentExtensionPoints) {
if (extensionPoints) {
extensionPoints.forEach(function (iep) {
if (iep) {
var existing = self[currentExtensionPoints].filter(function (ep) {
return ep.id === iep.id;
});
if (existing.length === 0) {
self[currentExtensionPoints].push(iep);
}
}
});
}
};
this.setDefinition = function (baseInstance, customInstance) {
self.instanceOf = (customInstance && customInstance.instanceOf) ? customInstance.instanceOf : baseInstance.instanceOf;
self.id = (customInstance && customInstance.id) ? customInstance.id : baseInstance.id;
self.description = (customInstance && customInstance.description) ? customInstance.description : baseInstance.description;
self.contextModel = (customInstance && customInstance.contextModel) ? customInstance.contextModel : baseInstance.contextModel;
setDefinitionExtensionPoints(baseInstance.extensionPoints, "baseExtensionPoints");
setConfig(baseInstance, "baseConfigs");
if (customInstance) {
setDefinitionExtensionPoints(customInstance.extensionPoints, "customExtensionPoints");
setConfig(customInstance, "customConfigs");
}
};
var getExtensions = function (extPointId, type, extensions) {
var currentUser = retrieveUserCallback();
var currentExtensions = _.values(extensions);
if (currentUser && currentExtensions) {
var extnType = type || 'all';
var userPrivileges = currentUser.privileges.map(function (priv) {
return priv.retired ? "" : priv.name;
});
var appsExtns = currentExtensions.filter(function (extn) {
return ((extnType === 'all') || (extn.type === extnType)) &&
(extn.extensionPointId === extPointId) && (!extn.requiredPrivilege ||
(userPrivileges.indexOf(extn.requiredPrivilege) >= 0));
});
appsExtns.sort(function (extn1, extn2) {
return extn1.order - extn2.order;
});
return appsExtns;
}
};
this.getExtensions = function (extPointId, type, shouldMerge) {
if (shouldMerge || shouldMerge === undefined) {
var mergedExtensions = mergeService.merge(self.baseExtensions, self.customExtensions);
return getExtensions(extPointId, type, mergedExtensions);
}
return [getExtensions(extPointId, type, self.baseExtensions), getExtensions(extPointId, type, self.customExtensions)];
};
this.getExtensionById = function (id, shouldMerge) {
if (shouldMerge || shouldMerge === undefined) {
var mergedExtensions = _.values(mergeService.merge(self.baseExtensions, self.customExtensions));
return mergedExtensions.filter(function (extn) {
return extn.id === id;
})[0];
} else {
return [self.baseExtensions.filter(function (extn) {
return extn.id === id;
})[0], self.customExtensions.filter(function (extn) {
return extn.id === id;
})[0]];
}
};
var getConfig = function (config, configName) {
var cfgList = _.values(config).filter(function (cfg) {
return cfg.name === configName;
});
return (cfgList.length > 0) ? cfgList[0] : null;
};
this.getConfig = function (configName, shouldMerge) {
if (shouldMerge || shouldMerge === undefined) {
return getConfig(mergeService.merge(self.baseConfigs, self.customConfigs), configName);
} else {
return [getConfig(self.baseConfigs, configName), getConfig(self.customConfigs, configName)];
}
};
this.getConfigValue = function (configName, shouldMerge) {
var config = this.getConfig(configName, shouldMerge);
if (shouldMerge || shouldMerge === undefined) {
return config ? config.value : null;
}
return config;
};
this.formatUrl = function (url, options, useQueryParams) {
var pattern = /{{([^}]*)}}/g,
matches = url.match(pattern),
replacedString = url,
checkQueryParams = useQueryParams || false,
queryParameters = this.parseQueryParams();
if (matches) {
matches.forEach(function (el) {
var key = el.replace("{{", '').replace("}}", '');
var value = options[key];
if (!value && (checkQueryParams === true)) {
value = queryParameters[key] || null;
}
replacedString = replacedString.replace(el, value);
});
}
return replacedString.trim();
};
this.parseQueryParams = function (locationSearchString) {
var urlParams;
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
queryString = locationSearchString || window.location.search.substring(1);
urlParams = {};
while (match = search.exec(queryString)) { // eslint-disable-line no-cond-assign
urlParams[decode(match[1])] = decode(match[2]);
}
return urlParams;
};
this.addConfigForPage = function (pageName, baseConfig, customConfig) {
self.basePageConfigs = self.basePageConfigs || {};
self.basePageConfigs[pageName] = baseConfig;
self.customPageConfigs = self.customPageConfigs || {};
self.customPageConfigs[pageName] = customConfig;
};
this.getConfigForPage = function (pageName, shouldMerge) {
if (shouldMerge || shouldMerge === undefined) {
return mergeService.merge(self.basePageConfigs[pageName], self.customPageConfigs[pageName]);
}
return [_.values(self.basePageConfigs[pageName]), _.values(self.customPageConfigs[pageName])];
};
};
'use strict';
angular.module('bahmni.common.appFramework')
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|file):/);
}])
.service('appService', ['$http', '$q', 'sessionService', '$rootScope', 'mergeService', 'loadConfigService', 'messagingService', '$translate',
function ($http, $q, sessionService, $rootScope, mergeService, loadConfigService, messagingService, $translate) {
var currentUser = null;
var baseUrl = Bahmni.Common.Constants.baseUrl;
var customUrl = Bahmni.Common.Constants.customUrl;
var appDescriptor = null;
var loadConfig = function (url) {
return loadConfigService.loadConfig(url, appDescriptor.contextPath);
};
var loadTemplate = function (appDescriptor) {
var deferrable = $q.defer();
loadConfig(baseUrl + appDescriptor.contextPath + "/appTemplate.json").then(
function (result) {
if (_.keys(result.data).length > 0) {
appDescriptor.setTemplate(result.data);
}
deferrable.resolve(appDescriptor);
},
function (error) {
if (error.status !== 404) {
deferrable.reject(error);
} else {
deferrable.resolve(appDescriptor);
}
}
);
return deferrable.promise;
};
var setDefinition = function (baseResultData, customResultData) {
if (customResultData && (_.keys(baseResultData).length > 0 || _.keys(customResultData.length > 0))) {
appDescriptor.setDefinition(baseResultData, customResultData);
} else if (_.keys(baseResultData).length > 0) {
appDescriptor.setDefinition(baseResultData);
}
};
var loadDefinition = function (appDescriptor) {
var deferrable = $q.defer();
loadConfig(baseUrl + appDescriptor.contextPath + "/app.json").then(
function (baseResult) {
if (baseResult.data.shouldOverRideConfig) {
loadConfig(customUrl + appDescriptor.contextPath + "/app.json").then(function (customResult) {
setDefinition(baseResult.data, customResult.data);
deferrable.resolve(appDescriptor);
},
function () {
setDefinition(baseResult.data);
deferrable.resolve(appDescriptor);
});
} else {
setDefinition(baseResult.data);
deferrable.resolve(appDescriptor);
}
}, function (error) {
if (error.status !== 404) {
deferrable.reject(error);
} else {
deferrable.resolve(appDescriptor);
}
});
return deferrable.promise;
};
var setExtensions = function (baseResultData, customResultData) {
if (customResultData) {
appDescriptor.setExtensions(baseResultData, customResultData);
} else {
appDescriptor.setExtensions(baseResultData);
}
};
var loadExtensions = function (appDescriptor, extensionFileName) {
var deferrable = $q.defer();
loadConfig(baseUrl + appDescriptor.extensionPath + extensionFileName).then(function (baseResult) {
if (baseResult.data.shouldOverRideConfig) {
loadConfig(customUrl + appDescriptor.extensionPath + extensionFileName).then(
function (customResult) {
setExtensions(baseResult.data, customResult.data);
deferrable.resolve(appDescriptor);
},
function () {
setExtensions(baseResult.data);
deferrable.resolve(appDescriptor);
});
} else {
setExtensions(baseResult.data);
deferrable.resolve(appDescriptor);
}
}, function (error) {
if (error.status !== 404) {
deferrable.reject(error);
} else {
deferrable.resolve(appDescriptor);
}
});
return deferrable.promise;
};
var setDefaultPageConfig = function (pageName, baseResultData, customResultData) {
if (customResultData && (_.keys(customResultData).length > 0 || _.keys(baseResultData).length > 0)) {
appDescriptor.addConfigForPage(pageName, baseResultData, customResultData);
} else if (_.keys(baseResultData).length > 0) {
appDescriptor.addConfigForPage(pageName, baseResultData);
}
};
var hasPrivilegeOf = function (privilegeName) {
return _.some(currentUser.privileges, {name: privilegeName});
};
var loadPageConfig = function (pageName, appDescriptor) {
var deferrable = $q.defer();
loadConfig(baseUrl + appDescriptor.contextPath + "/" + pageName + ".json").then(
function (baseResult) {
if (baseResult.data.shouldOverRideConfig) {
loadConfig(customUrl + appDescriptor.contextPath + "/" + pageName + ".json").then(
function (customResult) {
setDefaultPageConfig(pageName, baseResult.data, customResult.data);
deferrable.resolve(appDescriptor);
},
function () {
setDefaultPageConfig(pageName, baseResult.data);
deferrable.resolve(appDescriptor);
});
} else {
setDefaultPageConfig(pageName, baseResult.data);
deferrable.resolve(appDescriptor);
}
}, function (error) {
if (error.status !== 404) {
messagingService.showMessage('error', "Incorrect Configuration: " + error.message);
deferrable.reject(error);
} else {
deferrable.resolve(appDescriptor);
}
});
return deferrable.promise;
};
this.getAppDescriptor = function () {
return appDescriptor;
};
this.configBaseUrl = function () {
return baseUrl;
};
this.loadCsvFileFromConfig = function (name) {
return loadConfig(baseUrl + appDescriptor.contextPath + "/" + name);
};
this.loadConfig = function (name, shouldMerge) {
return loadConfig(baseUrl + appDescriptor.contextPath + "/" + name).then(
function (baseResponse) {
if (baseResponse.data.shouldOverRideConfig) {
return loadConfig(customUrl + appDescriptor.contextPath + "/" + name).then(function (customResponse) {
if (shouldMerge || shouldMerge === undefined) {
return mergeService.merge(baseResponse.data, customResponse.data);
}
return [baseResponse.data, customResponse.data];
}, function () {
return baseResponse.data;
});
} else {
return baseResponse.data;
}
}
);
};
this.loadMandatoryConfig = function (path) {
return $http.get(path);
};
this.getAppName = function () {
return this.appName;
};
this.checkPrivilege = function (privilegeName) {
if (hasPrivilegeOf(privilegeName)) {
return $q.when(true);
}
messagingService.showMessage("error", $translate.instant(Bahmni.Common.Constants.privilegeRequiredErrorMessage) + " [Privileges required: " + privilegeName + "]");
return $q.reject();
};
this.initApp = function (appName, options, extensionFileSuffix, configPages) {
this.appName = appName;
var appLoader = $q.defer();
var extensionFileName = (extensionFileSuffix && extensionFileSuffix.toLowerCase() !== 'default') ? "/extension-" + extensionFileSuffix + ".json" : "/extension.json";
var promises = [];
var opts = options || {'app': true, 'extension': true};
var inheritAppContext = (!opts.inherit) ? true : opts.inherit;
appDescriptor = new Bahmni.Common.AppFramework.AppDescriptor(appName, inheritAppContext, function () {
return currentUser;
}, mergeService);
var loadCredentialsPromise = sessionService.loadCredentials();
var loadProviderPromise = loadCredentialsPromise.then(sessionService.loadProviders);
promises.push(loadCredentialsPromise);
promises.push(loadProviderPromise);
if (opts.extension) {
promises.push(loadExtensions(appDescriptor, extensionFileName));
}
if (opts.template) {
promises.push(loadTemplate(appDescriptor));
}
if (opts.app) {
promises.push(loadDefinition(appDescriptor));
}
if (!_.isEmpty(configPages)) {
configPages.forEach(function (configPage) {
promises.push(loadPageConfig(configPage, appDescriptor));
});
}
$q.all(promises).then(function (results) {
currentUser = results[0];
appLoader.resolve(appDescriptor);
$rootScope.$broadcast('event:appExtensions-loaded');
}, function (errors) {
appLoader.reject(errors);
});
return appLoader.promise;
};
}]);
'use strict';
angular.module('bahmni.common.appFramework')
.service('mergeService', [function () {
this.merge = function (base, custom) {
var mergeResult = $.extend(true, {}, base, custom);
return deleteNullValuedKeys(mergeResult);
};
var deleteNullValuedKeys = function (currentObject) {
_.forOwn(currentObject, function (value, key) {
if (_.isUndefined(value) || _.isNull(value) || _.isNaN(value) ||
(_.isObject(value) && _.isNull(deleteNullValuedKeys(value)))) {
delete currentObject[key];
}
});
return currentObject;
};
}]);
angular.module('bahmni.common.uiHelper', ['ngClipboard']);
'use strict';
angular.module('bahmni.common.uiHelper')
.service('backlinkService', ['$window', function ($window) {
var self = this;
var urls = [];
self.reset = function () {
urls = [];
};
self.setUrls = function (backLinks) {
self.reset();
angular.forEach(backLinks, function (backLink) {
self.addUrl(backLink);
});
};
self.addUrl = function (backLink) {
urls.push(backLink);
};
self.addBackUrl = function (label) {
var backLabel = label || "Back";
urls.push({label: backLabel, action: $window.history.back});
};
self.getUrlByLabel = function (label) {
return urls.filter(function (url) {
return url.label === label;
});
};
self.getAllUrls = function () {
return urls;
};
}]);
'use strict';
angular.module('bahmni.common.uiHelper')
.filter('days', function () {
return function (startDate, endDate) {
return Bahmni.Common.Util.DateUtil.diffInDays(startDate, endDate);
};
}).filter('bahmniDateTime', function () {
return function (date) {
return Bahmni.Common.Util.DateUtil.formatDateWithTime(date);
};
}).filter('bahmniDate', function () {
return function (date) {
return Bahmni.Common.Util.DateUtil.formatDateWithoutTime(date);
};
}).filter('bahmniTime', function () {
return function (date) {
return Bahmni.Common.Util.DateUtil.formatTime(date);
};
}).filter('bahmniDateInStrictMode', function () {
return function (date) {
return Bahmni.Common.Util.DateUtil.formatDateInStrictMode(date);
};
});
'use strict';
angular.module('bahmni.common.uiHelper')
.factory('spinner', ['messagingService', '$timeout', function (messagingService, $timeout) {
var tokens = [];
var topLevelDiv = function (element) {
return $(element).find("div").eq(0);
};
var showSpinnerForElement = function (element) {
if ($(element).find(".dashboard-section-loader").length === 0) {
topLevelDiv(element)
.addClass('spinnable')
.append('<div class="dashboard-section-loader"></div>');
}
return {
element: $(element).find(".dashboard-section-loader")
};
};
var showSpinnerForOverlay = function () {
var token = Math.random();
tokens.push(token);
if ($('#overlay').length === 0) {
$('body').prepend('<div id="overlay"><div></div></div>');
}
var spinnerElement = $('#overlay');
spinnerElement.stop().show();
return {
element: spinnerElement,
token: token
};
};
var show = function (element) {
if (element !== undefined) {
return showSpinnerForElement(element);
}
return showSpinnerForOverlay();
};
var hide = function (spinner, parentElement) {
var spinnerElement = spinner.element;
if (spinner.token) {
_.pull(tokens, spinner.token);
if (tokens.length === 0) {
spinnerElement.fadeOut(300);
}
} else {
topLevelDiv(parentElement).removeClass('spinnable');
spinnerElement && spinnerElement.remove();
}
};
var forPromise = function (promise, element) {
return $timeout(function () {
// Added timeout to push a new event into event queue. So that its callback will be invoked once DOM is completely rendered
var spinner = show(element); // Don't inline this element
promise['finally'](function () {
hide(spinner, element);
});
return promise;
});
};
var forAjaxPromise = function (promise, element) {
var spinner = show(element);
promise.always(function () {
hide(spinner, element);
});
return promise;
};
return {
forPromise: forPromise,
forAjaxPromise: forAjaxPromise,
show: show,
hide: hide
};
}]);
'use strict';
angular.module('bahmni.common.uiHelper')
.directive('bmBackLinks', function () {
return {
template: '<ul>' +
'<li ng-repeat="backLink in backLinks">' +
'<a class="back-btn" ng-if="backLink.action" accesskey="{{backLink.accessKey}}" ng-click="closeAllDialogs();backLink.action()" id="{{backLink.id}}"> <span ng-bind-html="backLink.label"></span> </a>' +
'<a class="back-btn" ng-class="{\'dashboard-link\':backLink.image}" ng-if="backLink.url" accesskey="{{backLink.accessKey}}" ng-href="{{backLink.url}}" ng-click="closeAllDialogs()" id="{{backLink.id}}" title="{{backLink.title}}"> ' +
'<img ng-if="backLink.image" ng-src="{{backLink.image}}" onerror="this.onerror=null; this.src=\'../images/blank-user.gif\'"/>' +
'<i ng-if="backLink.icon && !backLink.image" class="fa {{backLink.icon}}"></i></a>' +
'<a class="back-btn" ng-if="backLink.state && !backLink.text" accesskey="{{backLink.accessKey}}" ui-sref="{{backLink.state}}" ng-click="closeAllDialogs()" id="{{backLink.id}}">' +
'<i ng-if="backLink.icon" class="fa {{backLink.icon}}"></i></a>' +
'<a ng-if="backLink.text && backLink.requiredPrivilege" show-if-privilege="{{backLink.requiredPrivilege}}" accesskey="{{backLink.accessKey}}" ui-sref="{{backLink.state}}" id="{{backLink.id}}" class="back-btn-noIcon" ui-sref-active="active">' +
'<span>{{backLink.text | translate}}</span>' +
' </a>' +
'<a ng-if="backLink.text && !backLink.requiredPrivilege" accesskey="{{backLink.accessKey}}" ui-sref="{{backLink.state}}" id="{{backLink.id}}" class="back-btn-noIcon" ui-sref-active="active">' +
'<span>{{backLink.text | translate}}</span>' +
' </a>' +
'</li>' +
'</ul>',
controller: function ($scope, backlinkService) {
$scope.backLinks = backlinkService.getAllUrls();
$scope.$on('$stateChangeSuccess', function (event, state) {
if (state.data && state.data.backLinks) {
backlinkService.setUrls(state.data.backLinks);
$scope.backLinks = backlinkService.getAllUrls();
}
});
$scope.$on("$destroy", function () {
window.onbeforeunload = undefined;
});
},
restrict: 'E'
};
});
'use strict';
angular.module('bahmni.common.uiHelper')
.directive('nonBlank', function () {
return function ($scope, element, attrs) {
var addNonBlankAttrs = function () {
element.attr({'required': 'required'});
};
var removeNonBlankAttrs = function () {
element.removeAttr('required');
};
if (!attrs.nonBlank) {
return addNonBlankAttrs(element);
}
$scope.$watch(attrs.nonBlank, function (value) {
return value ? addNonBlankAttrs() : removeNonBlankAttrs();
});
};
})
.directive('datepicker', function () {
var link = function ($scope, element, attrs, ngModel) {
var maxDate = attrs.maxDate;
var minDate = attrs.minDate || "-120y";
var format = attrs.dateFormat || 'dd-mm-yy';
element.datepicker({
changeYear: true,
changeMonth: true,
maxDate: maxDate,
minDate: minDate,
yearRange: 'c-120:c+120',
dateFormat: format,
onSelect: function (dateText) {
$scope.$apply(function () {
ngModel.$setViewValue(dateText);
});
}
});
};
return {
require: 'ngModel',
link: link
};
})
.directive('myAutocomplete', ['$parse', function ($parse) {
var link = function (scope, element, attrs, ngModelCtrl) {
var ngModel = $parse(attrs.ngModel);
var source = scope.source();
var responseMap = scope.responseMap();
var onSelect = scope.onSelect();
element.autocomplete({
autofocus: true,
minLength: 2,
source: function (request, response) {
source(attrs.id, request.term, attrs.itemType).then(function (data) {
var results = responseMap ? responseMap(data.data) : data.data;
response(results);
});
},
select: function (event, ui) {
scope.$apply(function (scope) {
ngModelCtrl.$setViewValue(ui.item.value);
scope.$eval(attrs.ngChange);
if (onSelect != null) {
onSelect(ui.item);
}
});
return true;
},
search: function (event) {
var searchTerm = $.trim(element.val());
if (searchTerm.length < 2) {
event.preventDefault();
}
}
});
};
return {
link: link,
require: 'ngModel',
scope: {
source: '&',
responseMap: '&',
onSelect: '&'
}
};
}])
.directive('bmForm', ['$timeout', function ($timeout) {
var link = function (scope, elem, attrs) {
$timeout(function () {
$(elem).unbind('submit').submit(function (e) {
var formScope = scope.$parent;
var formName = attrs.name;
e.preventDefault();
if (scope.autofillable) {
$(elem).find('input').trigger('change');
}
if (formScope[formName].$valid) {
formScope.$apply(attrs.ngSubmit);
$(elem).removeClass('submitted-with-error');
} else {
$(elem).addClass('submitted-with-error');
}
});
}, 0);
};
return {
link: link,
require: 'form',
scope: {
autofillable: "="
}
};
}])
.directive('patternValidate', ['$timeout', function ($timeout) {
return function ($scope, element, attrs) {
var addPatternToElement = function () {
if ($scope.fieldValidation && $scope.fieldValidation[attrs.id]) {
element.attr({"pattern": $scope.fieldValidation[attrs.id].pattern, "title": $scope.fieldValidation[attrs.id].errorMessage, "type": "text"});
}
};
$timeout(addPatternToElement);
};
}])
.directive('validateOn', function () {
var link = function (scope, element, attrs, ngModelCtrl) {
var validationMessage = attrs.validationMessage || 'Please enter a valid detail';
var setValidity = function (value) {
var valid = value ? true : false;
ngModelCtrl.$setValidity('blank', valid);
element[0].setCustomValidity(!valid ? validationMessage : '');
};
scope.$watch(attrs.validateOn, setValidity, true);
};
return {
link: link,
require: 'ngModel'
};
});
'use strict';
angular.module('bahmni.common.uiHelper')
.controller('MessageController', ['$scope', 'messagingService',
function ($scope, messagingService) {
$scope.messages = messagingService.messages;
$scope.getMessageText = function (level) {
var string = "";
$scope.messages[level].forEach(function (message) {
string = string.concat(message.value);
});
return string;
};
$scope.hideMessage = function (level) {
messagingService.hideMessages(level);
};
$scope.isErrorMessagePresent = function () {
return $scope.messages.error.length > 0;
};
$scope.isInfoMessagePresent = function () {
return $scope.messages.info.length > 0;
};
}]);
'use strict';
angular.module('bahmni.common.uiHelper')
.service('messagingService', ['$rootScope', '$timeout', function ($rootScope, $timeout) {
this.messages = {error: [], info: []};
var self = this;
$rootScope.$on('event:serverError', function (event, errorMessage) {
self.showMessage('error', errorMessage, 'serverError');
});
this.showMessage = function (level, message, errorEvent) {
var messageObject = {'value': '', 'isServerError': false};
messageObject.value = message;
if (errorEvent) {
messageObject.isServerError = true;
} else if (level == 'info') {
this.createTimeout('info', 4000);
}
var index = _.findIndex(this.messages[level], function (msg) {
return msg.value == messageObject.value;
});
if (index >= 0) {
this.messages[level].splice(index, 1);
}
this.messages[level].push(messageObject);
};
this.createTimeout = function (level, time) {
$timeout(function () {
self.messages[level] = [];
}, time, true);
};
this.hideMessages = function (level) {
self.messages[level].length = 0;
};
this.clearAll = function () {
self.messages["error"] = [];
self.messages["info"] = [];
};
}]);
'use strict';
Bahmni.Common.Util.DateUtil = {
diffInDays: function (dateFrom, dateTo) {
return Math.floor((this.parse(dateTo) - this.parse(dateFrom)) / (60 * 1000 * 60 * 24));
},
diffInMinutes: function (dateFrom, dateTo) {
return moment(dateTo).diff(moment(dateFrom), 'minutes');
},
diffInSeconds: function (dateFrom, dateTo) {
return moment(dateFrom).diff(moment(dateTo), 'seconds');
},
isInvalid: function (date) {
return date == "Invalid Date";
},
diffInDaysRegardlessOfTime: function (dateFrom, dateTo) {
var from = new Date(dateFrom);
var to = new Date(dateTo);
from.setHours(0, 0, 0, 0);
to.setHours(0, 0, 0, 0);
return Math.floor((to - from) / (60 * 1000 * 60 * 24));
},
addSeconds: function (date, seconds) {
return moment(date).add(seconds, 'seconds').toDate();
},
addMinutes: function (date, minutes) {
return this.addSeconds(date, minutes * 60);
},
addDays: function (date, days) {
return moment(date).add(days, 'day').toDate();
},
addMonths: function (date, months) {
return moment(date).add(months, 'month').toDate();
},
addYears: function (date, years) {
return moment(date).add(years, 'year').toDate();
},
subtractSeconds: function (date, seconds) {
return moment(date).subtract(seconds, 'seconds').toDate();
},
subtractDays: function (date, days) {
return this.addDays(date, -1 * days);
},
subtractMonths: function (date, months) {
return this.addMonths(date, -1 * months);
},
subtractYears: function (date, years) {
return this.addYears(date, -1 * years);
},
createDays: function (startDate, endDate) {
var startDate = this.getDate(startDate);
var endDate = this.getDate(endDate);
var numberOfDays = this.diffInDays(startDate, endDate);
var days = [];
for (var i = 0; i <= numberOfDays; i++) {
days.push({dayNumber: i + 1, date: this.addDays(startDate, i)});
}
return days;
},
getDayNumber: function (referenceDate, date) {
return this.diffInDays(this.getDate(referenceDate), this.getDate(date)) + 1;
},
getDateWithoutTime: function (datetime) {
return datetime ? moment(datetime).format("YYYY-MM-DD") : null;
},
getDateWitTime: function (datetime) {
return datetime ? moment(datetime).format("YYYY-MM-DD HH:mm:ss") : null;
},
getDateInMonthsAndYears: function (date, format) {
var format = format || "MMM YY";
var dateRepresentation = isNaN(Number(date)) ? date : Number(date);
if (!moment(dateRepresentation).isValid()) {
return date;
}
return dateRepresentation ? moment(dateRepresentation).format(format) : null;
},
formatDateWithTime: function (datetime) {
var dateRepresentation = isNaN(Number(datetime)) ? datetime : Number(datetime);
if (!moment(dateRepresentation).isValid()) {
return datetime;
}
return dateRepresentation ? moment(dateRepresentation).format("DD MMM YY h:mm a") : null;
},
formatDateWithoutTime: function (date) {
var dateRepresentation = isNaN(Number(date)) ? date : Number(date);
if (!moment(dateRepresentation).isValid()) {
return date;
}
return dateRepresentation ? moment(dateRepresentation).format("DD MMM YY") : null;
},
formatDateInStrictMode: function (date) {
var dateRepresentation = isNaN(Number(date)) ? date : Number(date);
if (moment(dateRepresentation, 'YYYY-MM-DD', true).isValid()) {
return moment(dateRepresentation).format("DD MMM YY");
}
if (moment(dateRepresentation, 'YYYY-MM-DDTHH:mm:ss.SSSZZ', true).isValid()) {
return moment(dateRepresentation).format("DD MMM YY");
}
return date;
},
formatTime: function (date) {
var dateRepresentation = isNaN(Number(date)) ? date : Number(date);
if (!moment(dateRepresentation).isValid()) {
return date;
}
return dateRepresentation ? moment(dateRepresentation).format("h:mm a") : null;
},
getDate: function (dateTime) {
return moment(this.parse(dateTime)).startOf('day').toDate();
},
parse: function (dateString) {
return dateString ? moment(dateString).toDate() : null;
},
parseDatetime: function (dateTimeString) {
return dateTimeString ? moment(dateTimeString) : null;
},
now: function () {
return new Date();
},
today: function () {
return this.getDate(this.now());
},
endOfToday: function () {
return moment(this.parse(this.now())).endOf('day').toDate();
},
getDateWithoutHours: function (dateString) {
return moment(dateString).toDate().setHours(0, 0, 0, 0);
},
getDateTimeWithoutSeconds: function (dateString) {
return moment(dateString).toDate().setSeconds(0, 0);
},
isSameDateTime: function (date1, date2) {
if (date1 == null || date2 == null) {
return false;
}
var dateOne = this.parse(date1);
var dateTwo = this.parse(date2);
return dateOne.getTime() == dateTwo.getTime();
},
isBeforeDate: function (date1, date2) {
return moment(date1).isBefore(moment(date2));
},
isSameDate: function (date1, date2) {
if (date1 == null || date2 == null) {
return false;
}
var dateOne = this.parse(date1);
var dateTwo = this.parse(date2);
return dateOne.getFullYear() === dateTwo.getFullYear() &&
dateOne.getMonth() === dateTwo.getMonth() &&
dateOne.getDate() === dateTwo.getDate();
},
diffInYearsMonthsDays: function (dateFrom, dateTo) {
dateFrom = this.parse(dateFrom);
dateTo = this.parse(dateTo);
var from = {
d: dateFrom.getDate(),
m: dateFrom.getMonth(),
y: dateFrom.getFullYear()
};
var to = {
d: dateTo.getDate(),
m: dateTo.getMonth(),
y: dateTo.getFullYear()
};
var age = {
d: 0,
m: 0,
y: 0
};
var daysFebruary = to.y % 4 != 0 || (to.y % 100 == 0 && to.y % 400 != 0) ? 28 : 29;
var daysInMonths = [31, daysFebruary, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
age.y = to.y - from.y;
age.m = to.m - from.m;
if (from.m > to.m) {
age.y = age.y - 1;
age.m = to.m - from.m + 12;
}
age.d = to.d - from.d;
if (from.d > to.d) {
age.m = age.m - 1;
if (from.m == to.m) {
age.y = age.y - 1;
age.m = age.m + 12;
}
age.d = to.d - from.d + daysInMonths[parseInt(from.m)];
}
return {
days: age.d,
months: age.m,
years: age.y
};
},
convertToUnits: function (minutes) {
var allUnits = {"Years": 365 * 24 * 60, "Months": 30 * 24 * 60, "Weeks": 7 * 24 * 60, "Days": 24 * 60, "Hours": 60, "Minutes": 1};
var durationRepresentation = function (value, unitName, unitValueInMinutes) {
return {"value": value, "unitName": unitName, "unitValueInMinutes": unitValueInMinutes, "allUnits": allUnits };
};
for (var unitName in allUnits) {
var unitValueInMinutes = allUnits[unitName];
if (minutes || minutes !== 0) {
if (minutes >= unitValueInMinutes && minutes % unitValueInMinutes === 0) {
return durationRepresentation(minutes / unitValueInMinutes, unitName, unitValueInMinutes);
}
}
}
return durationRepresentation(undefined, undefined, undefined);
},
getEndDateFromDuration: function (dateFrom, value, unit) {
dateFrom = this.parse(dateFrom);
var from = {
h: dateFrom.getHours(),
d: dateFrom.getDate(),
m: dateFrom.getMonth(),
y: dateFrom.getFullYear()
};
var to = new Date(from.y, from.m, from.d, from.h);
if (unit === "Months") {
to.setMonth(from.m + value);
} else if (unit === "Weeks") {
to.setDate(from.d + (value * 7));
} else if (unit === "Days") {
to.setDate(from.d + value);
} else if (unit === "Hours") {
to.setHours(from.h + value);
}
return to;
},
parseLongDateToServerFormat: function (longDate) {
return longDate ? moment(longDate).format("YYYY-MM-DDTHH:mm:ss.SSS") : null;
},
parseServerDateToDate: function (longDate) {
return longDate ? moment(longDate, "YYYY-MM-DDTHH:mm:ss.SSSZZ").toDate() : null;
},
getDateTimeInSpecifiedFormat: function (date, format) {
return date ? moment(date).format(format) : null;
},
getISOString: function (date) {
return date ? moment(date).toDate().toISOString() : null;
},
isBeforeTime: function (time, otherTime) {
return moment(time, 'hh:mm a').format('YYYY-MM-DD');
}
};
'use strict';
angular.module('bahmni.common.uiHelper')
.directive('toggle', function () {
var link = function ($scope, element) {
$scope.toggle = $scope.toggle === undefined ? false : $scope.toggle;
$(element).click(function () {
$scope.$apply(function () {
$scope.toggle = !$scope.toggle;
});
});
$scope.$watch('toggle', function () {
$(element).toggleClass('active', $scope.toggle);
});
$scope.$on("$destroy", function () {
element.off('click');
});
};
return {
scope: {
toggle: "="
},
link: link
};
});
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.Logging = Bahmni.Common.Logging || {};
angular.module('bahmni.common.logging', []);
'use strict';
angular.module('bahmni.common.logging')
.config(['$provide', function ($provide) {
$provide.decorator("$exceptionHandler", function ($delegate, $injector, $window, $log) {
var logError = function (exception, cause) {
try {
var messagingService = $injector.get('messagingService');
var loggingService = $injector.get('loggingService');
var errorMessage = exception.toString();
var stackTrace = printStackTrace({ e: exception });
var errorDetails = {
timestamp: new Date(),
browser: $window.navigator.userAgent,
errorUrl: $window.location.href,
errorMessage: errorMessage,
stackTrace: stackTrace,
cause: (cause || "")
};
loggingService.log(errorDetails);
messagingService.showMessage('error', errorMessage);
exposeException(errorDetails);
} catch (loggingError) {
$log.warn("Error logging failed");
$log.log(loggingError);
}
};
var exposeException = function (exceptionDetails) {
window.angular_exception = window.angular_exception || [];
window.angular_exception.push(exceptionDetails);
};
return function (exception, cause) {
$delegate(exception, cause);
logError(exception, cause);
};
});
}]);
'use strict';
var Bahmni = Bahmni || {};
Bahmni.Common = Bahmni.Common || {};
Bahmni.Common.I18n = Bahmni.Common.I18n || {};
angular.module('bahmni.common.i18n', []);
'use strict';
angular.module('bahmni.common.i18n', ['pascalprecht.translate'])
.provider('$bahmniTranslate', ['$translateProvider', function ($translateProvider) {
this.init = function (options) {
var preferredLanguage = window.localStorage["NG_TRANSLATE_LANG_KEY"] || "en";
$translateProvider.useLoader('mergeLocaleFilesService', options);
$translateProvider.useSanitizeValueStrategy('escaped');
$translateProvider.preferredLanguage(preferredLanguage);
$translateProvider.useLocalStorage();
};
this.$get = [function () {
return $translateProvider;
}];
}
])
.filter('titleTranslate', ['$translate', function ($translate) {
return function (input) {
if (!input) {
return input;
}
if (input.translationKey) {
return $translate.instant(input.translationKey);
}
if (input.dashboardName) {
return input.dashboardName;
}
if (input.title) {
return input.title;
}
if (input.label) {
return input.label;
}
if (input.display) {
return input.display;
}
return $translate.instant(input);
};
}]);
'use strict';
angular.module('bahmni.common.i18n')
.service('mergeLocaleFilesService', ['$http', '$q', 'mergeService', function ($http, $q, mergeService) {
return function (options) {
var baseLocaleUrl = '../i18n/';
var customLocaleUrl = Bahmni.Common.Constants.rootDir + '/bahmni_config/openmrs/i18n/';
var loadFile = function (url) {
return $http.get(url, {withCredentials: true});
};
var mergeLocaleFile = function (options) {
var fileURL = options.app + "/locale_" + options.key + ".json";
var loadBahmniTranslations = function () {
return loadFile(baseLocaleUrl + fileURL).then(function (result) {
return result;
}, function () {
return;
});
};
var loadCustomTranslations = function () {
return loadFile(customLocaleUrl + fileURL).then(function (result) {
return result;
}, function () {
return;
});
};
var mergeTranslations = function (result) {
var baseFileData = result[0] ? result[0].data : undefined;
var customFileData = result[1] ? result[1].data : undefined;
if (options.shouldMerge || options.shouldMerge === undefined) {
return mergeService.merge(baseFileData, customFileData);
}
return [baseFileData, customFileData];
};
return $q.all([loadBahmniTranslations(), loadCustomTranslations()])
.then(mergeTranslations);
};
return mergeLocaleFile(options);
};
}]);
'use strict';
angular.module('bahmni.home', ['ui.router', 'httpErrorInterceptor', 'bahmni.common.domain', 'bahmni.common.i18n', 'bahmni.common.uiHelper', 'bahmni.common.util',
'bahmni.common.appFramework', 'bahmni.common.logging', 'bahmni.common.routeErrorHandler', 'pascalprecht.translate', 'ngCookies',
'bahmni.common.models'])
.config(['$urlRouterProvider', '$stateProvider', '$httpProvider', '$bahmniTranslateProvider', '$compileProvider',
function ($urlRouterProvider, $stateProvider, $httpProvider, $bahmniTranslateProvider, $compileProvider) {
$urlRouterProvider.otherwise('/dashboard');
$compileProvider.debugInfoEnabled(false);
$stateProvider
.state('dashboard',
{
url: '/dashboard',
templateUrl: 'views/dashboard.html',
controller: 'DashboardController',
data: {extensionPointId: 'org.bahmni.home.dashboard'},
resolve: {
initialize: function (initialization) {
return initialization();
}
}
}).state('changePassword', {
url: '/changePassword',
templateUrl: 'views/changePassword.html',
controller: 'ChangePasswordController'
}).state('login',
{
url: '/login?showLoginMessage',
templateUrl: 'views/login.html',
controller: 'LoginController',
resolve: {
initialData: function (loginInitialization) {
return loginInitialization();
}
}
})
.state('errorLog', {
url: '/errorLog',
controller: 'ErrorLogController',
templateUrl: 'views/errorLog.html',
data: {
backLinks: [
{label: "Home", state: "dashboard", accessKey: "h", icon: "fa-home"}
]
},
resolve: {
}
});
$httpProvider.defaults.headers.common['Disable-WWW-Authenticate'] = true;
$bahmniTranslateProvider.init({app: 'home', shouldMerge: true});
}]).run(['$rootScope', '$templateCache', '$window', function ($rootScope, $templateCache, $window) {
moment.locale($window.localStorage["NG_TRANSLATE_LANG_KEY"] || "en");
// Disable caching view template partials
$rootScope.$on('$viewContentLoaded', function () {
$templateCache.removeAll();
});
}]);
'use strict';
angular.module('bahmni.home')
.factory('initialization', ['$rootScope', 'appService', 'spinner',
function ($rootScope, appService, spinner) {
var initApp = function () {
return appService.initApp('home');
};
return function () {
return spinner.forPromise(initApp());
};
}
]);
'use strict';
angular.module('bahmni.home')
.factory('loginInitialization', ['$rootScope', '$q', 'locationService', 'spinner', 'messagingService',
function ($rootScope, $q, locationService, spinner, messagingService) {
var init = function () {
var deferrable = $q.defer();
locationService.getAllByTag("Login Location").then(
function (response) {
deferrable.resolve({locations: response.data.results});
},
function (response) {
deferrable.reject();
if (response.status) {
response = 'MESSAGE_START_OPENMRS';
}
messagingService.showMessage('error', response);
}
);
return deferrable.promise;
};
return function () {
return spinner.forPromise(init());
};
}
]);
'use strict';
angular.module("bahmni.home")
.controller("LoginController", ["$rootScope", "$http", "$scope", "messagingService", "$window", "$location", "sessionService", "initialData", "spinner", "$q", "$stateParams", "$bahmniCookieStore", "localeService", "$translate", "userService", "auditLogService",
function ($rootScope, $http, $scope, messagingService, $window, $location, sessionService, initialData, spinner, $q, $stateParams, $bahmniCookieStore, localeService, $translate, userService, auditLogService) {
var redirectUrl = $location.search()['from'];
var landingPagePath = "/dashboard";
var loginPagePath = "/login";
$scope.locations = initialData.locations;
$scope.loginInfo = {};
var localeLanguages = [];
var hostName = $window.location.hostname;
var baseUrl = "https://" + hostName;
var getLocalTimeZone = function () {
var currentLocalTime = new Date().toString();
var localTimeZoneList = currentLocalTime.split(" ");
var localTimeZone = localTimeZoneList[localTimeZoneList.length - 1];
localTimeZone = localTimeZone.substring(1, localTimeZone.length - 1);
return localTimeZone;
};
var findLanguageByLocale = function (localeCode) {
return _.find(localeLanguages, function (localeLanguage) {
return localeLanguage.code == localeCode;
});
};
var logAuditForLoginAttempts = function (eventType, isFailedEvent) {
if ($scope.loginInfo.username) {
var messageParams = isFailedEvent ? {userName: $scope.loginInfo.username} : undefined;
auditLogService.log(undefined, eventType, messageParams, 'MODULE_LABEL_LOGIN_KEY');
}
};
var promise = localeService.allowedLocalesList();
localeService.serverDateTime().then(function (response) {
var serverTime = response.data.date;
var offset = response.data.offset;
var localTime = new Date().toLocaleString();
var localtimeZone = getLocalTimeZone();
var localeTimeZone = localTime + " " + localtimeZone;
$scope.timeZoneObject = {serverTime: serverTime, localeTimeZone: localeTimeZone};
if (offset && !new Date().toString().includes(offset)) {
$scope.warning = "Warning";
$scope.warningMessage = "WARNING_SERVER_TIME_ZONE_MISMATCH";
}
});
localeService.getLoginText().then(function (response) {
$scope.logo = response.data.loginPage.logo;
$scope.bottomLogos = response.data.loginPage.bottomLogos;
$scope.headerText = response.data.loginPage.showHeaderText;
$scope.titleText = response.data.loginPage.showTitleText;
$scope.helpLink = response.data.helpLink.url;
});
localeService.getLocalesLangs().then(function (response) {
localeLanguages = response.data.locales;
}).finally(function () {
promise.then(function (response) {
var localeList = response.data.replace(/\s+/g, '').split(',');
$scope.locales = [];
_.forEach(localeList, function (locale) {
var localeLanguage = findLanguageByLocale(locale);
if (_.isUndefined(localeLanguage)) {
$scope.locales.push({"code": locale, "nativeName": locale});
} else {
$scope.locales.push(localeLanguage);
}
});
$scope.selectedLocale = $translate.use() ? $translate.use() : $scope.locales[0].code;
});
});
$scope.isChrome = function () {
if ($window.navigator.userAgent.indexOf("Chrome") != -1) {
return true;
}
return false;
};
$scope.$watch("selectedLocale", function () {
$translate.use($scope.selectedLocale);
});
var getLoginLocationUuid = function () {
return $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName) ? $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName).uuid : null;
};
var getLastLoggedinLocation = function () {
return _.find(initialData.locations, function (location) {
return location.uuid === getLoginLocationUuid();
});
};
$scope.loginInfo.currentLocation = getLastLoggedinLocation();
if ($stateParams.showLoginMessage) {
$scope.errorMessageTranslateKey = "LOGIN_LABEL_LOGIN_ERROR_MESSAGE_KEY";
}
var redirectToLandingPageIfAlreadyAuthenticated = function () {
sessionService.get().then(function (data) {
if (data.authenticated) {
$location.path(landingPagePath);
}
});
};
if ($location.path() === loginPagePath) {
redirectToLandingPageIfAlreadyAuthenticated();
}
var onSuccessfulAuthentication = function () {
$bahmniCookieStore.remove(Bahmni.Common.Constants.retrospectiveEntryEncounterDateCookieName, {
path: '/',
expires: 1
});
$rootScope.$broadcast('event:auth-loggedin');
$scope.loginInfo.currentLocation = getLastLoggedinLocation();
};
$scope.login = async function () {
$scope.errorMessageTranslateKey = null;
var deferrable = $q.defer();
const userHeaders = new Headers();
userHeaders.append("Content-Type", "application/json");
userHeaders.append("Authorization", "Basic YWRtaW46dGVzdA==");
const headers = new Headers();
headers.append("Content-Type", "application/json");
var ensureNoSessionIdInRoot = function () {
$bahmniCookieStore.remove(Bahmni.Common.Constants.JSESSIONID, {
path: '/',
expires: 1
});
};
const checkAndFormatPassword = (password) => {
const formattedPassword = (password.search(/[A-Z]/) === -1 || password.search(/[a-z]/) === -1) ? password.charAt(0).toUpperCase() + password.charAt(1).toLowerCase() + password.slice(2) : password;
if (formattedPassword !== password) {
return formattedPassword + (/\d/.test(formattedPassword) ? '' : '123');
} else {
return password + (/\d/.test(password) ? '' : '123');
}
};
const updateUserPassword = async (userPayload, uuid) => {
return await fetch(
baseUrl + "/openmrs/ws/rest/v1/password/" + uuid,
{
method: "POST",
body: JSON.stringify(userPayload),
headers: userHeaders
}
);
};
const loginBahmni = (hrisLoggedIn, uuid) => {
sessionService.loginUser($scope.loginInfo.username, checkAndFormatPassword($scope.loginInfo.password), $scope.loginInfo.currentLocation, $scope.loginInfo.otp).then(
function (data) {
ensureNoSessionIdInRoot();
if (data && data.firstFactAuthorization) {
$scope.showOTP = true;
deferrable.resolve(data);
return;
}
sessionService.loadCredentials().then(function () {
onSuccessfulAuthentication();
$rootScope.currentUser.addDefaultLocale($scope.selectedLocale);
fetch("/openmrs/ws/rest/v1/provider?user=${$rootScope.currentUser.uuid}")
.then(res => res.json())
.then(data => {
localStorage.setItem('providerName', data.results[0].display);
});
userService.savePreferences().then(
function () {
deferrable.resolve();
},
function (error) {
deferrable.reject(error);
}
);
logAuditForLoginAttempts("USER_LOGIN_SUCCESS");
}, function (error) {
$scope.errorMessageTranslateKey = error;
deferrable.reject(error);
logAuditForLoginAttempts("USER_LOGIN_FAILED", true);
}
);
},
function (error) {
if (error === 'LOGIN_LABEL_LOGIN_ERROR_MESSAGE_KEY' && hrisLoggedIn) {
// check if user exists in the system, if exists already and is not able to login,
const userData = {
"newPassword": checkAndFormatPassword($scope.loginInfo.password)
};
const updateBahmniUserPassword = updateUserPassword(userData, uuid);
if (updateBahmniUserPassword) {
return loginBahmni(false);
}
} else {
$scope.errorMessageTranslateKey = error;
if (error === "LOGIN_LABEL_MAX_FAILED_ATTEMPTS" || error === "LOGIN_LABEL_OTP_EXPIRED") {
deleteUserCredentialsAndShowLoginPage();
} else if (error === "LOGIN_LABEL_WRONG_OTP_MESSAGE_KEY") {
delete $scope.loginInfo.otp;
}
deferrable.reject(error);
logAuditForLoginAttempts("USER_LOGIN_FAILED", true);
}
}
);
};
var deleteUserCredentialsAndShowLoginPage = function () {
$scope.showOTP = false;
delete $scope.loginInfo.otp;
delete $scope.loginInfo.username;
delete $scope.loginInfo.password;
};
$scope.resendOTP = function () {
var promise = sessionService.resendOTP($scope.loginInfo.username, $scope.loginInfo.password);
spinner.forPromise(promise);
promise.then(function () {
$scope.errorMessageTranslateKey = "LOGIN_LABEL_RESEND_SUCCESS";
}, function (response) {
if (response.status === 429) {
$scope.errorMessageTranslateKey = "LOGIN_LABEL_MAX_RESEND_ATTEMPTS";
deleteUserCredentialsAndShowLoginPage();
}
});
};
spinner.forPromise(deferrable.promise).then(
function (data) {
if (data) return;
if (redirectUrl) {
$window.location = redirectUrl;
} else {
$location.path(landingPagePath);
}
}
);
const checkInternet = async () => {
return await fetch("/openmrs/ws/rest/v1/angtcore/ajax/checkInternet.htm")
.then((response) => {
return response.json();
});
};
const userPayloadData = async (inputData) => {
const transformedData = {
username: inputData.userName,
password: inputData.password,
person: {
names: [
{
givenName: inputData.name.trim(),
preferred: true
}
],
gender: inputData.gender.charAt(0).toUpperCase(),
age: 0,
birthdate: new Date(inputData.birthDate).toISOString(),
birthdateEstimated: false,
dead: false,
addresses: [
{
preferred: true,
address1: inputData.address.text
}
],
deathdateEstimated: false
},
systemId: inputData.systemId,
roles: inputData.roles
};
return transformedData;
};
const createUser = async (userPayload) => {
return await fetch(
// "https://${$window.location.hostname}/openmrs/ws/rest/v1/user",
"https://${$window.location.hostname}/openmrs/ws/rest/v1/user",
{
method: "POST",
body: JSON.stringify(userPayload),
headers: userHeaders
}
)
.then((response) => {
return response.json();
});
};
const getDesignationUuid = async () => {
return await fetch(
"https://${$window.location.hostname}/openmrs/ws/rest/v1/providerattributetype?q=Designation",
{
method: "GET",
headers: userHeaders
}
)
.then((response) => {
return response.json();
});
};
const createProvider = async (providerData) => {
var hrisProvider = {
"name": providerData.name,
"personUuid": providerData.person,
"identifier": providerData.userPayload.systemId
}
return await fetch(
"/openmrs/ws/rest/v1/angtcore/hris/saveProvider.htm",
{
method: "POST",
body: JSON.stringify(hrisProvider),
headers: userHeaders
}
)
.then((response) => {
return response.json();
});
};
const createBahmniHRISUser = async (userPayload) => {
return await fetch(
"https://${$window.location.hostname}:6062/api/v1/hris-user",
{
method: "POST",
body: JSON.stringify(userPayload),
headers: headers
}
)
.then((response) => {
return response.json();
});
};
const hrisLogin = async (dataBody) => {
console.log(dataBody);
return await fetch(baseUrl+"/openmrs/ws/rest/v1/angtcore/hris/signin.htm",
{
method: "POST",
body: JSON.stringify(dataBody),
headers: headers
}
)
.then((response) => {
return response.json();
});
};
const getUserRolesUuid = async (roles) => {
return await fetch("/openmrs/ws/rest/v1/angtcore/hris/openMRSRoles.htm", {
method: "POST",
body: JSON.stringify(roles),
headers: headers
})
.then((response) => {
return response.json();
});
};
const checkUserName = async (username) => {
return await fetch("/openmrs/ws/rest/v1/angtcore/hris/openmrsUser.htm?username=" + username)
.then((response) => {
return response.json();
});
};
const getProviderFromHRIS = async (token) => {
return await fetch("/openmrs/ws/rest/v1/angtcore/hris/hrisInfoGetByToken.htm?token=" + token)
.then((response) => {
return response.json();
});
};
const getProviderDataFromHRIS = async (id) => {
return await fetch("/openmrs/ws/rest/v1/angtcore/hris/hrisProviderInfoGetByProviderId.htm?providerId=" + id)
.then((response) => {
return response.json();
});
};
const generateUsername = async (name) => {
const generateRandomUsername = () => {
return `HRM-${name.split(' ')[1]}-${Math.floor(Math.random() * 9000) + 1000}`;
};
const username = generateRandomUsername();
const userAvailable = await checkUserName(username);
if (userAvailable.statusCode === 404) {
return username;
} else {
return generateUsername(name);
}
};
try {
const dataBody = {
"email": $scope.loginInfo.username,
"password": $scope.loginInfo.password
};
// is ok status === 200
const internetAvailability = await checkInternet();
if (internetAvailability.content) {
const hrisRes = await hrisLogin(dataBody);
if (hrisRes.error) {
return loginBahmni(false);
} else {
const userAvailable = await checkUserName($scope.loginInfo.username);
if (userAvailable.statusCode === 404) {
const accessToken = hrisRes.access_token;
if (accessToken) {
const providerRes = await getProviderFromHRIS(accessToken);
const checkProvider = providerRes.profiles.find(p => p.name === 'provider');
if (!checkProvider) {
alert("You do not have privileges to access this system");
return loginBahmni(false);
} else {
const getUserData = await getProviderDataFromHRIS(checkProvider.id);
if (getUserData.telecom.length > 0) {
const userEmailData = getUserData.telecom.filter(data => data.system === 'email');
if (userEmailData.length > 0) {
const userEmail = userEmailData[0].value;
const roles = {
names: [
"Admin-App",
"InPatient-App",
"Reports-App",
"Doctor"
]
};
const roleDataRes = await getUserRolesUuid(roles);
const roleData = roleDataRes.content.uuidList
.map(item => ({
"uuid": item
}));
const userData = {...getUserData};
const userName = await generateUsername(userData.name);
userData.userName = userName;
userData.systemId = userEmail;
userData.roles = roleData;
userData.password = checkAndFormatPassword($scope.loginInfo.password);
const userPayload = await userPayloadData(userData);
const createBahmniUser = await createUser(userPayload);
if (createBahmniUser) {
const designationUuid = await getDesignationUuid();
if (designationUuid) {
const providerData = {
"name": createBahmniUser.person.display,
"description": null,
"person": createBahmniUser.person.uuid,
"identifier": null,
"attributes": [{
"attributeType": designationUuid.results[0].uuid,
"value": getUserData.properties.designation
}],
"retired": false,
"userPayload": userPayload
};
const createBahmniProvider = await createProvider(providerData);
if (createBahmniProvider) {
const bahmniUserPayload = {
userUuid: createBahmniUser.uuid,
personUuid: createBahmniUser.person.uuid,
providerUuid: createBahmniProvider.uuid,
object: JSON.stringify(getUserData),
activeStatus: getUserData.active,
url: getUserData.url,
providerId: getUserData.id
};
const createBahmniHRIS = await createBahmniHRISUser(bahmniUserPayload);
if (createBahmniHRIS) {
return loginBahmni(false);
} else {
return loginBahmni(false);
}
} else {
return loginBahmni(false);
}
}
} else {
return loginBahmni(false);
}
} else {
return loginBahmni(false);
}
}
}
} else {
return loginBahmni(false);
}
} else {
return loginBahmni(true, userAvailable.content);
}
}
} else {
return loginBahmni(false);
}
} catch (err) {
console.log(err);
return loginBahmni(false);
}
};
}]);
'use strict';
angular.module('bahmni.home')
.controller('DashboardController', ['$scope', '$state', 'appService', 'locationService', 'spinner', '$bahmniCookieStore', '$window', '$q',
function ($scope, $state, appService, locationService, spinner, $bahmniCookieStore, $window, $q) {
$scope.appExtensions = appService.getAppDescriptor().getExtensions($state.current.data.extensionPointId, "link") || [];
$scope.selectedLocationUuid = {};
var isOnline = function () {
return $window.navigator.onLine;
};
$scope.isVisibleExtension = function (extension) {
return extension.exclusiveOnlineModule ? isOnline() : extension.exclusiveOfflineModule ? !isOnline() : true;
};
var getCurrentLocation = function () {
return $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName) ? $bahmniCookieStore.get(Bahmni.Common.Constants.locationCookieName) : null;
};
var init = function () {
return locationService.getAllByTag("Login Location").then(function (response) {
$scope.locations = response.data.results;
$scope.selectedLocationUuid = getCurrentLocation().uuid;
}
);
};
var getLocationFor = function (uuid) {
return _.find($scope.locations, function (location) {
return location.uuid === uuid;
});
};
$scope.isCurrentLocation = function (location) {
return getCurrentLocation().uuid === location.uuid;
};
$scope.onLocationChange = function () {
var selectedLocation = getLocationFor($scope.selectedLocationUuid);
$bahmniCookieStore.remove(Bahmni.Common.Constants.locationCookieName);
$bahmniCookieStore.put(Bahmni.Common.Constants.locationCookieName, {
name: selectedLocation.display,
uuid: selectedLocation.uuid
}, {path: '/', expires: 7});
$window.location.reload();
};
$scope.changePassword = function () {
$state.go('changePassword');
};
return spinner.forPromise($q.all(init()));
}]);
'use strict';
angular.module('bahmni.home')
.controller('ChangePasswordController', ['$scope', '$state', 'sessionService', '$rootScope', 'authenticator', '$window', 'userService', 'messagingService', function ($scope, $state, sessionService, $rootScope, authenticator, $window, userService, messagingService) {
$scope.loginInfo = {};
$scope.passwordDoesNotMatch = false;
$scope.passwordPolicies = [];
$scope.redirectToHomePage = function () {
$state.go('dashboard');
};
var checkPasswordMatches = function () {
return $scope.loginInfo.newPassword == $scope.loginInfo.confirmPassword;
};
$scope.changePassword = function () {
if (_.isEmpty($scope.loginInfo.oldPassword) || _.isEmpty($scope.loginInfo.newPassword) || _.isEmpty($scope.loginInfo.confirmPassword)) {
return;
}
if (checkPasswordMatches()) {
$scope.passwordDoesNotMatch = false;
sessionService.changePassword($rootScope.currentUser.uuid, $scope.loginInfo.oldPassword, $scope.loginInfo.newPassword).then(function (data) {
messagingService.showMessage("info", 'CHANGE_PASSWORD_SUCCESSFUL_MESSAGE');
clearPasswordFields();
});
}
else {
$scope.passwordDoesNotMatch = true;
}
};
var clearPasswordFields = function () {
$scope.loginInfo.newPassword = undefined;
$scope.loginInfo.oldPassword = undefined;
$scope.loginInfo.confirmPassword = undefined;
};
var convertPasswordPolicies = function (policies) {
_.forEach(policies, function (value, key) {
switch (key) {
case "security.passwordCannotMatchUsername" :
value == "true" ? $scope.passwordPolicies.splice(0, 0, 'PASSWORD_SHOULD_NOT_MATCH_USER_NAME') : '';
break;
case "security.passwordMinimumLength" :
$scope.passwordLength = value;
$scope.passwordPolicies.splice(1, 0, 'PASSWORD_SHOULD_BE_MINIMUM_CHARACTERS');
break;
case "security.passwordRequiresUpperAndLowerCase":
value == "true" ? $scope.passwordPolicies.splice(2, 0, 'PASSWORD_SHOULD_BE_A_MIX_OF_BOTH_UPPER_CASE_AND_LOWER_CASE') : '';
break;
case "security.passwordRequiresDigit" :
value == "true" ? $scope.passwordPolicies.splice(3, 0, 'PASSWORD_SHOULD_CONTAIN_DIGITS') : '';
break;
case "security.passwordRequiresNonDigit" :
value == "true" ? $scope.passwordPolicies.splice(4, 0, 'PASSWORD_SHOULD_HAVE_ATLEAST_ONE_NON_DIGIT') : '';
break;
case "security.passwordCustomRegex":
if (!_.isEmpty(value)) {
$scope.passwordPolicies.splice(5, 0, 'PASSWORD_SHOULD_MATCH_THE_REGEX');
$scope.passwordRegex = value;
}
}
});
};
var init = function () {
authenticator.authenticateUser().then(function () {
userService.getPasswordPolicies().then(function (response) {
convertPasswordPolicies(response.data);
});
sessionService.loadCredentials().then(function (data) {
});
}, function () {
$window.location = "../home/index.html#/login";
});
};
init();
}]);
'use strict';
angular.module('bahmni.home')
.controller('ErrorLogController', ['$q', 'spinner', '$scope',
function ($q, spinner, $scope) {
$scope.errorLogs = [];
$scope.showErrorLog = true;
}]);
(function(window, undefined) {
"use strict";
var version = '0.2.0';
var internal_db_version = 5;
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.oIndexedDB || window.msIndexedDB;
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange
if (!indexedDB) throw 'IndexedDB required';
// define error(s) used by tcrypt
var extend_error = function(extend, errname) {
var err = function() {
var tmp = extend.apply(this, arguments);
tmp.name = this.name = errname;
this.stack = tmp.stack
this.message = tmp.message
return this;
};
err.prototype = Object.create(extend.prototype, {
constructor: {
value: err
}
});
return err;
}
var HustleError = extend_error(window.Error, 'HustleError');
var HustleDBClosed = extend_error(HustleError, 'HustleDBClosed');
var HustleDBOpened = extend_error(HustleError, 'HustleDBOpened');
var HustleBadTube = extend_error(HustleError, 'HustleBadTube');
var HustleBadID = extend_error(HustleError, 'HustleBadID');
var HustleNotice = extend_error(window.Error, 'HustleNotice');
var HustleNotFound = extend_error(HustleNotice, 'HustleNotFound');
var Hustle = function(qoptions) {
qoptions || (qoptions = {});
if (!qoptions.tubes) qoptions.tubes = [];
// database version. should change every time the tubes change
var db_version = qoptions.db_version ? qoptions.db_version : 1;
// how often we do DB maintenance
var maintenance_delay = qoptions.maintenance_delay ? qoptions.maintenance_delay : 1000;
// define some system db vars
var db_name = qoptions.db_name ? qoptions.db_name : 'hustle';
// our reserved tables
var tbl = {
ids: '_ids',
reserved: '_reserved',
delayed: '_delayed',
buried: '_buried'
};
// always add a default tube
if (qoptions.tubes.indexOf('default') < 0) qoptions.tubes.push('default');
var db = null;
// ---------------------------------------------------------------------
// database-related functions
// ---------------------------------------------------------------------
var check_db = function() {
if (!db) throw new HustleDBClosed('Closed database being operated on. Did you call Hustle.open()?');
return true;
};
// will be filled in later
var do_maintenance;
/**
* helper function, creates a table if it doesn't exist, otherwise grabs
* it. returns the store.
*/
var update_table_schema = function(e, tablename, options) {
options || (options = {});
var store = null;
var udb = e.target.result;
var keypath = options.keypath ? options.keypath : 'id';
var autoinc = options.autoincrement ? options.autoincrement : false;
// grab an existing object store or create a new one
if (udb.objectStoreNames.contains(tablename)) {
store = e.currentTarget.transaction.objectStore(tablename);
} else {
store = udb.createObjectStore(tablename, {
keyPath: keypath,
autoIncrement: autoinc
});
}
if (options.indexes) {
var keys = Object.keys(options.indexes);
for (var i = 0; i < keys.length; i++) {
(function(key, idx) {
var index_val = idx.index ? idx.index : key;
var unique = idx.unique ? true : false;
try {
store.createIndex(key, index_val, {
unique: unique
});
}
// index probably exists already
// TODO: check store.indexNames
catch (e) {}
})(keys[i], options.indexes[keys[i]]);
}
}
return store;
};
/**
* open the queue database and make sure the schema is ship-shape
*/
var open = function(options) {
options || (options = {});
if (db) throw new HustleDBOpened('db is already open');
var version = (internal_db_version * 1000) + db_version;
var req = indexedDB.open(db_name, version);
req.onerror = function(e) {
if (options.error) options.error(e);
}
req.onsuccess = function(e) {
db = req.result;
if (options.success) options.success(e);
do_maintenance();
};
req.onupgradeneeded = function(e) {
var store = null;
var tubes = qoptions.tubes;
update_table_schema(e, tbl.ids);
update_table_schema(e, tbl.reserved, {
indexes: {
expire: {
index: 'expire',
unique: false
}
}
});
update_table_schema(e, tbl.delayed, {
indexes: {
activate: {
index: 'activate',
unique: false
}
}
});
update_table_schema(e, tbl.buried, {
indexes: {
id: {
unique: false
}
}
});
for (var i = 0; i < tubes.length; i++) {
if ([tbl.reserved, tbl.buried].indexOf(tubes[i]) >= 0) continue;
update_table_schema(e, tubes[i], {
indexes: {
priority: {
index: ['priority', 'id'],
unique: false
}
}
});
}
};
};
/**
* close the queue database
*/
var close = function() {
if (!db) return false;
db.close();
db = null;
return true;
};
/**
* convenience function to obliterate the queue
*/
var wipe = function() {
close();
indexedDB.deleteDatabase(db_name);
return true;
};
/**
* generate a unique, auto-incrementing ID
*/
var new_id = function(options) {
check_db();
options || (options = {});
var id = null;
var trx = db.transaction([tbl.ids], 'readwrite');
trx.oncomplete = function(e) {
if (!id) {
if (options.error) options.error('bad id');
return;
}
if (options.success) options.success(id, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
// upsert the ID record
var store = trx.objectStore(tbl.ids);
var req = store.get('id');
req.onsuccess = function(e) {
var item = req.result;
if (!item) {
id = 1;
store.put({
id: 'id',
value: 1
});
} else {
item.value++;
id = item.value;
store.put(item);
}
};
};
/**
* generic function to move a queue item from one table to another.
*/
var move_item = function(id, from, to, options) {
options || (options = {});
var trx = db.transaction([from, to], 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
var do_move_item = function(item, success) {
if (options.transform) {
item = options.transform(item);
}
var store = trx.objectStore(to);
var req = store.add(item);
req.onsuccess = success;
};
var store = trx.objectStore(from);
var req;
if (from == tbl.buried) {
// if we're looking up the buried table, we use the "id" index
var index = store.index('id');
req = index.get(id);
} else {
req = store.get(id);
}
req.onsuccess = function(e) {
var item = req.result;
if (!item) {
if (options.error) options.error(new HustleNotFound('item ' + id + ' wasn\'t found'));
return;
}
var item_id = item.id;
// account for the buried table's IDs
if (from == tbl.buried) item_id = item._id;
do_move_item(item, function(e) {
var req = store.delete(item_id);
req.onerror = options.error;
});
};
};
/**
* wrapper to create a new queue item for storage in the DB
*
* valid option values are 'priority'
*/
var create_queue_item = function(data, options) {
var item = {
data: data
};
var fields = [{
name: 'priority',
type: 'int',
default: 1024
}, {
name: 'delay',
type: 'int',
default: 0
}, {
name: 'ttr',
type: 'int',
default: 0
}];
// loop over our fields, making sure they are the correct type and
// format.
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
if (options[field.name]) {
item[field.name] = options[field.name];
switch (field.type) {
case 'int':
item[field.name] = parseInt(item[field.name]);
break;
case 'float':
item[field.name] = parseFloat(item[field.name]);
break;
}
}
if (field.default && typeof item[field.name] == 'undefined') {
item[field.name] = field.default;
}
}
// some defaults
item.age = 0;
item.reserves = 0;
item.releases = 0;
item.timeouts = 0;
item.buries = 0;
item.kicks = 0;
item.created = new Date().getTime();
return item;
};
// ---------------------------------------------------------------------
// queue interface functions
// ---------------------------------------------------------------------
/**
* grab an item by id from the queue
*/
var peek = function(id, options) {
check_db();
options || (options = {});
if (!id) {
if (options.error) options.error(new HustleBadId('bad id given'));
return false;
}
var item = null;
var tables = [tbl.reserved, tbl.delayed, tbl.buried].concat(qoptions.tubes);
var trx = db.transaction(tables, 'readonly');
trx.oncomplete = function(e) {
if (!item && options.not_found_error) {
if (options.error) options.error(new HustleNotFound('item ' + id + ' not found'));
return;
}
if (options.success) options.success(item, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
};
// scan all tables for this id
tables.forEach(function(table) {
var req;
if (table == tbl.buried) {
var index = trx.objectStore(table).index('id');
req = index.get(id);
} else {
req = trx.objectStore(table).get(id);
}
req.onsuccess = function(e) {
var res = e && e.target && e.target.result;
if (item || !res) return false;
item = res;
item.age = Math.round((new Date().getTime() - item.expire) / 1000);
if (table == tbl.reserved) {
item.state = 'reserved';
if (item.ttr > 0) {
item.time_left = Math.round((item.expire - new Date().getTime()) / 1000);
}
} else if (table == tbl.buried) {
item.state = 'buried';
} else {
item.state = 'ready';
if (!item.tube) item.tube = table;
}
}
});
};
/**
* put a new item in the queue in the specified tube (or the "default"
* tube)
*/
var put = function(data, options) {
var getAllItems = function (tube, options) {
var tr = db.transaction([tube], 'readonly');
var store = tr.objectStore(tube);
if (store.getAll) {
store.getAll().onsuccess = function (e) {
if (options.success) options.success(e.target.result);
};
}
else {
var items = [];
store.openCursor().onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
items.push(cursor.value);
cursor.continue();
}
else {
options.success(items);
}
}
}
};
check_db();
options || (options = {});
if (!data) return false;
var tube = options.tube ? options.tube : 'default';
if (qoptions.tubes.indexOf(tube) < 0) throw new HustleBadTube('tube ' + tube + ' doesn\'t exist');
var item = create_queue_item(data, options);
if (item.delay && item.delay > 0) {
item.tube = tube;
item.activate = new Date().getTime() + (1000 * item.delay);
tube = tbl.delayed;
delete item.delayed;
}
var comparator = options.comparator;
var createItem = function () {
// grab a unique ID for this item
new_id({
success: function(id) {
item.id = id;
var trx = db.transaction([tube], 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(item, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
};
var store = trx.objectStore(tube);
store.openCursor().onsuccess = function (e) {
};
var req = store.add(item);
req.onsuccess = function(e) {
item.id = e.target.result;
};
},
error: function(e) {
if (options.error) options.error(new HustleBadID('error generating id'));
}
});
};
var addUniqueItemToQueue = function (items) {
var existingItem = items.find(function (currentItem) {
return comparator(item.data, currentItem.data);
});
existingItem ? options.success(existingItem) : createItem();
};
comparator ? getAllItems(tube, {success: addUniqueItemToQueue}) : createItem();
};
/**
* grab one item off of the given tube (or "default" tube) and move it
* onto the reserved table.
*/
var reserve = function(options) {
check_db();
options || (options = {});
var tube = options.tube ? options.tube : 'default';
if (qoptions.tubes.indexOf(tube) < 0) throw new HustleBadTube('tube ' + tube + ' doesn\'t exist');
var item = null;
var trx = db.transaction([tbl.reserved, tube], 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(item, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
// called once we have an item, puts the item in the reserved table
var put_in_reserved = function(citem, success) {
item = citem;
item.reserves++;
item.tube = tube;
if (item.ttr > 0) {
item.expire = new Date().getTime() + (1000 * item.ttr);
}
var store = trx.objectStore(tbl.reserved);
var req = store.add(item);
req.onsuccess = success;
};
// grab one item from the tube, and put it in reserved
var store = trx.objectStore(tube);
var index = store.index('priority');
index.openCursor().onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
put_in_reserved(cursor.value, function(e) {
// remove the item from the tube once we know it's reserved
var req = store.delete(cursor.value.id);
req.onerror = options.error;
});
}
};
};
/**
* delete a queue item by id. checks all tubes and the reserved/buried
* tables as well.
*/
var del = function(id, options) {
check_db();
options || (options = {});
peek(id, {
success: function(item) {
if (!item) {
if (options.success) options.success(null);
return;
}
var table = item.tube;
var item_id = item.id;
if (item.state == 'reserved') {
table = tbl.reserved;
} else if (item.state == 'buried') {
table = tbl.buried;
// be mindful of the buried table's own IDs
item_id = item._id;
}
var trx = db.transaction(table, 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(item, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
trx.objectStore(table).delete(item_id);
},
error: options.error
});
};
/**
* release a reserved item back into the queue (from the tube it came
* from).
*/
var release = function(id, options) {
check_db();
options || (options = {});
peek(id, {
not_found_error: true,
success: function(item) {
if (item.state != 'reserved') {
if (options.error) options.error(new HustleNotFound('item ' + id + ' isn\'t reserved'));
return;
}
var tube = item.tube;
if (options.delay) {
var delay = parseInt(options.delay);
if (delay) {
item.activate = new Date().getTime() + (1000 * delay);
tube = tbl.delayed;
}
}
move_item(id, tbl.reserved, tube, {
transform: function(item) {
item.releases++;
if (options.priority) {
var pri = parseInt(options.priority);
if (pri) item.priority = pri;
}
delete item.tube;
return item;
},
success: options.success,
error: options.error
});
},
error: options.error
});
};
/**
* move an item to the buried table. this is a great way to track items
* that fail a lot and can't be ignored, allowing you to look over them
* later on and see what jobs are failing.
*/
var bury = function(id, options) {
check_db();
options || (options = {});
peek(id, {
not_found_error: true,
success: function(item) {
if (item.state == 'buried') {
if (options.success) options.success();
return;
}
var table = item.tube;
if (item.state == 'reserved') {
table = tbl.reserved;
}
move_item(id, table, tbl.buried, {
transform: function(titem) {
titem.buries++;
titem.tube = item.tube;
if (options.priority) {
var pri = parseInt(options.priority);
if (pri) titem.priority = pri;
}
return titem;
},
success: options.success,
error: options.error
});
},
error: options.error
});
};
/**
* kick N many buried items back into their tubes
*/
var kick = function(num, options) {
check_db();
options || (options = {});
var records = 0;
// open all tables since we may get a range of tubes when kicking
var tables = [tbl.buried].concat(qoptions.tubes);
var trx = db.transaction(tables, 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(records, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
var put_in_tube = function(item, success) {
item.kicks++;
var tube = item.tube;
// remove the buried table's ID
delete item._id;
delete item.tube;
var store = trx.objectStore(tube)
var req = store.add(item);
req.onsuccess = success;
};
// grab one item from the tube, and put it in reserved
var store = trx.objectStore(tbl.buried);
store.openCursor().onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
put_in_tube(cursor.value, function(e) {
// remove the item from the tube once we know it's reserved
var req = store.delete(cursor.key);
req.onerror = options.error;
});
records++;
if (records < num) cursor.continue();
}
};
};
/**
* kick a job from the buried table by its id
*/
var kick_job = function(id, options) {
check_db();
options || (options = {});
peek(id, {
not_found_error: true,
success: function(item) {
if (item.state != 'buried') {
if (options.error) options.error(new HustleNotFound('item ' + id + ' isn\'t buried'));
return;
}
move_item(id, tbl.buried, item.tube, {
transform: function(item) {
item.kicks++;
delete item._id;
delete item.tube;
return item;
},
success: options.success,
error: options.error
});
},
error: options.error
});
};
/**
* reset a job's ttr
*/
var touch = function(id, options) {
check_db();
options || (options = {});
peek(id, {
not_found_error: true,
success: function(item) {
if (item.state != 'reserved') {
console.log('item.state: ', item.state);
if (options.error) options.error(new HustleNotFound('item ' + id + ' isn\'t reserved'));
return;
}
if (item.ttr <= 0) {
if (options.success) options.success();
return;
}
var trx = db.transaction(tbl.reserved, 'readwrite');
trx.oncomplete = function(e) {
if (options.success) options.success(e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
var store = trx.objectStore(tbl.reserved);
var req = store.get(id);
req.onsuccess = function(e) {
var item = req.result;
item.expire = new Date().getTime() + (item.ttr * 1000);
store.put(item);
};
},
error: options.error
});
};
var count_reserved = function(options) {
check_db();
options || (options = {});
var count = null;
var trx = db.transaction(tbl.reserved, 'readonly');
trx.oncomplete = function(e) {
if (options.success) options.success(count, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
};
var store = trx.objectStore(tbl.reserved);
var req = store.count();
req.onsuccess = function(e) {
count = req.result;
};
};
var count_ready = function(tube, options) {
check_db();
options || (options = {});
if (qoptions.tubes.indexOf(tube) < 0) throw new HustleBadTube('tube ' + tube + ' doesn\'t exist');
var count = null;
var trx = db.transaction(tube, 'readonly');
trx.oncomplete = function(e) {
if (options.success) options.success(count, e);
};
trx.onerror = function(e) {
if (options.error) options.error(e);
}
var store = trx.objectStore(tube);
var req = store.count();
req.onsuccess = function(e) {
count = req.result;
};
};
/**
* A class that makes consumption of a tube more manageable. For each
* reserved item, calls the given handler function.
*
* Has two public methods: start and stop. The consumer is started by
* default on instantiation.
*/
var Consumer = function(fn, coptions) {
coptions || (coptions = {});
var tube = coptions.tube ? coptions.tube : 'default';
var delay = coptions.delay ? coptions.delay : 100;
var do_stop = false;
var poll = function(options) {
options || (options = {});
if (do_stop || !db) return;
if (coptions.enable_fn) {
var res = coptions.enable_fn();
if (!res) {
do_stop = true;
return false;
}
}
// grab an item from the tube
reserve({
tube: tube,
success: function(item) {
if (!item) return;
fn(item);
// immediately poll for new items
setTimeout(function() {
poll({
skip_recurse: true
});
}, 0);
}
});
// poll again
if (!options.skip_recurse) setTimeout(poll, delay);
};
var start = function() {
if (!do_stop) return false;
do_stop = false;
setTimeout(poll, delay);
return true;
};
var stop = function() {
if (do_stop) return false;
do_stop = true;
return true;
};
setTimeout(poll, delay);
this.start = start;
this.stop = stop;
return this;
};
// ---------------------------------------------------------------------
// maintenance/cleanup
// ---------------------------------------------------------------------
/**
* move jobs in the delayed state into their respective tubes
*/
var move_delayed_jobs_to_ready = function(options) {
options || (options = {});
var move_items = [];
var trx = db.transaction(tbl.delayed, 'readonly');
trx.oncomplete = function(e) {
move_items.forEach(function(item) {
move_item(item.id, tbl.delayed, item.tube, {
error: function(e) {
console.error('Hustle: delayed move: ', e);
}
});
});
};
trx.onerror = function(e) {
console.error('Hustle: delayed move: ', e);
if (options.error) options.error(e);
}
var store = trx.objectStore(tbl.delayed);
var index = store.index('activate');
var bound = new Date().getTime();
var range = IDBKeyRange.upperBound(bound);
index.openCursor(range).onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
move_items.push(cursor.value);
cursor.continue();
}
}
};
/**
* move expired jobs to their ready tube
*/
var move_expired_jobs_to_ready = function(options) {
options || (options = {});
var move_items = [];
var trx = db.transaction(tbl.reserved, 'readonly');
trx.oncomplete = function(e) {
move_items.forEach(function(item) {
move_item(item.id, tbl.reserved, item.tube, {
transform: function(item) {
delete item.expire;
item.timeouts++;
return item;
},
error: function(e) {
if (e instanceof HustleNotFound) {
move_items.erase(item);
}
console.error('Hustle: ttr move: ', e);
}
});
});
};
trx.onerror = function(e) {
console.error('Hustle: ttr move: ', e);
if (options.error) options.error(e);
}
var store = trx.objectStore(tbl.reserved);
var index = store.index('expire');
var bound = new Date().getTime();
var range = IDBKeyRange.upperBound(bound);
index.openCursor(range).onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
move_items.push(cursor.value);
cursor.continue();
}
}
};
/**
* bury any items in the reserved queue
*/
var cleanup_abandoned_items = function(options) {
options || (options = {});
var abandoned_items = [];
var number_of_buried_items = 0;
var move_items_to_buried = function() {
abandoned_items.forEach(function(item) {
move_item(item.id, tbl.reserved, tbl.buried, {
transform: function(transform_item) {
transform_item.abandoned = true;
return transform_item;
},
success: exit_after_processing_all_items,
error: function(e) {
if (options.error) options.error(e);
}
});
});
};
var exit_after_processing_all_items = function() {
number_of_buried_items++;
if(number_of_buried_items == abandoned_items.length) {
if (options.success) options.success();
}
};
var trx = db.transaction(tbl.reserved, 'readonly');
trx.oncomplete = function() {
if (abandoned_items.length == 0) {
if (options.success) options.success();
} else {
move_items_to_buried();
}
};
trx.onerror = function(e) {
if (options.error) options.error(e);
};
var store = trx.objectStore(tbl.reserved);
store.openCursor().onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
abandoned_items.push(cursor.value);
cursor.continue();
}
}
};
/**
* rescues any items in the reserved queue by moving it to its tube
* or moving it to buried queue if it exceeds a maximum rescue limit
*/
var rescue_reserved_items = function (options) {
var items_in_reserved = [];
var number_of_rescued_items = 0;
var DEFAULT_RESCUE_LIMIT = 5, DEFAULT_RESCUE_TIME_LIMIT_IN_SECONDS = 60;
var maxRescueLimit = options.maxRescueLimit || DEFAULT_RESCUE_LIMIT;
var rescueTimeLimitInSeconds = options.rescueTimeLimitInSeconds || DEFAULT_RESCUE_TIME_LIMIT_IN_SECONDS;
var exit_after_processing_all_items = function () {
number_of_rescued_items++;
if(number_of_rescued_items == items_in_reserved.length) {
if(options.success) options.success();
}
};
var move_items_in_reserved = function () {
var move_item_to_tube = function (item) {
/**
* increase number of times it has been rescued based on timestamp it was rescued last
*/
var should_increase_abandon_count = function (item) {
if(!item.lastAbandonedTime) {
return true;
}
var timeInSecondsAfterLastAbandoned = (new Date().getTime() - item.lastAbandonedTime)/1000;
return timeInSecondsAfterLastAbandoned > rescueTimeLimitInSeconds;
};
move_item(item.id, tbl.reserved, item.tube, {
transform: function (item) {
if(should_increase_abandon_count(item)) {
item.lastAbandonedTime = new Date();
item.abandon_count = item.abandon_count || 0;
item.abandon_count++;
}
return item;
},
success: exit_after_processing_all_items,
error: function (e) {
if (options.error) options.error(e);
}
});
};
var move_item_to_buried = function (item) {
move_item(item.id, tbl.reserved, tbl.buried, {
success: exit_after_processing_all_items,
error: function (e) {
if (options.error) options.error(e);
}
});
};
items_in_reserved.forEach(function (item) {
var shouldRescue = !item.abandon_count || maxRescueLimit > item.abandon_count;
if(shouldRescue) {
move_item_to_tube(item);
} else {
move_item_to_buried(item);
}
});
};
var trx = db.transaction(tbl.reserved, 'readonly');
trx.oncomplete = function () {
if (items_in_reserved.length == 0) {
if(options.success) options.success();
} else {
move_items_in_reserved();
}
};
trx.onerror = function(e) {
if (options.error) options.error(e);
};
var store = trx.objectStore(tbl.reserved);
store.openCursor().onsuccess = function (e) {
var cursor = e.target.result;
if(cursor) {
items_in_reserved.push(cursor.value);
cursor.continue();
}
};
};
/**
* this function does database cleanup. only runs while db is open.
*/
do_maintenance = function() {
var run_maintenance = function() {
if (!db) return false;
move_delayed_jobs_to_ready();
move_expired_jobs_to_ready();
setTimeout(run_maintenance, maintenance_delay);
};
setTimeout(run_maintenance, maintenance_delay);
};
// ---------------------------------------------------------------------
// exports
// ---------------------------------------------------------------------
var Queue = {
peek: peek,
put: put,
reserve: reserve,
delete: del,
release: release,
bury: bury,
kick: kick,
kick_job: kick_job,
touch: touch,
count_ready: count_ready,
count_reserved: count_reserved,
cleanup_abandoned_items: cleanup_abandoned_items,
rescue_reserved_items: rescue_reserved_items,
Consumer: Consumer
};
this.open = open;
this.close = close;
this.is_open = function() {
return !!db;
};
this.wipe = wipe;
this.Error = Error;
this.Queue = Queue;
this.promisify = function() {
var _self = this;
var do_promisify = function(fn, opts_idx) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
if (!args[opts_idx]) args[opts_idx] = {};
return new Promise(function(success, error) {
args[opts_idx].success = success;
args[opts_idx].error = error;
fn.apply(_self, args);
});
};
};
this.open = do_promisify(this.open, 0);
this.Queue.peek = do_promisify(this.Queue.peek, 1);
this.Queue.put = do_promisify(this.Queue.put, 1);
this.Queue.reserve = do_promisify(this.Queue.reserve, 0);
this.Queue.delete = do_promisify(this.Queue.delete, 1);
this.Queue.release = do_promisify(this.Queue.release, 1);
this.Queue.bury = do_promisify(this.Queue.bury, 1);
this.Queue.kick = do_promisify(this.Queue.kick, 1);
this.Queue.kick_job = do_promisify(this.Queue.kick_job, 1);
this.Queue.touch = do_promisify(this.Queue.touch, 1);
this.Queue.count_ready = do_promisify(this.Queue.count_ready, 1);
this.Queue.count_reserved = do_promisify(this.Queue.count_reserved, 0);
this.Queue.cleanup_abandoned_items = do_promisify(this.Queue.cleanup_abandoned_items, 0);
this.Queue.rescue_reserved_items = do_promisify(this.Queue.rescue_reserved_items, 0);
return this;
}.bind(this);
this.debug = {
get_db: function() {
return db;
}
};
return this;
};
Hustle.Error = {
DBClosed: HustleDBClosed,
DBOpened: HustleDBOpened,
BadTube: HustleBadTube,
BadID: HustleBadID,
NotFound: HustleNotFound
};
window.Hustle = Hustle;
})(window);