src/browser/notes/note.js
/*************************************************
* Contains code to communicate with the Notes
* database.
* @author : Abijeet Patro
*************************************************/
'use strict';
var _appConfig = require(__dirname + '/../../../config.js');
var _app = require(_appConfig.browserSrcPath + 'app/app.js');
var _appError = require(_appConfig.commonsPath + 'app-error.js');
var _appUtil = require(_appConfig.commonsPath + 'utility');
var _i18n = require('i18n');
var Notes = function() {
/**
* Fetches the notes present in the given notebook.
* @param {String} notebookID Notebook ID
* @param {function} cbMain Callback method that is sent an errror object
* or the list of notes SORTED by createdOn
* @return {undefined} No return type.
*/
function getAllNotesByID(notebookID, cbMain) {
var notesDb = _app.getNotesDb();
notesDb.find({
notebookID: notebookID
}).sort({
createdOn: 1
}).exec(function(err, notes) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_fetch_error')));
}
return cbMain(null, notes);
});
}
/**
* Updates or Inserts the details of a note in the database
* @param {Object} noteObj The note to be updated
* @param {Boolean} isNewNote Determies if it's a new note.
* @param {function} cbMain Callback function. Is sent the error object if
* there was an error, else is sent the updated / inserted note object.
* @return {undefined} No return type.
*/
function _modifyNote(noteObj, isNewNote, cbMain) {
if (!_validateNote(noteObj, isNewNote)) {
return cbMain(new _appError(new Error('Invalid note object'),
_i18n.__('error.notes_save_validation_err')));
}
var noteElem = noteObj.noteElem;
var isBlur = noteObj.isBlur;
var noteID = noteObj._id;
noteObj = _populateValues(noteObj, true);
var notesDb = _app.getNotesDb();
// Delete _id, just in case so nedb can create its own.
delete noteObj._id;
/**
* Callback method called after a note has been inserted or updated.
* This adds the original element back to the note object and calls the
* original callback method sent as parameter to `modifyNote`
* @param {error} err Error object returned if there was an error,
* else returns null.
* @param {Object} noteObj Updated / Inserted note object
* @return {undefined} No return type.
*/
function cbNoteModified(err, noteObj) {
noteObj.noteElem = noteElem;
noteObj.isBlur = isBlur;
if (err) {
cbMain(new _appError(err, _i18n.__('error.notes_modification_err')), noteObj);
} else {
cbMain(null, noteObj);
}
noteObj = null;
cbMain = null;
return;
}
if (isNewNote) {
// Insert
notesDb.insert(noteObj, cbNoteModified);
} else {
// Update
notesDb.update({
_id: noteID
}, noteObj, function(err, numReplaced) {
if (numReplaced <= 0) {
err = new _appError(err, _i18n.__('error.notes_update_err'));
}
return cbNoteModified(err, noteObj);
});
}
}
/**
* Fetches note details by the ID
* @param {String} noteID ID of the note
* @param {function} cbMain Callback that is sent the note object that
* contains the details of the note, if there was an error is returned the
* error object.
* @return {undefined} No return type.
*/
function getNoteByID(noteID, cbMain) {
var notesDb = _app.getNotesDb();
if (!noteID) {
// TODO Add proper error.
return cbMain(new _appError());
}
notesDb.findOne({
_id: noteID
}, function(err, noteObj) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.note_fetch_error')));
}
return cbMain(null, noteObj);
});
}
/**
* Delete's a note with the given ID
* @param {String} noteID Note ID
* @param {function} cbMain Callback function. Error is passed as an argument
* if deletion failed, else error is passed as null
* @return {undefined} No return type.
*/
function deleteNote(noteID, cbMain) {
if (!noteID) {
var err = new _appError(new ReferenceError('Note ID is a mandatory value'), _i18n.__('error.note_delete_validation_err'));
return cbMain(err);
}
var notesDb = _app.getNotesDb();
notesDb.remove({
_id: noteID
}, {}, function(err, numRemoved) {
if (err) {
return cbMain(new _appError(err), _i18n.__('error.note_delete_err'));
}
if (numRemoved <= 0) {
return cbMain(new _appError(), _i18n.__('error.note_delete_not_found'));
}
cbMain(null);
});
}
/**
* Fetches all the active notes in a notebook. Active notes are notes that are
* created on today OR created on in the past but NOT completed.
* @param {String} notebookID Notebook ID
* @param {function} cbMain Callback function
* @return {undefined}
* No return type.
*/
function getAllActiveNotes(notebookID, cbMain) {
var notesDb = _app.getNotesDb();
var dtNow = new Date();
notesDb.find({
$where: function() {
// Check if belongs to current notebook.
if (this.notebookID !== notebookID) {
return false;
}
// If completed today, show note.
if (this.isComplete) {
if (this.completedOn && _appUtil.checkDates(this.completedOn, dtNow) === 0) {
return true;
}
}
// Check if date is less than current date, and note is not complete.
if (_appUtil.checkDates(this.targetDate, dtNow) <= 0 && this.isComplete === false) {
return true;
}
return false;
}
}).sort({
isComplete: -1,
createdOn: 1
}).exec(function(err, notes) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_fetch_error')));
}
return cbMain(null, notes);
});
}
/**
* Fetches all the completed notes for a given day.
* @param {String} notebookID Notebook ID
* @param {Date} date The requested date
* @param {function} cbMain Callback function
* @return {undefined} No return type.
*/
function getCompletedNotesForDate(notebookID, date, cbMain) {
var notesDb = _app.getNotesDb();
var dtSelectedDate = date;
notesDb.find({
$where: function() {
// Check if belongs to current notebook.
if (this.notebookID !== notebookID) {
return false;
}
// Check if note its completed.
if (this.isComplete === true) {
// Check if completed on date is set.
if (this.completedOn) {
if (_appUtil.checkDates(this.completedOn, dtSelectedDate) === 0) {
return true;
}
} else if (this.modifiedOn && _appUtil.checkDates(this.modifiedOn, dtSelectedDate) === 0) {
// Although note is complete, completed on date is not set, check the
// modified on date. This is because of #41 where the completedOn
// was not being updated when notes were completed.
// This will only come into play when completedOn is not set properly.
return true;
}
}
return false;
}
}).sort({
createdOn: -1
}).exec(function(err, notes) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_fetch_error')));
}
return cbMain(null, notes);
});
}
function getFutureNotesByDate(notebookID, futureDate, cbMain) {
var notesDb = _app.getNotesDb();
var dtFutureDate = new Date(futureDate.setHours(0, 0, 0, 0));
notesDb.find({
$and: [{
targetDate: dtFutureDate
}, {
isComplete: false
}]
}).sort({
createdOn: -1
}).exec(function(err, notes) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_fetch_error')));
}
return cbMain(null, notes);
});
}
/**
* Private function used to validate a note object. If it's NOT a new note
* ensures that the _id parameter has been provided.
* @param {Object} noteObj Note object
* @param {Boolean} isNewNote Is this a new note?
* @return {Boolean} true if it's a valid note object, else false.
*/
function _validateNote(noteObj, isNewNote) {
if (!noteObj) {
return false;
}
if (!isNewNote) {
// It's an old note. Reason for this crazy NOT usage is that _populateValues uses
// isNewNote, and hence using it here too, to maintain uniformity.
// Validate that the _id key is present.
if (!noteObj._id) {
return false;
}
}
if (!noteObj.notebookID) {
return false;
}
return true;
}
/**
* Private function to populate values into the note object before its saved
* or updated. Adds the createdOn property if it's a new note.
* @param {Object} noteObj Note Object
* @param {Boolean} isNewNote Is this a new note?
* @return {Object} Modified note object
*/
function _populateValues(noteObj, isNewNote) {
delete noteObj.noteElem;
delete noteObj.isBlur;
if (isNewNote) {
noteObj.createdOn = new Date();
}
noteObj.modifiedOn = new Date();
return noteObj;
}
function changeNoteDate(noteID, updatedDate, isComplete, cbMain) {
var notesDb = _app.getNotesDb();
var err = null;
if (!noteID) {
err = new _appError(new Error('Please provide the note ID.'),
_i18n.__('error.invalid_note_id'));
return cbMain(err);
}
var currDateTime = new Date();
var currDate = new Date(currDateTime.getFullYear(), currDateTime.getMonth(), currDateTime.getDate());
var noteObj = {
targetDate: updatedDate,
modifiedOn: currDateTime
};
if (updatedDate.getTime() < currDate.getTime()) {
// Note being moved to the past, set the completed on date in the past,
// and set the note as isComplete
noteObj.completedOn = updatedDate;
noteObj.isComplete = true;
} else if (updatedDate.getTime() > currDateTime.getTime()) {
// note is moved to the future, remove completedOn and isComplete to false
noteObj.completedOn = null;
noteObj.isComplete = false;
} else {
// todays date, change the completedOn to todays date,
// otherwise the note will not move to today's date
if (isComplete) {
noteObj.completedOn = currDate;
}
}
notesDb.update({
_id: noteID
}, {
$set: noteObj
}, function(err, numReplaced) {
if (numReplaced <= 0) {
err = new _appError(err, _i18n.__('error.notes_update_err'));
}
return cbMain(err, noteObj);
});
}
function _updateCompletion(noteID, isComplete, cbMain) {
var notesDb = _app.getNotesDb();
var currDate = new Date();
var completedOn = null;
if (isComplete) {
completedOn = currDate;
}
notesDb.update({
_id: noteID
}, {
$set: {
isComplete: isComplete,
modifiedOn: currDate,
completedOn: completedOn
}
}, {}, function(err, numReplaced) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_complete')));
}
if (numReplaced === 1) {
return cbMain(null);
}
return cbMain(new Error(_i18n.__('error.notes_complete'),
_i18n.__('error.notes_complete')));
});
}
function _deleteByNotebookID(notebookID, cbMain) {
var notesDb = _app.getNotesDb();
notesDb.remove({
notebookID: notebookID
}, {
multi: true
}, function(err, numRemoved) {
if (err) {
return cbMain(new _appError(err, _i18n.__('error.notes_delete_err')));
}
return cbMain(null, numRemoved);
});
}
return {
getNoteByID: getNoteByID,
modifyNote: _modifyNote,
deleteNote: deleteNote,
getAllActiveNotes: getAllActiveNotes,
getCompletedNotesForDate: getCompletedNotesForDate,
getFutureNotesByDate: getFutureNotesByDate,
changeDate: changeNoteDate,
updateCompletion: _updateCompletion,
deleteByNotebookID: _deleteByNotebookID
};
};
module.exports = new Notes();