Merge pull request #2259 from ParsePlatform/client-sdk-info

Exposes the ClientSDK infos if available
This commit is contained in:
Nikita Lutsenko
2016-07-12 11:17:52 -07:00
committed by GitHub
12 changed files with 74 additions and 30 deletions

View File

@@ -23,7 +23,8 @@ describe('InstallationsRouter', () => {
deviceType: 'android' deviceType: 'android'
} }
}, },
query: {} query: {},
info: {}
}; };
var router = new InstallationsRouter(); var router = new InstallationsRouter();
@@ -56,7 +57,8 @@ describe('InstallationsRouter', () => {
where: { where: {
deviceType: 'android' deviceType: 'android'
} }
} },
info: {}
}; };
var router = new InstallationsRouter(); var router = new InstallationsRouter();
@@ -87,7 +89,8 @@ describe('InstallationsRouter', () => {
body: {}, body: {},
query: { query: {
limit: 0 limit: 0
} },
info: {}
}; };
var router = new InstallationsRouter(); var router = new InstallationsRouter();
@@ -118,7 +121,8 @@ describe('InstallationsRouter', () => {
body: {}, body: {},
query: { query: {
count: 1 count: 1
} },
info: {}
}; };
var router = new InstallationsRouter(); var router = new InstallationsRouter();
@@ -153,7 +157,8 @@ describe('InstallationsRouter', () => {
query: { query: {
limit: 0, limit: 0,
count: 1 count: 1
} },
info: {}
}; };
var router = new InstallationsRouter(); var router = new InstallationsRouter();

View File

@@ -66,4 +66,24 @@ describe('middlewares', () => {
}); });
}); });
}); });
it('should properly parse the SDK versions', () => {
let clientSDKFromVersion = middlewares.clientSDKFromVersion;
expect(clientSDKFromVersion('i1.1.1')).toEqual({
sdk: 'i',
version: '1.1.1'
});
expect(clientSDKFromVersion('i1')).toEqual({
sdk: 'i',
version: '1'
});
expect(clientSDKFromVersion('apple-tv1.13.0')).toEqual({
sdk: 'apple-tv',
version: '1.13.0'
});
expect(clientSDKFromVersion('js1.9.0')).toEqual({
sdk: 'js',
version: '1.9.0'
});
})
}); });

View File

@@ -14,12 +14,13 @@ import { default as FilesController } from './Controllers/FilesController';
// include // include
// keys // keys
// redirectClassNameForKey // redirectClassNameForKey
function RestQuery(config, auth, className, restWhere = {}, restOptions = {}) { function RestQuery(config, auth, className, restWhere = {}, restOptions = {}, clientSDK) {
this.config = config; this.config = config;
this.auth = auth; this.auth = auth;
this.className = className; this.className = className;
this.restWhere = restWhere; this.restWhere = restWhere;
this.clientSDK = clientSDK;
this.response = null; this.response = null;
this.findOptions = {}; this.findOptions = {};
if (!this.auth.isMaster) { if (!this.auth.isMaster) {

View File

@@ -23,13 +23,13 @@ import _ from 'lodash';
// RestWrite will handle objectId, createdAt, and updatedAt for // RestWrite will handle objectId, createdAt, and updatedAt for
// everything. It also knows to use triggers and special modifications // everything. It also knows to use triggers and special modifications
// for the _User class. // for the _User class.
function RestWrite(config, auth, className, query, data, originalData) { function RestWrite(config, auth, className, query, data, originalData, clientSDK) {
this.config = config; this.config = config;
this.auth = auth; this.auth = auth;
this.className = className; this.className = className;
this.clientSDK = clientSDK;
this.storage = {}; this.storage = {};
this.runOptions = {}; this.runOptions = {};
if (!query && data.objectId) { if (!query && data.objectId) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'objectId is an invalid field name.'); throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'objectId is an invalid field name.');
} }

View File

@@ -46,7 +46,7 @@ export class ClassesRouter extends PromiseRouter {
if (typeof body.where === 'string') { if (typeof body.where === 'string') {
body.where = JSON.parse(body.where); body.where = JSON.parse(body.where);
} }
return rest.find(req.config, req.auth, req.params.className, body.where, options) return rest.find(req.config, req.auth, req.params.className, body.where, options, req.info.clientSDK)
.then((response) => { .then((response) => {
if (response && response.results) { if (response && response.results) {
for (let result of response.results) { for (let result of response.results) {
@@ -77,7 +77,7 @@ export class ClassesRouter extends PromiseRouter {
options.include = String(body.include); options.include = String(body.include);
} }
return rest.get(req.config, req.auth, req.params.className, req.params.objectId, options) return rest.get(req.config, req.auth, req.params.className, req.params.objectId, options, req.info.clientSDK)
.then((response) => { .then((response) => {
if (!response.results || response.results.length == 0) { if (!response.results || response.results.length == 0) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
@@ -99,15 +99,15 @@ export class ClassesRouter extends PromiseRouter {
} }
handleCreate(req) { handleCreate(req) {
return rest.create(req.config, req.auth, req.params.className, req.body); return rest.create(req.config, req.auth, req.params.className, req.body, req.info.clientSDK);
} }
handleUpdate(req) { handleUpdate(req) {
return rest.update(req.config, req.auth, req.params.className, req.params.objectId, req.body); return rest.update(req.config, req.auth, req.params.className, req.params.objectId, req.body, req.info.clientSDK);
} }
handleDelete(req) { handleDelete(req) {
return rest.del(req.config, req.auth, req.params.className, req.params.objectId) return rest.del(req.config, req.auth, req.params.className, req.params.objectId, req.info.clientSDK)
.then(() => { .then(() => {
return {response: {}}; return {response: {}};
}); });

View File

@@ -43,7 +43,7 @@ function validateWithAppStore(url, receipt) {
} }
function getFileForProductIdentifier(productIdentifier, req) { function getFileForProductIdentifier(productIdentifier, req) {
return rest.find(req.config, req.auth, '_Product', { productIdentifier: productIdentifier }).then(function(result){ return rest.find(req.config, req.auth, '_Product', { productIdentifier: productIdentifier }, undefined, req.info.clientSDK).then(function(result){
const products = result.results; const products = result.results;
if (!products || products.length != 1) { if (!products || products.length != 1) {
// Error not found or too many // Error not found or too many

View File

@@ -26,7 +26,7 @@ export class InstallationsRouter extends ClassesRouter {
} }
return rest.find(req.config, req.auth, return rest.find(req.config, req.auth,
'_Installation', body.where, options) '_Installation', body.where, options, req.info.clientSDK)
.then((response) => { .then((response) => {
return {response: response}; return {response: response};
}); });

View File

@@ -36,7 +36,7 @@ export class SessionsRouter extends ClassesRouter {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
'Session token required.'); 'Session token required.');
} }
return rest.find(req.config, Auth.master(req.config), '_Session', { sessionToken: req.info.sessionToken }) return rest.find(req.config, Auth.master(req.config), '_Session', { sessionToken: req.info.sessionToken }, undefined, req.info.clientSDK)
.then((response) => { .then((response) => {
if (!response.results || response.results.length == 0) { if (!response.results || response.results.length == 0) {
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,

View File

@@ -47,7 +47,7 @@ export class UsersRouter extends ClassesRouter {
let sessionToken = req.info.sessionToken; let sessionToken = req.info.sessionToken;
return rest.find(req.config, Auth.master(req.config), '_Session', return rest.find(req.config, Auth.master(req.config), '_Session',
{ sessionToken }, { sessionToken },
{ include: 'user' }) { include: 'user' }, req.info.clientSDK)
.then((response) => { .then((response) => {
if (!response.results || if (!response.results ||
response.results.length == 0 || response.results.length == 0 ||
@@ -145,7 +145,7 @@ export class UsersRouter extends ClassesRouter {
let success = {response: {}}; let success = {response: {}};
if (req.info && req.info.sessionToken) { if (req.info && req.info.sessionToken) {
return rest.find(req.config, Auth.master(req.config), '_Session', return rest.find(req.config, Auth.master(req.config), '_Session',
{ sessionToken: req.info.sessionToken } { sessionToken: req.info.sessionToken }, undefined, req.info.clientSDK
).then((records) => { ).then((records) => {
if (records.results && records.results.length) { if (records.results && records.results.length) {
return rest.del(req.config, Auth.master(req.config), '_Session', return rest.del(req.config, Auth.master(req.config), '_Session',

View File

@@ -52,7 +52,8 @@ function handleBatch(router, req) {
body: restRequest.body, body: restRequest.body,
params: match.params, params: match.params,
config: req.config, config: req.config,
auth: req.auth auth: req.auth,
info: req.info
}; };
promises.push(match.handler(request).then((response) => { promises.push(match.handler(request).then((response) => {

View File

@@ -6,6 +6,17 @@ var Parse = require('parse/node').Parse;
var auth = require('./Auth'); var auth = require('./Auth');
var Config = require('./Config'); var Config = require('./Config');
function clientSDKFromVersion(version) {
let versionRE = /([-a-zA-Z]+)([0-9\.]+)/;
let match = version.toLowerCase().match(versionRE);
if (match && match.length === 3) {
return {
sdk: match[1],
version: match[2]
}
}
}
// Checks that the request is authorized for this app and checks user // Checks that the request is authorized for this app and checks user
// auth too. // auth too.
// The bodyparser should run before this middleware. // The bodyparser should run before this middleware.
@@ -25,7 +36,8 @@ function handleParseHeaders(req, res, next) {
clientKey: req.get('X-Parse-Client-Key'), clientKey: req.get('X-Parse-Client-Key'),
javascriptKey: req.get('X-Parse-Javascript-Key'), javascriptKey: req.get('X-Parse-Javascript-Key'),
dotNetKey: req.get('X-Parse-Windows-Key'), dotNetKey: req.get('X-Parse-Windows-Key'),
restAPIKey: req.get('X-Parse-REST-API-Key') restAPIKey: req.get('X-Parse-REST-API-Key'),
clientVersion: req.get('X-Parse-Client-Version')
}; };
var basicAuth = httpAuth(req); var basicAuth = httpAuth(req);
@@ -93,6 +105,10 @@ function handleParseHeaders(req, res, next) {
} }
} }
if (info.clientVersion) {
info.clientSDK = clientSDKFromVersion(info.clientVersion);
}
if (fileViaJSON) { if (fileViaJSON) {
// We need to repopulate req.body with a buffer // We need to repopulate req.body with a buffer
var base64 = req.body.base64; var base64 = req.body.base64;
@@ -283,5 +299,6 @@ module.exports = {
handleParseErrors: handleParseErrors, handleParseErrors: handleParseErrors,
handleParseHeaders: handleParseHeaders, handleParseHeaders: handleParseHeaders,
enforceMasterKeyAccess: enforceMasterKeyAccess, enforceMasterKeyAccess: enforceMasterKeyAccess,
promiseEnforceMasterKeyAccess promiseEnforceMasterKeyAccess,
clientSDKFromVersion
}; };

View File

@@ -15,21 +15,21 @@ var RestWrite = require('./RestWrite');
var triggers = require('./triggers'); var triggers = require('./triggers');
// Returns a promise for an object with optional keys 'results' and 'count'. // Returns a promise for an object with optional keys 'results' and 'count'.
function find(config, auth, className, restWhere, restOptions) { function find(config, auth, className, restWhere, restOptions, clientSDK) {
enforceRoleSecurity('find', className, auth); enforceRoleSecurity('find', className, auth);
let query = new RestQuery(config, auth, className, restWhere, restOptions); let query = new RestQuery(config, auth, className, restWhere, restOptions, clientSDK);
return query.execute(); return query.execute();
} }
// get is just like find but only queries an objectId. // get is just like find but only queries an objectId.
const get = (config, auth, className, objectId, restOptions) => { const get = (config, auth, className, objectId, restOptions, clientSDK) => {
enforceRoleSecurity('get', className, auth); enforceRoleSecurity('get', className, auth);
let query = new RestQuery(config, auth, className, { objectId }, restOptions); let query = new RestQuery(config, auth, className, { objectId }, restOptions, clientSDK);
return query.execute(); return query.execute();
} }
// Returns a promise that doesn't resolve to any useful value. // Returns a promise that doesn't resolve to any useful value.
function del(config, auth, className, objectId) { function del(config, auth, className, objectId, clientSDK) {
if (typeof objectId !== 'string') { if (typeof objectId !== 'string') {
throw new Parse.Error(Parse.Error.INVALID_JSON, throw new Parse.Error(Parse.Error.INVALID_JSON,
'bad objectId'); 'bad objectId');
@@ -92,16 +92,16 @@ function del(config, auth, className, objectId) {
} }
// Returns a promise for a {response, status, location} object. // Returns a promise for a {response, status, location} object.
function create(config, auth, className, restObject) { function create(config, auth, className, restObject, clientSDK) {
enforceRoleSecurity('create', className, auth); enforceRoleSecurity('create', className, auth);
var write = new RestWrite(config, auth, className, null, restObject); var write = new RestWrite(config, auth, className, null, restObject, clientSDK);
return write.execute(); return write.execute();
} }
// Returns a promise that contains the fields of the update that the // Returns a promise that contains the fields of the update that the
// REST API is supposed to return. // REST API is supposed to return.
// Usually, this is just updatedAt. // Usually, this is just updatedAt.
function update(config, auth, className, objectId, restObject) { function update(config, auth, className, objectId, restObject, clientSDK) {
enforceRoleSecurity('update', className, auth); enforceRoleSecurity('update', className, auth);
return Promise.resolve().then(() => { return Promise.resolve().then(() => {
@@ -117,7 +117,7 @@ function update(config, auth, className, objectId, restObject) {
originalRestObject = response.results[0]; originalRestObject = response.results[0];
} }
var write = new RestWrite(config, auth, className, {objectId: objectId}, restObject, originalRestObject); var write = new RestWrite(config, auth, className, {objectId: objectId}, restObject, originalRestObject, clientSDK);
return write.execute(); return write.execute();
}); });
} }