'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;