diff --git a/LesionTracker/.meteor/packages b/LesionTracker/.meteor/packages
index 91343c364..a17d120ed 100644
--- a/LesionTracker/.meteor/packages
+++ b/LesionTracker/.meteor/packages
@@ -52,3 +52,5 @@ aldeed:template-extension@4.0.0
zuuk:stale-session
gilbertwat:bootstrap3-daterangepicker
email
+peppelg:bootstrap-3-modal
+simple:reactive-method
diff --git a/LesionTracker/.meteor/versions b/LesionTracker/.meteor/versions
index 8ff293c77..37f81bc2d 100644
--- a/LesionTracker/.meteor/versions
+++ b/LesionTracker/.meteor/versions
@@ -83,6 +83,7 @@ npm-bcrypt@0.7.8_2
npm-mongo@1.4.39_1
observe-sequence@1.0.7
ordered-dict@1.0.4
+peppelg:bootstrap-3-modal@1.0.4
practicalmeteor:chai@2.1.0_1
practicalmeteor:loglevel@1.2.0_2
promise@0.5.1
@@ -98,6 +99,7 @@ service-configuration@1.0.5
session@1.1.1
sha@1.0.4
silentcicero:jszip@0.0.4
+simple:reactive-method@1.0.2
spacebars@1.0.7
spacebars-compiler@1.0.7
srp@1.0.4
diff --git a/LesionTracker/client/routes.js b/LesionTracker/client/routes.js
index 6beedb3f6..f983af0c1 100644
--- a/LesionTracker/client/routes.js
+++ b/LesionTracker/client/routes.js
@@ -26,7 +26,8 @@ var data = {
'associationModal',
'optionsModal',
'serverInformationModal',
- 'confirmRemoveTimepointAssociation'
+ 'confirmRemoveTimepointAssociation',
+ 'lastLoginModal'
]
};
diff --git a/LesionTracker/defaultSettings.js b/LesionTracker/defaultSettings.js
index 2b1f48637..f7cb4245a 100644
--- a/LesionTracker/defaultSettings.js
+++ b/LesionTracker/defaultSettings.js
@@ -40,12 +40,8 @@ Meteor.startup(function() {
// Bind events if window is closed
$(window).bind('beforeunload', function (e) {
- closingWindow();
// have to return null, unless you want a chrome popup alert
- //return 'If you leave this page then any unsaved changes will be lost.';
+ // return 'If you leave this page then any unsaved changes will be lost.';
});
});
-closingWindow = function(){
- Meteor.call('removeUserFromReviewers', Meteor.userId());
-};
diff --git a/Packages/active-entry/server/methods.js b/Packages/active-entry/server/methods.js
index 5b6cbb1c1..5225148e9 100644
--- a/Packages/active-entry/server/methods.js
+++ b/Packages/active-entry/server/methods.js
@@ -123,7 +123,12 @@ Meteor.methods({
},
updateLastLoginDate: function () {
- Meteor.users.update({_id: Meteor.userId()}, {$set: {lastLoginDate: new Date()}});
+ var user = Meteor.users.findOne(Meteor.userId());
+ if (!user) {
+ return;
+ }
+ // Update priorLoginDate and lastLoginDate
+ Meteor.users.update({_id: Meteor.userId()}, {$set: {priorLoginDate: user.lastLoginDate, lastLoginDate: new Date()}});
},
isAccountInactive: function (inactivityParameters) {
diff --git a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.html b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.html
index 9ea39789f..e24036ac0 100644
--- a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.html
+++ b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.html
@@ -16,7 +16,7 @@
{{entryTimestamp}}
- {{userName}} initialized HIPAA Audit Log.
+ {{userName}} initialized HIPAA Audit Log.
@@ -60,7 +60,7 @@
{{entryTimestamp}}
{{#if hasPatientInfo}}
-
{{userName}} modified record
{{getRecordId}} in the
{{getCollectionName}} collection, regarding patient
{{getPatientName}}.
+
{{userName}} modified record
{{getRecordId}} in the
{{getCollectionName}} collection, regarding patient
{{getPatientName}}.
{{else}}
{{userName}} modified record
{{getRecordId}} in the
{{getCollectionName}} collection.
{{/if}}
@@ -77,7 +77,7 @@
{{entryTimestamp}}
- {{userName}} cloned record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} cloned record {{getRecordId}} in the {{getCollectionName}} collection.
@@ -90,7 +90,7 @@
{{entryTimestamp}}
- {{userName}} deleted record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} deleted record {{getRecordId}} in the {{getCollectionName}} collection.
@@ -103,7 +103,7 @@
{{entryTimestamp}}
- {{userName}} was denied access to record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} was denied access to record {{getRecordId}} in the {{getCollectionName}} collection.
@@ -117,9 +117,9 @@
{{entryTimestamp}}
{{#if hasPatientInfo}}
- {{userName}} viewed record {{getRecordId}} in the {{getCollectionName}} collection, regarding patient {{getPatientName}}.
+ {{userName}} viewed record {{getRecordId}} in the {{getCollectionName}} collection, regarding patient {{getPatientName}}.
{{else}}
- {{userName}} viewed record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} viewed record {{getRecordId}} in the {{getCollectionName}} collection.
{{/if}}
@@ -133,7 +133,7 @@
{{entryTimestamp}}
- {{userName}} published record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} published record {{getRecordId}} in the {{getCollectionName}} collection.
@@ -146,7 +146,7 @@
{{entryTimestamp}}
- {{userName}} unpublished record {{getRecordId}} in the {{getCollectionName}} collection.
+ {{userName}} unpublished record {{getRecordId}} in the {{getCollectionName}} collection.
@@ -159,7 +159,7 @@
{{entryTimestamp}}
- {{userName}} received a data access error while performing an action!
+ {{userName}} received a data access error while performing an action!
{{getErrorMessage}}
diff --git a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.js b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.js
index acd458a9b..ffe8fc177 100644
--- a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.js
+++ b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.js
@@ -20,7 +20,7 @@ Template.hipaaAuditLog.helpers({
},
hipaaAudit: function () {
// return HipaaLog.find();
- return HipaaLog.find({
+ return HipaaLog.find({
$or: [
{
userName: {
@@ -33,6 +33,18 @@ Template.hipaaAuditLog.helpers({
$regex: Session.get('hipaaSearchFilter'),
$options: 'i'
}
+ },
+ {
+ recordId: {
+ $regex: Session.get('hipaaSearchFilter'),
+ $options: 'i'
+ }
+ },
+ {
+ collectionName: {
+ $regex: Session.get('hipaaSearchFilter'),
+ $options: 'i'
+ }
}
],
eventType: {
@@ -54,6 +66,23 @@ Template.hipaaAuditLog.helpers({
Template.hipaaAuditLog.events({
"keyup #hipaaSearchFilter": function (event, template) {
Session.set("hipaaSearchFilter", $('#hipaaSearchFilter').val());
+ },
+ "click .userName": function(event, template) {
+ var userName = $(event.currentTarget).text();
+ Session.set('hipaaSearchFilter', userName);
+ },
+ "click .patientName": function(event, template) {
+ var patientName = $(event.currentTarget).text();
+ var patientNameRegex = patientName.replace(/[!@#$%^&*()+=\-[\]\\';,./{}|":<>?~_]/g, "\\$&");
+ Session.set('hipaaSearchFilter', patientNameRegex);
+ },
+ "click .mongoRecordId": function(event, template) {
+ var mongoRecordId = $(event.currentTarget).text();
+ Session.set('hipaaSearchFilter', mongoRecordId);
+ },
+ "click .collectionName": function(event, template) {
+ var collectionName = $(event.currentTarget).text();
+ Session.set('hipaaSearchFilter', collectionName);
}
});
diff --git a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.less b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.less
index 0d902457e..e600a3850 100644
--- a/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.less
+++ b/Packages/hipaa-audit-log/components/hipaaAuditLog/hipaaAuditLog.less
@@ -70,5 +70,9 @@
width: 100%;
}
+ .userName, .patientName, .mongoRecordId, .collectionName{
+ cursor: pointer;
+ }
+
}
diff --git a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.html b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.html
index c0a38264a..076b5e387 100644
--- a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.html
+++ b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.html
@@ -1,13 +1,17 @@
diff --git a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.js b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.js
index 01f38cc6f..fa5dffc3b 100644
--- a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.js
+++ b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.js
@@ -8,7 +8,10 @@ Template.hipaaRibbon.events({
"change #endDateInput": function (event, template) {
Session.set("endDateFilter", $('#endDateInput').val() + "T00:00:00.000Z");
},
-
+ 'change #actionFilter': function(e) {
+ var actionType = e.currentTarget.value;
+ Session.set("hipaaTypeFilter", actionType);
+ },
'click #filterCreatedButton': function () {
Session.set("hipaaTypeFilter", 'create');
},
@@ -20,6 +23,9 @@ Template.hipaaRibbon.events({
},
'click #filterAllButton': function () {
Session.set("hipaaTypeFilter", '');
+ },
+ 'click #searchClear': function() {
+ Session.set("hipaaSearchFilter", '');
}
});
diff --git a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.less b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.less
index f4beb9abf..001c3bd62 100644
--- a/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.less
+++ b/Packages/hipaa-audit-log/components/hipaaRibbon/hipaaRibbon.less
@@ -28,6 +28,17 @@
.form-control{
display: inline-block !important;
}
+ #searchClear {
+ position: absolute;
+ right: 14px;
+ top: 0;
+ bottom: 0;
+ height: 14px;
+ margin: auto;
+ font-size: 14px;
+ cursor: pointer;
+ color: #ccc;
+ }
}
// @media only screen and (max-width: 850px) {
diff --git a/Packages/lesiontracker/client/components/associationModal/associationModal.js b/Packages/lesiontracker/client/components/associationModal/associationModal.js
index 57dbed08f..5cc60b76e 100644
--- a/Packages/lesiontracker/client/components/associationModal/associationModal.js
+++ b/Packages/lesiontracker/client/components/associationModal/associationModal.js
@@ -59,6 +59,10 @@ Template.associationModal.events({
// Sort the study dates, so we can get a range for these values
studyDates = studyDates.sort();
+ // HipaaEventType to log changes in collections
+ var hipaaEventType;
+ var hipaaEvent;
+
// Check if these studies are already associated with an existing Timepoint
var existingTimepoint;
if (timepointType === 'baseline') {
@@ -91,6 +95,7 @@ Template.associationModal.events({
}
});
timepointId = existingTimepoint.timepointId;
+ hipaaEventType = 'modify';
} else {
// Create a new timepoint to represent the (baseline or follow-up) studies
var timepoint = {
@@ -105,8 +110,20 @@ Template.associationModal.events({
// Insert this timepoint into the Timepoints Collection
Timepoints.insert(timepoint);
timepointId = timepoint.timepointId;
+ hipaaEventType = 'create';
}
+ // Log
+ hipaaEvent = {
+ eventType: hipaaEventType,
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Timepoints",
+ recordId: timepointId,
+ patientId: relatedStudies[0].patientId,
+ patientName: relatedStudies[0].patientName
+ };
+
// Loop through these studies to associate them with the newly created timepoint
relatedStudies.forEach(function(study) {
// Check if a study already exists in the Studies collection
@@ -121,6 +138,8 @@ Template.associationModal.events({
timepointId: timepointId
}
});
+ // Log modify
+ hipaaEventType = 'modify';
} else {
// If no such study exists, update the entry with the new timepointId
@@ -130,7 +149,22 @@ Template.associationModal.events({
// Attach the timepointId and insert it into the Studies Collection
study.timepointId = timepointId;
Studies.insert(study);
+
+ // Log create
+ hipaaEventType = 'create';
}
+
+ // Log
+ hipaaEvent = {
+ eventType: hipaaEventType,
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Studies",
+ recordId: study.studyInstanceUid,
+ patientId: study.patientId,
+ patientName: study.patientName
+ };
+ HipaaLogger.logEvent(hipaaEvent);
});
});
diff --git a/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.html b/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.html
new file mode 100644
index 000000000..4b15781fb
--- /dev/null
+++ b/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
×
+ {{#if lastLoginDate}}
+
You last logged in on {{lastLoginDate}}
+ {{/if}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.js b/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.js
new file mode 100644
index 000000000..388677bf0
--- /dev/null
+++ b/Packages/lesiontracker/client/components/lastLoginModal/lastLoginModal.js
@@ -0,0 +1,9 @@
+Template.lastLoginModal.helpers({
+ lastLoginDate: function() {
+ var userLoginDate = ReactiveMethod.call('getPriorLoginDate');
+ if (userLoginDate && userLoginDate.priorLoginDate) {
+ return moment(userLoginDate.priorLoginDate).format("MMMM Do YYYY, HH:mm:ss A");
+ }
+ return;
+ }
+});
\ No newline at end of file
diff --git a/Packages/lesiontracker/client/components/lesionTrackerLayout/lesionTrackerLayout.js b/Packages/lesiontracker/client/components/lesionTrackerLayout/lesionTrackerLayout.js
index c90d9b4c1..7ba31f20d 100644
--- a/Packages/lesiontracker/client/components/lesionTrackerLayout/lesionTrackerLayout.js
+++ b/Packages/lesiontracker/client/components/lesionTrackerLayout/lesionTrackerLayout.js
@@ -1,42 +1,5 @@
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
-
-Template.lesionTrackerLayout.helpers({
- fullName: function() {
- return Meteor.user().profile.fullName;
- },
-
- showWorklistMenu: function() {
- return Template.instance().showWorklistMenu.get();
- },
-
- currentUser: function() {
- var verifyEmail = Meteor.settings && Meteor.settings.public && Meteor.settings.public.verifyEmail || false;
-
- if (!Meteor.user() || !Meteor.userId()) {
- return false;
- }
-
- if (!verifyEmail) {
- return true;
- }
-
- if (Meteor.user().emails[0].verified) {
- return true;
- }
-
- return false;
- }
-});
-
Template.lesionTrackerLayout.onCreated(function() {
- // showViewer to go to viewer from audit
- this.showWorklistMenu = new ReactiveVar(true);
- // Get url and check worklist
- var currentPath = Router.current().route.path(this);
- if (currentPath === '/' || currentPath === '/worklist') {
- this.showWorklistMenu.set(false);
- }
-
// Show countdown dialog
var handle;
$(document).on('TriggerOpenTimeoutCountdownDialog', function(e, leftTime) {
@@ -68,3 +31,54 @@ Template.lesionTrackerLayout.onCreated(function() {
}
});
});
+
+Template.lesionTrackerLayout.onRendered(function() {
+ var oldUserId = undefined;
+ var userName;
+ var lastLoginModalInterval;
+
+ Tracker.autorun(function() {
+ // Hook login/logout
+ var newUserId = Meteor.userId();
+ if (oldUserId === null && newUserId) {
+ Session.set('showLastLoginModal', true);
+ userName = Meteor.user().profile.fullName;
+ // Log
+ HipaaLogger.logEvent({
+ eventType: 'init',
+ userId: Meteor.userId(),
+ userName: userName
+ });
+ } else if (newUserId === null && oldUserId) {
+ // Set showLastLoginModal as null
+ Session.set('showLastLoginModal', null);
+ // Destroy interval for last login modal
+ Meteor.clearInterval(lastLoginModalInterval);
+ console.log('The user logged out');
+
+ // Log
+ // TODO: eventype is not defined for logout in hipaa-audit-log
+ /*HipaaLogger.logEvent({
+ eventType: 'logout',
+ userId: oldUserId,
+ userName: userName
+ });*/
+
+ // Remove the user from Reviewers
+ Meteor.call('removeUserFromReviewers', oldUserId);
+ }
+ oldUserId = Meteor.userId();
+
+ // Trigger last login date popup
+ if (Session.get('showLastLoginModal')) {
+ Modal.show('lastLoginModal');
+ lastLoginModalInterval = Meteor.setInterval( function() {
+ Modal.hide('lastLoginModal');
+ Session.set("showLastLoginModal", null);
+ }, 3000);
+ return true;
+ }
+ });
+});
+
+
diff --git a/Packages/lesiontracker/client/components/lesionTrackerWorklistContextMenu/lesionTrackerWorklistContextMenu.js b/Packages/lesiontracker/client/components/lesionTrackerWorklistContextMenu/lesionTrackerWorklistContextMenu.js
index 555b5135b..ca43814b6 100644
--- a/Packages/lesiontracker/client/components/lesionTrackerWorklistContextMenu/lesionTrackerWorklistContextMenu.js
+++ b/Packages/lesiontracker/client/components/lesionTrackerWorklistContextMenu/lesionTrackerWorklistContextMenu.js
@@ -37,7 +37,20 @@ function removeTimepointAssociations() {
Meteor.call('removeAssociatedStudy', study._id, function(error) {
if (error) {
log.warn(error);
+ return;
}
+
+ // Log
+ var hipaaEvent = {
+ eventType: 'delete',
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Studies",
+ recordId: study.studyInstanceUid,
+ patientId: study.patientId,
+ patientName: study.patientName
+ };
+ HipaaLogger.logEvent(hipaaEvent);
});
// Find the Timepoint that was previously referenced
@@ -64,13 +77,38 @@ function removeTimepointAssociations() {
studyInstanceUids: timepoint.studyInstanceUids
}
});
+
+ // Log
+ var hipaaEvent = {
+ eventType: 'modify',
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Timepoints",
+ recordId: study.timepointId,
+ patientId: study.patientId,
+ patientName: study.patientName
+ };
+ HipaaLogger.logEvent(hipaaEvent);
} else {
// If no more Studies are associated with this Timepoint, we should remove it
// from the Timepoints Collection via a server call
Meteor.call('removeTimepoint', timepoint._id, function(error) {
if (error) {
log.warn(error);
+ return;
}
+
+ // Log
+ var hipaaEvent = {
+ eventType: 'delete',
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Timepoints",
+ recordId: study.timepointId,
+ patientId: study.patientId,
+ patientName: study.patientName
+ };
+ HipaaLogger.logEvent(hipaaEvent);
});
}
});
@@ -81,10 +119,10 @@ function removeTimepointAssociations() {
*/
function exportSelectedStudies() {
var selectedStudies = WorklistSelectedStudies.find({}, {
- sort: {
- studyDate: 1
- }
- }).fetch();
+ sort: {
+ studyDate: 1
+ }
+ }).fetch();
if (!selectedStudies) {
return;
@@ -98,10 +136,10 @@ function exportSelectedStudies() {
*/
function viewStudies() {
var selectedStudies = WorklistSelectedStudies.find({}, {
- sort: {
- studyDate: 1
- }
- }).fetch();
+ sort: {
+ studyDate: 1
+ }
+ }).fetch();
if (!selectedStudies) {
return;
diff --git a/Packages/lesiontracker/package.js b/Packages/lesiontracker/package.js
index d1647ae86..cc905a869 100644
--- a/Packages/lesiontracker/package.js
+++ b/Packages/lesiontracker/package.js
@@ -156,6 +156,8 @@ Package.onUse(function(api) {
api.addFiles('client/components/confirmRemoveTimepointAssociation/confirmRemoveTimepointAssociation.html', 'client');
api.addFiles('client/components/confirmRemoveTimepointAssociation/confirmRemoveTimepointAssociation.js', 'client');
+ api.addFiles('client/components/lastLoginModal/lastLoginModal.html', 'client');
+ api.addFiles('client/components/lastLoginModal/lastLoginModal.js', 'client');
// Server functions
api.addFiles('server/collections.js', 'server');
diff --git a/Packages/lesiontracker/server/reviewers.js b/Packages/lesiontracker/server/reviewers.js
index 2ed801c47..27aa79d84 100644
--- a/Packages/lesiontracker/server/reviewers.js
+++ b/Packages/lesiontracker/server/reviewers.js
@@ -45,6 +45,18 @@ Meteor.methods({
} else {
Reviewers.insert({timepointId: timepoint.timepointId, reviewers: [{userId: user._id, userName: user.profile.fullName}]});
}
+
+ // Log
+ var hipaaEvent = {
+ eventType: 'modify',
+ userId: Meteor.userId(),
+ userName: Meteor.user().profile.fullName,
+ collectionName: "Measurements",
+ recordId: study.studyInstanceUid,
+ patientId: study.patientId,
+ patientName: study.patientName
+ };
+ HipaaLogger.logEvent(hipaaEvent);
},
removeReviewer: function (timepointId) {
@@ -70,6 +82,10 @@ Meteor.methods({
Reviewers.find().map(function (timepoint) {
Reviewers.update({_id: timepoint._id}, {"$pull": {"reviewers": {"userId": userId}}});
});
+ },
+
+ getPriorLoginDate: function() {
+ return Meteor.users.findOne({_id: Meteor.userId()}, {fields: {priorLoginDate: 1}});
}
});