Source: routes/account.js

module.exports = Account

var debug = require('debug')('snapchat:account')
var Promise = require('bluebird')

var constants = require('../lib/constants')

var SKBlob = require('../models/blob')

/**
 * Snapchat wrapper for account-related API calls.
 *
 * @class
 * @param {Object} opts
 */
function Account (client, opts) {
  var self = this
  if (!(self instanceof Account)) return new Account(client, opts)
  if (!opts) opts = {}

  self.client = client
}

/**
 * Updates the number of best friends to display.
 *
 * @param {number} number A number from 3 to 7. Defaults to 3 and will max out at 7.
 * @param {function} cb
 */
Account.prototype.updateBestFriendsCount = function (number, cb) {
  var self = this

  return new Promise(function (resolve, reject) {
    debug('Account.updateBestFriendsCount (%d)', number)

    if (number < 3) number = 3
    if (number > 7) number = 7

    self.client.post(constants.endpoints.account.setBestsCount, {
      'num_best_friends': number | 0,
      'username': self.client.username
    }, function (err, result) {
      if (err) {
        return reject(err)
      } else if (result) {
        self.client.session.bestFriendUsernames = result['best_friends']
        return resolve()
      }

      return reject(new Error('Snapchat.Account.updateBestFriendsCount parse error'))
    })
  }).nodeify(cb)
}

/**
 * Updates who can send you snaps.
 *
 * @param privacy SnapPrivacy.Friends or SnapPrivacy.Everyone. Defaults to SnapPrivacy.Friends.
 * @param {function} cb
 */
Account.prototype.updateSnapPrivacy = function (privacy, cb) {
  var self = this
  debug('Account.updateSnapPrivacy (%d)', privacy)

  privacy = Math.min(privacy, 1) | 0

  return self.client.post(constants.endpoints.account.settings, {
    'action': 'updatePrivacy',
    'privacySetting': privacy,
    'username': self.client.username
  }, cb)
}

/**
 * Updates who can see your stories. \e friends is only necessary when using StoryPrivacy.Custom.
 *
 * @param {number} privacy StoryPrivacy.Everyone, StoryPrivacy.Friends, StoryPrivacy.Custom.
 * @param {Array<string>=} friends Optional list of strings of usernames to hide your stories from. Used only when privacy is StoryPrivacy.Custom.
 * @param {function} cb
 */
Account.prototype.updateStoryPrivacy = function (privacy, friends, cb) {
  var self = this
  debug('Account.updateStoryPrivacy (%d)', privacy)

  if (typeof friends === 'function') {
    cb = friends
    friends = null
  }

  var params = {
    'action': 'updateStoryPrivacy',
    'privacySetting': constants.stringFromStoryPrivacy(privacy | 0),
    'username': self.client.username
  }

  if (friends) {
    params.storyFriendsToBlock = friends
  }

  return self.client.post(constants.endpoints.account.settings, params, cb)
}

/**
 * Updates your account's email address.
 *
 * @param {string} address Your new email address.
 * @param {function} cb
 */
Account.prototype.updateEmail = function (address, cb) {
  var self = this
  debug('Account.updateEmail (%s)', address)

  return self.client.post(constants.endpoints.account.settings, {
    'action': 'updateEmail',
    'email': address,
    'username': self.client.username
  }, cb)
}

/**
 * Updates whether your account can be found with your phone number.
 *
 * @param {boolean} searchable The new value for this preference.
 * @param {function} cb
 */
Account.prototype.updateSearchableByNumber = function (searchable, cb) {
  var self = this
  debug('Account.updateSearchableByNumber (%d)', searchable)

  return self.client.post(constants.endpoints.account.settings, {
    'action': 'updateSearchableByPhoneNumber',
    'searchable': !!searchable,
    'username': self.client.username
  }, cb)
}

/**
 * Updates your 'notification sounds' preference.
 *
 * @param {boolean} enableSound The new value for this preference.
 * @param {function} cb
 */
Account.prototype.updateNotificationSoundSetting = function (enableSound, cb) {
  var self = this
  debug('Account.updateNotificationSoundSetting (%d)', enableSound)

  return self.client.post(constants.endpoints.account.settings, {
    'action': 'updateNotificationSoundSetting',
    'notificationSoundSetting': enableSound ? 'ON' : 'OFF',
    'username': self.client.username
  }, cb)
}

/**
 * Updates your display name.
 *
 * Your 'display name' is what your contact name defaults to when someone new adds you, not your username.
 * @param {string} displayName Your new display name.
 * @param {function} cb
 */
Account.prototype.updateDisplayName = function (displayName, cb) {
  var self = this
  debug('Account.updateDisplayName (%s)', displayName)

  return self.client.friends.updateDisplayNameForUser(self.client.username, displayName, cb)
}

/**
 * Updates your account's feature settings.
 *
 * See constants.Feature for valid keys. Invalid keys will be silently ignored.
 * @warning Raises an exception if \e settings contains more than 8 key-value pairs.
 *
 * @param Object settings A dictionary of string-boolean pairs. Missing keys-value pairs default to the current values. Behavior is undefined for values other than booleans.
 * @param {function} cb
 */
Account.prototype.updateFeatureSettings = function (settings, cb) {
  var self = this
  debug('Account.updateFeatureSettings')

  var features = { }
  features[constants.featureSettings.frontFacingFlash] = settings[constants.featureSettings.frontFacingFlash] || self.client.session.enableFrontFacingFlash
  features[constants.featureSettings.replaySnaps] = settings[constants.featureSettings.replaySnaps] || self.client.session.enableReplaySnaps
  features[constants.featureSettings.smartFilters] = settings[constants.featureSettings.smartFilters] || self.client.session.enableSmartFilters
  features[constants.featureSettings.visualFilters] = settings[constants.featureSettings.visualFilters] || self.client.session.enableVisualFilters
  features[constants.featureSettings.powerSaveMode] = settings[constants.featureSettings.powerSaveMode] || self.client.session.enablePowerSaveMode
  features[constants.featureSettings.specialText] = settings[constants.featureSettings.specialText] || self.client.session.enableSpecialText
  features[constants.featureSettings.swipeCashMode] = settings[constants.featureSettings.swipeCashMode] || self.client.session.enableSwipeCashMode
  features[constants.featureSettings.travelMode] = settings[constants.featureSettings.travelMode] || self.client.session.enableTravelMode

  return self.client.post(constants.endpoints.update.featureSettings, {
    'settings': JSON.stringify(features),
    'username': self.client.username
  }, cb)
}

/**
 * Downloads your account's snaptag, a personal Snapchat QR code.
 *
 * @param {function} cb
 */
Account.prototype.downloadSnaptag = function (cb) {
  var self = this

  return new Promise(function (resolve, reject) {
    debug('Account.downloadSnaptag')

    self.client.post(constants.endpoints.account.snaptag, {
      'image': self.client.session.QRPath,
      'type': 'SVG',
      'username': self.client.username
    }, function (err) {
      if (err) {
        return reject(err)
      }

      // TODO: this returns application/json but it's actually an XML doc:
      // '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<svg height="320" version="1.1" viewBox="0 0 320 320" width="320" xmlns="http://www.w3.org/2000/svg">\n  <path d="M162.31,52.4......74" fill="#FFFC00"/>\n</svg>\n'
      return reject(new Error('downloadSnaptag TODO'))
      // SKBlob.initWithData(body, cb)
    })
  }).nodeify(cb)
}

/**
 * Uploads a new animated avatar. Not working yet.
 *
 * @param {Array<Buffer>} images An array of 5 image Buffer objects.
 * @param {function} cb
 */
Account.prototype.uploadAvatar = function (images, cb) {
  return new Promise(function (resolve, reject) {
    debug('Account.uploadAvatar')

    // SKEPAccount.avatar.set
    // multipart/form-data; takes a single 'data' parameter in addition to the usual 'username' param
    return reject(new Error('Account.uploadAvatar TODO'))
  }).nodeify(cb)
}

/**
 * Downloads the animated avatar for user. Currently encrypted, or something.
 *
 * @param {string} username The username tied to the avatar to download.
 * @param {function} cb
 */
Account.prototype.downloadAvatar = function (username, cb) {
  var self = this
  return new Promise(function (resolve, reject) {

    debug('Account.downloadAvatar')

    self.client.post(constants.endpoints.account.avatar.get, {
      'username_image': username,
      'username': self.client.username,
      'size': 'MEDIUM'
    }, function (err, body) {
      if (err) {
        return reject(err)
      } else {
        SKBlob.initWithData(body, function (err, blob) {
          if (err) {
            return reject(err)
          }
          return resolve(blob)
        })
      }
    })

  }).nodeify(cb)
}

/**
 * Updates your TOS agreement status for each of the three Terms of Service.
 *
 * @param {boolean} snapcash
 * @param {boolean} snapcashV2
 * @param {boolean} square
 * @param {function} cb
 */
Account.prototype.updateTOSAgreementStatus = function (snapcash, snapcashV2, square, cb) {
  var self = this
  debug('Account.updateTOSAgreementStatus')

  var agreements = {
    'snapcash_new_tos_accepted': snapcash ? 'true' : 'false',
    'snapcash_tos_v2_accepted': snapcashV2 ? 'true' : 'false',
    'square_tos_accepted': square ? 'true' : 'false'
  }

  return self.client.post(constants.endpoints.update.user, {
    'username': self.client.username,
    'agreements': JSON.stringify(agreements)
  }, cb)
}