Features Endpoint for Dashboard.
This commit is contained in:
26
spec/features.spec.js
Normal file
26
spec/features.spec.js
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -14,6 +14,10 @@ export class ParsePushAdapter extends PushAdapter {
|
|||||||
super(pushConfig);
|
super(pushConfig);
|
||||||
this.validPushTypes = ['ios', 'android'];
|
this.validPushTypes = ['ios', 'android'];
|
||||||
this.senderMap = {};
|
this.senderMap = {};
|
||||||
|
// used in PushController for Dashboard Features
|
||||||
|
this.feature = {
|
||||||
|
immediatePush: true
|
||||||
|
};
|
||||||
let pushTypes = Object.keys(pushConfig);
|
let pushTypes = Object.keys(pushConfig);
|
||||||
|
|
||||||
for (let pushType of pushTypes) {
|
for (let pushType of pushTypes) {
|
||||||
|
|||||||
@@ -18,8 +18,12 @@ export class AdaptableController {
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
|
this.setFeature();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sets features for Dashboard to consume from features router
|
||||||
|
setFeature() {}
|
||||||
|
|
||||||
set adapter(adapter) {
|
set adapter(adapter) {
|
||||||
this.validateAdapter(adapter);
|
this.validateAdapter(adapter);
|
||||||
this[_adapter] = adapter;
|
this[_adapter] = adapter;
|
||||||
@@ -67,4 +71,4 @@ export class AdaptableController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdaptableController;
|
export default AdaptableController;
|
||||||
|
|||||||
@@ -3,9 +3,16 @@ import PromiseRouter from '../PromiseRouter';
|
|||||||
import rest from '../rest';
|
import rest from '../rest';
|
||||||
import AdaptableController from './AdaptableController';
|
import AdaptableController from './AdaptableController';
|
||||||
import { PushAdapter } from '../Adapters/Push/PushAdapter';
|
import { PushAdapter } from '../Adapters/Push/PushAdapter';
|
||||||
|
import features from '../features';
|
||||||
|
|
||||||
|
const FEATURE_NAME = 'push';
|
||||||
|
|
||||||
export class PushController extends AdaptableController {
|
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.
|
* Check whether the deviceType parameter in qury condition is valid or not.
|
||||||
* @param {Object} where A query condition
|
* @param {Object} where A query condition
|
||||||
|
|||||||
32
src/Routers/FeaturesRouter.js
Normal file
32
src/Routers/FeaturesRouter.js
Normal 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
107
src/features.js
Normal 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,
|
||||||
|
};
|
||||||
@@ -18,6 +18,7 @@ import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
|
|||||||
import PromiseRouter from './PromiseRouter';
|
import PromiseRouter from './PromiseRouter';
|
||||||
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 { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
|
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';
|
||||||
@@ -207,7 +208,8 @@ function ParseServer({
|
|||||||
new SchemasRouter(),
|
new SchemasRouter(),
|
||||||
new PushRouter(),
|
new PushRouter(),
|
||||||
new LogsRouter(),
|
new LogsRouter(),
|
||||||
new IAPValidationRouter()
|
new IAPValidationRouter(),
|
||||||
|
new FeaturesRouter(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
|
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {
|
||||||
|
|||||||
Reference in New Issue
Block a user