Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added afterLogout trigger #6217

Merged
merged 5 commits into from
Nov 16, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions spec/CloudCode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2219,10 +2219,14 @@ describe('afterFind hooks', () => {
it('should validate triggers correctly', () => {
expect(() => {
Parse.Cloud.beforeSave('_Session', () => {});
}).toThrow('Triggers are not supported for _Session class.');
}).toThrow(
'Only the afterLogout trigger is allowed for the _Session class.'
);
expect(() => {
Parse.Cloud.afterSave('_Session', () => {});
}).toThrow('Triggers are not supported for _Session class.');
}).toThrow(
'Only the afterLogout trigger is allowed for the _Session class.'
);
expect(() => {
Parse.Cloud.beforeSave('_PushStatus', () => {});
}).toThrow('Only afterSave is allowed on _PushStatus');
Expand All @@ -2247,6 +2251,22 @@ describe('afterFind hooks', () => {
expect(() => {
Parse.Cloud.beforeLogin('SomeClass', () => {});
}).toThrow('Only the _User class is allowed for the beforeLogin trigger');
expect(() => {
Parse.Cloud.afterLogout(() => {});
}).not.toThrow();
expect(() => {
Parse.Cloud.afterLogout('_Session', () => {});
}).not.toThrow();
expect(() => {
Parse.Cloud.afterLogout('_User', () => {});
}).toThrow(
'Only the _Session class is allowed for the afterLogout trigger.'
);
expect(() => {
Parse.Cloud.afterLogout('SomeClass', () => {});
}).toThrow(
'Only the _Session class is allowed for the afterLogout trigger.'
);
});

it('should skip afterFind hooks for aggregate', done => {
Expand Down Expand Up @@ -2436,6 +2456,19 @@ describe('beforeLogin hook', () => {
done();
});

it('should trigger afterLogout hook on logout', async done => {
let hit = 0;
Parse.Cloud.afterLogout(() => {
hit++;
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
});

const user = await Parse.User.signUp('user', 'pass');
await user.save();
await Parse.User.logOut();
expect(hit).toBe(1);
done();
});

it('should have expected data in request', async done => {
Parse.Cloud.beforeLogin(req => {
expect(req.object).toBeDefined();
Expand Down
15 changes: 15 additions & 0 deletions spec/ParseUser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,21 @@ describe('Parse.User testing', () => {
done();
});

it('logout with provider should call afterLogout trigger', async done => {
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);

let hit = 0;
Parse.Cloud.afterLogout(() => {
hit++;
});
await Parse.User._logInWith('facebook');
await Parse.User.current().save({ name: 'user' });
await Parse.User.logOut();
expect(hit).toBe(1);
done();
});

it('link with provider', async done => {
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Expand Down
27 changes: 27 additions & 0 deletions src/RestWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,33 @@ RestWrite.prototype.runBeforeLoginTrigger = async function(userData) {
);
};

RestWrite.prototype.runAfterLogoutTrigger = async function(sessionData) {
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
// Avoid doing any setup for triggers if there is no 'afterLogout' trigger
if (
!triggers.triggerExists(
this.className,
triggers.Types.afterLogout,
this.config.applicationId
)
) {
return;
}

// Cloud code gets a bit of extra data for its objects
const extraData = { className: this.className };
const session = triggers.inflate(extraData, sessionData);

// no need to return a response
await triggers.maybeRunTrigger(
triggers.Types.afterLogout,
this.auth,
session,
null,
this.config,
this.context
);
};

RestWrite.prototype.setRequiredFieldsIfNeeded = function() {
if (this.data) {
return this.validSchemaController.getAllClasses().then(allClasses => {
Expand Down
12 changes: 12 additions & 0 deletions src/Routers/UsersRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ export class UsersRouter extends ClassesRouter {
records.results[0].objectId
)
.then(() => {
this._runAfterLogoutTrigger(req, records.results[0]);
return Promise.resolve(success);
});
}
Expand All @@ -311,6 +312,17 @@ export class UsersRouter extends ClassesRouter {
return Promise.resolve(success);
}

_runAfterLogoutTrigger(req, session) {
// After logout trigger
maybeRunTrigger(
TriggerTypes.afterLogout,
req.auth,
Parse.Session.fromJSON(Object.assign({ className: '_Session' }, session)),
null,
req.config
);
}

_throwOnBadEmailConfig(req) {
try {
Config.validateEmailConfiguration({
Expand Down
35 changes: 35 additions & 0 deletions src/cloud-code/Parse.Cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,41 @@ ParseCloud.beforeLogin = function(handler) {
);
};

/**
*
* Registers the after logout function.
*
* **Available in Cloud Code only.**
*
* This function is triggered after a user logs out.
*
* ```
* Parse.Cloud.afterLogout((request) => {
* // code here
* })
*
* ```
*
* @method afterLogout
* @name Parse.Cloud.afterLogout
* @param {Function} func The function to run after a logout. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest};
*/
ParseCloud.afterLogout = function(handler) {
let className = '_Session';
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.afterLogout,
className,
handler,
Parse.applicationId
);
};

/**
* Registers an after save function.
*
Expand Down
14 changes: 13 additions & 1 deletion src/triggers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { logger } from './logger';

export const Types = {
beforeLogin: 'beforeLogin',
afterLogout: 'afterLogout',
beforeSave: 'beforeSave',
afterSave: 'afterSave',
beforeDelete: 'beforeDelete',
Expand Down Expand Up @@ -32,7 +33,8 @@ const baseStore = function() {
};

function validateClassNameForTriggers(className, type) {
const restrictedClassNames = ['_Session'];
// Contains classes which do not allow triggers of any kind
const restrictedClassNames = [];
if (restrictedClassNames.indexOf(className) != -1) {
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
throw `Triggers are not supported for ${className} class.`;
}
Expand All @@ -47,6 +49,16 @@ function validateClassNameForTriggers(className, type) {
// than this anti-pattern of throwing strings
throw 'Only the _User class is allowed for the beforeLogin trigger';
}
if (type === Types.afterLogout && className !== '_Session') {
// TODO: check if upstream code will handle `Error` instance rather
// than this anti-pattern of throwing strings
throw 'Only the _Session class is allowed for the afterLogout trigger.';
}
if (className === '_Session' && type !== Types.afterLogout) {
// TODO: check if upstream code will handle `Error` instance rather
// than this anti-pattern of throwing strings
throw 'Only the afterLogout trigger is allowed for the _Session class.';
}
return className;
}

Expand Down