Skip to content

Commit 9bc1a35

Browse files
committed
Merge pull request #791 from ParsePlatform/nlutsenko.triggers.installationId
Propagate installationId to all Cloud Code triggers.
2 parents 1053adf + edc7720 commit 9bc1a35

File tree

6 files changed

+108
-35
lines changed

6 files changed

+108
-35
lines changed

spec/ParseAPI.spec.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,80 @@ describe('miscellaneous', function() {
749749
});
750750
});
751751

752+
it('test beforeSave/afterSave get installationId', function(done) {
753+
let triggerTime = 0;
754+
Parse.Cloud.beforeSave('GameScore', function(req, res) {
755+
triggerTime++;
756+
expect(triggerTime).toEqual(1);
757+
expect(req.installationId).toEqual('yolo');
758+
res.success();
759+
});
760+
Parse.Cloud.afterSave('GameScore', function(req) {
761+
triggerTime++;
762+
expect(triggerTime).toEqual(2);
763+
expect(req.installationId).toEqual('yolo');
764+
});
765+
766+
var headers = {
767+
'Content-Type': 'application/json',
768+
'X-Parse-Application-Id': 'test',
769+
'X-Parse-REST-API-Key': 'rest',
770+
'X-Parse-Installation-Id': 'yolo'
771+
};
772+
request.post({
773+
headers: headers,
774+
url: 'http://localhost:8378/1/classes/GameScore',
775+
body: JSON.stringify({ a: 'b' })
776+
}, (error, response, body) => {
777+
expect(error).toBe(null);
778+
expect(triggerTime).toEqual(2);
779+
780+
Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore");
781+
Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore");
782+
done();
783+
});
784+
});
785+
786+
it('test beforeDelete/afterDelete get installationId', function(done) {
787+
let triggerTime = 0;
788+
Parse.Cloud.beforeDelete('GameScore', function(req, res) {
789+
triggerTime++;
790+
expect(triggerTime).toEqual(1);
791+
expect(req.installationId).toEqual('yolo');
792+
res.success();
793+
});
794+
Parse.Cloud.afterDelete('GameScore', function(req) {
795+
triggerTime++;
796+
expect(triggerTime).toEqual(2);
797+
expect(req.installationId).toEqual('yolo');
798+
});
799+
800+
var headers = {
801+
'Content-Type': 'application/json',
802+
'X-Parse-Application-Id': 'test',
803+
'X-Parse-REST-API-Key': 'rest',
804+
'X-Parse-Installation-Id': 'yolo'
805+
};
806+
request.post({
807+
headers: headers,
808+
url: 'http://localhost:8378/1/classes/GameScore',
809+
body: JSON.stringify({ a: 'b' })
810+
}, (error, response, body) => {
811+
expect(error).toBe(null);
812+
request.del({
813+
headers: headers,
814+
url: 'http://localhost:8378/1/classes/GameScore/' + JSON.parse(body).objectId
815+
}, (error, response, body) => {
816+
expect(error).toBe(null);
817+
expect(triggerTime).toEqual(2);
818+
819+
Parse.Cloud._removeHook("Triggers", "beforeDelete", "GameScore");
820+
Parse.Cloud._removeHook("Triggers", "afterDelete", "GameScore");
821+
done();
822+
});
823+
});
824+
});
825+
752826
it('test cloud function query parameters', (done) => {
753827
Parse.Cloud.define('echoParams', (req, res) => {
754828
res.success(req.params);

spec/ParseRole.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('Parse Role testing', () => {
8686
return createRole(rolesNames[2], anotherRole, user);
8787
}).then( (lastRole) => {
8888
roleIds[lastRole.get("name")] = lastRole.id;
89-
var auth = new Auth(new Config("test") , true, user);
89+
var auth = new Auth({ config: new Config("test"), isMaster: true, user: user });
9090
return auth._loadRoles();
9191
})
9292
}).then( (roles) => {

src/Auth.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import cache from './cache';
77
// An Auth object tells you who is requesting something and whether
88
// the master key was used.
99
// userObject is a Parse.User and can be null if there's no user.
10-
function Auth(config, isMaster, userObject) {
10+
function Auth({ config, isMaster = false, user, installationId } = {}) {
1111
this.config = config;
12+
this.installationId = installationId;
1213
this.isMaster = isMaster;
13-
this.user = userObject;
14+
this.user = user;
1415

1516
// Assuming a users roles won't change during a single request, we'll
1617
// only load them once.
@@ -33,19 +34,19 @@ Auth.prototype.couldUpdateUserId = function(userId) {
3334

3435
// A helper to get a master-level Auth object
3536
function master(config) {
36-
return new Auth(config, true, null);
37+
return new Auth({ config, isMaster: true });
3738
}
3839

3940
// A helper to get a nobody-level Auth object
4041
function nobody(config) {
41-
return new Auth(config, false, null);
42+
return new Auth({ config, isMaster: false });
4243
}
4344

4445
// Returns a promise that resolves to an Auth object
45-
var getAuthForSessionToken = function(config, sessionToken) {
46+
var getAuthForSessionToken = function({ config, sessionToken, installationId } = {}) {
4647
var cachedUser = cache.users.get(sessionToken);
4748
if (cachedUser) {
48-
return Promise.resolve(new Auth(config, false, cachedUser));
49+
return Promise.resolve(new Auth({ config, isMaster: false, installationId, user: cachedUser }));
4950
}
5051
var restOptions = {
5152
limit: 1,
@@ -67,7 +68,7 @@ var getAuthForSessionToken = function(config, sessionToken) {
6768
obj['sessionToken'] = sessionToken;
6869
let userObject = Parse.Object.fromJSON(obj);
6970
cache.users.set(sessionToken, userObject);
70-
return new Auth(config, false, userObject);
71+
return new Auth({ config, isMaster: false, installationId, user: userObject });
7172
});
7273
};
7374

src/Controllers/UserController.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,22 @@ export class UserController extends AdaptableController {
2222
}
2323
super.validateAdapter(adapter);
2424
}
25-
25+
2626
expectedAdapterType() {
2727
return MailAdapter;
2828
}
29-
29+
3030
get shouldVerifyEmails() {
3131
return this.options.verifyUserEmails;
3232
}
33-
33+
3434
setEmailVerifyToken(user) {
3535
if (this.shouldVerifyEmails) {
3636
user._email_verify_token = randomString(25);
3737
user.emailVerified = false;
3838
}
3939
}
40-
41-
40+
4241
verifyEmail(username, token) {
4342
if (!this.shouldVerifyEmails) {
4443
// Trying to verify email when not enabled
@@ -62,7 +61,7 @@ export class UserController extends AdaptableController {
6261
return document;
6362
});
6463
}
65-
64+
6665
checkResetTokenValidity(username, token) {
6766
return this.config.database.adaptiveCollection('_User')
6867
.then(collection => {
@@ -78,7 +77,7 @@ export class UserController extends AdaptableController {
7877
return results[0];
7978
});
8079
}
81-
80+
8281
getUserIfNeeded(user) {
8382
if (user.username && user.email) {
8483
return Promise.resolve(user);
@@ -90,7 +89,7 @@ export class UserController extends AdaptableController {
9089
if (user.email) {
9190
where.email = user.email;
9291
}
93-
92+
9493
var query = new RestQuery(this.config, Auth.master(this.config), '_User', where);
9594
return query.execute().then(function(result){
9695
if (result.results.length != 1) {
@@ -99,7 +98,7 @@ export class UserController extends AdaptableController {
9998
return result.results[0];
10099
})
101100
}
102-
101+
103102

104103
sendVerificationEmail(user) {
105104
if (!this.shouldVerifyEmails) {
@@ -122,7 +121,7 @@ export class UserController extends AdaptableController {
122121
}
123122
});
124123
}
125-
124+
126125
setPasswordResetToken(email) {
127126
let token = randomString(25);
128127
return this.config.database
@@ -142,19 +141,19 @@ export class UserController extends AdaptableController {
142141
// TODO: No adapter?
143142
return;
144143
}
145-
144+
146145
return this.setPasswordResetToken(email).then((user) => {
147146

148147
const token = encodeURIComponent(user._perishable_token);
149-
const username = encodeURIComponent(user.username);
148+
const username = encodeURIComponent(user.username);
150149
let link = `${this.config.requestResetPasswordURL}?token=${token}&username=${username}`
151150

152151
let options = {
153152
appName: this.config.appName,
154153
link: link,
155154
user: inflate('_User', user),
156155
};
157-
156+
158157
if (this.adapter.sendPasswordResetEmail) {
159158
this.adapter.sendPasswordResetEmail(options);
160159
} else {
@@ -164,13 +163,13 @@ export class UserController extends AdaptableController {
164163
return Promise.resolve(user);
165164
});
166165
}
167-
166+
168167
updatePassword(username, token, password, config) {
169168
return this.checkResetTokenValidity(username, token).then(() => {
170169
return updateUserPassword(username, token, password, this.config);
171170
});
172171
}
173-
172+
174173
defaultVerificationEmail({link, user, appName, }) {
175174
let text = "Hi,\n\n" +
176175
"You are being asked to confirm the e-mail address " + user.email + " with " + appName + "\n\n" +
@@ -180,9 +179,9 @@ export class UserController extends AdaptableController {
180179
let subject = 'Please verify your e-mail for ' + appName;
181180
return { text, to, subject };
182181
}
183-
182+
184183
defaultResetPasswordEmail({link, user, appName, }) {
185-
let text = "Hi,\n\n" +
184+
let text = "Hi,\n\n" +
186185
"You requested to reset your password for " + appName + ".\n\n" +
187186
"" +
188187
"Click here to reset it:\n" + link;
@@ -193,9 +192,9 @@ export class UserController extends AdaptableController {
193192
}
194193

195194
// Mark this private
196-
function updateUserPassword(username, token, password, config) {
195+
function updateUserPassword(username, token, password, config) {
197196
var write = new RestWrite(config, Auth.master(config), '_User', {
198-
username: username,
197+
username: username,
199198
_perishable_token: token
200199
}, {password: password, _perishable_token: null }, undefined);
201200
return write.execute();

src/middlewares.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ function handleParseHeaders(req, res, next) {
8989
var isMaster = (info.masterKey === req.config.masterKey);
9090

9191
if (isMaster) {
92-
req.auth = new auth.Auth(req.config, true);
92+
req.auth = new auth.Auth({ config: req.config, installationId: info.installationId, isMaster: true });
9393
next();
9494
return;
9595
}
@@ -114,23 +114,23 @@ function handleParseHeaders(req, res, next) {
114114
}
115115

116116
if (!info.sessionToken) {
117-
req.auth = new auth.Auth(req.config, false);
117+
req.auth = new auth.Auth({ config: req.config, installationId: info.installationId, isMaster: false });
118118
next();
119119
return;
120120
}
121121

122-
return auth.getAuthForSessionToken(
123-
req.config, info.sessionToken).then((auth) => {
122+
return auth.getAuthForSessionToken({ config: req.config, installationId: info.installationId, sessionToken: info.sessionToken })
123+
.then((auth) => {
124124
if (auth) {
125125
req.auth = auth;
126126
next();
127127
}
128-
}).catch((error) => {
128+
})
129+
.catch((error) => {
129130
// TODO: Determine the correct error scenario.
130131
console.log(error);
131132
throw new Parse.Error(Parse.Error.UNKNOWN_ERROR, error);
132133
});
133-
134134
}
135135

136136
var allowCrossDomain = function(req, res, next) {

src/triggers.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,11 @@ export function getRequestObject(triggerType, auth, parseObject, originalParseOb
110110
if (auth.user) {
111111
request['user'] = auth.user;
112112
}
113-
// TODO: Add installation to Auth?
114113
if (auth.installationId) {
115114
request['installationId'] = auth.installationId;
116115
}
117116
return request;
118-
};
117+
}
119118

120119
// Creates the response object, and uses the request object to pass data
121120
// The API will call this with REST API formatted objects, this will

0 commit comments

Comments
 (0)