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();