diff --git a/spec/ParsePushAdapter.spec.js b/spec/ParsePushAdapter.spec.js index ca0da190..1f860a90 100644 --- a/spec/ParsePushAdapter.spec.js +++ b/spec/ParsePushAdapter.spec.js @@ -2,14 +2,6 @@ var ParsePushAdapter = require('../src/Adapters/Push/ParsePushAdapter'); describe('ParsePushAdapter', () => { it('can be initialized', (done) => { - var parsePushAdapter = new ParsePushAdapter(); - - expect(parsePushAdapter.validPushTypes).toEqual(['ios', 'android']); - done(); - }); - - it('can initialize', (done) => { - var parsePushAdapter = new ParsePushAdapter(); // Make mock config var pushConfig = { android: { @@ -30,7 +22,7 @@ describe('ParsePushAdapter', () => { ] }; - parsePushAdapter.initialize(pushConfig); + var parsePushAdapter = new ParsePushAdapter(pushConfig); // Check ios var iosSenders = parsePushAdapter.senders['ios']; expect(iosSenders.length).toBe(2); @@ -53,7 +45,6 @@ describe('ParsePushAdapter', () => { }); it('can throw on initializing with unsupported push type', (done) => { - var parsePushAdapter = new ParsePushAdapter(); // Make mock config var pushConfig = { win: { @@ -63,20 +54,19 @@ describe('ParsePushAdapter', () => { }; expect(function() { - parsePushAdapter.initialize(pushConfig) + new ParsePushAdapter(pushConfig); }).toThrow(); done(); }); it('can throw on initializing with invalid pushConfig', (done) => { - var parsePushAdapter = new ParsePushAdapter(); // Make mock config var pushConfig = { android: 123 }; expect(function() { - parsePushAdapter.initialize(pushConfig) + new ParsePushAdapter(pushConfig); }).toThrow(); done(); }); diff --git a/spec/push.spec.js b/spec/PushController.spec.js similarity index 80% rename from spec/push.spec.js rename to spec/PushController.spec.js index ba7588f3..5414eca2 100644 --- a/spec/push.spec.js +++ b/spec/PushController.spec.js @@ -1,6 +1,6 @@ -var push = require('../src/push'); +var PushController = require('../src/Controllers/PushController').PushController; -describe('push', () => { +describe('PushController', () => { it('can check valid master key of request', (done) => { // Make mock request var request = { @@ -13,7 +13,7 @@ describe('push', () => { } expect(() => { - push.validateMasterKey(request); + PushController.validateMasterKey(request); }).not.toThrow(); done(); }); @@ -30,7 +30,7 @@ describe('push', () => { } expect(() => { - push.validateMasterKey(request); + PushController.validateMasterKey(request); }).toThrow(); done(); }); @@ -43,7 +43,7 @@ describe('push', () => { } } - var where = push.getQueryCondition(request); + var where = PushController.getQueryCondition(request); expect(where).toEqual({ 'channels': { '$in': ['Giants', 'Mets'] @@ -62,7 +62,7 @@ describe('push', () => { } } - var where = push.getQueryCondition(request); + var where = PushController.getQueryCondition(request); expect(where).toEqual({ 'injuryReports': true }); @@ -77,7 +77,7 @@ describe('push', () => { } expect(function() { - push.getQueryCondition(request); + PushController.getQueryCondition(request); }).toThrow(); done(); }); @@ -96,7 +96,7 @@ describe('push', () => { } expect(function() { - push.getQueryCondition(request); + PushController.getQueryCondition(request); }).toThrow(); done(); }); @@ -108,7 +108,7 @@ describe('push', () => { var validPushTypes = ['ios', 'android']; expect(function(){ - push.validatePushType(where, validPushTypes); + PushController.validatePushType(where, validPushTypes); }).not.toThrow(); done(); }); @@ -121,7 +121,7 @@ describe('push', () => { var validPushTypes = ['ios', 'android']; expect(function(){ - push.validatePushType(where, validPushTypes); + PushController.validatePushType(where, validPushTypes); }).not.toThrow(); done(); }); @@ -136,7 +136,7 @@ describe('push', () => { var validPushTypes = ['ios', 'android']; expect(function(){ - push.validatePushType(where, validPushTypes); + PushController.validatePushType(where, validPushTypes); }).not.toThrow(); done(); }); @@ -149,7 +149,7 @@ describe('push', () => { var validPushTypes = ['ios', 'android']; expect(function(){ - push.validatePushType(where, validPushTypes); + PushController.validatePushType(where, validPushTypes); }).toThrow(); done(); }); @@ -162,7 +162,7 @@ describe('push', () => { var validPushTypes = ['ios', 'android']; expect(function(){ - push.validatePushType(where, validPushTypes); + PushController.validatePushType(where, validPushTypes); }).toThrow(); done(); }); @@ -176,7 +176,7 @@ describe('push', () => { } } - var time = push.getExpirationTime(request); + var time = PushController.getExpirationTime(request); expect(time).toEqual(new Date(timeStr).valueOf()); done(); }); @@ -190,7 +190,7 @@ describe('push', () => { } } - var time = push.getExpirationTime(request); + var time = PushController.getExpirationTime(request); expect(time).toEqual(timeNumber * 1000); done(); }); @@ -204,7 +204,7 @@ describe('push', () => { } expect(function(){ - push.getExpirationTime(request); + PushController.getExpirationTime(request); }).toThrow(); done(); }); diff --git a/src/Adapters/Push/ParsePushAdapter.js b/src/Adapters/Push/ParsePushAdapter.js index 55b99032..43987bc5 100644 --- a/src/Adapters/Push/ParsePushAdapter.js +++ b/src/Adapters/Push/ParsePushAdapter.js @@ -7,16 +7,10 @@ const Parse = require('parse/node').Parse; const GCM = require('../../GCM'); const APNS = require('../../APNS'); -function ParsePushAdapter() { - this.validPushTypes = ['ios', 'android']; - this.senders = {}; -} +function ParsePushAdapter(pushConfig) { + this.validPushTypes = ['ios', 'android']; + this.senders = {}; -/** - * Register push senders - * @param {Object} pushConfig The push configuration which is given when parse server is initialized - */ -ParsePushAdapter.prototype.initialize = function(pushConfig) { // Initialize senders for (let validPushType of this.validPushTypes) { this.senders[validPushType] = []; diff --git a/src/Adapters/Push/PushAdapter.js b/src/Adapters/Push/PushAdapter.js index ab2f7133..1e07467f 100644 --- a/src/Adapters/Push/PushAdapter.js +++ b/src/Adapters/Push/PushAdapter.js @@ -3,27 +3,15 @@ // Allows you to change the push notification mechanism. // // Adapter classes must implement the following functions: -// * initialize(pushConfig) -// * getPushSenders(parseConfig) -// * getValidPushTypes(parseConfig) +// * getValidPushTypes() // * send(devices, installations) // // Default is ParsePushAdapter, which uses GCM for // android push and APNS for ios push. +export class PushAdapter { + send(devices, installations) { } -var ParsePushAdapter = require('./ParsePushAdapter'); - -var adapter = new ParsePushAdapter(); - -function setAdapter(pushAdapter) { - adapter = pushAdapter; + getValidPushTypes() { } } -function getAdapter() { - return adapter; -} - -module.exports = { - getAdapter: getAdapter, - setAdapter: setAdapter -}; +export default PushAdapter; diff --git a/src/push.js b/src/Controllers/PushController.js similarity index 67% rename from src/push.js rename to src/Controllers/PushController.js index 013b85d4..9f9252dc 100644 --- a/src/push.js +++ b/src/Controllers/PushController.js @@ -1,27 +1,44 @@ -// push.js +import { Parse } from 'parse/node'; +import PromiseRouter from '../PromiseRouter'; +import rest from '../rest'; -var Parse = require('parse/node').Parse, - PromiseRouter = require('./PromiseRouter'), - PushAdapter = require('./Adapters/Push/PushAdapter'), - rest = require('./rest'); +export class PushController { -function handlePushWithoutQueue(req) { - validateMasterKey(req); - var where = getQueryCondition(req); - var pushAdapter = PushAdapter.getAdapter(); - validatePushType(where, pushAdapter.getValidPushTypes()); - // Replace the expiration_time with a valid Unix epoch milliseconds time - req.body['expiration_time'] = getExpirationTime(req); - // TODO: If the req can pass the checking, we return immediately instead of waiting - // pushes to be sent. We probably change this behaviour in the future. - rest.find(req.config, req.auth, '_Installation', where).then(function(response) { - return pushAdapter.send(req.body, response.results); - }); - return Parse.Promise.as({ - response: { - 'result': true - } - }); + constructor(pushAdapter) { + this._pushAdapter = pushAdapter; + } + + handlePOST(req) { + if (!this._pushAdapter) { + throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED, + 'Push adapter is not availabe'); + } + + validateMasterKey(req); + var where = getQueryCondition(req); + var pushAdapter = this._pushAdapter; + validatePushType(where, pushAdapter.getValidPushTypes()); + // Replace the expiration_time with a valid Unix epoch milliseconds time + req.body['expiration_time'] = getExpirationTime(req); + // TODO: If the req can pass the checking, we return immediately instead of waiting + // pushes to be sent. We probably change this behaviour in the future. + rest.find(req.config, req.auth, '_Installation', where).then(function(response) { + return pushAdapter.send(req.body, response.results); + }); + return Parse.Promise.as({ + response: { + 'result': true + } + }); + } + + getExpressRouter() { + var router = new PromiseRouter(); + router.route('POST','/push', (req) => { + return this.handlePOST(req); + }); + return router; + } } /** @@ -116,16 +133,11 @@ function validateMasterKey(req) { } } -var router = new PromiseRouter(); -router.route('POST','/push', handlePushWithoutQueue); - -module.exports = { - router: router, -} - if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { - module.exports.getQueryCondition = getQueryCondition; - module.exports.validateMasterKey = validateMasterKey; - module.exports.getExpirationTime = getExpirationTime; - module.exports.validatePushType = validatePushType; + PushController.getQueryCondition = getQueryCondition; + PushController.validateMasterKey = validateMasterKey; + PushController.getExpirationTime = getExpirationTime; + PushController.validatePushType = validatePushType; } + +export default PushController; diff --git a/src/index.js b/src/index.js index 1bc02dc7..16c15098 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,6 @@ var batch = require('./batch'), cache = require('./cache'), DatabaseAdapter = require('./DatabaseAdapter'), express = require('express'), - PushAdapter = require('./Adapters/Push/PushAdapter'), middlewares = require('./middlewares'), multer = require('multer'), Parse = require('parse/node').Parse, @@ -14,9 +13,12 @@ var batch = require('./batch'), import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter'; import { S3Adapter } from './Adapters/Files/S3Adapter'; - import { FilesController } from './Controllers/FilesController'; +import ParsePushAdapter from './Adapters/Push/ParsePushAdapter'; +import { PushController } from './Controllers/PushController'; + + // Mutate the Parse object to add the Cloud Code handlers addParseCloud(); @@ -42,6 +44,8 @@ addParseCloud(); // "dotNetKey": optional key from Parse dashboard // "restAPIKey": optional key from Parse dashboard // "javascriptKey": optional key from Parse dashboard +// "push": optional key from configure push + function ParseServer(args) { if (!args.appId || !args.masterKey) { throw 'You must provide an appId and masterKey!'; @@ -51,8 +55,18 @@ function ParseServer(args) { DatabaseAdapter.setAdapter(args.databaseAdapter); } + // Make files adapter let filesAdapter = args.filesAdapter || new GridStoreAdapter(); + // Make push adapter + let pushConfig = args.push; + let pushAdapter; + if (pushConfig && pushConfig.adapter) { + pushAdapter = pushConfig.adapter; + } else if (pushConfig) { + pushAdapter = new ParsePushAdapter(pushConfig) + } + if (args.databaseURI) { DatabaseAdapter.setAppDatabaseURI(args.appId, args.databaseURI); } @@ -87,10 +101,6 @@ function ParseServer(args) { cache.apps[args.appId]['facebookAppIds'].push(process.env.FACEBOOK_APP_ID); } - // Register push senders - var pushConfig = args.push; - PushAdapter.getAdapter().initialize(pushConfig); - // Initialize the node client SDK automatically Parse.initialize(args.appId, args.javascriptKey || '', args.masterKey); if(args.serverURL) { @@ -122,13 +132,14 @@ function ParseServer(args) { router.merge(require('./sessions')); router.merge(require('./roles')); router.merge(require('./analytics')); - router.merge(require('./push').router); router.merge(require('./installations')); router.merge(require('./functions')); router.merge(require('./schemas')); if (process.env.PARSE_EXPERIMENTAL_CONFIG_ENABLED || process.env.TESTING) { router.merge(require('./global_config')); } + let pushController = new PushController(pushAdapter); + router.merge(pushController.getExpressRouter()); batch.mountOnto(router);