Skip to content

Commit 72e6eae

Browse files
committed
Merge pull request #739 from ParsePlatform/peterjs.featuresEndpoint
Features Endpoint for Dashboard.
2 parents 750a579 + 66eaf6c commit 72e6eae

File tree

7 files changed

+184
-2
lines changed

7 files changed

+184
-2
lines changed

spec/features.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var features = require('../src/features')
2+
3+
describe('features', () => {
4+
it('set and get features', (done) => {
5+
features.setFeature('users', {
6+
testOption1: true,
7+
testOption2: false
8+
});
9+
10+
var _features = features.getFeatures();
11+
12+
var expected = {
13+
testOption1: true,
14+
testOption2: false
15+
};
16+
17+
expect(_features.users).toEqual(expected);
18+
done();
19+
});
20+
21+
it('get features that does not exist', (done) => {
22+
var _features = features.getFeatures();
23+
expect(_features.test).toBeUndefined();
24+
done();
25+
});
26+
});

src/Adapters/Push/ParsePushAdapter.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export class ParsePushAdapter extends PushAdapter {
1414
super(pushConfig);
1515
this.validPushTypes = ['ios', 'android'];
1616
this.senderMap = {};
17+
// used in PushController for Dashboard Features
18+
this.feature = {
19+
immediatePush: true
20+
};
1721
let pushTypes = Object.keys(pushConfig);
1822

1923
for (let pushType of pushTypes) {

src/Controllers/AdaptableController.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ export class AdaptableController {
1818
this.options = options;
1919
this.appId = appId;
2020
this.adapter = adapter;
21+
this.setFeature();
2122
}
2223

24+
// sets features for Dashboard to consume from features router
25+
setFeature() {}
26+
2327
set adapter(adapter) {
2428
this.validateAdapter(adapter);
2529
this[_adapter] = adapter;
@@ -67,4 +71,4 @@ export class AdaptableController {
6771
}
6872
}
6973

70-
export default AdaptableController;
74+
export default AdaptableController;

src/Controllers/PushController.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@ import PromiseRouter from '../PromiseRouter';
33
import rest from '../rest';
44
import AdaptableController from './AdaptableController';
55
import { PushAdapter } from '../Adapters/Push/PushAdapter';
6+
import features from '../features';
7+
8+
const FEATURE_NAME = 'push';
69

710
export class PushController extends AdaptableController {
811

12+
setFeature() {
13+
features.setFeature(FEATURE_NAME, this.adapter.feature || {});
14+
}
15+
916
/**
1017
* Check whether the deviceType parameter in qury condition is valid or not.
1118
* @param {Object} where A query condition

src/Routers/FeaturesRouter.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import PromiseRouter from '../PromiseRouter';
2+
import {getFeatures} from '../features';
3+
4+
let masterKeyRequiredResponse = () => {
5+
return Promise.resolve({
6+
status: 401,
7+
response: {error: 'master key not specified'},
8+
})
9+
}
10+
11+
export class FeaturesRouter extends PromiseRouter {
12+
13+
mountRoutes() {
14+
this.route('GET','/features', (req) => {
15+
return this.handleGET(req);
16+
});
17+
}
18+
19+
handleGET(req) {
20+
if (!req.auth.isMaster) {
21+
return masterKeyRequiredResponse();
22+
}
23+
24+
return Promise.resolve({
25+
response: {
26+
results: [getFeatures()]
27+
}
28+
});
29+
}
30+
}
31+
32+
export default FeaturesRouter;

src/features.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* features.js
3+
* Feature config file that holds information on the features that are currently
4+
* available on Parse Server. This is primarily created to work with an UI interface
5+
* like the web dashboard. The list of features will change depending on the your
6+
* app, choice of adapter as well as Parse Server version. This approach will enable
7+
* the dashboard to be built independently and still support these use cases.
8+
*
9+
*
10+
* Default features and feature options are listed in the features object.
11+
*
12+
* featureSwitch is a convenient way to turn on/off features without changing the config
13+
*
14+
* Features that use Adapters should specify the feature options through
15+
* the setFeature method in your controller and feature
16+
* Reference PushController and ParsePushAdapter as an example.
17+
*
18+
* NOTE: When adding new endpoints be sure to update this list both (features, featureSwitch)
19+
* if you are planning to have a UI consume it.
20+
*/
21+
22+
// default features
23+
let features = {
24+
analytics: {
25+
slowQueries: false,
26+
performanceAnalysis: false,
27+
retentionAnalysis: false,
28+
},
29+
classes: {},
30+
files: {},
31+
functions: {},
32+
globalConfig: {
33+
create: true,
34+
read: true,
35+
update: true,
36+
delete: true,
37+
},
38+
hooks: {
39+
create: false,
40+
read: false,
41+
update: false,
42+
delete: false,
43+
},
44+
iapValidation: {},
45+
installations: {},
46+
logs: {
47+
info: true,
48+
error: true,
49+
},
50+
publicAPI: {},
51+
push: {},
52+
roles: {},
53+
schemas: {
54+
addField: true,
55+
removeField: true,
56+
addClass: true,
57+
removeClass: true,
58+
clearAllDataFromClass: false,
59+
exportClass: false,
60+
},
61+
sessions: {},
62+
users: {},
63+
};
64+
65+
// master switch for features
66+
let featuresSwitch = {
67+
analytics: true,
68+
classes: true,
69+
files: true,
70+
functions: true,
71+
globalConfig: true,
72+
hooks: true,
73+
iapValidation: true,
74+
installations: true,
75+
logs: true,
76+
publicAPI: true,
77+
push: true,
78+
roles: true,
79+
schemas: true,
80+
sessions: true,
81+
users: true,
82+
};
83+
84+
/**
85+
* set feature config options
86+
*/
87+
function setFeature(key, value) {
88+
features[key] = value;
89+
}
90+
91+
/**
92+
* get feature config options
93+
*/
94+
function getFeatures() {
95+
let result = {};
96+
Object.keys(features).forEach((key) => {
97+
if (featuresSwitch[key]) {
98+
result[key] = features[key];
99+
}
100+
});
101+
return result;
102+
}
103+
104+
module.exports = {
105+
getFeatures,
106+
setFeature,
107+
};

src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
1818
import PromiseRouter from './PromiseRouter';
1919
import { AnalyticsRouter } from './Routers/AnalyticsRouter';
2020
import { ClassesRouter } from './Routers/ClassesRouter';
21+
import { FeaturesRouter } from './Routers/FeaturesRouter';
2122
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
2223
import { FilesController } from './Controllers/FilesController';
2324
import { FilesRouter } from './Routers/FilesRouter';
@@ -207,7 +208,8 @@ function ParseServer({
207208
new SchemasRouter(),
208209
new PushRouter(),
209210
new LogsRouter(),
210-
new IAPValidationRouter()
211+
new IAPValidationRouter(),
212+
new FeaturesRouter(),
211213
];
212214

213215
if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) {

0 commit comments

Comments
 (0)