Merge pull request #739 from ParsePlatform/peterjs.featuresEndpoint

Features Endpoint for Dashboard.
This commit is contained in:
Drew
2016-03-01 15:08:15 -08:00
7 changed files with 184 additions and 2 deletions

26
spec/features.spec.js Normal file
View File

@@ -0,0 +1,26 @@
var features = require('../src/features')
describe('features', () => {
it('set and get features', (done) => {
features.setFeature('users', {
testOption1: true,
testOption2: false
});
var _features = features.getFeatures();
var expected = {
testOption1: true,
testOption2: false
};
expect(_features.users).toEqual(expected);
done();
});
it('get features that does not exist', (done) => {
var _features = features.getFeatures();
expect(_features.test).toBeUndefined();
done();
});
});

View File

@@ -14,6 +14,10 @@ export class ParsePushAdapter extends PushAdapter {
super(pushConfig);
this.validPushTypes = ['ios', 'android'];
this.senderMap = {};
// used in PushController for Dashboard Features
this.feature = {
immediatePush: true
};
let pushTypes = Object.keys(pushConfig);
for (let pushType of pushTypes) {

View File

@@ -18,8 +18,12 @@ export class AdaptableController {
this.options = options;
this.appId = appId;
this.adapter = adapter;
this.setFeature();
}
// sets features for Dashboard to consume from features router
setFeature() {}
set adapter(adapter) {
this.validateAdapter(adapter);
this[_adapter] = adapter;
@@ -67,4 +71,4 @@ export class AdaptableController {
}
}
export default AdaptableController;
export default AdaptableController;

View File

@@ -3,9 +3,16 @@ import PromiseRouter from '../PromiseRouter';
import rest from '../rest';
import AdaptableController from './AdaptableController';
import { PushAdapter } from '../Adapters/Push/PushAdapter';
import features from '../features';
const FEATURE_NAME = 'push';
export class PushController extends AdaptableController {
setFeature() {
features.setFeature(FEATURE_NAME, this.adapter.feature || {});
}
/**
* Check whether the deviceType parameter in qury condition is valid or not.
* @param {Object} where A query condition

View File

@@ -0,0 +1,32 @@
import PromiseRouter from '../PromiseRouter';
import {getFeatures} from '../features';
let masterKeyRequiredResponse = () => {
return Promise.resolve({
status: 401,
response: {error: 'master key not specified'},
})
}
export class FeaturesRouter extends PromiseRouter {
mountRoutes() {
this.route('GET','/features', (req) => {
return this.handleGET(req);
});
}
handleGET(req) {
if (!req.auth.isMaster) {
return masterKeyRequiredResponse();
}
return Promise.resolve({
response: {
results: [getFeatures()]
}
});
}
}
export default FeaturesRouter;

107
src/features.js Normal file
View File

@@ -0,0 +1,107 @@
/**
* features.js
* Feature config file that holds information on the features that are currently
* available on Parse Server. This is primarily created to work with an UI interface
* like the web dashboard. The list of features will change depending on the your
* app, choice of adapter as well as Parse Server version. This approach will enable
* the dashboard to be built independently and still support these use cases.
*
*
* Default features and feature options are listed in the features object.
*
* featureSwitch is a convenient way to turn on/off features without changing the config
*
* Features that use Adapters should specify the feature options through
* the setFeature method in your controller and feature
* Reference PushController and ParsePushAdapter as an example.
*
* NOTE: When adding new endpoints be sure to update this list both (features, featureSwitch)
* if you are planning to have a UI consume it.
*/
// default features
let features = {
analytics: {
slowQueries: false,
performanceAnalysis: false,
retentionAnalysis: false,
},
classes: {},
files: {},
functions: {},
globalConfig: {
create: true,
read: true,
update: true,
delete: true,
},
hooks: {
create: false,
read: false,
update: false,
delete: false,
},
iapValidation: {},
installations: {},
logs: {
info: true,
error: true,
},
publicAPI: {},
push: {},
roles: {},
schemas: {
addField: true,
removeField: true,
addClass: true,
removeClass: true,
clearAllDataFromClass: false,
exportClass: false,
},
sessions: {},
users: {},
};
// master switch for features
let featuresSwitch = {
analytics: true,
classes: true,
files: true,
functions: true,
globalConfig: true,
hooks: true,
iapValidation: true,
installations: true,
logs: true,
publicAPI: true,
push: true,
roles: true,
schemas: true,
sessions: true,
users: true,
};
/**
* set feature config options
*/
function setFeature(key, value) {
features[key] = value;
}
/**
* get feature config options
*/
function getFeatures() {
let result = {};
Object.keys(features).forEach((key) => {
if (featuresSwitch[key]) {
result[key] = features[key];
}
});
return result;
}
module.exports = {
getFeatures,
setFeature,
};

View File

@@ -18,6 +18,7 @@ import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
import PromiseRouter from './PromiseRouter';
import { AnalyticsRouter } from './Routers/AnalyticsRouter';
import { ClassesRouter } from './Routers/ClassesRouter';
import { FeaturesRouter } from './Routers/FeaturesRouter';
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
import { FilesController } from './Controllers/FilesController';
import { FilesRouter } from './Routers/FilesRouter';
@@ -207,7 +208,8 @@ function ParseServer({
new SchemasRouter(),
new PushRouter(),
new LogsRouter(),
new IAPValidationRouter()
new IAPValidationRouter(),
new FeaturesRouter(),
];
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {