diff --git a/.eslintrc.json b/.eslintrc.json
index 058fd6f03..dc4a0b0a5 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -42,6 +42,7 @@
"jsdoc/require-param-description": 0,
"jsdoc/require-property-description": 0,
"jsdoc/require-param-type": 0,
+ "jsdoc/tag-lines": 0,
"jsdoc/check-param-names": [
"error",
{
diff --git a/integration/test/ParseUserTest.js b/integration/test/ParseUserTest.js
index 64b6f2bd9..2704c34b8 100644
--- a/integration/test/ParseUserTest.js
+++ b/integration/test/ParseUserTest.js
@@ -148,6 +148,27 @@ describe('Parse User', () => {
expect(sessions[1].get('sessionToken')).toBe(installationUser.getSessionToken());
});
+ it('can login with userId', async () => {
+ Parse.User.enableUnsafeCurrentUser();
+
+ const user = await Parse.User.signUp('parsetest', 'parse', { code: 'red' });
+ assert.equal(Parse.User.current(), user);
+ await Parse.User.logOut();
+ assert(!Parse.User.current());
+
+ const newUser = await Parse.User.loginAs(user.id);
+ assert.equal(Parse.User.current(), newUser);
+ assert(newUser);
+ assert.equal(user.id, newUser.id);
+ assert.equal(user.get('code'), 'red');
+
+ await Parse.User.logOut();
+ assert(!Parse.User.current());
+ await expectAsync(Parse.User.loginAs('garbage')).toBeRejectedWithError(
+ 'user not found'
+ );
+ });
+
it('can become a user', done => {
Parse.User.enableUnsafeCurrentUser();
let session = null;
@@ -782,6 +803,16 @@ describe('Parse User', () => {
expect(user.doSomething()).toBe(5);
});
+ it('can loginAs user with subclass static', async () => {
+ Parse.User.enableUnsafeCurrentUser();
+
+ let user = await CustomUser.signUp('username', 'password');
+
+ user = await CustomUser.loginAs(user.id);
+ expect(user instanceof CustomUser).toBe(true);
+ expect(user.doSomething()).toBe(5);
+ });
+
it('can get user (me) with subclass static', async () => {
Parse.User.enableUnsafeCurrentUser();
diff --git a/src/ParseUser.js b/src/ParseUser.js
index 1bd9c3780..d2014f1ac 100644
--- a/src/ParseUser.js
+++ b/src/ParseUser.js
@@ -653,6 +653,25 @@ class ParseUser extends ParseObject {
return user.logIn(options);
}
+ /**
+ * Logs in a user with an objectId. On success, this saves the session
+ * to disk, so you can retrieve the currently logged in user using
+ * current
.
+ *
+ * @param {string} userId The objectId for the user.
+ * @static
+ * @returns {Promise} A promise that is fulfilled with the user when
+ * the login completes.
+ */
+ static loginAs(userId: string) {
+ if (!userId) {
+ throw new ParseError(ParseError.USERNAME_MISSING, 'Cannot log in as user with an empty user id');
+ }
+ const controller = CoreManager.getUserController();
+ const user = new this();
+ return controller.loginAs(user, userId);
+ }
+
/**
* Logs in a user with a session token. On success, this saves the session
* to disk, so you can retrieve the currently logged in user using
@@ -1097,6 +1116,18 @@ const DefaultController = {
);
},
+ loginAs(user: ParseUser, userId: string): Promise {
+ const RESTController = CoreManager.getRESTController();
+ return RESTController.request('POST', 'loginAs', { userId }, { useMasterKey: true }).then(response => {
+ user._finishFetch(response);
+ user._setExisted(true);
+ if (!canUseCurrentUser) {
+ return Promise.resolve(user);
+ }
+ return DefaultController.setCurrentUser(user);
+ });
+ },
+
become(user: ParseUser, options: RequestOptions): Promise {
const RESTController = CoreManager.getRESTController();
return RESTController.request('GET', 'users/me', {}, options).then(response => {
diff --git a/src/__tests__/ParseUser-test.js b/src/__tests__/ParseUser-test.js
index 4f030123a..f671149c3 100644
--- a/src/__tests__/ParseUser-test.js
+++ b/src/__tests__/ParseUser-test.js
@@ -360,6 +360,73 @@ describe('ParseUser', () => {
});
});
+ it('does not allow loginAs without id', (done) => {
+ try {
+ ParseUser.loginAs(null, null);
+ } catch (e) {
+ expect(e.message).toBe('Cannot log in as user with an empty user id')
+ done();
+ }
+ });
+
+ it('can login as a user with an objectId', async () => {
+ ParseUser.disableUnsafeCurrentUser();
+ ParseUser._clearCache();
+ CoreManager.setRESTController({
+ request(method, path, body, options) {
+ expect(method).toBe('POST');
+ expect(path).toBe('loginAs');
+ expect(body.userId).toBe('uid4');
+ expect(options.useMasterKey).toBe(true);
+
+ return Promise.resolve(
+ {
+ objectId: 'uid4',
+ username: 'username',
+ sessionToken: '123abc',
+ },
+ 200
+ );
+ },
+ ajax() {},
+ });
+
+ const user = await ParseUser.loginAs('uid4');
+ expect(user.id).toBe('uid4');
+ expect(user.isCurrent()).toBe(false);
+ expect(user.existed()).toBe(true);
+ });
+
+ it('can loginAs a user with async storage', async () => {
+ const currentStorage = CoreManager.getStorageController();
+ CoreManager.setStorageController(mockAsyncStorage);
+ ParseUser.enableUnsafeCurrentUser();
+ ParseUser._clearCache();
+ CoreManager.setRESTController({
+ request(method, path, body, options) {
+ expect(method).toBe('POST');
+ expect(path).toBe('loginAs');
+ expect(body.userId).toBe('uid5');
+ expect(options.useMasterKey).toBe(true);
+ return Promise.resolve(
+ {
+ objectId: 'uid5',
+ username: 'username',
+ sessionToken: '123abc',
+ },
+ 200
+ );
+ },
+ ajax() {},
+ });
+
+ const user = await ParseUser.loginAs('uid5');
+ expect(user.id).toBe('uid5');
+ expect(user.isCurrent()).toBe(true);
+ expect(user.existed()).toBe(true);
+ CoreManager.setStorageController(currentStorage);
+ });
+
it('can become a user with a session token', done => {
ParseUser.enableUnsafeCurrentUser();
ParseUser._clearCache();