Add new afterLogin cloud code hook (#6387)
* add new afterLogin cloud code hook * include user on req.user for afterLogin hook
This commit is contained in:
@@ -2269,21 +2269,43 @@ describe('afterFind hooks', () => {
|
|||||||
expect(() => {
|
expect(() => {
|
||||||
Parse.Cloud.beforeLogin(() => {});
|
Parse.Cloud.beforeLogin(() => {});
|
||||||
}).not.toThrow(
|
}).not.toThrow(
|
||||||
'Only the _User class is allowed for the beforeLogin trigger'
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
);
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Parse.Cloud.beforeLogin('_User', () => {});
|
Parse.Cloud.beforeLogin('_User', () => {});
|
||||||
}).not.toThrow(
|
}).not.toThrow(
|
||||||
'Only the _User class is allowed for the beforeLogin trigger'
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
);
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Parse.Cloud.beforeLogin(Parse.User, () => {});
|
Parse.Cloud.beforeLogin(Parse.User, () => {});
|
||||||
}).not.toThrow(
|
}).not.toThrow(
|
||||||
'Only the _User class is allowed for the beforeLogin trigger'
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
);
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Parse.Cloud.beforeLogin('SomeClass', () => {});
|
Parse.Cloud.beforeLogin('SomeClass', () => {});
|
||||||
}).toThrow('Only the _User class is allowed for the beforeLogin trigger');
|
}).toThrow(
|
||||||
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
Parse.Cloud.afterLogin(() => {});
|
||||||
|
}).not.toThrow(
|
||||||
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
Parse.Cloud.afterLogin('_User', () => {});
|
||||||
|
}).not.toThrow(
|
||||||
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
Parse.Cloud.afterLogin(Parse.User, () => {});
|
||||||
|
}).not.toThrow(
|
||||||
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
Parse.Cloud.afterLogin('SomeClass', () => {});
|
||||||
|
}).toThrow(
|
||||||
|
'Only the _User class is allowed for the beforeLogin and afterLogin triggers'
|
||||||
|
);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Parse.Cloud.afterLogout(() => {});
|
Parse.Cloud.afterLogout(() => {});
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
@@ -2574,3 +2596,66 @@ describe('beforeLogin hook', () => {
|
|||||||
expect(afterFinds).toEqual(1);
|
expect(afterFinds).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('afterLogin hook', () => {
|
||||||
|
it('should run afterLogin after successful login', async done => {
|
||||||
|
let hit = 0;
|
||||||
|
Parse.Cloud.afterLogin(req => {
|
||||||
|
hit++;
|
||||||
|
expect(req.object.get('username')).toEqual('testuser');
|
||||||
|
});
|
||||||
|
|
||||||
|
await Parse.User.signUp('testuser', 'p@ssword');
|
||||||
|
const user = await Parse.User.logIn('testuser', 'p@ssword');
|
||||||
|
expect(hit).toBe(1);
|
||||||
|
expect(user).toBeDefined();
|
||||||
|
expect(user.getUsername()).toBe('testuser');
|
||||||
|
expect(user.getSessionToken()).toBeDefined();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not run afterLogin after unsuccessful login', async done => {
|
||||||
|
let hit = 0;
|
||||||
|
Parse.Cloud.afterLogin(req => {
|
||||||
|
hit++;
|
||||||
|
expect(req.object.get('username')).toEqual('testuser');
|
||||||
|
});
|
||||||
|
|
||||||
|
await Parse.User.signUp('testuser', 'p@ssword');
|
||||||
|
try {
|
||||||
|
await Parse.User.logIn('testuser', 'badpassword');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
|
||||||
|
}
|
||||||
|
expect(hit).toBe(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not run afterLogin on sign up', async done => {
|
||||||
|
let hit = 0;
|
||||||
|
Parse.Cloud.afterLogin(req => {
|
||||||
|
hit++;
|
||||||
|
expect(req.object.get('username')).toEqual('testuser');
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = await Parse.User.signUp('testuser', 'p@ssword');
|
||||||
|
expect(user).toBeDefined();
|
||||||
|
expect(hit).toBe(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have expected data in request', async done => {
|
||||||
|
Parse.Cloud.afterLogin(req => {
|
||||||
|
expect(req.object).toBeDefined();
|
||||||
|
expect(req.user).toBeDefined();
|
||||||
|
expect(req.headers).toBeDefined();
|
||||||
|
expect(req.ip).toBeDefined();
|
||||||
|
expect(req.installationId).toBeDefined();
|
||||||
|
expect(req.context).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Parse.User.signUp('testuser', 'p@ssword');
|
||||||
|
await Parse.User.logIn('testuser', 'p@ssword');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -264,6 +264,18 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
user.sessionToken = sessionData.sessionToken;
|
user.sessionToken = sessionData.sessionToken;
|
||||||
|
|
||||||
await createSession();
|
await createSession();
|
||||||
|
|
||||||
|
const afterLoginUser = Parse.User.fromJSON(
|
||||||
|
Object.assign({ className: '_User' }, user)
|
||||||
|
);
|
||||||
|
maybeRunTrigger(
|
||||||
|
TriggerTypes.afterLogin,
|
||||||
|
{ ...req.auth, user: afterLoginUser },
|
||||||
|
afterLoginUser,
|
||||||
|
null,
|
||||||
|
req.config
|
||||||
|
);
|
||||||
|
|
||||||
return { response: user };
|
return { response: user };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,42 @@ ParseCloud.beforeLogin = function(handler) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Registers the after login function.
|
||||||
|
*
|
||||||
|
* **Available in Cloud Code only.**
|
||||||
|
*
|
||||||
|
* This function is triggered after a user logs in successfully,
|
||||||
|
* and after a _Session object has been created.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* Parse.Cloud.afterLogin((request) => {
|
||||||
|
* // code here
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @method afterLogin
|
||||||
|
* @name Parse.Cloud.afterLogin
|
||||||
|
* @param {Function} func The function to run after a login. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest};
|
||||||
|
*/
|
||||||
|
ParseCloud.afterLogin = function(handler) {
|
||||||
|
let className = '_User';
|
||||||
|
if (typeof handler === 'string' || isParseObjectConstructor(handler)) {
|
||||||
|
// validation will occur downstream, this is to maintain internal
|
||||||
|
// code consistency with the other hook types.
|
||||||
|
className = getClassName(handler);
|
||||||
|
handler = arguments[1];
|
||||||
|
}
|
||||||
|
triggers.addTrigger(
|
||||||
|
triggers.Types.afterLogin,
|
||||||
|
className,
|
||||||
|
handler,
|
||||||
|
Parse.applicationId
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Registers the after logout function.
|
* Registers the after logout function.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { logger } from './logger';
|
|||||||
|
|
||||||
export const Types = {
|
export const Types = {
|
||||||
beforeLogin: 'beforeLogin',
|
beforeLogin: 'beforeLogin',
|
||||||
|
afterLogin: 'afterLogin',
|
||||||
afterLogout: 'afterLogout',
|
afterLogout: 'afterLogout',
|
||||||
beforeSave: 'beforeSave',
|
beforeSave: 'beforeSave',
|
||||||
afterSave: 'afterSave',
|
afterSave: 'afterSave',
|
||||||
@@ -39,10 +40,13 @@ function validateClassNameForTriggers(className, type) {
|
|||||||
// TODO: Allow proper documented way of using nested increment ops
|
// TODO: Allow proper documented way of using nested increment ops
|
||||||
throw 'Only afterSave is allowed on _PushStatus';
|
throw 'Only afterSave is allowed on _PushStatus';
|
||||||
}
|
}
|
||||||
if (type === Types.beforeLogin && className !== '_User') {
|
if (
|
||||||
|
(type === Types.beforeLogin || type === Types.afterLogin) &&
|
||||||
|
className !== '_User'
|
||||||
|
) {
|
||||||
// TODO: check if upstream code will handle `Error` instance rather
|
// TODO: check if upstream code will handle `Error` instance rather
|
||||||
// than this anti-pattern of throwing strings
|
// than this anti-pattern of throwing strings
|
||||||
throw 'Only the _User class is allowed for the beforeLogin trigger';
|
throw 'Only the _User class is allowed for the beforeLogin and afterLogin triggers';
|
||||||
}
|
}
|
||||||
if (type === Types.afterLogout && className !== '_Session') {
|
if (type === Types.afterLogout && className !== '_Session') {
|
||||||
// TODO: check if upstream code will handle `Error` instance rather
|
// TODO: check if upstream code will handle `Error` instance rather
|
||||||
@@ -615,7 +619,8 @@ export function maybeRunTrigger(
|
|||||||
const promise = trigger(request);
|
const promise = trigger(request);
|
||||||
if (
|
if (
|
||||||
triggerType === Types.afterSave ||
|
triggerType === Types.afterSave ||
|
||||||
triggerType === Types.afterDelete
|
triggerType === Types.afterDelete ||
|
||||||
|
triggerType === Types.afterLogin
|
||||||
) {
|
) {
|
||||||
logTriggerAfterHook(
|
logTriggerAfterHook(
|
||||||
triggerType,
|
triggerType,
|
||||||
|
|||||||
Reference in New Issue
Block a user