Skip to content

Commit

Permalink
Clean up namespacing in accounts system too.
Browse files Browse the repository at this point in the history
  • Loading branch information
gschmidt authored and glasser committed Jul 26, 2013
1 parent 3d1c097 commit d2024cc
Show file tree
Hide file tree
Showing 68 changed files with 237 additions and 219 deletions.
23 changes: 14 additions & 9 deletions packages/accounts-base/accounts_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var loggingInDeps = new Deps.Dependency;
// This is mostly just called within this file, but Meteor.loginWithPassword
// also uses it to make loggingIn() be true during the beginPasswordExchange
// method call too.
// @export Accounts._setLoggingIn
Accounts._setLoggingIn = function (x) {
if (loggingIn !== x) {
loggingIn = x;
Expand Down Expand Up @@ -60,6 +61,8 @@ Meteor.user = function () {
// its error will be passed to the callback).
// - userCallback: Will be called with no arguments once the user is fully
// logged in, or with the error on error.
//
// @export Accounts.callLoginMethod
Accounts.callLoginMethod = function (options) {
options = _.extend({
methodName: 'login',
Expand All @@ -81,11 +84,11 @@ Accounts.callLoginMethod = function (options) {
// getting the results of subscription rerun, we WILL NOT re-send this
// method (because we never re-send methods whose results we've received)
// but we WILL call loggedInAndDataReadyCallback at "reconnect quiesce"
// time. This will lead to _makeClientLoggedIn(result.id) even though we
// time. This will lead to makeClientLoggedIn(result.id) even though we
// haven't actually sent a login method!
//
// But by making sure that we send this "resume" login in that case (and
// calling _makeClientLoggedOut if it fails), we'll end up with an accurate
// calling makeClientLoggedOut if it fails), we'll end up with an accurate
// client-side userId. (It's important that livedata_connection guarantees
// that the "reconnect quiesce"-time call to loggedInAndDataReadyCallback
// will occur before the callback from the resume login call.)
Expand All @@ -103,7 +106,7 @@ Accounts.callLoginMethod = function (options) {
_suppressLoggingIn: true,
userCallback: function (error) {
if (error) {
Accounts._makeClientLoggedOut();
makeClientLoggedOut();
}
options.userCallback(error);
}});
Expand Down Expand Up @@ -141,7 +144,7 @@ Accounts.callLoginMethod = function (options) {
}

// Make the client logged in. (The user data should already be loaded!)
Accounts._makeClientLoggedIn(result.id, result.token);
makeClientLoggedIn(result.id, result.token);
options.userCallback();
};

Expand All @@ -154,14 +157,14 @@ Accounts.callLoginMethod = function (options) {
loggedInAndDataReadyCallback);
};

Accounts._makeClientLoggedOut = function() {
Accounts._unstoreLoginToken();
makeClientLoggedOut = function() {
unstoreLoginToken();
Meteor.connection.setUserId(null);
Meteor.connection.onReconnect = null;
};

Accounts._makeClientLoggedIn = function(userId, token) {
Accounts._storeLoginToken(userId, token);
makeClientLoggedIn = function(userId, token) {
storeLoginToken(userId, token);
Meteor.connection.setUserId(userId);
};

Expand All @@ -171,7 +174,7 @@ Meteor.logout = function (callback) {
if (error) {
callback && callback(error);
} else {
Accounts._makeClientLoggedOut();
makeClientLoggedOut();
callback && callback();
}
});
Expand All @@ -186,6 +189,8 @@ var loginServicesHandle = Meteor.subscribe("meteor.loginServiceConfiguration");
// A reactive function returning whether the loginServiceConfiguration
// subscription is ready. Used by accounts-ui to hide the login button
// until we have all the configuration loaded
//
// @export Accounts.loginServicesConfigured
Accounts.loginServicesConfigured = function () {
return loginServicesHandle.ready();
};
Expand Down
16 changes: 9 additions & 7 deletions packages/accounts-base/accounts_common.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
// @export Accounts
if (typeof Accounts === 'undefined')
Accounts = {};

if (!Accounts._options) {
Accounts._options = {};
}
// Currently this is read directly by packages like accounts-password
// and accounts-ui-unstyled.
// @export Accounts._options
Accounts._options = {};

// Set up config for the accounts system. Call this on both the client
// and the server.
Expand All @@ -21,6 +18,8 @@ if (!Accounts._options) {
// client signups.
// - forbidClientAccountCreation {Boolean}
// Do not allow clients to create accounts directly.
//
// @export Accounts.config
Accounts.config = function(options) {
// validate option keys
var VALID_KEYS = ["sendVerificationEmail", "forbidClientAccountCreation"];
Expand Down Expand Up @@ -52,11 +51,14 @@ Meteor.users = new Meteor.Collection("users", {_preventAutopublish: true});
// collection.

// loginServiceConfiguration and ConfigError are maintained for backwards compatibility
// @export Accounts.loginServiceConfiguration
// @export Accounts.ConfigError
Accounts.loginServiceConfiguration = ServiceConfiguration.configurations;
Accounts.ConfigError = ServiceConfiguration.ConfigError;

// Thrown when the user cancels the login process (eg, closes an oauth
// popup, declines retina scan, etc)
// @export Accounts.LoginCancelledError
Accounts.LoginCancelledError = function(description) {
this.message = description;
};
Expand Down
38 changes: 25 additions & 13 deletions packages/accounts-base/accounts_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,22 @@ Meteor.user = function () {
// - `undefined`, meaning don't handle;
// - {id: userId, token: *}, if the user logged in successfully.
// - throw an error, if the user failed to log in.
//
// @export Accounts.registerLoginHandler
Accounts.registerLoginHandler = function(handler) {
Accounts._loginHandlers.push(handler);
loginHandlers.push(handler);
};

// list of all registered handlers.
Accounts._loginHandlers = [];
loginHandlers = [];


// Try all of the registered login handlers until one of them doesn'
// return `undefined`, meaning it handled this call to `login`. Return
// that return value, which ought to be a {id/token} pair.
var tryAllLoginHandlers = function (options) {
for (var i = 0; i < Accounts._loginHandlers.length; ++i) {
var handler = Accounts._loginHandlers[i];
for (var i = 0; i < loginHandlers.length; ++i) {
var handler = loginHandlers[i];
var result = handler(options);
if (result !== undefined)
return result;
Expand Down Expand Up @@ -82,7 +84,7 @@ Meteor.methods({

logout: function() {
if (this._sessionData.loginToken && this.userId)
Accounts._removeLoginToken(this.userId, this._sessionData.loginToken);
removeLoginToken(this.userId, this._sessionData.loginToken);
this.setUserId(null);
}
});
Expand Down Expand Up @@ -111,11 +113,13 @@ Accounts.registerLoginHandler(function(options) {
});

// Semi-public. Used by other login methods to generate tokens.
//
// @export Accounts._generateStampedLoginToken
Accounts._generateStampedLoginToken = function () {
return {token: Random.id(), when: +(new Date)};
};

Accounts._removeLoginToken = function (userId, loginToken) {
removeLoginToken = function (userId, loginToken) {
Meteor.users.update(userId, {
$pull: {
"services.resume.loginTokens": { "token": loginToken }
Expand All @@ -127,6 +131,8 @@ Accounts._removeLoginToken = function (userId, loginToken) {
///
/// CREATE USER HOOKS
///

// @export Accounts.onCreateUser
var onCreateUserHook = null;
Accounts.onCreateUser = function (func) {
if (onCreateUserHook)
Expand All @@ -142,6 +148,9 @@ var defaultCreateUserHook = function (options, user) {
user.profile = options.profile;
return user;
};

// Called by accounts-password
// @export Accounts.insertUserDoc
Accounts.insertUserDoc = function (options, user) {
// - clone user document, to protect from modification
// - add createdAt timestamp
Expand Down Expand Up @@ -205,6 +214,7 @@ Accounts.insertUserDoc = function (options, user) {
return result;
};

// @export Accounts.validateNewUser
var validateNewUserHooks = [];
Accounts.validateNewUser = function (func) {
validateNewUserHooks.push(func);
Expand All @@ -225,6 +235,8 @@ Accounts.validateNewUser = function (func) {
// (eg, profile)
// @returns {Object} Object with token and id keys, like the result
// of the "login" method.
//
// @export Accounts.updateOrCreateUserFromExternalService
Accounts.updateOrCreateUserFromExternalService = function(
serviceName, serviceData, options) {
options = _.clone(options || {});
Expand Down Expand Up @@ -308,7 +320,7 @@ Meteor.publish(null, function() {
// Accounts.addAutopublishFields Notably, this isn't implemented with
// multiple publishes since DDP only merges only across top-level
// fields, not subfields (such as 'services.facebook.accessToken')
Accounts._autopublishFields = {
autopublishFields = {
loggedInUser: ['profile', 'username', 'emails'],
otherUsers: ['profile', 'username']
};
Expand All @@ -320,10 +332,10 @@ Accounts._autopublishFields = {
// - forLoggedInUser {Array} Array of fields published to the logged-in user
// - forOtherUsers {Array} Array of fields published to users that aren't logged in
Accounts.addAutopublishFields = function(opts) {
Accounts._autopublishFields.loggedInUser.push.apply(
Accounts._autopublishFields.loggedInUser, opts.forLoggedInUser);
Accounts._autopublishFields.otherUsers.push.apply(
Accounts._autopublishFields.otherUsers, opts.forOtherUsers);
autopublishFields.loggedInUser.push.apply(
autopublishFields.loggedInUser, opts.forLoggedInUser);
autopublishFields.otherUsers.push.apply(
autopublishFields.otherUsers, opts.forOtherUsers);
};

Meteor.server.onAutopublish(function () {
Expand All @@ -338,7 +350,7 @@ Meteor.server.onAutopublish(function () {
if (this.userId) {
return Meteor.users.find(
{_id: this.userId},
{fields: toFieldSelector(Accounts._autopublishFields.loggedInUser)});
{fields: toFieldSelector(autopublishFields.loggedInUser)});
} else {
return null;
}
Expand All @@ -359,7 +371,7 @@ Meteor.server.onAutopublish(function () {

return Meteor.users.find(
selector,
{fields: toFieldSelector(Accounts._autopublishFields.otherUsers)});
{fields: toFieldSelector(autopublishFields.otherUsers)});
}, /*suppress autopublish warning*/{is_auto: true});
});

Expand Down
52 changes: 33 additions & 19 deletions packages/accounts-base/localstorage_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@ Meteor.loginWithToken = function (token, callback) {
userCallback: callback});
};

var autoLoginEnabled = true;

// Semi-internal API. Call at startup to prevent automatic login.
// @export Accounts._disableAutoLogin
Acocunts._disableAutoLogin = function () {
autoLoginEnabled = false;
};

// Semi-internal API. Call this function to re-enable auto login after
// if it was disabled at startup.
// @export Accounts._enableAutoLogin
Accounts._enableAutoLogin = function () {
Accounts._preventAutoLogin = false;
Accounts._pollStoredLoginToken();
autoLoginEnabled = true;
pollStoredLoginToken();
};


Expand All @@ -31,34 +40,39 @@ var userIdKey = "Meteor.userId";
// Call this from the top level of the test file for any test that does
// logging in and out, to protect multiple tabs running the same tests
// simultaneously from interfering with each others' localStorage.
// @export Accounts._isolateLoginTokenForTest
Accounts._isolateLoginTokenForTest = function () {
loginTokenKey = loginTokenKey + Random.id();
userIdKey = userIdKey + Random.id();
};

Accounts._storeLoginToken = function(userId, token) {
storeLoginToken = function(userId, token) {
Meteor._localStorage.setItem(userIdKey, userId);
Meteor._localStorage.setItem(loginTokenKey, token);

// to ensure that the localstorage poller doesn't end up trying to
// connect a second time
Accounts._lastLoginTokenWhenPolled = token;
lastLoginTokenWhenPolled = token;
};

Accounts._unstoreLoginToken = function() {
unstoreLoginToken = function() {
Meteor._localStorage.removeItem(userIdKey);
Meteor._localStorage.removeItem(loginTokenKey);

// to ensure that the localstorage poller doesn't end up trying to
// connect a second time
Accounts._lastLoginTokenWhenPolled = null;
lastLoginTokenWhenPolled = null;
};

Accounts._storedLoginToken = function() {
// This is private, but it is exported for now because it is used by a
// test in accounts-password.
//
// @export Accounts._storedLoginToken
storedLoginToken = Accounts._storedLoginToken = function() {
return Meteor._localStorage.getItem(loginTokenKey);
};

Accounts._storedUserId = function() {
storedUserId = function() {
return Meteor._localStorage.getItem(userIdKey);
};

Expand All @@ -67,41 +81,41 @@ Accounts._storedUserId = function() {
/// AUTO-LOGIN
///

if (!Accounts._preventAutoLogin) {
if (autoLoginEnabled) {
// Immediately try to log in via local storage, so that any DDP
// messages are sent after we have established our user account
var token = Accounts._storedLoginToken();
var token = storedLoginToken();
if (token) {
// On startup, optimistically present us as logged in while the
// request is in flight. This reduces page flicker on startup.
var userId = Accounts._storedUserId();
var userId = storedUserId();
userId && Meteor.connection.setUserId(userId);
Meteor.loginWithToken(token, function (err) {
if (err) {
Meteor._debug("Error logging in with token: " + err);
Accounts._makeClientLoggedOut();
makeClientLoggedOut();
}
});
}
}

// Poll local storage every 3 seconds to login if someone logged in in
// another tab
Accounts._lastLoginTokenWhenPolled = token;
Accounts._pollStoredLoginToken = function() {
if (Accounts._preventAutoLogin)
lastLoginTokenWhenPolled = token;
pollStoredLoginToken = function() {
if (! autoLoginEnabled)
return;

var currentLoginToken = Accounts._storedLoginToken();
var currentLoginToken = storedLoginToken();

// != instead of !== just to make sure undefined and null are treated the same
if (Accounts._lastLoginTokenWhenPolled != currentLoginToken) {
if (lastLoginTokenWhenPolled != currentLoginToken) {
if (currentLoginToken)
Meteor.loginWithToken(currentLoginToken); // XXX should we pass a callback here?
else
Meteor.logout();
}
Accounts._lastLoginTokenWhenPolled = currentLoginToken;
lastLoginTokenWhenPolled = currentLoginToken;
};

setInterval(Accounts._pollStoredLoginToken, 3000);
setInterval(pollStoredLoginToken, 3000);
3 changes: 0 additions & 3 deletions packages/accounts-facebook/facebook_common.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/accounts-facebook/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Package.on_use(function(api) {

api.add_files('facebook_login_button.css', 'client');

api.add_files('facebook_common.js', ['client', 'server']);
api.add_files('facebook_server.js', 'server');
api.add_files('facebook_client.js', 'client');
});
3 changes: 0 additions & 3 deletions packages/accounts-github/github_common.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/accounts-github/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Package.on_use(function(api) {

api.add_files('github_login_button.css', 'client');

api.add_files('github_common.js', ['client', 'server']);
api.add_files('github_server.js', 'server');
api.add_files('github_client.js', 'client');
});
Loading

0 comments on commit d2024cc

Please sign in to comment.