<commit_before>var db = require('../../config/neo4j').db;
var Q = require('q');
var Parse = require('../../config/parse.js');
var Facebook = require('../../config/api/facebook.js');
var request = require('request');
var Promise = require('bluebird');
var User = require('./User.model.js');
var _ = require('lodash');

Promise.promisifyAll(request);
Promise.promisifyAll(db);


var User = function() {
  this.query = db.cypherQuery;
};

User.prototype.all = function(callback) {
  var q = "MATCH (i:Menu) RETURN i";
  this.query(q, function(err, result) {
    callback(err, result.data);
  });
};

User.prototype.find = function(review_id, callback) {
  var params = {
    review_id: Number(review_id)
  };
  var q = "START review=node({review_id})" + "MATCH (body:Body)<-[:BODY]-(review)-[:PHOTO]->(photo:Photo)" + "RETURN review, photo, body";
  this.query(q, params, function(err, result) {
    callback(err, result.data);
  });
};

User.prototype.findByParseUsername = function(username, callback) {
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', username);
  return query.find()
    .then(function(user) {
      console.log(user)
      callback(null, user[0]);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

// Creates a new Parse user and new neo4j user.
User.prototype.create = function(userInfo, callback) {
  var newParseUserData = {
    username: userInfo.username,
    password: <PASSWORD>
  };

  return createParseUser(newParseUserData)
    .then(function(completeUser) {
      // Check for Facebook session ID and use for local storage token.
      if (completeUser.attributes.fbSessionId) {
        completeUser.attributes.token = completeUser.attributes.fbSessionId;
      }
      else {
        completeUser.attributes.token = completeUser._sessionToken;
      }
      callback(null, completeUser);
    }, function(error) {
      // Any errors upstream will be caught and handled here.
      error.error = true;
      callback(error, null);
    });
};

// Logs in a native user through Parse.
User.prototype.login = function (username, password, callback) {
  Parse.User.logIn(username, password)
    .then(function(data) {
      data.attributes.token = data._sessionToken;
      callback(null, data);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

// Retrieves a long term token for Facebook.
// Updates existing user info with new token or creates a new user from Facebook info.
User.prototype.fbLogin = function (fbData, callback) {
  var fbLongToken;
  request.getAsync(
    // Format request to Facebook API for long term token.
    'https://graph.facebook.com/oauth/access_token?' +
    'grant_type=fb_exchange_token&' +
    'client_id=' + Facebook.appId + '&' +
    'client_secret=' + Facebook.appSecret + '&' +
    'fb_exchange_token=' + fbData.token)
      .get(1)
      .then(function(body) {
        // Parse the long token returned from Facebook.
        fbLongToken = body.split('&')[0].split('=')[1];
        return findUserByFbId(fbData.fbId);
      })
      .then(function(foundFbUser) {
        // Update user info for an existing Facebook connected user.
        if (foundFbUser.length > 0) {
          return updateFbUser(
            foundFbUser[0].id,
            fbData.fbId,
            fbData.email,
            fbLongToken,
            fbData.photo
          );
        }
        // Else search for an existing native user.
        return findUserByNativeId(fbData.username)
          .then(function(foundNativeId) {
            // Update user info for an existing native user.
            if (foundNativeId.length > 0) {
              return updateFbUser(
                foundNativeId[0].id,
                fbData.fbId,
                fbData.email,
                fbLongToken,
                fbData.photo
              );
            }
            // Else create a new user from the Facebook data.
            return createFbUser(
              fbData.fbId,
              fbData.email,
              fbLongToken,
              fbData.photo
            );
          });
      })
      .then(function(fbUser) {
        fbUser.attributes.token = fbUser._sessionToken;
        callback(null, fbUser);
      })
      .catch(function(error) {
        console.log('fbLogin ERROR: ', error);
        callback(error, null);
      });
};

User.prototype.updateParseUser = function(username, updateData, callback) {
  Parse.Cloud.useMasterKey();
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', username);
  return query.find()
    .then(function(updateUser) {
      _.forOwn(updateData, function(value, key) {
        updateUser[0].set(key, value);
      });
      return updateUser[0].save();
    })
    .then(function(updatedUser) {
      callback(null, updatedUser);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

var collectQueries = {
  true:  ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_COLLECTIONS]->(c)",
          "MERGE (c)-[:COLLECTED]->(i)",
          "RETURN i"].join(""),

  false: ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_COLLECTIONS]->(c)-[r:COLLECTED]->(i)",
          "DELETE r",
          "RETURN i"].join(" ")
};

var bookmarkQueries = {
  true:  ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_BOOKMARKS]->(c)",
          "MERGE (c)-[:BOOKMARKED]->(i)",
          "RETURN i"].join(""),

  false: ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_BOOKMARKS]->(c)-[r:BOOKMARKED]->(i)",<commit_msg>Fix bookmark/collection selection bug<commit_after>var db = require('../../config/neo4j').db;
var Q = require('q');
var Parse = require('../../config/parse.js');
var Facebook = require('../../config/api/facebook.js');
var request = require('request');
var Promise = require('bluebird');
var User = require('./User.model.js');
var _ = require('lodash');

Promise.promisifyAll(request);
Promise.promisifyAll(db);


var User = function() {
  this.query = db.cypherQuery;
};

User.prototype.all = function(callback) {
  var q = "MATCH (i:Menu) RETURN i";
  this.query(q, function(err, result) {
    callback(err, result.data);
  });
};

User.prototype.find = function(review_id, callback) {
  var params = {
    review_id: Number(review_id)
  };
  var q = "START review=node({review_id})" + "MATCH (body:Body)<-[:BODY]-(review)-[:PHOTO]->(photo:Photo)" + "RETURN review, photo, body";
  this.query(q, params, function(err, result) {
    callback(err, result.data);
  });
};

User.prototype.findByParseUsername = function(username, callback) {
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', username);
  return query.find()
    .then(function(user) {
      console.log(user)
      callback(null, user[0]);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

// Creates a new Parse user and new neo4j user.
User.prototype.create = function(userInfo, callback) {
  var newParseUserData = {
    username: userInfo.username,
    password: <PASSWORD>
  };

  return createParseUser(newParseUserData)
    .then(function(completeUser) {
      // Check for Facebook session ID and use for local storage token.
      if (completeUser.attributes.fbSessionId) {
        completeUser.attributes.token = completeUser.attributes.fbSessionId;
      }
      else {
        completeUser.attributes.token = completeUser._sessionToken;
      }
      callback(null, completeUser);
    }, function(error) {
      // Any errors upstream will be caught and handled here.
      error.error = true;
      callback(error, null);
    });
};

// Logs in a native user through Parse.
User.prototype.login = function (username, password, callback) {
  Parse.User.logIn(username, password)
    .then(function(data) {
      data.attributes.token = data._sessionToken;
      callback(null, data);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

// Retrieves a long term token for Facebook.
// Updates existing user info with new token or creates a new user from Facebook info.
User.prototype.fbLogin = function (fbData, callback) {
  var fbLongToken;
  request.getAsync(
    // Format request to Facebook API for long term token.
    'https://graph.facebook.com/oauth/access_token?' +
    'grant_type=fb_exchange_token&' +
    'client_id=' + Facebook.appId + '&' +
    'client_secret=' + Facebook.appSecret + '&' +
    'fb_exchange_token=' + fbData.token)
      .get(1)
      .then(function(body) {
        // Parse the long token returned from Facebook.
        fbLongToken = body.split('&')[0].split('=')[1];
        return findUserByFbId(fbData.fbId);
      })
      .then(function(foundFbUser) {
        // Update user info for an existing Facebook connected user.
        if (foundFbUser.length > 0) {
          return updateFbUser(
            foundFbUser[0].id,
            fbData.fbId,
            fbData.email,
            fbLongToken,
            fbData.photo
          );
        }
        // Else search for an existing native user.
        return findUserByNativeId(fbData.username)
          .then(function(foundNativeId) {
            // Update user info for an existing native user.
            if (foundNativeId.length > 0) {
              return updateFbUser(
                foundNativeId[0].id,
                fbData.fbId,
                fbData.email,
                fbLongToken,
                fbData.photo
              );
            }
            // Else create a new user from the Facebook data.
            return createFbUser(
              fbData.fbId,
              fbData.email,
              fbLongToken,
              fbData.photo
            );
          });
      })
      .then(function(fbUser) {
        fbUser.attributes.token = fbUser._sessionToken;
        callback(null, fbUser);
      })
      .catch(function(error) {
        console.log('fbLogin ERROR: ', error);
        callback(error, null);
      });
};

User.prototype.updateParseUser = function(username, updateData, callback) {
  Parse.Cloud.useMasterKey();
  var query = new Parse.Query(Parse.User);
  query.equalTo('username', username);
  return query.find()
    .then(function(updateUser) {
      _.forOwn(updateData, function(value, key) {
        updateUser[0].set(key, value);
      });
      return updateUser[0].save();
    })
    .then(function(updatedUser) {
      callback(null, updatedUser);
    }, function(error) {
      error.error = true;
      callback(error, null);
    });
};

var collectQueries = {
  true:  ["START u=node({user_id}), i=node({item_id})",
          "MERGE u-[:HAS_COLLECTIONS]->(c)",
          "MERGE (c)-[:COLLECTED]->(i)",
          "RETURN i"].join(""),

  false: ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_COLLECTIONS]->(c)-[r:COLLECTED]->(i)",
          "DELETE r",
          "RETURN i"].join(" ")
};

var bookmarkQueries = {
  true:  ["START u=node({user_id}), i=node({item_id})",
          "MERGE u-[:HAS_BOOKMARKS]->(c)",
          "MERGE (c)-[:BOOKMARKED]->(i)",
          "RETURN i"].join(""),

  false: ["START u=node({user_id}), i=node({item_id})",
          "MATCH u-[:HAS_BOOKMARKS]->(c)-[r:BOOKMARKED]->(i)",
{'fraction_non_alphanumeric': 0.15085825517607504, 'fraction_numerical': 0.002123517961422757, 'mean_word_length': 2.5266770670826832, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 27, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5083257', 'n_tokens_mistral': 3565, 'n_tokens_neox': 3462, 'n_words': 736}