diff options
| author | kumar <kumar.damani@mail.utoronto.ca> | 2016-07-27 18:12:37 +0000 |
|---|---|---|
| committer | kumar <kumar.damani@mail.utoronto.ca> | 2016-07-27 18:12:37 +0000 |
| commit | caedcd2b27518e63ab3dc51d81852125137289aa (patch) | |
| tree | 41fcb64f5767199759c98d236933b7112ed9e6d1 /dbTests/node_simple_backup.js | |
| parent | 11854aac96d07d7f1f428df693d349b0c38750eb (diff) | |
more improvement docs changes
Diffstat (limited to 'dbTests/node_simple_backup.js')
| -rw-r--r-- | dbTests/node_simple_backup.js | 1458 |
1 files changed, 1458 insertions, 0 deletions
diff --git a/dbTests/node_simple_backup.js b/dbTests/node_simple_backup.js new file mode 100644 index 0000000..4b31f7e --- /dev/null +++ b/dbTests/node_simple_backup.js @@ -0,0 +1,1458 @@ +/** + * A simple node driver to interact with mongo database + */ + +/********************** + **** COLLECTIONS: **** + * ******************** + * + * * * ADMINS - Admins login info + * { + * fname: first name, + * lname: last name, + * username: admin username, + * password: hashed password + * } + * + * * * COURSES - Course info + * { + * course_code: course code, + * title: course title + * } + * + * + * * * EXAMS - Exams info + * { + * course_code: course code, + * year: course year, + * term: course term, + * type: midterm or final, + * instructors: array of instructor names, + * page_count: the midterm/exam's number of pages, + * questions_count: the midterm/exam's number of questions, + * questions_list: array containing question objects, {q_id: question #, question: question}, + * upload_date: date, + * uploaded_by: username + * } + * + * + * * * LOGINS - Users login info + * { + * email: user email, + * user_name: user username, + * password: users hashed password + * } + * + * + * * * MAIL - messaging system base + * { + * sender: the message sender's username, + * receiver: the receiver's username, + * message: message, + * date: date message was sent + * } + * + * + * * * SOLUTIONS - exam solutions + * { + * exam_id: the id of the exam this solution applies to, + * q_id: question id, + * text: users solution, + * votes: votes, + * comments: list of comment objects, {text: comment, date: comment date, by: username} + * } + * + * * * USERS + * { + * email: user email, + * username: username, + * f_name: first name, + * l_name: last name, + * university: user's university, + * department: user's department, + * answered: number of solutions user posted, + * messages: user's inbox count, + * comments: user comment count, + * phone_num: user phone number, + * followers: the list of exams that the user follows + * } + * + * + * * * VERIFICATIONS - link facebook profile to the user + * { + * username: user username, + * facebookID: facebook profile id, + * facebookToken: facebook token, + * } + * + * + */ + + +var exports = module.exports = {}; + +const debug_mode = false; + +Object.assign = require('object-assign'); +var mongodb = require('mongodb'); +var mongoFactory = require('mongo-factory'); +var ObjectId = require('mongodb').ObjectID; +var assert = require('assert'); +var _ = require('underscore'); + +// Standard URI format: mongodb://[dbuser:dbpassword@]host:port/dbname +// var uri = exports.uri = 'mongodb://general:assignment4@ds057862.mlab.com:57862/solutions_repo'; + + +// Keep this for testing on local machine, do not remove. - Humair +var uri = exports.uri = 'mongodb://localhost:27017/db'; + + +/*******************************FUNCTIONS************************************************/ + + + +/************************* USERS **********************************/ + +/** + * This function will remove the user given user_name from the users table + * and the logins table. So far. + * IF there is a sessions table, we need to remove it from there as well. + * We can leave it in the mail table (involves another user). + * We can leave it in the solutions table (solution may still be valid). + * + * @param {string} username: the unique user_name for the user + * @param {function} callback: 2 args: (boolean, <string>), + * where <boolean> : err ? false : true + * where <string> : error ? error_mssg : success_mssg + */ +exports.remove_user = function (username, callback) { + + mongoFactory.getConnection(uri).then(function(db) { + + // fetch the exams table + var users = db.collection('users'); + var logins = db.collection('logins'); + + // look for the specific user + users.removeOne( { user_name: username }, function (err, docs) { + if (err) throw err; + else if (docs.deletedCount == 1) { + // now remove it from logins .... + logins.removeOne( { user_name: username }, function (err, result) { + if (err) throw err; + else if (result.deletedCount == 1) { + callback(true, "User was removed successfully from both tables"); + + } + }); + } + else if (docs.deletedCount == 0) { + callback(false, "No such user was found"); + + } + }); + }).catch(function(err) { + console.error(err); + }); +}; + +/** + * This function will search through the users table to look for 'token'. + * It will search the user_name, f_name, l_name fields of the table. + * Do not worry about case sensitivity. Malicious string is a possibility though. + * Returns a [] of user object(s) + * + * @params {string} token: search term (hopefully user info) + * @params {function} callback: with 2 args: (boolean, <string>), + * where <boolean> : err ? false : true + * where <string> can be error message + * OR on success <[Objs]> RESULT + * */ +exports.search_users = function ( token, callback ) { + + mongoFactory.getConnection(uri).then(function (db) { + var users = db.collection('users'); + users.createIndex( // make the following fields searchable + { + "user_name":"text", + "f_name":"text", + "l_name":"text" + }); + users.find( + { $text: { $search: token } }, + { score: { $meta: "textScore" } } + ).sort( { score: { $meta:"textScore" } } ).toArray(function (err, docs) { + if (err) callback(false, "Error: some error while searching"); + else { + callback(true, docs); + } + }); + + + + }).catch(function (err) { + console.error(err); + }); +}; + + +/** + * This function will return a list of followers of user i.e. a list of + * exam_ids that the user has chosen to follow + * + * @param {string} user_name: the unique user name for the user + * @param {function} callback: with 2 args: (boolean, <string>), + * where boolean : err ? false : true + * where <string> can be error message + * OR on success <[<strings>]> RESULT + **/ +exports.retrieveFollows = function (user_name, callback) { + + mongoFactory.getConnection(uri).then(function (db) { + + // find the solutions table + var users = db.collection('users'); + // insert data into table + users.find( {user_name: user_name} ).toArray(function (err, docs) { + // if (err) throw err; + if (err) callback(false, "Error: followers could not be retrieved for some reason"); + else { + callback(true, docs[0].followers); + } + }); + + }).catch(function (err) { + console.error(err); + }); +}; + +/** + * This function will retrieve ALL the comments a user has ever made. + * It returns an array containing objects of the form: {exam_id, comment, date, ... + * course_code, year, term}. + * Note: a comment should only exist IF a solution exists. + * + * @param {string} username: the unique user name for the user + * @param {function} callback: with 2 args: (boolean, <string>), + * where boolean : err ? false : true + * where <string> can be error message + * OR on success <[Objs]> RESULT + **/ +exports.retrieve_userComments_history = function (username, callback) { + + // get a connection + mongoFactory.getConnection(uri).then(function (db) { + var solutions = db.collection('solutions'); + var exams = db.collection('exams'); + var mylist = []; + solutions.aggregate([ + + { $match : { + "comments.by": username + }}, + { $unwind : "$comments" }, + { $match : { + "comments.by": username + }}, + {$project: { + comment: "$comments.text", + date: "$comments.date", + exam_id: "$exam_id", + _id: 0 + }} + ]).toArray(function (err, res) { + if(!res.length){ // Ensure a callback is executed if res is empty + callback(true, res); + }else{ + var finised = _.after(res.length, doCall); // execute "doCall" only after res.length # of attempts + res.forEach(function (comment) { + exams.find( { _id: ObjectId(comment.exam_id) } ).toArray(function (err, docs) {// get the exam info + comment.course_code = docs[0].course_code; + comment.year = docs[0].year; + comment.term = docs[0].term; + mylist.push(comment); // save it to array + finised(); + }); + }); + } + }); + + function doCall() { + callback(true, mylist); + } + + + }).catch(function (err) { + callback(false, "Error: failed to connect to db"); + }) +}; + +/** We CAN use this. IF we do, we should remove the comments_count field from a user + * IF we dont wanna go that route, need to update these fields whenever they are altered + * by the user manually. + * + * @param {string} username: the unique user name for the user + * @param {function} callback: with 2 args: (boolean, <string>), + * where boolean : err ? false : true + * where <string> can be error message + * OR on success <int> RESULT + **/ +exports.retrieve_userComments_count = function (username, callback) { + + exports.retrieve_userComments_history(username, function (bool, results) { + if (!bool) callback(false, "Error: error occurred"); + else { + var length = results.length; + callback(true, length); + } + }); + +}; + +/** + * This function will retrieve ALL the solutions a user has ever provided. + * It returns an array containing objects of the solution form. + * + * @param {string} username: the unique user name for the user + * @param {function} callback: with 2 args: (boolean, <string>), + * where boolean : err ? false : true + * where <string> can be error message + * OR on success <[Objs]> RESULT + **/ +exports.retrieve_userSolutions_history = function (username, callback) { + + // get a connection + mongoFactory.getConnection(uri).then(function (db) { + + var solutions = db.collection('solutions'); + solutions.find( { author: username } ).toArray(function (err, result) { + if (err) callback(false, "Error: problem while looking for stuff"); + else { + callback(true, result); + } + + }); + + }).catch(function (err) { + // console.err(err); + callback(false, "Error: failed to connect to db"); + }) +}; + +/** We CAN use this. IF we do, we should remove the solutions_count field from a user + * IF we dont wanna go that route, need to update these fields whenever they are altered + * by the user manually. + * + * @param {string} username: the unique user name for the user + * @param {function} callback: with 2 args: (boolean, <string>), + * where boolean is false if err OR true if no error + * where <string> can be error message + * OR on success <int> RESULT + **/ +exports.retrieve_userSolutions_count = function (username, callback) { + + exports.retrieve_userSolutions_history(username, function (bool, results) { + if (!bool) callback(false, "Error: error occured"); + else { + var length = results.length; + callback(true, length); + } + }); + +}; + +/** + * This function creates and adds a user to users table. + * IFF both the email and the user_name are not in the database already. + * If either of them exist, the user is NOT added. + * + * @param {string[]} fields: [email, user_name, f_name, l_name, uni, department, password, phone_num] + * @param {function} callbackUser: of the form (<boolean1>, <boolean2>, <string>) + * where, <boolean1> - + * <boolean2> - + * <string> - error ? error_mssg : success_mssg + **/ +exports.add_user = function (fields, callbackUser) { + // create a user object + var user_data = { + email: fields[0], + user_name: fields[1], + f_name: fields[2], + l_name: fields[3], + university: fields[4], + department: fields[5], + answered: 0, + messages: 0, + comments: 0, + phone_num: fields[7], + followers: [] + }; + + var login_data = { + email: fields[0], + user_name: fields[1], + password: fields[6] + }; + + // find out if this user already exists by checking their email + exports.find_user( fields[0], function (result) { + if (result == false) { + + // find out if the user_name is taken + exports.find_user_name( fields[1], function (docs) { + if (docs == false) { // if not ... + // continue + + // when both are valid add the user to the users and logins table + mongoFactory.getConnection(uri) + .then(function (db) { + + var users = db.collection('users'); + var logins = db.collection('logins'); + + // Add users, and login through callbacks + users.insertOne( user_data, function (err) { + if (err) { + callbackUser(false, true, "Error : User has not been added."); + + } + + else {// user insert successfull + logins.insertOne(login_data, function (err) { + if (err) { + callbackUser(false, true, "Error : User has not been added."); + + } + + else {// login insert successfull + callbackUser(true, false, "User has been added."); + + } + }); + } + }); + + }) + .catch(function (err) { + callbackUser(false, true, "Unable to connect."); + }) + } + else { + callbackUser(false, false, "Username is taken."); + } + }); + } + else { + callbackUser(false, false, "User with this email already exists."); + } + }); +}; + + + + +/** + * This function returns whether the user with the given username has already been signed in before. + * This is important because we need to link a unique facebook account with a username. If the user has signed in + * before, return the verification object, consisting of facebook profile id. + * + * @param {string} username + * @param {function} callbackUser: of the form (<boolean>, verifications object (See COLLECTION)) - + * callbackUser(error, object) + * + **/ + +exports.userVerifiedBefore = function(username, callback) { + mongoFactory.getConnection(uri) + .then(function (db) { + var verif = db.collection('verifications'); + + verif.find( { username : username } ).toArray(function(err, result) { + if (err) { + callback(true, null); + } else { + callback(false, result); + } + + }); + }); +} + + +/** + * THis function adds the user's facebook account verification to the database and links it to the user's local in site + * account. + * + * @param {object} - verifications object + * @param {function} callbackUser: of the form (<boolean>) - callback(error) + * + **/ +exports.addVerification = function(verification, callBack) { + mongoFactory.getConnection(uri) + .then(function (db) { + var verif = db.collection('verifications'); + + verif.insertOne(verification, function (err) { + if (err) { + callBack(true); + } else { + callBack(false); + } + }) + }); +} + +/** + * This (helper) function returns true IFF user_name already exists in the database + * + * @param {string} user_name: the user name + * @param {function} callback: of the arg (bool) + * where <bool> : found ? true : false + * */ +exports.find_user_name = function (user_name, callback) { + // make a connection + mongoFactory.getConnection(uri) + .then(function (db) { + + var logins = db.collection('logins'); + var admins = db.collection('admins'); + logins.find( { user_name: user_name } ).toArray(function (err, result) { + if (err) throw err; + else if (result.length == 0) { // nothing was found in users + // check if user_name is taken by admin + admins.find({username : user_name}).toArray(function(err, data) { + if (err) throw err; + else if (data.length == 0) { + callback(false); + } + else { + callback(true); + } + }); + } + else { + callback(true); + } + }); + }) + .catch(function (err) { + console.err(err); + }) +}; + +/** + * This function retrieves the user object given their user_name + * + * @param {string} username: the user name + * @param {function} callback: with args (<bool1>,<bool2>,<string1>,<string2>) + * where, <bool1> : success ? true : false + * where, <bool2> : error ? true : false + * where, <string1> : success ? {Obj} : null + * where, <string2> : success ? success_mssg : err_mssg + * */ +exports.retrieveUser = function (username, callback) { + + mongoFactory.getConnection(uri).then(function (db) { + var users = db.collection('users'); + + users.find({user_name: username}).toArray(function (err, result) { + if (err) { + // callback(success, error, user, message) + callback(false, true, null, "Error : Could not retrieve user."); + } + + else if (result.length) { + callback(true, false, result[0], "User retrieved"); + } + + else { + callback(false, false, null, "Username is undefined."); + } + }); + }); +} + +/** + * Returns the hashed password given the username. Assume username exists. + * Used for both admins and users. + * + * @param {string} username: the user name + * @param {function} callback: with args (<bool>,<string>,<string>) + * where, <bool> : success ? true : false + * where, <string> : success ? "pwd" : null + * where, <string> : success ? success_mssg : err_mssg + * */ +exports.retrievePassword = function (username, callback) { + mongoFactory.getConnection(uri).then(function (db) { + + var collection = db.collection('logins'); + + collection.find({user_name: username}).toArray(function(err, result) { + if (err) { + // callback(success, password, message) + callback(false, null, "Error : Could not retrieve password."); + } + + else { + var pwd = result[0].password; //result is an array + callback(true, pwd, "Password retrieved"); + } + + }); + }); +} + +/** + * This (helper) function returns true IFF email already exists in the database + * + * @param {string} email: unique email of the user + * @param {function} callback: <bool> : found ? true : false + * */ +exports.find_user = function (email, callback) { + // make a connection + mongoFactory.getConnection(uri) + .then(function (db) { + + var logins = db.collection('logins'); + logins.find( { email: email } ).toArray(function (err, result) { + if (err) throw err; + else if (result.length == 0) { // nothing was found so this user is new + callback(false); + } + else { + callback(true); + } + }); + }) + .catch(function (err) { + console.err(err); + }) +}; + + +/** + * This function retrieves the user object from the users collection given the object id. + * + * @param {string} id + * @param {function} callbackUser: of the form (<boolean>, user object (See COLLECTION)) - + * callbackUser(error, object) + * + **/ +exports.findUserByID = function (id, callback) { + // make a connection + mongoFactory.getConnection(uri) + .then(function (db) { + var logins = db.collection('logins'); + logins.find( { _id : id }, function (err, result) { + callback(err, result); + + }); + }) + .catch(function (err) { + console.err(err); + }) +}; + +/************************* COURSES / EXAMS **********************************/ + + +/** + * Remvove a course from ONLY the courses table IN CASE of accidental + * addition. + * + * @param {string} course_code: the course code + * @param {function} callback: 2 args: (boolean, <string>), + * where <boolean> : err ? false : true + * where <string> : error ? error_mssg : success_mssg + */ +exports.remove_course = function (course_code, callback) { + + mongoFactory.getConnection(uri).then(function(db) { + + // fetch the exams table + var courses = db.collection('courses'); + + courses.createIndex( // make the following fields searchable + { + "course_code":"text" + }); + // look for the specific course + courses.removeOne( { $text: { $search: course_code } }, function (err, docs) { + // if (err) throw err; + if (err) callback(false, "Error: Failed to remove the course."); + + else if (docs.deletedCount == 1) { + callback(true, "Course was removed successfully from JUST courses"); + + } + else if (docs.deletedCount == 0) { + callback(false, "No such user was found"); + + } + }); + }).catch(function(err) { + console.error(err); + }); +}; + + +/** + * This function will add the given exam_id to the given user's followers list. + * It simply appends the exam_id to the list and nothing else. + * If the exam_id already exists in the user's followers list, + * false will be returned, andnothing will be added. + * + * Ideally the user shouldnt even be able to attempt to follow an exam twice. + * + * @param {string} user_name: the unique user name for the user + * @param {string} exam_id: the _id of the exam TO follow + * @param {function} callback: with 2 args: (boolean, <string>), + * where <boolean> : err ? false : true + * where <string> : error ? err_messg : success_messg + **/ +exports.followExam = function (user_name, exam_id, callback) { + + exports.retrieveFollows(user_name, function (bool, result) { + if (!bool) console.log(result); + else { // no err occured so far... + + var found = false; + for (var i = 0; i < result.length; i++) { // search through the list of exams followed + if (result[i] == exam_id) { + found = true; + } + } + + if (found) { // means exam is already followed by user + callback(false, "user is already following this exam"); + } + + else { // add it to the user follower list + mongoFactory.getConnection(uri).then(function (db) { + + // find the user table + var users = db.collection('users'); + // insert data into table + users.updateOne( {user_name: user_name}, {$push: {followers: exam_id}} , function (err) { + // if (err) throw err; + if (err) callback(false, "Error: some error occurred while following the exam"); + else { + callback(true, "Success: user is following this exam"); + } + }); + + + }).catch(function (err) { + console.error(err); + }); + } + } + }); +}; + + + + + +/** + * This function returns an array where each element contains info for a particular question + * such as the question number (_id), number of solutions (count), and number of comments + * (comments). [ {_id,count,comments}, {} , ...] + * + * @param {string} exam_id: the exam_id of which the info is required + * @param {function} callback: with arg (<[Objs]>) - RESULT + * */ +exports.get_exam_info_by_ID = function (exam_id, callback) { + + mongoFactory.getConnection(uri) + .then(function (db) { + + var solutions = db.collection('solutions'); + + solutions.aggregate( + [ + + // {$unwind: "$comments"}, + { $match: { exam_id: exam_id }}, + { + $project: + { + num_comments: { $size: "$comments" }, + _id: "$exam_id", + q_id: "$q_id" + } + }, + { + $group : { + _id : "$q_id", + count: { $sum: 1 }, + comments: {$sum: "$num_comments"} + // num_comments: { $size: "$comments" } + + } + } + + + ]).toArray(function (err, result) { + callback(result); + + }); + }) + .catch(function (err) { + console.err(err); + }) + +}; + +/** + * CALLBACK ADDED RECENTLY, BEWARE WHEN CALLING IT + * This function will add a comment to the solutions table + * + * @param {string} sol_id: id of the solution to which to add the comment + * @param {string[]} fields: <[text, by_username]> + * @param {function} serverCallback: with args (<bool>,<string>) + * where <bool> : err ? false : true + * where <string> : err ? err_mssg : success_mssg + * */ +exports.add_comment = function (sol_id, fields, serverCallback) { + var date = new Date(); + var Data = { + text: fields[0], + date: date.toString().slice(0, 24), + by: fields[1] + }; + + mongoFactory.getConnection(uri) + .then(function (db) { + + // find the solutions table + var solutions = db.collection('solutions'); + var users = db.collection('users'); + // insert data into table + solutions.updateOne( {_id: ObjectId(sol_id)}, {$push: {comments: Data}} , function (err, result) { + if (err) { + serverCallback(false, "Error: Solution found, but could not update comments."); + throw err; + } + else { + users.updateOne( { user_name: fields[1] }, { $inc: { comments: 1} }, function (err) { + if (err) serverCallback(false, "Error: Some error occured while updating user info"); + else { + serverCallback(true, "Success: comment added successfully"); + } + + }); + } + + }); + + }) + .catch(function (err) { + serverCallback(false, "Error: Could not establish connection with database."); + console.error(err); + }) +}; + +/** + * This function will get all the solution for a given exam_id and q_num + * sorted by highest to lowest votes. + * + * @param {string} exam_id: exam_id for which the info is required. + * @param {int} q_num: the question number for which solutions are required. + * @param {function} callback: <[Objs]> - RESULT + * */ +exports.get_all_solutions = function (exam_id, q_num, callback) { + + // check if the exam id already exists... + exports.get_exam_byID(exam_id, function (success, failure, exam) { + if (!success && failure) { // some error occurred while searching + callback(false, true, "Error: Some error occurred while searching for exam", null); + } else if (!success && !failure) { + callback(false, true, "Error: this exam does not exist", null); + } else if (success && !failure) { // this exam exists proceed with task + mongoFactory.getConnection(uri).then(function (db) { + + var solutions = db.collection('solutions'); + + solutions.find( + { + exam_id: exam_id, + q_id: q_num + } + ).sort({ votes: -1}).toArray( function (err, docs) { + if (err) callback(false, true, "Error: Some error occurred while looking for solutions"); + else { // either nothing was found or something was found + callback(true, false, "Solutions", docs); + } + + }); + }).catch(function () { + callback(false, true, "Error: Some error occurred with the db connection", null); + }) + } + }); + +}; + +/** + * CALLBACK ADDED RECENTLY, BEWARE WHEN CALLING IT + * This function will add a solution to the solutions table in the database. + * + * @param {string[]} fields: [exam_id , question_id, solution text, user_name] + * @param {function} callback: with args (bool, string) + * where, <bool>: err ? false : true + * where, <string>: err ? err_mssg : success_mssg + * */ +exports.add_solution = function (fields, callback) { + var Data = { + exam_id: fields[0], + q_id: fields[1], + text: fields[2], + votes: 0, + comments: [], + author: fields[3] + }; + + // establish a connection + mongoFactory.getConnection(uri).then(function(db) { + + // find the solutions table + var solutions = db.collection('solutions'); + var users = db.collection('users'); + // insert data into table + solutions.insert(Data, function(err) { + if (err) callback(false , "Error: Failed to add the solution"); + else { + users.updateOne( { user_name: fields[3] }, { $inc: { answered: 1} }, function (err) { + if (err) callback(false, "Error: Failed to update the user solution count"); + else { + callback(true, "Success: added solution successfully!"); + } + }); + } + }); + + + }).catch(function(err) { + console.error(err); + }); + +}; + +/** + * This function will update the vote count of a solution. + * + * @param {string} sol_id: the sol_id of the solution to vote + * @param {string} upORdown: <string> : up_vote ? "up" : "down" + * @param {function} callback: with args (bool, string) + * where, <bool>: err ? false : true + * where, <string>: err ? err_mssg : success_mssg + * */ +exports.vote_solution = function (sol_id, upORdown , callback) { + var vote = (upORdown == "up") ? 1 : -1; + + mongoFactory.getConnection(uri).then(function (db) { + var solutions = db.collection('solutions'); + solutions.updateOne( + {_id: ObjectId(sol_id) }, + { $inc: { votes: vote} }, function (err) { + // if (err) throw err; + if (err) callback(false, "Error: couldnt update the vote count"); + else { + callback(true, "Success: updated vote count"); + } + + }); + }).catch(function (err) { + console.log(err); + }); +}; + +/** + * This function will retrieve all exams in the database given the course code ... + * ... ordered by the year of the exam. + * + * @param {string} course_code: the course code to get all the exams for + * @param {function} callback: with args (<string>) + * where on success is <[Objs]> + * */ +exports.get_all_exams = function (course_code, callback) { + + // get a connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // get the exams table + var exam_collection = db.collection('exams'); + + exam_collection.createIndex( // make the following fields searchable + { + "course_code":"text" + }); + // search exams table with given course code + exam_collection.find( + { $text: { $search: course_code } } + ).sort({ year: -1}).toArray( function (err, docs) { // order by year + if (err) throw err; + + else { // get the title + exports.find_course(course_code, function (result, data) { + + if (result == true) { + // append the title from data to each exam object from docs + docs.forEach(function (doc) { + doc.title = data[0].title; + }); + + if (debug_mode == true){ + console.log(docs); + console.log(data); + } + /*callback(docs); // send back the data*/ + } + else if (result == false) { // no such course was found + console.log("This course has not been added to the database."); + } + callback(docs); // send back the data + + }); + } + }); + }) + .catch(function(err) { + console.error(err); + }); + +}; + +/** + * This function will add an exam to the database UNLESS the exams already exists. + * If the exams table is empty, this will create one and then add the data. + * Note: this assumes that (course_code + year + term + type) together form a unique exam. + * i.e there can't be two exams occurring for the same course in the same year in the same term with the same type. + * + * @param {string[]} fields: an array of format ["course_code", year, "term", + * ["instructor1",...,"instructor n"], page_count, question_count + * "upload_date", "user_name"] + * @param {string[]} questions_array: a array by format ["q_1", "q_2", ... , "q_question_count"] + * @param {function} serverCallback: with args (<bool>, <string>) + * where <bool> : err ? false : true + * where <string> : err ? err_mssg : success_mssg + * + * */ +exports.add_exam = function (fields, questions_array, serverCallback) { + + // construct an exam object + var Data = + { + course_code: fields[0], + year: fields[1], + term: fields[2], + type: fields[3], + instructors: fields[4], + page_count: fields[5], + questions_count: fields[6], + questions_list: [], + upload_date: fields[7], + uploaded_by: fields[8] + }; + + // create the questions objects + for (var i = 1; i <= Data.questions_count; i++) { + Data.questions_list.push( + { + q_id: i, + question: questions_array[i - 1] + } + ); + } + + // first see if the exam already exists + // pass in course_code, year, term and type... + exports.find_exam([fields[0], fields[1], fields[2], fields[3]], serverCallback, function(result, serverCallback) { + + if (result == true) { // meaning that the exam was found + serverCallback(false, "This exam already exists in the database."); + } + + else { // add Data to the database + // make a connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // find the exams table + var exam_collection = db.collection('exams'); + // insert data into table + exam_collection.insert(Data, function(err) { + if (err) { + serverCallback(false, "Error: Could not add exam into database."); + throw err; + } + else { + serverCallback(true, "Exam Successfully added."); + } + }); + }) + .catch(function(err) { + serverCallback(false, "Error: Could not establish connection with database."); + console.error(err); + }); + } + }); +}; + +/** + * This function will return TRUE if the provided exam info already exists in the database + * OR FALSE if it does not exist in the database. + * + * @param {string[]} fields: an array of format ["course_code", year, "term", "type"] + * @param {function} serverCallback: ... + * @param {function} callback: with args (<bool>, ...) + * where <bool> : found ? true : false + * */ +exports.find_exam = function (fields, serverCallback, callback) { + + var course_code = fields[0]; + var year = fields[1]; + var term = fields[2]; + var type = fields[3]; + + // check the data to see if this exam exists... + + // first make a connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // fetch the exams table + var exams = db.collection('exams'); + + // look for the exam + exams.find( + { + course_code: course_code, + year: year, + term: term, + type: type + } + ).toArray(function (err, docs) { + if (err) throw err; + + if (docs.length == 0) { // if this exam doesnt exist.... add it + callback(false, serverCallback); + } + else { // exam was found + callback(true, serverCallback); + } + }); + }) + .catch(function(err) { + console.error(err); + }); +}; + +/** + * This function will add a course to the database UNLESS the course already exists. + * If the course table is empty, this will create one and then add the data. + * Note: this assumes that (course_codes) are unique. + * + * @param {string} course_code: the course code + * @param {string} title: the course description + * @param {function} serverCallback: with args (<bool>, <string>) + * where <bool> : err ? false : true + * where <string> : err ? err_mssg : success_mssg + * */ +exports.add_course = function (course_code, title, serverCallback) { + + var courseData = { + course_code: course_code, + title: title + }; + + exports.find_course(course_code, function (result) { + + if (result == true){ + serverCallback(false, "Course already exists"); + } + else if (result == false) { // add it + mongoFactory.getConnection(uri) + .then(function(db) { + + // find the exams table + var courses = db.collection('courses'); + // insert data into table + courses.insert(courseData, function(err) { + if (err) throw err; + else { + serverCallback(true, "Course added successfully."); + } + }); + }) + .catch(function(err) { + console.error(err); + }); + } + }); +}; + +/** + * This function will return TRUE if the provided course info already exists in the database + * OR FALSE if it does not exist in the database. + * + * @param {string} course_code: the course code + * @param {function} callback: with args (<bool>, <string>) + * where <bool> : found ? true : false + * where <string> : found ? null : [{Obj}] + * */ +exports.find_course = function (course_code, callback) { + // check the data to see if this exam exists... + + // first make a connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // fetch the courses table + var courses = db.collection('courses'); + courses.createIndex( // make the following fields searchable + { + "course_code":"text" + }); + // look for the courses + courses.find( + { $text: { $search: course_code } } + ).toArray(function (err, docs) { + if (err) throw err; + // if this course doesnt exist.... add it (via add_course call) + if (docs.length == 0) { + callback(false); + } + else { // course was found + callback(true, docs); + } + }); + }) + .catch(function(err) { + console.error(err); + }); +}; + +/** + * This function will remove the exam from the database given the combination + * of (course_code+ year + term + type) + * + * @param {string[]} fields: an array of format ["course_code", year, "term", "type"] + * @param {function} serverCallback: with args (<bool>, <string>) + * where <bool> : success ? true : false + * where <string> : success ? success_mssg ? err_mssg + * + * */ +exports.remove_exam = function (fields, serverCallback) { + + var course_code = fields[0]; + var year = fields[1]; + var term = fields[2]; + var type = fields[3]; + + // establish connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // fetch the exams table + var exams = db.collection('exams'); + + // look for the specific exam + exams.removeOne( + { + course_code: course_code, + year: year, + term: term, + type: type + }, function (err, docs) { + if (err) throw err; + else { + if (docs.deletedCount == 1) { + serverCallback(true, "Exam was removed successfully"); + } + else if (docs.deletedCount == 0) { + serverCallback(false, "No such exam was found"); + } + } + } + ); + }) + .catch(function(err) { + console.error(err); + }); +}; + +/** + * This function will get the specific exam object given its ID. + * + * @param {string} id: the exma_id + * @param {function} callback: with args (<bool>,<bool>,<string>) + * where, <bool> : success ? true : false + * where, <bool> : error ? true : false + * where, <string> : success ? {Obj} + * */ +exports.get_exam_byID = function (id, callback) { + + // establish a connection + mongoFactory.getConnection(uri) + .then(function(db) { + + // find the solutions table + var exams = db.collection('exams'); + // query + exams.find( {_id: ObjectId(id)} ).toArray(function (err, docs) { + if (err) { + callback(false, true, null); + } else if (docs.length == 0) { + callback(false, false, null); + } + else { + callback(true, false, docs[0]); + } + }); + }) + .catch(function(err) { + callback(false, true, null); + }); +}; + +/****************************** ADMINS *********************************/ + +/** + * This function adds the admin given the admin data admin_data (see ADMINS in COLLECTIONS) into the admins collection. + * Does not add and returns a message if the username in admin_data already exists. + * + * @param {object} admin object (see ADMINS in COLLECTIONS) + * @param {function} callbackUser: of the form (<boolean1>, <boolean2>, <string>) - + * callback(error, success, message) + * + **/ + +exports.addAdmin = function (admin_data, callback) { + var logins = db.collection('logins'); + // Check if the admin username already exists. Also check for user username. If it does, then we don't add the + // admin_data and return a message. + exports.adminExists( admin_data.username , function (error, exists, data, message) { + if (!exists && !error) { + logins.find({username: username}).toArray(function (err, result) { + if (err){ + callback(true, false, "Error: could not retreive logins collection in addAdmin()."); + } else if (result.length) { + callback(false, false, 'User with given username already exists.'); + } else { + mongoFactory.getConnection(uri).then(function (db) { + + var admins = db.collection('admins'); + + admins.insertOne(admin_data, function (err) { + if (err) { + callback(false, true, message); + } + else { + callback(true, false, "Admin added."); + } + + }); + }); + } + }).catch(function (err) { + callbackUser(false, true, "Unable to connect."); + }) + } else { + callback(error, exists, message); + } + }); + +}; + +/** + * This function checks if the admin username already exists in the ADMINS collection. If it does, then callback + * returns success, and the admin object is passed through the callback. + * + * @param {string} username - admin username + * @param {function} callbackUser: of the form (<boolean1>, <boolean2>,<object>, <string>) - + * callback(error, success, object, message) + * + **/ +exports.adminExists = function (username, callback) { + // make a connection + mongoFactory.getConnection(uri).then(function (db) { + + var admins = db.collection('admins'); + admins.find( { username: username } ).toArray(function (err, result) { + if (err) { + callback(true, false, null, "Error: could not retrieve admin in adminExists()."); + } else if (result.length) { + callback(false, true, result[0], "Admin with given username exists"); + } else { + callback(false, false, null, "Admin with given username does not exist"); + } + }); + }) + .catch(function (err) { + callback(true, false, "Error: could not connect to the database."); + }) +}; + +/****************************** MAIL *********************************/ + +/** + * This function adds the message object (see MAIL in COLLECTIONS) to the MAIL collection. + * + * @param {object} mail object + * @param {function} callbackUser: of the form (<boolean1>, <boolean2>, <string>) - + * callback(error, success, message) + * + **/ +exports.sendMail = function (mail_data, callback) { + exports.find_user_name(mail_data.receiver, function (exist){ + if (exist) { + mongoFactory.getConnection(uri).then(function(db) { + var mail = db.collection('mail'); + mail.insertOne(mail_data, function(err) { + if (err) { + callback(false, true, 'Error: could not send message.'); + } + else { + callback(true, false, "Message sent."); + } + + }); + }); + } else { + callback(false, false, 'The receiver\'s username is undefined.'); + } + }); +} + +/** + * This function checks if the user with the given username has mail. If the user does, then sends a list of all + * mail through callback. + * + * @param {object} admin object (see ADMINS in COLLECTIONS) + * @param {function} callbackUser: of the form (<boolean1>, <boolean2>, <array of objects>, <string>) - + * callback(error, success, mail, message) + * + **/ +exports.checkMailbox = function (username, callback) { + + mongoFactory.getConnection(uri).then(function(db) { + + var mail = db.collection('mail'); + + mail.find({receiver: username}).toArray(function (err, data) { + if (err) { + callback(false, true, null, 'Error: could not retrieve inbox messages.'); + } else if (!data) { + callback(false, false, null, 'No inbox.'); + } else { + callback(true, false, data, 'Retrieved inbox'); + } + + }); + }); + +} |
