Merge pull request #748 from drew-gross/touch-up-features-endpoint

Touch up features endpoint
This commit is contained in:
Drew
2016-03-02 16:43:12 -08:00
5 changed files with 62 additions and 61 deletions

View File

@@ -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',

View File

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

View File

@@ -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,
} };
}); });
} }
} }

View File

@@ -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];
} }
}); });

View File

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