Source: account.js

'use strict';

var url = require('url'),
  request = require('request'),
  Firebase = require('firebase'),
  Q = require('q'),
  FirebaseInstance = require('./instance');


/**
 * Creates a new reference to a Firebase account.
 * @constructor
 * @param {String} adminToken The admin token for the account.
 */
function FirebaseAccount(adminToken) {

  var deferred = Q.defer();

  this._dbs = {};
  this.adminToken = adminToken;

}

FirebaseAccount.defaultAuthConfig = {
  domains: [
    'localhost',
    '127.0.0.1'
  ],
  sessionLengthSeconds: 86400,
  anonymous: {
    'enabled': false
  },
  facebook: {
    'enabled': false,
    'key': '',
    'secret': ''
  },
  github: {
    'enabled': false,
    'key': '',
    'secret': ''
  },
  google: {
    'enabled': false,
    'key': '',
    'secret': ''
  },
  password: {
    'enabled': false,
    'emails': {
      'password-reset': {
        'from': 'no-reply@example.com',
        'fromname': '',
        'replyto': '',
        'subject': '',
        'template': 'Hello!\n\n' +
          'It looks like you\'ve forgotten your password.\n\n' +
          'Use the following temporary password within the next 24 hours ' +
          'to log in and update your account: %TOKEN%\n\nThanks!\n'
      }
    }
  },
  twitter: {
    'enabled': false,
    'key': '',
    'secret': ''
  }
};

/**
 * Promises to create a new Firebase instance under the account.
 * @param {String} name The name of the new instance.
 * @returns {external:Promise} A promise that resolves with a
 * {@link FirebaseInstance} if successful and rejects with an Error if
 * there's an error.
 * @example
 * account.createDatabase('newfirebase')
 * .then(function(db) {
 *   // get a Firebase reference to the new instance
 *   var fb = new Firebase(db.toString());
 *   fb.child('spam/spam/spam/spam').set('wonderful');
 * })
 * .catch(function(err) {
 *   console.error('Error while creating new instance:', err);
 * });
 */
FirebaseAccount.prototype.createDatabase = function(name) {

  var deferred = Q.defer();

  request.post({
    url: 'https://admin.firebase.com/firebase/' + name,
    form: {
      token: this.adminToken,
      appName: name
    }
  }, function(err, response, body) {
    body = JSON.parse(body);
    if (err) {
      deferred.reject(err);
    } else if (response.statusCode !== 200) {
      deferred.reject(new Error(response.statusCode));
    } else if (body.error) {
      deferred.reject(new Error('Firebase error: ' + body.error));
    } else if (body.success === false) {
      deferred.reject(new Error('Bad credentials or server error.'));
    } else {
      this._dbs[name] = new FirebaseInstance(name, this.adminToken);
      deferred.resolve(this._dbs[name]);
    }
  }.bind(this));

  return deferred.promise;

};


/**
 * Promises to retrieve a new Firebase instance under the account.
 * @param {String} name The name of the instance.
 * @returns {external:Promise} A promise that resolves with a
 * {@link FirebaseInstance} if successful and rejects with an Error if
 * there's an error.
 * @example
 * account.getDatabase('existingfirebase')
 * .then(function(db) {
 *   // get a Firebase reference to the instance
 *   var fb = new Firebase(db.toString());
 *   fb.child('spam/spam/spam/spam').on('value', function(snap) {
 *     console.log(snap.val(), 'spam, lovely spam');
 *   });
 * })
 * .catch(function(err) {
 *   console.error('Error retrieving instance:', err);
 * });
 */
FirebaseAccount.prototype.getDatabase = function(name) {

  if (this._dbs[name]) {
    /* jshint newcap:false */
    return Q(this._dbs[name]);
  } else {
    var newDb = new FirebaseInstance(name, this.adminToken);

    return newDb.ready
    .then(function() {
      this._dbs[name] = newDb;
      return newDb;
    }.bind(this));
  }

};


/**
 * Promises to remove a Firebase instance from the account
 * @param {FirebaseInstance} db The instance to remove.
 * @returns {external:Promise} A promise that resolves if db is deleted
 * successfully and rejects with an Error if there's an error.
 */
FirebaseAccount.prototype.deleteDatabase = function(db) {

  if (db.deleted) {
    return Q.reject(
      new Error('Cannot delete already-deleted database ' + db.toString())
    );
  }

  var deferred = Q.defer();

  request.post({
    url: 'https://admin.firebase.com/firebase/' + db.name,
    form: {
      token: this.adminToken,
      namespace: db.name,
      _method: 'DELETE'
    }
  }, function(err, response, body) {
    body = JSON.parse(body);
    if (err) {
      deferred.reject(err);
    } else if (response.statusCode !== 200) {
      deferred.reject(new Error(response.statusCode));
    } else if (body.error) {
      deferred.reject(new Error('Firebase error: ' + body.error));
    } else if (body.success === false) {
      deferred.reject(new Error('Bad credentials or server error.'));
    } else {
      db.deleted = true;
      delete this._dbs[db.name];
      deferred.resolve();
    }

  }.bind(this));

  return deferred.promise;

};


/**
 * Promises to create a new Firebase instance under the account
 * with the specified username and password. A convenience method.
 * @param {String} email The email address associated with the account.
 * @param {String} password The password for the account.
 * @returns {external:Promise} A promise that resolves with a
 * {@link FirebaseInstance} if successful and rejects with an Error if
 * there's an error. This instance also has an extra method, tearDown, that
 * deletes the database.
 * @example
 * FirebaseAccount.bootstrapInstance('token')
 * .then(function(db) {
 *   // get a Firebase reference to the new instance
 *   var fb = new   Firebase(db.toString());
 *   fb.child('spam/spam/spam/spam').set('wonderful');
 * }, function(err) {
 *   console.error('Error while creating new instance:', err);
 * });
 */
FirebaseAccount.bootstrapInstance = function(token) {

  var account = new FirebaseAccount(token);

  return account.createDatabase(Math.random().toString(36).slice(2))
  .then(function(db) {

    db.tearDown = function() {
      return account.deleteDatabase(db);
    };
    return db;

  });

};


module.exports = FirebaseAccount;