forked from lpender/meteor-accounts-patch-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaccounts-patch-ui.js
162 lines (148 loc) · 5.42 KB
/
accounts-patch-ui.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"use strict";
/* globals AccountsPatchUi: true, LoginState */
// Remember the official Meteor versions of the functions we will be
// monkey patching.
var meteorUserIdFunc = Meteor.userId;
var meteorUserFunc = Meteor.user;
var accountsCallLoginMethod = Accounts.callLoginMethod;
var addServicePkg = Package['brettle:accounts-add-service'];
var mergeUserErrorReason = addServicePkg && addServicePkg.AccountsAddService &&
addServicePkg.AccountsAddService._mergeUserErrorReason;
/** Returns a function that will execute `func` with
* `Meteor.userId` set to `userIdFunc` and `Meteor.user` set to `userFunc`.
* @param {Function} userIdFunc - the function to use for `Meteor.userId`.
* @param {Function} userFunc - the function to use for `Meteor.user`.
* @param {Function} func - the function to wrap.
* @returns {Function} - the wrapped function
*/
var wrapWithUserFuncs = function (userIdFunc, userFunc, func) {
return function ( /*arguments*/ ) {
var savedUserIdFunc = Meteor.userId;
var savedUserFunc = Meteor.user;
Meteor.userId = userIdFunc;
Meteor.user = userFunc;
try {
return func.apply(this, arguments);
} finally {
Meteor.userId = savedUserIdFunc;
Meteor.user = savedUserFunc;
}
};
};
// A version of Meteor.userId() that returns null for users who have not signed
// up. NOTE: We use the original Meteor.user and Meteor.userId while in this
// function to avoid infinite recursion.
var signedUpUserIdFunc = wrapWithUserFuncs(meteorUserIdFunc, meteorUserFunc,
function () {
var meteorUserId = Meteor.userId();
if (!meteorUserId) {
return null;
}
var user = Meteor.users.findOne(meteorUserId);
if (!user) {
// Meteor.userId() was not null, but the userId wasn't found locally. That
// only happens before startup has finished and the Meteor.users
// subscription is not yet ready. So, just act like regular
// Meteor.userId() in this case (i.e. assume the user is signed up).
return meteorUserId;
}
if (LoginState.signedUp()) {
return meteorUserId;
}
return null;
});
// A version of Meteor.user() that returns null for user who have not signed up.
// NOTE: We use the original Meteor.user and Meteor.userId while in this
// function to avoid infinite recursion.
var signedUpUserFunc = wrapWithUserFuncs(meteorUserIdFunc, meteorUserFunc,
function () {
if (LoginState.signedUp()) {
return meteorUserFunc.call(Meteor);
}
return null;
});
var callLoginMethod = function(options) {
var origCallback = options && options.userCallback;
if (! origCallback) {
return accountsCallLoginMethod.apply(this, arguments);
}
options = _.clone(options);
options.userCallback = function (error) {
if (error && error.error === Accounts.LoginCancelledError.numericError &&
error.reason === mergeUserErrorReason) {
return origCallback.call(this);
} else {
return origCallback.apply(this, arguments);
}
}
return accountsCallLoginMethod.call(this, options);
}
function AccountsPatchUiConstructor() {}
_.extend(AccountsPatchUiConstructor.prototype, {
/** Returns a function that will execute the passed function with a version
* `Meteor.userId()` and `Meteor.user()` that return null for users who have
* not signed up.
* @param {Function} func - the function to wrap.
* @returns {Function} - the wrapped function
*/
wrapWithSignedUp: function (func) {
return wrapWithUserFuncs(signedUpUserIdFunc, signedUpUserFunc, func);
},
/** Returns a function that will execute the passed function with a version
* `Accounts.callLoginMethod()` (which is used by `Meteor.loginWithPassword()`
* and `Meteor.createUser()`) that calls the user's callback with no arguments
* (indicating success) if the login method returns the error that
* `brettle:accounts-add-service` uses to indicate that the service was
* merged into the current user's account.
* @param {Function} func - the function to wrap.
* @returns {Function} - the wrapped function
*/
wrapWithMergedErrorSuppressed: function (func) {
return function ( /*arguments*/ ) {
var savedCallLoginMethod = Accounts.callLoginMethod;
Accounts.callLoginMethod = callLoginMethod;
try {
return func.apply(this, arguments);
} finally {
Accounts.callLoginMethod = savedCallLoginMethod;
}
};
},
/** Returns a function has been wrapped with both
* `wrapWithMergedErrorSuppressed()` and `wrapWithSignedUp()`.
* @param {Function} func - the function to wrap.
* @returns {Function} - the wrapped function
*/
wrap: function (func) {
return this.wrapWithMergedErrorSuppressed(
this.wrapWithSignedUp(func));
},
_signedUpUser: signedUpUserFunc,
_wrapTemplate: function (template) {
var self = this;
if (!template) {
return;
}
self._wrapMethods(template.__helpers);
if (!_.isArray(template.__eventMaps)) {
throw new TypeError('__eventMaps not an Array');
}
_.each(template.__eventMaps, function (value, index, eventMaps) {
self._wrapMethods(eventMaps[index]);
});
},
_wrapMethods: function (obj) {
if (obj === undefined) {
return;
}
if (!_.isObject(obj)) {
throw new TypeError('Not an object');
}
_.each(obj, function (value, key) {
if (_.isFunction(value)) {
obj[key] = AccountsPatchUi.wrap(value);
}
});
}
});
AccountsPatchUi = new AccountsPatchUiConstructor();