Merge pull request #1113 from realm/user-lookup

Add support for getting user id (retrieveAccount)
This commit is contained in:
blagoev 2017-07-07 17:32:48 +03:00 committed by GitHub
commit 4b68730cfd
8 changed files with 232 additions and 21 deletions

View File

@ -2,4 +2,4 @@ PACKAGE_NAME=realm-js
VERSION=1.8.3
REALM_CORE_VERSION=2.8.4
REALM_SYNC_VERSION=1.10.1
REALM_OBJECT_SERVER_VERSION=1.7.6
REALM_OBJECT_SERVER_VERSION=1.8.1

12
lib/index.d.ts vendored
View File

@ -240,6 +240,17 @@ declare namespace Realm {
*/
declare namespace Realm.Sync {
interface UserInfo {
id: string;
isAdmin: boolean;
}
interface Account {
provider_id: string;
provider: string;
user: UserInfo
}
/**
* User
* @see { @link https://realm.io/docs/javascript/latest/api/Realm.Sync.User.html }
@ -258,6 +269,7 @@ declare namespace Realm.Sync {
static registerWithProvider(server: string, options: { provider: string, providerToken: string, userInfo: any }, callback: (error: Error | null, user: User | null) => void): void;
logout(): void;
openManagementRealm(): Realm;
retrieveAccount(provider: string, username: string): Promise<Account>;
}
interface SyncConfiguration {

View File

@ -27,7 +27,7 @@ function node_require(module) {
function checkTypes(args, types) {
args = Array.prototype.slice.call(args);
for (var i = 0; i < types.length; ++i) {
if (typeof args[i] !== types[i]) {
if (typeof args[i] !== types[i]) {
throw new TypeError('param ' + i + ' must be of type ' + types[i]);
}
}
@ -37,13 +37,13 @@ const performFetch = typeof fetch === 'undefined' ? node_require('node-fetch') :
const url_parse = require('url-parse');
const postHeaders = {
const postHeaders = {
'content-type': 'application/json;charset=utf-8',
'accept': 'application/json'
};
function auth_url(server) {
if (server.charAt(server.length-1) != '/') {
if (server.charAt(server.length - 1) != '/') {
return server + '/auth';
}
return server + 'auth';
@ -122,7 +122,7 @@ function _authenticate(userConstructor, server, json, callback) {
open_timeout: 5000
};
performFetch(url, options)
.then((response) => {
.then((response) => {
if (response.status !== 200) {
return response.json().then((body) => callback(new AuthError(body)));
} else {
@ -132,7 +132,7 @@ function _authenticate(userConstructor, server, json, callback) {
const identity = body.refresh_token.token_data.identity;
const isAdmin = body.refresh_token.token_data.is_admin;
callback(undefined, userConstructor.createUser(server, identity, token, false, isAdmin));
})
})
}
})
.catch(callback);
@ -154,8 +154,8 @@ module.exports = {
adminUser(token) {
checkTypes(arguments, ['string']);
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
var user = this.createUser('', uuid, token, true);
@ -164,18 +164,18 @@ module.exports = {
register(server, username, password, callback) {
checkTypes(arguments, ['string', 'string', 'string', 'function']);
_authenticate(this, server, {
provider: 'password',
user_info: { password: password, register: true },
_authenticate(this, server, {
provider: 'password',
user_info: { password: password, register: true },
data: username
}, callback);
},
login(server, username, password, callback) {
checkTypes(arguments, ['string', 'string', 'string', 'function']);
_authenticate(this, server, {
provider: 'password',
user_info: { password: password },
_authenticate(this, server, {
provider: 'password',
user_info: { password: password },
data: username
}, callback);
},
@ -190,7 +190,7 @@ module.exports = {
provider: arguments[1],
providerToken: arguments[2]
};
callback = arguments[3];
callback = arguments[3];
} else {
checkTypes(arguments, ['string', 'object', 'function']);
}
@ -229,6 +229,33 @@ module.exports = {
url: url.href
}
});
}
}
},
retrieveAccount(provider, provider_id) {
checkTypes(arguments, ['string', 'string']);
const url = url_parse(this.server);
url.set('pathname', `/api/providers/${provider}/accounts/${provider_id}`);
const headers = {
Authorization: this.token
};
const options = {
method: 'GET',
headers,
open_timeout: 5000
};
return performFetch(url.href, options)
.then((response) => {
if (response.status !== 200) {
return response.json()
.then(body => {
throw new AuthError(body);
});
} else {
return response.json();
}
});
},
},
};

View File

@ -0,0 +1,81 @@
'use strict';
function node_require(module) {
return require(module);
}
let fs = node_require("fs");
let path = node_require("path");
var Realm = node_require('realm');
function random(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
exports.createAdminUser = function () {
return new Promise((resolve, reject) => {
let isAdminRetryCounter = 0;
let newAdminName = 'admin' + random(1, 100000);
let password = '123';
Realm.Sync.User.register('http://localhost:9080', newAdminName, password, (error, user) => {
if (error) {
reject(error);
} else {
let userIdentity = user.identity;
user.logout();
let admin_token_user = Realm.Sync.User.adminUser(fs.readFileSync(path.join(__dirname, '/../../object-server-for-testing/admin_token.base64'), 'utf-8'));
const config = {
sync: {
user: admin_token_user,
url: `realm://localhost:9080/__admin`,
error: err =>
console.log('Error opening __admin realm ' + err.user + ' ' + err.url + ' ' + err.state),
}
};
Realm.open(config).then(realm => {
let pendingAdminUser = realm.objectForPrimaryKey('User', userIdentity);
realm.write(() => {
pendingAdminUser.isAdmin = true;
});
admin_token_user.logout();
}).then(() => {
let waitForServerToUpdateAdminUser = function () {
isAdminRetryCounter++;
if (isAdminRetryCounter > 10) {
reject("admin-user-helper: Create admin user timeout");
return;
}
Realm.Sync.User.login('http://localhost:9080', newAdminName, password, (error, newAdminUser) => {
if (error) {
reject(error);
} else {
let isAdmin = newAdminUser.isAdmin;
user.logout();
if (!isAdmin) {
setTimeout(() => {
waitForServerToUpdateAdminUser();
}, 500);
return;
}
resolve({
username: newAdminName,
password
});
}
});
}
waitForServerToUpdateAdminUser();
});
}
});
});
}

View File

@ -27,7 +27,7 @@ Realm.Sync.User.register('http://localhost:9080', username, 'password', (error,
});
console.log("Dogs count " + realm.objects('Dog').length);
setTimeout(_ => process.exit(0), 3000);
setTimeout(() => process.exit(0), 3000);
}
});

View File

@ -41,10 +41,11 @@ if (Realm.Sync) {
TESTS.SessionTests = require('./session-tests');
}
function node_require(module) { return require(module); }
function node_require(module) { return require(module); }
// If on node, run the async tests
if (typeof process === 'object' && process + '' === '[object process]') {
const isNodeProcess = typeof process === 'object' && process + '' === '[object process]';
if (isNodeProcess) {
TESTS.AsyncTests = node_require('./async-tests');
}
@ -73,6 +74,22 @@ exports.registerTests = function(tests) {
}
};
exports.prepare = function(done) {
if (!isNodeProcess || global.testAdminUserInfo) {
done();
}
let helper = require('./admin-user-helper');
helper.createAdminUser().then(userInfo => {
global.testAdminUserInfo = userInfo;
done();
})
.catch(error => {
console.error("Error running admin-user-helper: " + error);
done();
});
};
exports.runTest = function(suiteName, testName) {
var testSuite = TESTS[suiteName];
var testMethod = testSuite && testSuite[testName];
@ -103,4 +120,4 @@ exports.runTest = function(suiteName, testName) {
} else if (!testSuite || !(testName in SPECIAL_METHODS)) {
throw new Error('Missing test: ' + suiteName + '.' + testName);
}
};
}

View File

@ -22,6 +22,7 @@
const Realm = require('realm');
const TestCase = require('./asserts');
const isNodeProcess = typeof process === 'object' && process + '' === '[object process]';
function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
@ -295,6 +296,76 @@ module.exports = {
});
},
testRetrieveAccount() {
return new Promise((resolve, reject) => {
if (!isNodeProcess) {
resolve();
}
if (!global.testAdminUserInfo) {
reject("Test requires an admin user");
}
Realm.Sync.User.login('http://localhost:9080', global.testAdminUserInfo.username, global.testAdminUserInfo.password, (error, user) => {
if (error) {
reject(error);
}
TestCase.assertTrue(user.isAdmin, "Test requires an admin user");
user.retrieveAccount('password', global.testAdminUserInfo.username)
.then(account => {
// {
// "provider_id": "admin",
// "provider": "password",
// "user": {
// "id": "07ac9a0a-a97a-4ee1-b53c-b05a6542035a",
// "isAdmin": true,
// }
// }
TestCase.assertEqual(account.provider_id, global.testAdminUserInfo.username);
TestCase.assertEqual(account.provider, 'password');
TestCase.assertTrue(account.user);
TestCase.assertTrue(account.user.isAdmin !== undefined);
TestCase.assertTrue(account.user.id);
resolve();
})
.catch(e => reject(e));
})
});
},
testRetrieveNotExistingAccount() {
return new Promise((resolve, reject) => {
if (!isNodeProcess) {
resolve();
}
if (!global.testAdminUserInfo) {
reject("Test requires an admin user");
}
Realm.Sync.User.login('http://localhost:9080', global.testAdminUserInfo.username, global.testAdminUserInfo.password, (error, user) => {
if (error) {
reject(error);
}
TestCase.assertTrue(user.isAdmin, "Test requires an admin user");
let notExistingUsername = uuid();
user.retrieveAccount('password', notExistingUsername)
.then(account => {
reject("Retrieving not existing account should fail");
})
.catch(e => {
TestCase.assertEqual(e.code, 404);
resolve()
});
})
});
},
/* This test fails because of realm-object-store #243 . We should use 2 users.
testSynchronizeChangesWithTwoClientsAndOneUser() {
// Test Schema

View File

@ -55,6 +55,9 @@ Realm.copyBundledRealmFiles = function() {
const tests = RealmTests.getTestNames();
for (const suiteName in tests) {
describe(suiteName, () => {
beforeAll(done => RealmTests.prepare(done));
beforeEach(() => RealmTests.runTest(suiteName, 'beforeEach'));
for (const testName of tests[suiteName]) {