Merge pull request #748 from drew-gross/touch-up-features-endpoint
Touch up features endpoint
This commit is contained in:
@@ -5,7 +5,7 @@ const request = require("request");
|
|||||||
|
|
||||||
describe('features', () => {
|
describe('features', () => {
|
||||||
it('set and get features', (done) => {
|
it('set and get features', (done) => {
|
||||||
features.setFeature('users', {
|
features.setFeature('push', {
|
||||||
testOption1: true,
|
testOption1: true,
|
||||||
testOption2: false
|
testOption2: false
|
||||||
});
|
});
|
||||||
@@ -14,10 +14,10 @@ describe('features', () => {
|
|||||||
|
|
||||||
var expected = {
|
var expected = {
|
||||||
testOption1: true,
|
testOption1: true,
|
||||||
testOption2: false
|
testOption2: false
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(_features.users).toEqual(expected);
|
expect(_features.push).toEqual(expected);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ describe('features', () => {
|
|||||||
|
|
||||||
it('requires the master key to get all schemas', done => {
|
it('requires the master key to get all schemas', done => {
|
||||||
request.get({
|
request.get({
|
||||||
url: 'http://localhost:8378/1/features',
|
url: 'http://localhost:8378/1/serverInfo',
|
||||||
json: true,
|
json: true,
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': 'test',
|
'X-Parse-Application-Id': 'test',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var request = require('request');
|
var request = require('request');
|
||||||
|
var parseServerPackage = require('../package.json');
|
||||||
var MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
|
var MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
|
||||||
|
|
||||||
describe('server', () => {
|
describe('server', () => {
|
||||||
@@ -153,4 +154,18 @@ describe('server', () => {
|
|||||||
})).toThrow('SimpleMailgunAdapter requires an API Key and domain.');
|
})).toThrow('SimpleMailgunAdapter requires an API Key and domain.');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can report the server version', done => {
|
||||||
|
request.get({
|
||||||
|
url: 'http://localhost:8378/1/serverInfo',
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-Master-Key': 'test',
|
||||||
|
},
|
||||||
|
json: true,
|
||||||
|
}, (error, response, body) => {
|
||||||
|
expect(body.parseServerVersion).toEqual(parseServerPackage.version);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import PromiseRouter from '../PromiseRouter';
|
import { version } from '../../package.json';
|
||||||
|
import PromiseRouter from '../PromiseRouter';
|
||||||
import * as middleware from "../middlewares";
|
import * as middleware from "../middlewares";
|
||||||
import { getFeatures } from '../features';
|
import { getFeatures } from '../features';
|
||||||
|
|
||||||
export class FeaturesRouter extends PromiseRouter {
|
export class FeaturesRouter extends PromiseRouter {
|
||||||
mountRoutes() {
|
mountRoutes() {
|
||||||
this.route('GET','/features', middleware.promiseEnforceMasterKeyAccess, () => {
|
this.route('GET','/serverInfo', middleware.promiseEnforceMasterKeyAccess, () => {
|
||||||
return { response: {
|
return { response: {
|
||||||
results: [getFeatures()]
|
features: getFeatures(),
|
||||||
} };
|
parseServerVersion: version,
|
||||||
|
} };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,26 +14,18 @@
|
|||||||
* Features that use Adapters should specify the feature options through
|
* Features that use Adapters should specify the feature options through
|
||||||
* the setFeature method in your controller and feature
|
* the setFeature method in your controller and feature
|
||||||
* Reference PushController and ParsePushAdapter as an example.
|
* Reference PushController and ParsePushAdapter as an example.
|
||||||
*
|
*
|
||||||
* NOTE: When adding new endpoints be sure to update this list both (features, featureSwitch)
|
* NOTE: When adding new endpoints be sure to update this list both (features, featureSwitch)
|
||||||
* if you are planning to have a UI consume it.
|
* if you are planning to have a UI consume it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// default features
|
// default features
|
||||||
let features = {
|
let features = {
|
||||||
analytics: {
|
|
||||||
slowQueries: false,
|
|
||||||
performanceAnalysis: false,
|
|
||||||
retentionAnalysis: false,
|
|
||||||
},
|
|
||||||
classes: {},
|
|
||||||
files: {},
|
|
||||||
functions: {},
|
|
||||||
globalConfig: {
|
globalConfig: {
|
||||||
create: true,
|
create: false,
|
||||||
read: true,
|
read: false,
|
||||||
update: true,
|
update: false,
|
||||||
delete: true,
|
delete: false,
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
create: false,
|
create: false,
|
||||||
@@ -41,15 +33,19 @@ let features = {
|
|||||||
update: false,
|
update: false,
|
||||||
delete: false,
|
delete: false,
|
||||||
},
|
},
|
||||||
iapValidation: {},
|
|
||||||
installations: {},
|
|
||||||
logs: {
|
logs: {
|
||||||
info: true,
|
level: false,
|
||||||
error: true,
|
size: false,
|
||||||
|
order: false,
|
||||||
|
until: false,
|
||||||
|
from: false,
|
||||||
|
},
|
||||||
|
push: {
|
||||||
|
immediatePush: false,
|
||||||
|
scheduledPush: false,
|
||||||
|
storedPushData: false,
|
||||||
|
pushAudiences: false,
|
||||||
},
|
},
|
||||||
publicAPI: {},
|
|
||||||
push: {},
|
|
||||||
roles: {},
|
|
||||||
schemas: {
|
schemas: {
|
||||||
addField: true,
|
addField: true,
|
||||||
removeField: true,
|
removeField: true,
|
||||||
@@ -58,27 +54,15 @@ let features = {
|
|||||||
clearAllDataFromClass: false,
|
clearAllDataFromClass: false,
|
||||||
exportClass: false,
|
exportClass: false,
|
||||||
},
|
},
|
||||||
sessions: {},
|
|
||||||
users: {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// master switch for features
|
// master switch for features
|
||||||
let featuresSwitch = {
|
let featuresSwitch = {
|
||||||
analytics: true,
|
|
||||||
classes: true,
|
|
||||||
files: true,
|
|
||||||
functions: true,
|
|
||||||
globalConfig: true,
|
globalConfig: true,
|
||||||
hooks: true,
|
hooks: true,
|
||||||
iapValidation: true,
|
|
||||||
installations: true,
|
|
||||||
logs: true,
|
logs: true,
|
||||||
publicAPI: true,
|
|
||||||
push: true,
|
push: true,
|
||||||
roles: true,
|
|
||||||
schemas: true,
|
schemas: true,
|
||||||
sessions: true,
|
|
||||||
users: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,7 +78,7 @@ function setFeature(key, value) {
|
|||||||
function getFeatures() {
|
function getFeatures() {
|
||||||
let result = {};
|
let result = {};
|
||||||
Object.keys(features).forEach((key) => {
|
Object.keys(features).forEach((key) => {
|
||||||
if (featuresSwitch[key]) {
|
if (featuresSwitch[key] && features[key]) {
|
||||||
result[key] = features[key];
|
result[key] = features[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
38
src/index.js
38
src/index.js
@@ -10,12 +10,13 @@ var batch = require('./batch'),
|
|||||||
multer = require('multer'),
|
multer = require('multer'),
|
||||||
Parse = require('parse/node').Parse;
|
Parse = require('parse/node').Parse;
|
||||||
|
|
||||||
|
//import passwordReset from './passwordReset';
|
||||||
import cache from './cache';
|
import cache from './cache';
|
||||||
import Config from './Config';
|
import Config from './Config';
|
||||||
|
import parseServerPackage from '../package.json';
|
||||||
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
|
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
|
||||||
//import passwordReset from './passwordReset';
|
|
||||||
import PromiseRouter from './PromiseRouter';
|
import PromiseRouter from './PromiseRouter';
|
||||||
|
import requiredParameter from './requiredParameter';
|
||||||
import { AnalyticsRouter } from './Routers/AnalyticsRouter';
|
import { AnalyticsRouter } from './Routers/AnalyticsRouter';
|
||||||
import { ClassesRouter } from './Routers/ClassesRouter';
|
import { ClassesRouter } from './Routers/ClassesRouter';
|
||||||
import { FeaturesRouter } from './Routers/FeaturesRouter';
|
import { FeaturesRouter } from './Routers/FeaturesRouter';
|
||||||
@@ -23,28 +24,27 @@ import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
|
|||||||
import { FilesController } from './Controllers/FilesController';
|
import { FilesController } from './Controllers/FilesController';
|
||||||
import { FilesRouter } from './Routers/FilesRouter';
|
import { FilesRouter } from './Routers/FilesRouter';
|
||||||
import { FunctionsRouter } from './Routers/FunctionsRouter';
|
import { FunctionsRouter } from './Routers/FunctionsRouter';
|
||||||
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
|
|
||||||
import { IAPValidationRouter } from './Routers/IAPValidationRouter';
|
|
||||||
import { LogsRouter } from './Routers/LogsRouter';
|
|
||||||
import { HooksRouter } from './Routers/HooksRouter';
|
|
||||||
import { PublicAPIRouter } from './Routers/PublicAPIRouter';
|
|
||||||
import { GlobalConfigRouter } from './Routers/GlobalConfigRouter';
|
import { GlobalConfigRouter } from './Routers/GlobalConfigRouter';
|
||||||
|
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
|
||||||
import { HooksController } from './Controllers/HooksController';
|
import { HooksController } from './Controllers/HooksController';
|
||||||
import { UserController } from './Controllers/UserController';
|
import { HooksRouter } from './Routers/HooksRouter';
|
||||||
|
import { IAPValidationRouter } from './Routers/IAPValidationRouter';
|
||||||
import { InstallationsRouter } from './Routers/InstallationsRouter';
|
import { InstallationsRouter } from './Routers/InstallationsRouter';
|
||||||
import { loadAdapter } from './Adapters/AdapterLoader';
|
import { loadAdapter } from './Adapters/AdapterLoader';
|
||||||
import { LoggerController } from './Controllers/LoggerController';
|
import { LoggerController } from './Controllers/LoggerController';
|
||||||
|
import { LogsRouter } from './Routers/LogsRouter';
|
||||||
|
import { PublicAPIRouter } from './Routers/PublicAPIRouter';
|
||||||
import { PushController } from './Controllers/PushController';
|
import { PushController } from './Controllers/PushController';
|
||||||
import { PushRouter } from './Routers/PushRouter';
|
import { PushRouter } from './Routers/PushRouter';
|
||||||
|
import { randomString } from './cryptoUtils';
|
||||||
import { RolesRouter } from './Routers/RolesRouter';
|
import { RolesRouter } from './Routers/RolesRouter';
|
||||||
import { S3Adapter } from './Adapters/Files/S3Adapter';
|
import { S3Adapter } from './Adapters/Files/S3Adapter';
|
||||||
import { SchemasRouter } from './Routers/SchemasRouter';
|
import { SchemasRouter } from './Routers/SchemasRouter';
|
||||||
import { SessionsRouter } from './Routers/SessionsRouter';
|
import { SessionsRouter } from './Routers/SessionsRouter';
|
||||||
|
import { setFeature } from './features';
|
||||||
|
import { UserController } from './Controllers/UserController';
|
||||||
import { UsersRouter } from './Routers/UsersRouter';
|
import { UsersRouter } from './Routers/UsersRouter';
|
||||||
|
|
||||||
import requiredParameter from './requiredParameter';
|
|
||||||
import { randomString } from './cryptoUtils';
|
|
||||||
// Mutate the Parse object to add the Cloud Code handlers
|
// Mutate the Parse object to add the Cloud Code handlers
|
||||||
addParseCloud();
|
addParseCloud();
|
||||||
|
|
||||||
@@ -106,11 +106,11 @@ function ParseServer({
|
|||||||
passwordResetSuccess: undefined
|
passwordResetSuccess: undefined
|
||||||
},
|
},
|
||||||
}) {
|
}) {
|
||||||
|
setFeature('serverVersion', parseServerPackage.version);
|
||||||
// Initialize the node client SDK automatically
|
// Initialize the node client SDK automatically
|
||||||
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
|
Parse.initialize(appId, javascriptKey || 'unused', masterKey);
|
||||||
Parse.serverURL = serverURL;
|
Parse.serverURL = serverURL;
|
||||||
|
|
||||||
if (databaseAdapter) {
|
if (databaseAdapter) {
|
||||||
DatabaseAdapter.setAdapter(databaseAdapter);
|
DatabaseAdapter.setAdapter(databaseAdapter);
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ function ParseServer({
|
|||||||
const hooksController = new HooksController(appId, collectionPrefix);
|
const hooksController = new HooksController(appId, collectionPrefix);
|
||||||
const userController = new UserController(emailControllerAdapter, appId, { verifyUserEmails });
|
const userController = new UserController(emailControllerAdapter, appId, { verifyUserEmails });
|
||||||
|
|
||||||
|
|
||||||
cache.apps.set(appId, {
|
cache.apps.set(appId, {
|
||||||
masterKey: masterKey,
|
masterKey: masterKey,
|
||||||
serverURL: serverURL,
|
serverURL: serverURL,
|
||||||
@@ -173,7 +173,7 @@ function ParseServer({
|
|||||||
if (process.env.FACEBOOK_APP_ID) {
|
if (process.env.FACEBOOK_APP_ID) {
|
||||||
cache.apps.get(appId)['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
|
cache.apps.get(appId)['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.validate(cache.apps.get(appId));
|
Config.validate(cache.apps.get(appId));
|
||||||
|
|
||||||
// This app serves the Parse API directly.
|
// This app serves the Parse API directly.
|
||||||
@@ -186,7 +186,7 @@ function ParseServer({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
api.use('/', bodyParser.urlencoded({extended: false}), new PublicAPIRouter().expressApp());
|
api.use('/', bodyParser.urlencoded({extended: false}), new PublicAPIRouter().expressApp());
|
||||||
|
|
||||||
// TODO: separate this from the regular ParseServer object
|
// TODO: separate this from the regular ParseServer object
|
||||||
if (process.env.TESTING == 1) {
|
if (process.env.TESTING == 1) {
|
||||||
api.use('/', require('./testing-routes').router);
|
api.use('/', require('./testing-routes').router);
|
||||||
@@ -215,17 +215,17 @@ function ParseServer({
|
|||||||
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
|
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
|
||||||
routers.push(new GlobalConfigRouter());
|
routers.push(new GlobalConfigRouter());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
|
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
|
||||||
routers.push(new HooksRouter());
|
routers.push(new HooksRouter());
|
||||||
}
|
}
|
||||||
|
|
||||||
let routes = routers.reduce((memo, router) => {
|
let routes = routers.reduce((memo, router) => {
|
||||||
return memo.concat(router.routes);
|
return memo.concat(router.routes);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
let appRouter = new PromiseRouter(routes);
|
let appRouter = new PromiseRouter(routes);
|
||||||
|
|
||||||
batch.mountOnto(appRouter);
|
batch.mountOnto(appRouter);
|
||||||
|
|
||||||
api.use(appRouter.expressApp());
|
api.use(appRouter.expressApp());
|
||||||
|
|||||||
Reference in New Issue
Block a user